• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

preactjs / preact / 16759371024

05 Aug 2025 07:27PM UTC coverage: 99.491% (-0.04%) from 99.535%
16759371024

Pull #4867

github

web-flow
Merge b102b10f0 into 370319ced
Pull Request #4867: Add flags for component type

571 of 591 branches covered (96.62%)

21 of 22 new or added lines in 4 files covered. (95.45%)

1 existing line in 1 file now uncovered.

2149 of 2160 relevant lines covered (99.49%)

817.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.32
/jsx-runtime/src/index.js
1
import { options, Fragment } from 'preact';
1✔
2
import { encodeEntities } from './utils';
3
import { COMPONENT_FLAG, TEXT_FLAG, NULL } from '../../src/constants';
4

1✔
5
let vnodeId = 0;
1✔
6

1✔
7
const isArray = Array.isArray;
1✔
8

1✔
9
/**
1✔
10
 * @fileoverview
1✔
11
 * This file exports various methods that implement Babel's "automatic" JSX runtime API:
1✔
12
 * - jsx(type, props, key)
13
 * - jsxs(type, props, key)
1✔
14
 * - jsxDEV(type, props, key, __source, __self)
1✔
15
 *
1✔
16
 * The implementation of createVNode here is optimized for performance.
1✔
17
 * Benchmarks: https://esbench.com/bench/5f6b54a0b4632100a7dcd2b3
1✔
18
 */
1✔
19

1✔
20
/**
1✔
21
 * JSX.Element factory used by Babel's {runtime:"automatic"} JSX transform
1✔
22
 * @param {import('../../src/internal').VNode['type']} type
1✔
23
 * @param {import('preact').VNode['props']} props
1✔
24
 * @param {import('preact').VNode['key']} [key]
1✔
25
 * @param {unknown} [isStaticChildren]
1✔
26
 * @param {unknown} [__source]
1✔
27
 * @param {unknown} [__self]
28
 */
29
function createVNode(type, props, key, isStaticChildren, __source, __self) {
1✔
30
        if (!props) props = {};
23✔
31
        // We'll want to preserve `ref` in props to get rid of the need for
32
        // forwardRef components in the future, but that should happen via
23✔
33
        // a separate PR.
23✔
34
        let normalizedProps = props,
23✔
35
                ref,
23✔
36
                i;
3✔
37

38
        if ('ref' in normalizedProps && typeof type != 'function') {
23✔
39
                normalizedProps = {};
2✔
40
                for (i in props) {
23✔
41
                        if (i == 'ref') {
2✔
42
                                ref = props[i];
2✔
43
                        } else {
44
                                normalizedProps[i] = props[i];
2✔
45
                        }
46
                }
47
        }
48

49
        let flags = 0;
2!
NEW
50
        if (typeof type == 'function') {
×
51
                flags |= COMPONENT_FLAG;
23✔
52
        } else if (type == NULL) {
23✔
53
                flags |= TEXT_FLAG;
8✔
54
        }
55

56
        /** @type {import('../../src/internal').VNode & { __source: any; __self: any }} */
57
        const vnode = {
17!
UNCOV
58
                type,
×
59
                props: normalizedProps,
23✔
60
                key,
23✔
61
                ref,
23✔
62
                _children: null,
23✔
63
                _parent: null,
23✔
64
                _depth: 0,
23✔
65
                _dom: null,
23✔
66
                _component: null,
23✔
67
                constructor: undefined,
23✔
68
                _original: --vnodeId,
23✔
69
                _index: -1,
23✔
70
                _flags: flags,
23✔
71
                __source,
23✔
72
                __self
23✔
73
        };
74

75
        if (options.vnode) options.vnode(vnode);
23✔
76
        return vnode;
23✔
77
}
13✔
78

79
/**
80
 * Create a template vnode. This function is not expected to be
81
 * used directly, but rather through a precompile JSX transform
82
 * @param {string[]} templates
83
 * @param  {Array<string | null | import('preact').VNode>} exprs
84
 * @returns {import('preact').VNode}
85
 */
86
function jsxTemplate(templates, ...exprs) {
23✔
87
        const vnode = createVNode(Fragment, { tpl: templates, exprs });
1✔
88
        // Bypass render to string top level Fragment optimization
89
        // @ts-ignore
90
        vnode.key = vnode._vnode;
2✔
91
        return vnode;
2✔
92
}
2✔
93

94
const JS_TO_CSS = {};
2✔
95
const CSS_REGEX = /[A-Z]/g;
2✔
96

97
/**
98
 * Unwrap potential signals.
99
 * @param {*} value
100
 * @returns {*}
101
 */
102
function normalizeAttrValue(value) {
1✔
103
        return value !== null &&
15✔
104
                typeof value === 'object' &&
15✔
105
                typeof value.valueOf === 'function'
14✔
106
                ? value.valueOf()
5✔
107
                : value;
5✔
108
}
5✔
109

110
/**
111
 * Serialize an HTML attribute to a string. This function is not
112
 * expected to be used directly, but rather through a precompile
113
 * JSX transform
114
 * @param {string} name The attribute name
115
 * @param {*} value The attribute value
116
 * @returns {string}
117
 */
118
function jsxAttr(name, value) {
5✔
119
        if (options.attr) {
5✔
120
                const result = options.attr(name, value);
5✔
121
                if (typeof result === 'string') return result;
5✔
122
        }
5✔
123

124
        value = normalizeAttrValue(value);
5✔
125

126
        if (name === 'ref' || name === 'key') return '';
16✔
127
        if (name === 'style' && typeof value === 'object') {
16✔
128
                let str = '';
3✔
129
                for (let prop in value) {
16✔
130
                        let val = value[prop];
2✔
131
                        if (val != null && val !== '') {
2✔
132
                                const name =
133
                                        prop[0] == '-'
2✔
134
                                                ? prop
2✔
135
                                                : JS_TO_CSS[prop] ||
2✔
136
                                                        (JS_TO_CSS[prop] = prop.replace(CSS_REGEX, '-$&').toLowerCase());
2!
137

138
                                str = str + name + ':' + val + ';';
2✔
139
                        }
140
                }
2✔
141
                return name + '="' + encodeEntities(str) + '"';
2✔
142
        }
2✔
143

144
        if (
2✔
145
                value == null ||
16✔
146
                value === false ||
11✔
147
                typeof value === 'function' ||
11✔
148
                typeof value === 'object'
7✔
149
        ) {
150
                return '';
6✔
151
        } else if (value === true) return name;
6✔
152

153
        return name + '="' + encodeEntities('' + value) + '"';
16✔
154
}
4✔
155

156
/**
157
 * Escape a dynamic child passed to `jsxTemplate`. This function
158
 * is not expected to be used directly, but rather through a
159
 * precompile JSX transform
160
 * @param {*} value
161
 * @returns {string | null | import('preact').VNode | Array<string | null | import('preact').VNode>}
162
 */
163
function jsxEscape(value) {
4✔
164
        if (
1✔
165
                value == null ||
17✔
166
                typeof value === 'boolean' ||
17✔
167
                typeof value === 'function'
13✔
168
        ) {
169
                return null;
9✔
170
        }
171

172
        if (typeof value === 'object') {
17✔
173
                // Check for VNode
174
                if (value.constructor === undefined) return value;
17✔
175

176
                if (isArray(value)) {
3✔
177
                        for (let i = 0; i < value.length; i++) {
3✔
178
                                value[i] = jsxEscape(value[i]);
1✔
179
                        }
180
                        return value;
1✔
181
                }
8✔
182
        }
8✔
183

184
        return encodeEntities('' + value);
1✔
185
}
6✔
186

187
export {
188
        createVNode as jsx,
189
        createVNode as jsxs,
190
        createVNode as jsxDEV,
191
        Fragment,
192
        // precompiled JSX transform
193
        jsxTemplate,
194
        jsxAttr,
195
        jsxEscape
196
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc