@knighted/jsx 1.5.1 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/internal/attribute-resolution.cjs +37 -0
- package/dist/cjs/internal/attribute-resolution.d.cts +10 -0
- package/dist/cjs/internal/event-bindings.cjs +84 -0
- package/dist/cjs/internal/event-bindings.d.cts +18 -0
- package/dist/cjs/jsx.cjs +8 -109
- package/dist/cjs/loader/jsx.cjs +20 -0
- package/dist/cjs/node/bootstrap.cjs +19 -19
- package/dist/cjs/node/bootstrap.d.cts +2 -1
- package/dist/cjs/node/index.cjs +1 -1
- package/dist/internal/attribute-resolution.d.ts +10 -0
- package/dist/internal/attribute-resolution.js +33 -0
- package/dist/internal/event-bindings.d.ts +18 -0
- package/dist/internal/event-bindings.js +79 -0
- package/dist/jsx.js +6 -107
- package/dist/lite/index.js +4 -4
- package/dist/lite/node/index.js +4 -4
- package/dist/loader/jsx.js +20 -0
- package/dist/node/bootstrap.d.ts +2 -1
- package/dist/node/bootstrap.js +19 -19
- package/dist/node/index.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createResolveAttributes = void 0;
|
|
4
|
+
const createResolveAttributes = (deps) => {
|
|
5
|
+
const { getIdentifierName, evaluateExpressionWithNamespace } = deps;
|
|
6
|
+
return (attributes, ctx, namespace) => {
|
|
7
|
+
const props = {};
|
|
8
|
+
attributes.forEach(attribute => {
|
|
9
|
+
if (attribute.type === 'JSXSpreadAttribute') {
|
|
10
|
+
const spreadValue = evaluateExpressionWithNamespace(attribute.argument, ctx, namespace);
|
|
11
|
+
if (spreadValue &&
|
|
12
|
+
typeof spreadValue === 'object' &&
|
|
13
|
+
!Array.isArray(spreadValue)) {
|
|
14
|
+
Object.assign(props, spreadValue);
|
|
15
|
+
}
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const name = getIdentifierName(attribute.name);
|
|
19
|
+
if (!attribute.value) {
|
|
20
|
+
props[name] = true;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (attribute.value.type === 'Literal') {
|
|
24
|
+
props[name] = attribute.value.value;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (attribute.value.type === 'JSXExpressionContainer') {
|
|
28
|
+
if (attribute.value.expression.type === 'JSXEmptyExpression') {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
props[name] = evaluateExpressionWithNamespace(attribute.value.expression, ctx, namespace);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return props;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
exports.createResolveAttributes = createResolveAttributes;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Expression, JSXAttribute, JSXElement, JSXFragment, JSXSpreadAttribute } from '@oxc-project/types';
|
|
2
|
+
import type { TemplateComponent, TemplateContext } from '../runtime/shared.cjs';
|
|
3
|
+
export type Namespace = 'svg' | null;
|
|
4
|
+
export type EvaluateExpressionWithNamespace<TComponent extends TemplateComponent> = (expression: Expression | JSXElement | JSXFragment, ctx: TemplateContext<TComponent>, namespace: Namespace) => unknown;
|
|
5
|
+
export type ResolveAttributesDependencies<TComponent extends TemplateComponent> = {
|
|
6
|
+
getIdentifierName: (name: JSXAttribute['name']) => string;
|
|
7
|
+
evaluateExpressionWithNamespace: EvaluateExpressionWithNamespace<TComponent>;
|
|
8
|
+
};
|
|
9
|
+
export type ResolveAttributesFn<TComponent extends TemplateComponent> = (attributes: (JSXAttribute | JSXSpreadAttribute)[], ctx: TemplateContext<TComponent>, namespace: Namespace) => Record<string, unknown>;
|
|
10
|
+
export declare const createResolveAttributes: <TComponent extends TemplateComponent>(deps: ResolveAttributesDependencies<TComponent>) => ResolveAttributesFn<TComponent>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveEventHandlerValue = exports.parseEventPropName = void 0;
|
|
4
|
+
const captureSuffix = 'Capture';
|
|
5
|
+
const stripCaptureSuffix = (rawName) => {
|
|
6
|
+
if (rawName.endsWith(captureSuffix)) {
|
|
7
|
+
return { eventName: rawName.slice(0, -captureSuffix.length), capture: true };
|
|
8
|
+
}
|
|
9
|
+
return { eventName: rawName, capture: false };
|
|
10
|
+
};
|
|
11
|
+
const parseEventPropName = (name) => {
|
|
12
|
+
if (!name.startsWith('on')) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
if (name.startsWith('on:')) {
|
|
16
|
+
const raw = name.slice(3);
|
|
17
|
+
if (!raw) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const parsed = stripCaptureSuffix(raw);
|
|
21
|
+
if (!parsed.eventName) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return parsed;
|
|
25
|
+
}
|
|
26
|
+
const raw = name.slice(2);
|
|
27
|
+
if (!raw) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const parsed = stripCaptureSuffix(raw);
|
|
31
|
+
if (!parsed.eventName) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
eventName: parsed.eventName.toLowerCase(),
|
|
36
|
+
capture: parsed.capture,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
exports.parseEventPropName = parseEventPropName;
|
|
40
|
+
const isEventListenerObject = (value) => {
|
|
41
|
+
if (!value || typeof value !== 'object') {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
return ('handleEvent' in value &&
|
|
45
|
+
typeof value.handleEvent === 'function');
|
|
46
|
+
};
|
|
47
|
+
const isEventHandlerDescriptor = (value) => {
|
|
48
|
+
if (!value || typeof value !== 'object' || !('handler' in value)) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const handler = value.handler;
|
|
52
|
+
if (typeof handler === 'function') {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return isEventListenerObject(handler);
|
|
56
|
+
};
|
|
57
|
+
const resolveEventHandlerValue = (value) => {
|
|
58
|
+
if (typeof value === 'function' || isEventListenerObject(value)) {
|
|
59
|
+
return { listener: value };
|
|
60
|
+
}
|
|
61
|
+
if (!isEventHandlerDescriptor(value)) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const descriptor = value;
|
|
65
|
+
let options = descriptor.options ? { ...descriptor.options } : undefined;
|
|
66
|
+
const assignOption = (key, optionValue) => {
|
|
67
|
+
if (optionValue === undefined || optionValue === null) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!options) {
|
|
71
|
+
options = {};
|
|
72
|
+
}
|
|
73
|
+
options[key] = optionValue;
|
|
74
|
+
};
|
|
75
|
+
assignOption('capture', descriptor.capture);
|
|
76
|
+
assignOption('once', descriptor.once);
|
|
77
|
+
assignOption('passive', descriptor.passive);
|
|
78
|
+
assignOption('signal', descriptor.signal ?? undefined);
|
|
79
|
+
return {
|
|
80
|
+
listener: descriptor.handler,
|
|
81
|
+
options,
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
exports.resolveEventHandlerValue = resolveEventHandlerValue;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type ParsedEventBinding = {
|
|
2
|
+
eventName: string;
|
|
3
|
+
capture: boolean;
|
|
4
|
+
};
|
|
5
|
+
export declare const parseEventPropName: (name: string) => ParsedEventBinding | null;
|
|
6
|
+
export type EventHandlerDescriptor = {
|
|
7
|
+
handler: EventListenerOrEventListenerObject;
|
|
8
|
+
capture?: boolean;
|
|
9
|
+
once?: boolean;
|
|
10
|
+
passive?: boolean;
|
|
11
|
+
signal?: AbortSignal | null;
|
|
12
|
+
options?: AddEventListenerOptions;
|
|
13
|
+
};
|
|
14
|
+
export type ResolvedEventHandler = {
|
|
15
|
+
listener: EventListenerOrEventListenerObject;
|
|
16
|
+
options?: AddEventListenerOptions;
|
|
17
|
+
};
|
|
18
|
+
export declare const resolveEventHandlerValue: (value: unknown) => ResolvedEventHandler | null;
|
package/dist/cjs/jsx.cjs
CHANGED
|
@@ -4,6 +4,8 @@ exports.jsx = void 0;
|
|
|
4
4
|
const oxc_parser_1 = require("oxc-parser");
|
|
5
5
|
const shared_js_1 = require("./runtime/shared.cjs");
|
|
6
6
|
const property_information_1 = require("property-information");
|
|
7
|
+
const attribute_resolution_js_1 = require("./internal/attribute-resolution.cjs");
|
|
8
|
+
const event_bindings_js_1 = require("./internal/event-bindings.cjs");
|
|
7
9
|
const ensureDomAvailable = () => {
|
|
8
10
|
if (typeof document === 'undefined' || typeof document.createElement !== 'function') {
|
|
9
11
|
throw new Error('The jsx template tag requires a DOM-like environment (document missing).');
|
|
@@ -71,85 +73,6 @@ const shouldAssignProperty = (element, namespace, info) => {
|
|
|
71
73
|
}
|
|
72
74
|
return info.property in element;
|
|
73
75
|
};
|
|
74
|
-
const captureSuffix = 'Capture';
|
|
75
|
-
const stripCaptureSuffix = (rawName) => {
|
|
76
|
-
if (rawName.endsWith(captureSuffix) && rawName.length > captureSuffix.length) {
|
|
77
|
-
return { eventName: rawName.slice(0, -captureSuffix.length), capture: true };
|
|
78
|
-
}
|
|
79
|
-
return { eventName: rawName, capture: false };
|
|
80
|
-
};
|
|
81
|
-
const parseEventPropName = (name) => {
|
|
82
|
-
if (!name.startsWith('on')) {
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
if (name.startsWith('on:')) {
|
|
86
|
-
const raw = name.slice(3);
|
|
87
|
-
if (!raw) {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
const parsed = stripCaptureSuffix(raw);
|
|
91
|
-
if (!parsed.eventName) {
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
return parsed;
|
|
95
|
-
}
|
|
96
|
-
const raw = name.slice(2);
|
|
97
|
-
if (!raw) {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
const parsed = stripCaptureSuffix(raw);
|
|
101
|
-
if (!parsed.eventName) {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
return {
|
|
105
|
-
eventName: parsed.eventName.toLowerCase(),
|
|
106
|
-
capture: parsed.capture,
|
|
107
|
-
};
|
|
108
|
-
};
|
|
109
|
-
const isEventListenerObject = (value) => {
|
|
110
|
-
if (!value || typeof value !== 'object') {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
return ('handleEvent' in value &&
|
|
114
|
-
typeof value.handleEvent === 'function');
|
|
115
|
-
};
|
|
116
|
-
const isEventHandlerDescriptor = (value) => {
|
|
117
|
-
if (!value || typeof value !== 'object' || !('handler' in value)) {
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
const handler = value.handler;
|
|
121
|
-
if (typeof handler === 'function') {
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
return isEventListenerObject(handler);
|
|
125
|
-
};
|
|
126
|
-
const resolveEventHandlerValue = (value) => {
|
|
127
|
-
if (typeof value === 'function' || isEventListenerObject(value)) {
|
|
128
|
-
return { listener: value };
|
|
129
|
-
}
|
|
130
|
-
if (!isEventHandlerDescriptor(value)) {
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
const descriptor = value;
|
|
134
|
-
let options = descriptor.options ? { ...descriptor.options } : undefined;
|
|
135
|
-
const assignOption = (key, optionValue) => {
|
|
136
|
-
if (optionValue === undefined || optionValue === null) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (!options) {
|
|
140
|
-
options = {};
|
|
141
|
-
}
|
|
142
|
-
options[key] = optionValue;
|
|
143
|
-
};
|
|
144
|
-
assignOption('capture', descriptor.capture);
|
|
145
|
-
assignOption('once', descriptor.once);
|
|
146
|
-
assignOption('passive', descriptor.passive);
|
|
147
|
-
assignOption('signal', descriptor.signal ?? undefined);
|
|
148
|
-
return {
|
|
149
|
-
listener: descriptor.handler,
|
|
150
|
-
options,
|
|
151
|
-
};
|
|
152
|
-
};
|
|
153
76
|
const setDomProp = (element, name, value, namespace) => {
|
|
154
77
|
if (value === null || value === undefined) {
|
|
155
78
|
return;
|
|
@@ -191,9 +114,9 @@ const setDomProp = (element, name, value, namespace) => {
|
|
|
191
114
|
});
|
|
192
115
|
return;
|
|
193
116
|
}
|
|
194
|
-
const eventBinding = parseEventPropName(name);
|
|
117
|
+
const eventBinding = (0, event_bindings_js_1.parseEventPropName)(name);
|
|
195
118
|
if (eventBinding) {
|
|
196
|
-
const handlerValue = resolveEventHandlerValue(value);
|
|
119
|
+
const handlerValue = (0, event_bindings_js_1.resolveEventHandlerValue)(value);
|
|
197
120
|
if (handlerValue) {
|
|
198
121
|
let options = handlerValue.options ? { ...handlerValue.options } : undefined;
|
|
199
122
|
if (eventBinding.capture) {
|
|
@@ -288,34 +211,10 @@ const appendChildValue = (parent, value) => {
|
|
|
288
211
|
parent.appendChild(document.createTextNode(String(value)));
|
|
289
212
|
};
|
|
290
213
|
const evaluateExpressionWithNamespace = (expression, ctx, namespace) => (0, shared_js_1.evaluateExpression)(expression, ctx, node => evaluateJsxNode(node, ctx, namespace));
|
|
291
|
-
const resolveAttributes = (
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const spreadValue = evaluateExpressionWithNamespace(attribute.argument, ctx, namespace);
|
|
296
|
-
if (spreadValue && typeof spreadValue === 'object' && !Array.isArray(spreadValue)) {
|
|
297
|
-
Object.assign(props, spreadValue);
|
|
298
|
-
}
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
const name = (0, shared_js_1.getIdentifierName)(attribute.name);
|
|
302
|
-
if (!attribute.value) {
|
|
303
|
-
props[name] = true;
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
if (attribute.value.type === 'Literal') {
|
|
307
|
-
props[name] = attribute.value.value;
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
if (attribute.value.type === 'JSXExpressionContainer') {
|
|
311
|
-
if (attribute.value.expression.type === 'JSXEmptyExpression') {
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
props[name] = evaluateExpressionWithNamespace(attribute.value.expression, ctx, namespace);
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
return props;
|
|
318
|
-
};
|
|
214
|
+
const resolveAttributes = (0, attribute_resolution_js_1.createResolveAttributes)({
|
|
215
|
+
getIdentifierName: shared_js_1.getIdentifierName,
|
|
216
|
+
evaluateExpressionWithNamespace,
|
|
217
|
+
});
|
|
319
218
|
const applyDomAttributes = (element, attributes, ctx, namespace) => {
|
|
320
219
|
const props = resolveAttributes(attributes, ctx, namespace);
|
|
321
220
|
Object.entries(props).forEach(([name, value]) => {
|
package/dist/cjs/loader/jsx.cjs
CHANGED
|
@@ -165,6 +165,9 @@ class ReactTemplateBuilder {
|
|
|
165
165
|
throw new Error('[jsx-loader] Unable to inline complex expressions in react mode.');
|
|
166
166
|
}
|
|
167
167
|
/* c8 ignore next */
|
|
168
|
+
/* v8 ignore next */
|
|
169
|
+
/* istanbul ignore next */
|
|
170
|
+
// Should never happen because OXC always annotates expression ranges.
|
|
168
171
|
throw new Error('[jsx-loader] Unable to compile expression for react mode.');
|
|
169
172
|
}
|
|
170
173
|
buildCreateElement(type, props, children) {
|
|
@@ -276,11 +279,15 @@ const shouldInterpolateName = (name) => /^[A-Z]/.test(name.name);
|
|
|
276
279
|
const addSlot = (slots, source, range) => {
|
|
277
280
|
if (!range) {
|
|
278
281
|
/* c8 ignore next */
|
|
282
|
+
/* v8 ignore next */
|
|
283
|
+
// OXC always provides ranges; guard defends against malformed AST nodes.
|
|
279
284
|
return;
|
|
280
285
|
}
|
|
281
286
|
const [start, end] = range;
|
|
282
287
|
if (start === end) {
|
|
283
288
|
/* c8 ignore next */
|
|
289
|
+
/* v8 ignore next */
|
|
290
|
+
// Zero-length ranges indicate parser bugs and would emit empty slices.
|
|
284
291
|
return;
|
|
285
292
|
}
|
|
286
293
|
slots.push({
|
|
@@ -293,6 +300,9 @@ const collectSlots = (program, source) => {
|
|
|
293
300
|
const slots = [];
|
|
294
301
|
const recordComponentName = (name) => {
|
|
295
302
|
if (!name) {
|
|
303
|
+
/* c8 ignore next */
|
|
304
|
+
/* v8 ignore next */
|
|
305
|
+
// JSX elements emitted by OXC always carry a name; this is defensive.
|
|
296
306
|
return;
|
|
297
307
|
}
|
|
298
308
|
switch (name.type) {
|
|
@@ -362,6 +372,8 @@ const renderTemplateWithSlots = (source, slots) => {
|
|
|
362
372
|
slots.forEach(slot => {
|
|
363
373
|
if (slot.start < cursor) {
|
|
364
374
|
/* c8 ignore next */
|
|
375
|
+
/* v8 ignore next */
|
|
376
|
+
// Slots are generated from non-overlapping JSX ranges; this protects against parser regressions.
|
|
365
377
|
throw new Error('Overlapping JSX expressions detected inside template literal.');
|
|
366
378
|
}
|
|
367
379
|
output += escapeTemplateChunk(source.slice(cursor, slot.start));
|
|
@@ -469,6 +481,8 @@ const buildTemplateSource = (quasis, expressions, source, tag) => {
|
|
|
469
481
|
let chunk = quasi.value.cooked;
|
|
470
482
|
if (typeof chunk !== 'string') {
|
|
471
483
|
/* c8 ignore next */
|
|
484
|
+
/* v8 ignore next */
|
|
485
|
+
// Cooked text is always available for valid templates; fall back shields invalid escape sequences.
|
|
472
486
|
chunk = quasi.value.raw ?? '';
|
|
473
487
|
}
|
|
474
488
|
if (trimStartNext > 0) {
|
|
@@ -484,6 +498,8 @@ const buildTemplateSource = (quasis, expressions, source, tag) => {
|
|
|
484
498
|
const end = expression.end ?? null;
|
|
485
499
|
if (start === null || end === null) {
|
|
486
500
|
/* c8 ignore next */
|
|
501
|
+
/* v8 ignore next */
|
|
502
|
+
// Expressions parsed from tagged templates always include start/end ranges.
|
|
487
503
|
throw new Error('Unable to read template expression source range.');
|
|
488
504
|
}
|
|
489
505
|
const nextChunk = quasis[index + 1];
|
|
@@ -554,6 +570,8 @@ const isLoaderPlaceholderIdentifier = (node) => {
|
|
|
554
570
|
(node.type !== 'Identifier' && node.type !== 'JSXIdentifier') ||
|
|
555
571
|
typeof node.name !== 'string') {
|
|
556
572
|
/* c8 ignore next */
|
|
573
|
+
/* v8 ignore next */
|
|
574
|
+
// Visitor only calls this helper with identifier-like nodes; guard prevents crashes on malformed ASTs.
|
|
557
575
|
return false;
|
|
558
576
|
}
|
|
559
577
|
return (node.name.startsWith(TEMPLATE_EXPR_PLACEHOLDER_PREFIX) ||
|
|
@@ -605,6 +623,8 @@ const transformSource = (source, config) => {
|
|
|
605
623
|
return;
|
|
606
624
|
}
|
|
607
625
|
/* c8 ignore next */
|
|
626
|
+
/* v8 ignore next */
|
|
627
|
+
// Modes are validated during option parsing; this fallback guards future extensions.
|
|
608
628
|
throw new Error(`[jsx-loader] Transformation mode "${mode}" not implemented yet for tag "${tagName}".`);
|
|
609
629
|
});
|
|
610
630
|
return {
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
const nodeRequire = createRequire(import.meta.url);
|
|
3
|
+
let requireOverride = null;
|
|
4
|
+
const resolveRequire = () => requireOverride ?? nodeRequire;
|
|
1
5
|
const DOM_TEMPLATE = '<!doctype html><html><body></body></html>';
|
|
2
6
|
const GLOBAL_KEYS = [
|
|
3
7
|
'window',
|
|
@@ -23,13 +27,13 @@ const assignGlobalTargets = (windowObj) => {
|
|
|
23
27
|
}
|
|
24
28
|
});
|
|
25
29
|
};
|
|
26
|
-
const loadLinkedom =
|
|
27
|
-
const { parseHTML } =
|
|
30
|
+
const loadLinkedom = () => {
|
|
31
|
+
const { parseHTML } = resolveRequire()('linkedom');
|
|
28
32
|
const { window } = parseHTML(DOM_TEMPLATE);
|
|
29
33
|
return window;
|
|
30
34
|
};
|
|
31
|
-
const loadJsdom =
|
|
32
|
-
const { JSDOM } =
|
|
35
|
+
const loadJsdom = () => {
|
|
36
|
+
const { JSDOM } = resolveRequire()('jsdom');
|
|
33
37
|
const { window } = new JSDOM(DOM_TEMPLATE);
|
|
34
38
|
return window;
|
|
35
39
|
};
|
|
@@ -52,11 +56,11 @@ const selectLoaders = () => {
|
|
|
52
56
|
}
|
|
53
57
|
return [loadLinkedom, loadJsdom];
|
|
54
58
|
};
|
|
55
|
-
const createShimWindow =
|
|
59
|
+
const createShimWindow = () => {
|
|
56
60
|
const errors = [];
|
|
57
61
|
for (const loader of selectLoaders()) {
|
|
58
62
|
try {
|
|
59
|
-
return
|
|
63
|
+
return loader();
|
|
60
64
|
}
|
|
61
65
|
catch (error) {
|
|
62
66
|
errors.push(error);
|
|
@@ -65,19 +69,15 @@ const createShimWindow = async () => {
|
|
|
65
69
|
const help = 'Unable to bootstrap a DOM-like environment. Install "linkedom" or "jsdom" (both optional peer dependencies) or set KNIGHTED_JSX_NODE_SHIM to pick one explicitly.';
|
|
66
70
|
throw new AggregateError(errors, help);
|
|
67
71
|
};
|
|
68
|
-
let
|
|
69
|
-
export const ensureNodeDom =
|
|
70
|
-
if (hasDom()) {
|
|
72
|
+
let bootstrapped = false;
|
|
73
|
+
export const ensureNodeDom = () => {
|
|
74
|
+
if (hasDom() || bootstrapped) {
|
|
71
75
|
return;
|
|
72
76
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
throw error;
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
return bootstrapPromise;
|
|
77
|
+
const windowObj = createShimWindow();
|
|
78
|
+
assignGlobalTargets(windowObj);
|
|
79
|
+
bootstrapped = true;
|
|
80
|
+
};
|
|
81
|
+
export const __setNodeRequireForTesting = (mockRequire) => {
|
|
82
|
+
requireOverride = mockRequire;
|
|
83
83
|
};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export declare const ensureNodeDom: () =>
|
|
1
|
+
export declare const ensureNodeDom: () => void;
|
|
2
|
+
export declare const __setNodeRequireForTesting: (mockRequire: NodeJS.Require | null) => void;
|
package/dist/cjs/node/index.cjs
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Expression, JSXAttribute, JSXElement, JSXFragment, JSXSpreadAttribute } from '@oxc-project/types';
|
|
2
|
+
import type { TemplateComponent, TemplateContext } from '../runtime/shared.js';
|
|
3
|
+
export type Namespace = 'svg' | null;
|
|
4
|
+
export type EvaluateExpressionWithNamespace<TComponent extends TemplateComponent> = (expression: Expression | JSXElement | JSXFragment, ctx: TemplateContext<TComponent>, namespace: Namespace) => unknown;
|
|
5
|
+
export type ResolveAttributesDependencies<TComponent extends TemplateComponent> = {
|
|
6
|
+
getIdentifierName: (name: JSXAttribute['name']) => string;
|
|
7
|
+
evaluateExpressionWithNamespace: EvaluateExpressionWithNamespace<TComponent>;
|
|
8
|
+
};
|
|
9
|
+
export type ResolveAttributesFn<TComponent extends TemplateComponent> = (attributes: (JSXAttribute | JSXSpreadAttribute)[], ctx: TemplateContext<TComponent>, namespace: Namespace) => Record<string, unknown>;
|
|
10
|
+
export declare const createResolveAttributes: <TComponent extends TemplateComponent>(deps: ResolveAttributesDependencies<TComponent>) => ResolveAttributesFn<TComponent>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const createResolveAttributes = (deps) => {
|
|
2
|
+
const { getIdentifierName, evaluateExpressionWithNamespace } = deps;
|
|
3
|
+
return (attributes, ctx, namespace) => {
|
|
4
|
+
const props = {};
|
|
5
|
+
attributes.forEach(attribute => {
|
|
6
|
+
if (attribute.type === 'JSXSpreadAttribute') {
|
|
7
|
+
const spreadValue = evaluateExpressionWithNamespace(attribute.argument, ctx, namespace);
|
|
8
|
+
if (spreadValue &&
|
|
9
|
+
typeof spreadValue === 'object' &&
|
|
10
|
+
!Array.isArray(spreadValue)) {
|
|
11
|
+
Object.assign(props, spreadValue);
|
|
12
|
+
}
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const name = getIdentifierName(attribute.name);
|
|
16
|
+
if (!attribute.value) {
|
|
17
|
+
props[name] = true;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (attribute.value.type === 'Literal') {
|
|
21
|
+
props[name] = attribute.value.value;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (attribute.value.type === 'JSXExpressionContainer') {
|
|
25
|
+
if (attribute.value.expression.type === 'JSXEmptyExpression') {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
props[name] = evaluateExpressionWithNamespace(attribute.value.expression, ctx, namespace);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return props;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type ParsedEventBinding = {
|
|
2
|
+
eventName: string;
|
|
3
|
+
capture: boolean;
|
|
4
|
+
};
|
|
5
|
+
export declare const parseEventPropName: (name: string) => ParsedEventBinding | null;
|
|
6
|
+
export type EventHandlerDescriptor = {
|
|
7
|
+
handler: EventListenerOrEventListenerObject;
|
|
8
|
+
capture?: boolean;
|
|
9
|
+
once?: boolean;
|
|
10
|
+
passive?: boolean;
|
|
11
|
+
signal?: AbortSignal | null;
|
|
12
|
+
options?: AddEventListenerOptions;
|
|
13
|
+
};
|
|
14
|
+
export type ResolvedEventHandler = {
|
|
15
|
+
listener: EventListenerOrEventListenerObject;
|
|
16
|
+
options?: AddEventListenerOptions;
|
|
17
|
+
};
|
|
18
|
+
export declare const resolveEventHandlerValue: (value: unknown) => ResolvedEventHandler | null;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const captureSuffix = 'Capture';
|
|
2
|
+
const stripCaptureSuffix = (rawName) => {
|
|
3
|
+
if (rawName.endsWith(captureSuffix)) {
|
|
4
|
+
return { eventName: rawName.slice(0, -captureSuffix.length), capture: true };
|
|
5
|
+
}
|
|
6
|
+
return { eventName: rawName, capture: false };
|
|
7
|
+
};
|
|
8
|
+
export const parseEventPropName = (name) => {
|
|
9
|
+
if (!name.startsWith('on')) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
if (name.startsWith('on:')) {
|
|
13
|
+
const raw = name.slice(3);
|
|
14
|
+
if (!raw) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const parsed = stripCaptureSuffix(raw);
|
|
18
|
+
if (!parsed.eventName) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return parsed;
|
|
22
|
+
}
|
|
23
|
+
const raw = name.slice(2);
|
|
24
|
+
if (!raw) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const parsed = stripCaptureSuffix(raw);
|
|
28
|
+
if (!parsed.eventName) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
eventName: parsed.eventName.toLowerCase(),
|
|
33
|
+
capture: parsed.capture,
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
const isEventListenerObject = (value) => {
|
|
37
|
+
if (!value || typeof value !== 'object') {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return ('handleEvent' in value &&
|
|
41
|
+
typeof value.handleEvent === 'function');
|
|
42
|
+
};
|
|
43
|
+
const isEventHandlerDescriptor = (value) => {
|
|
44
|
+
if (!value || typeof value !== 'object' || !('handler' in value)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const handler = value.handler;
|
|
48
|
+
if (typeof handler === 'function') {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return isEventListenerObject(handler);
|
|
52
|
+
};
|
|
53
|
+
export const resolveEventHandlerValue = (value) => {
|
|
54
|
+
if (typeof value === 'function' || isEventListenerObject(value)) {
|
|
55
|
+
return { listener: value };
|
|
56
|
+
}
|
|
57
|
+
if (!isEventHandlerDescriptor(value)) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const descriptor = value;
|
|
61
|
+
let options = descriptor.options ? { ...descriptor.options } : undefined;
|
|
62
|
+
const assignOption = (key, optionValue) => {
|
|
63
|
+
if (optionValue === undefined || optionValue === null) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!options) {
|
|
67
|
+
options = {};
|
|
68
|
+
}
|
|
69
|
+
options[key] = optionValue;
|
|
70
|
+
};
|
|
71
|
+
assignOption('capture', descriptor.capture);
|
|
72
|
+
assignOption('once', descriptor.once);
|
|
73
|
+
assignOption('passive', descriptor.passive);
|
|
74
|
+
assignOption('signal', descriptor.signal ?? undefined);
|
|
75
|
+
return {
|
|
76
|
+
listener: descriptor.handler,
|
|
77
|
+
options,
|
|
78
|
+
};
|
|
79
|
+
};
|
package/dist/jsx.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { parseSync } from 'oxc-parser';
|
|
2
2
|
import { buildTemplate, evaluateExpression, extractRootNode, formatParserError, getIdentifierName, normalizeJsxTextSegments, parserOptions, } from './runtime/shared.js';
|
|
3
3
|
import { find as findPropertyInfo, html as htmlProperties, svg as svgProperties, } from 'property-information';
|
|
4
|
+
import { createResolveAttributes, } from './internal/attribute-resolution.js';
|
|
5
|
+
import { parseEventPropName, resolveEventHandlerValue, } from './internal/event-bindings.js';
|
|
4
6
|
const ensureDomAvailable = () => {
|
|
5
7
|
if (typeof document === 'undefined' || typeof document.createElement !== 'function') {
|
|
6
8
|
throw new Error('The jsx template tag requires a DOM-like environment (document missing).');
|
|
@@ -68,85 +70,6 @@ const shouldAssignProperty = (element, namespace, info) => {
|
|
|
68
70
|
}
|
|
69
71
|
return info.property in element;
|
|
70
72
|
};
|
|
71
|
-
const captureSuffix = 'Capture';
|
|
72
|
-
const stripCaptureSuffix = (rawName) => {
|
|
73
|
-
if (rawName.endsWith(captureSuffix) && rawName.length > captureSuffix.length) {
|
|
74
|
-
return { eventName: rawName.slice(0, -captureSuffix.length), capture: true };
|
|
75
|
-
}
|
|
76
|
-
return { eventName: rawName, capture: false };
|
|
77
|
-
};
|
|
78
|
-
const parseEventPropName = (name) => {
|
|
79
|
-
if (!name.startsWith('on')) {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
if (name.startsWith('on:')) {
|
|
83
|
-
const raw = name.slice(3);
|
|
84
|
-
if (!raw) {
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
const parsed = stripCaptureSuffix(raw);
|
|
88
|
-
if (!parsed.eventName) {
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
return parsed;
|
|
92
|
-
}
|
|
93
|
-
const raw = name.slice(2);
|
|
94
|
-
if (!raw) {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
const parsed = stripCaptureSuffix(raw);
|
|
98
|
-
if (!parsed.eventName) {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
return {
|
|
102
|
-
eventName: parsed.eventName.toLowerCase(),
|
|
103
|
-
capture: parsed.capture,
|
|
104
|
-
};
|
|
105
|
-
};
|
|
106
|
-
const isEventListenerObject = (value) => {
|
|
107
|
-
if (!value || typeof value !== 'object') {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
return ('handleEvent' in value &&
|
|
111
|
-
typeof value.handleEvent === 'function');
|
|
112
|
-
};
|
|
113
|
-
const isEventHandlerDescriptor = (value) => {
|
|
114
|
-
if (!value || typeof value !== 'object' || !('handler' in value)) {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
const handler = value.handler;
|
|
118
|
-
if (typeof handler === 'function') {
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
return isEventListenerObject(handler);
|
|
122
|
-
};
|
|
123
|
-
const resolveEventHandlerValue = (value) => {
|
|
124
|
-
if (typeof value === 'function' || isEventListenerObject(value)) {
|
|
125
|
-
return { listener: value };
|
|
126
|
-
}
|
|
127
|
-
if (!isEventHandlerDescriptor(value)) {
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
const descriptor = value;
|
|
131
|
-
let options = descriptor.options ? { ...descriptor.options } : undefined;
|
|
132
|
-
const assignOption = (key, optionValue) => {
|
|
133
|
-
if (optionValue === undefined || optionValue === null) {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (!options) {
|
|
137
|
-
options = {};
|
|
138
|
-
}
|
|
139
|
-
options[key] = optionValue;
|
|
140
|
-
};
|
|
141
|
-
assignOption('capture', descriptor.capture);
|
|
142
|
-
assignOption('once', descriptor.once);
|
|
143
|
-
assignOption('passive', descriptor.passive);
|
|
144
|
-
assignOption('signal', descriptor.signal ?? undefined);
|
|
145
|
-
return {
|
|
146
|
-
listener: descriptor.handler,
|
|
147
|
-
options,
|
|
148
|
-
};
|
|
149
|
-
};
|
|
150
73
|
const setDomProp = (element, name, value, namespace) => {
|
|
151
74
|
if (value === null || value === undefined) {
|
|
152
75
|
return;
|
|
@@ -285,34 +208,10 @@ const appendChildValue = (parent, value) => {
|
|
|
285
208
|
parent.appendChild(document.createTextNode(String(value)));
|
|
286
209
|
};
|
|
287
210
|
const evaluateExpressionWithNamespace = (expression, ctx, namespace) => evaluateExpression(expression, ctx, node => evaluateJsxNode(node, ctx, namespace));
|
|
288
|
-
const resolveAttributes = (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const spreadValue = evaluateExpressionWithNamespace(attribute.argument, ctx, namespace);
|
|
293
|
-
if (spreadValue && typeof spreadValue === 'object' && !Array.isArray(spreadValue)) {
|
|
294
|
-
Object.assign(props, spreadValue);
|
|
295
|
-
}
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
const name = getIdentifierName(attribute.name);
|
|
299
|
-
if (!attribute.value) {
|
|
300
|
-
props[name] = true;
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
if (attribute.value.type === 'Literal') {
|
|
304
|
-
props[name] = attribute.value.value;
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
if (attribute.value.type === 'JSXExpressionContainer') {
|
|
308
|
-
if (attribute.value.expression.type === 'JSXEmptyExpression') {
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
props[name] = evaluateExpressionWithNamespace(attribute.value.expression, ctx, namespace);
|
|
312
|
-
}
|
|
313
|
-
});
|
|
314
|
-
return props;
|
|
315
|
-
};
|
|
211
|
+
const resolveAttributes = createResolveAttributes({
|
|
212
|
+
getIdentifierName,
|
|
213
|
+
evaluateExpressionWithNamespace,
|
|
214
|
+
});
|
|
316
215
|
const applyDomAttributes = (element, attributes, ctx, namespace) => {
|
|
317
216
|
const props = resolveAttributes(attributes, ctx, namespace);
|
|
318
217
|
Object.entries(props).forEach(([name, value]) => {
|
package/dist/lite/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {parseSync}from'oxc-parser';import {find,svg,html}from'property-information';var
|
|
2
|
-
${
|
|
3
|
-
${e.codeframe}`),
|
|
4
|
-
export{
|
|
1
|
+
import {parseSync}from'oxc-parser';import {find,svg,html}from'property-information';var M=/<\s*$/,W=/<\/\s*$/,w="__KX_EXPR__",C=new RegExp(`${w}\\d+_\\d+__`,"g"),H=0,T={lang:"jsx",sourceType:"module",range:true,preserveParens:true},N=e=>{let t=`[oxc-parser] ${e.message}`;if(e.labels?.length){let n=e.labels[0];n.message&&(t+=`
|
|
2
|
+
${n.message}`);}return e.codeframe&&(t+=`
|
|
3
|
+
${e.codeframe}`),t},A=e=>{for(let t of e.body)if(t.type==="ExpressionStatement"){let n=t.expression;if(n.type==="JSXElement"||n.type==="JSXFragment")return n}throw new Error("The jsx template must contain a single JSX element or fragment.")},x=e=>{switch(e.type){case "JSXIdentifier":return e.name;case "JSXNamespacedName":return `${e.namespace.name}:${e.name.name}`;case "JSXMemberExpression":return `${x(e.object)}.${e.property.name}`;default:return ""}},y=(e,t)=>{if(!e||typeof e!="object")return;let n=e;typeof n.type=="string"&&(t(n),Object.values(n).forEach(r=>{if(r){if(Array.isArray(r)){r.forEach(s=>y(s,t));return}typeof r=="object"&&y(r,t);}}));},X=(e,t)=>{let n=e.replace(/\r/g,"").replace(/\n\s+/g," "),r=e.match(/^\s*/)?.[0]??"",s=e.match(/\s*$/)?.[0]??"",o=/\n/.test(r),a=/\n/.test(s),p=n;if(o&&(p=p.replace(/^\s+/,"")),a&&(p=p.replace(/\s+$/,"")),p.length===0||p.trim().length===0)return [];let i=[];C.lastIndex=0;let c=0,l;for(;l=C.exec(p);){let m=l.index,u=p.slice(c,m);u&&i.push(u);let f=l[0];t.has(f)?i.push(t.get(f)):i.push(f),c=m+f.length;}let d=p.slice(c);return d&&i.push(d),i},V=(e,t)=>{let n=new Set;return y(e,r=>{r.type==="Identifier"&&t.placeholders.has(r.name)&&n.add(r.name);}),Array.from(n)},k=(e,t,n)=>{if(e.type==="JSXElement"||e.type==="JSXFragment")return n(e);if(!("range"in e)||!e.range)throw new Error("Unable to evaluate expression: missing source range information.");let[r,s]=e.range,o=t.source.slice(r,s),a=V(e,t);try{let p=new Function(...a,`"use strict"; return (${o});`),i=a.map(c=>t.placeholders.get(c));return p(...i)}catch(p){throw new Error(`Failed to evaluate expression ${o}: ${p.message}`)}},z=e=>{let t=e.replace(/[^a-zA-Z0-9_$]/g,"");return t?/[A-Za-z_$]/.test(t[0])?t:`Component${t}`:"Component"},U=(e,t,n)=>{let r=n.get(e);if(r)return r;let s=e.displayName||e.name||`Component${t.length}`,o=z(s??""),a=o,p=1;for(;t.some(c=>c.name===a);)a=`${o}${p++}`;let i={name:a,value:e};return t.push(i),n.set(e,i),i},R=(e,t)=>{let n=e.raw??e,r=new Map,s=[],o=new Map,a=n[0]??"",p=H++,i=0;for(let c=0;c<t.length;c++){let l=n[c]??"",d=n[c+1]??"",m=t[c],u=M.test(l)||W.test(l);if(u&&typeof m=="function"){let D=U(m,s,o);a+=D.name+d;continue}if(u&&typeof m=="string"){a+=m+d;continue}let f=`${w}${p}_${i++}__`;r.set(f,m),a+=f+d;}return {source:a,placeholders:r,bindings:s}};var v=e=>{let{getIdentifierName:t,evaluateExpressionWithNamespace:n}=e;return (r,s,o)=>{let a={};return r.forEach(p=>{if(p.type==="JSXSpreadAttribute"){let c=n(p.argument,s,o);c&&typeof c=="object"&&!Array.isArray(c)&&Object.assign(a,c);return}let i=t(p.name);if(!p.value){a[i]=true;return}if(p.value.type==="Literal"){a[i]=p.value.value;return}if(p.value.type==="JSXExpressionContainer"){if(p.value.expression.type==="JSXEmptyExpression")return;a[i]=n(p.value.expression,s,o);}}),a}};var P="Capture",j=e=>e.endsWith(P)?{eventName:e.slice(0,-P.length),capture:true}:{eventName:e,capture:false},O=e=>{if(!e.startsWith("on"))return null;if(e.startsWith("on:")){let r=e.slice(3);if(!r)return null;let s=j(r);return s.eventName?s:null}let t=e.slice(2);if(!t)return null;let n=j(t);return n.eventName?{eventName:n.eventName.toLowerCase(),capture:n.capture}:null},I=e=>!e||typeof e!="object"?false:"handleEvent"in e&&typeof e.handleEvent=="function",K=e=>{if(!e||typeof e!="object"||!("handler"in e))return false;let t=e.handler;return typeof t=="function"?true:I(t)},F=e=>{if(typeof e=="function"||I(e))return {listener:e};if(!K(e))return null;let t=e,n=t.options?{...t.options}:void 0,r=(s,o)=>{o!=null&&(n||(n={}),n[s]=o);};return r("capture",t.capture),r("once",t.once),r("passive",t.passive),r("signal",t.signal??void 0),{listener:t.handler,options:n}};var Y=()=>{if(typeof document>"u"||typeof document.createElement!="function")throw new Error("The jsx template tag requires a DOM-like environment (document missing).")},ee=e=>typeof Node>"u"?false:e instanceof Node||e instanceof DocumentFragment,te=e=>!e||typeof e=="string"?false:typeof e[Symbol.iterator]=="function",_=e=>!e||typeof e!="object"&&typeof e!="function"?false:typeof e.then=="function",ne={xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},$=e=>{if(!(!e||e==="html"||e==="svg"))return ne[e]},re=e=>e==="svg"?svg:html,E=(e,t,n)=>{let r=$(t.space),s=String(n);if(r){e.setAttributeNS(r,t.attribute,s);return}e.setAttribute(t.attribute,s);},L=(e,t)=>{let n=$(t.space);if(n){e.removeAttributeNS(n,t.attribute);return}e.removeAttribute(t.attribute);},h=(e,t)=>Array.isArray(e)?e.filter(Boolean).join(t):e,oe=(e,t,n)=>t==="svg"||!n.property||n.property.includes(":")?false:n.property in e,se=(e,t,n,r)=>{if(n==null)return;if(t==="dangerouslySetInnerHTML"&&typeof n=="object"&&n&&"__html"in n){e.innerHTML=String(n.__html??"");return}if(t==="ref"){if(typeof n=="function"){n(e);return}if(n&&typeof n=="object"){n.current=e;return}}if(t==="style"&&typeof n=="object"&&n!==null){let c=n,l=e.style;if(!l)return;let d=l;Object.entries(c).forEach(([m,u])=>{if(u!=null){if(m.startsWith("--")){l.setProperty(m,String(u));return}d[m]=u;}});return}let s=O(t);if(s){let c=F(n);if(c){let l=c.options?{...c.options}:void 0;s.capture&&(l?l.capture=true:l={capture:true}),e.addEventListener(s.eventName,c.listener,l);return}}let o=find(re(r),t),a=e,p=oe(e,r,o);if(o.mustUseProperty){let c=o.boolean?!!n:n;a[o.property]=c;return}if(o.boolean){let c=!!n;p&&(a[o.property]=c),c?E(e,o,""):L(e,o);return}let i=n;if(o.spaceSeparated?i=h(n," "):o.commaSeparated?i=h(n,","):o.commaOrSpaceSeparated&&(i=h(n," ")),o.booleanish&&typeof i=="boolean"&&(i=i?"true":"false"),o.overloadedBoolean){if(i===false){L(e,o);return}if(i===true){E(e,o,"");return}}if(p){a[o.property]=i;return}i!==false&&E(e,o,i);},g=(e,t)=>{if(t!=null&&typeof t!="boolean"){if(_(t))throw new Error("Async values are not supported inside jsx template results.");if(Array.isArray(t)){t.forEach(n=>g(e,n));return}if(te(t)){for(let n of t)g(e,n);return}if(ee(t)){e.appendChild(t);return}e.appendChild(document.createTextNode(String(t)));}},b=(e,t,n)=>k(e,t,r=>J(r,t,n)),B=v({getIdentifierName:x,evaluateExpressionWithNamespace:b}),ae=(e,t,n,r)=>{let s=B(t,n,r);Object.entries(s).forEach(([o,a])=>{if(o!=="key"){if(o==="children"){g(e,a);return}se(e,o,a,r);}});},S=(e,t,n)=>{let r=[];return e.forEach(s=>{switch(s.type){case "JSXText":{X(s.value,t.placeholders).forEach(a=>{r.push(a);});break}case "JSXExpressionContainer":{if(s.expression.type==="JSXEmptyExpression")break;r.push(b(s.expression,t,n));break}case "JSXSpreadChild":{let o=b(s.expression,t,n);o!=null&&r.push(o);break}case "JSXElement":case "JSXFragment":{r.push(J(s,t,n));break}}}),r},ie=(e,t,n,r)=>{let s=B(e.openingElement.attributes,t,r),o=S(e.children,t,r);o.length===1?s.children=o[0]:o.length>1&&(s.children=o);let a=n(s);if(_(a))throw new Error("Async jsx components are not supported.");return a},pe=(e,t,n)=>{let r=e.openingElement,s=x(r.name),o=t.components.get(s);if(o)return ie(e,t,o,n);if(/[A-Z]/.test(s[0]??""))throw new Error(`Unknown component "${s}". Did you interpolate it with the template literal?`);let a=s==="svg"?"svg":n,p=s==="foreignObject"?null:a,i=a==="svg"?document.createElementNS("http://www.w3.org/2000/svg",s):document.createElement(s);return ae(i,r.attributes,t,a),S(e.children,t,p).forEach(l=>g(i,l)),i},J=(e,t,n)=>{if(e.type==="JSXFragment"){let r=document.createDocumentFragment();return S(e.children,t,n).forEach(o=>g(r,o)),r}return pe(e,t,n)},ce=(e,...t)=>{Y();let n=R(e,t),r=parseSync("inline.jsx",n.source,T);if(r.errors.length>0)throw new Error(N(r.errors[0]));let s=A(r.program),o={source:n.source,placeholders:n.placeholders,components:new Map(n.bindings.map(a=>[a.name,a.value]))};return J(s,o,null)};
|
|
4
|
+
export{ce as jsx};
|
package/dist/lite/node/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {parseSync}from'oxc-parser';import {find,svg,html}from'property-information';var k="<!doctype html><html><body></body></html>",
|
|
2
|
-
${
|
|
3
|
-
${e.codeframe}`),
|
|
4
|
-
export{
|
|
1
|
+
import {createRequire}from'module';import {parseSync}from'oxc-parser';import {find,svg,html}from'property-information';var G=createRequire(import.meta.url),N=()=>G,k="<!doctype html><html><body></body></html>",Y=["window","self","document","HTMLElement","Element","Node","DocumentFragment","customElements","Text","Comment","MutationObserver","navigator"],Q=()=>typeof document<"u"&&typeof document.createElement=="function",ee=e=>{let t=globalThis,n=e;Y.forEach(r=>{t[r]===void 0&&n[r]!==void 0&&(t[r]=n[r]);});},y=()=>{let{parseHTML:e}=N()("linkedom"),{window:t}=e(k);return t},E=()=>{let{JSDOM:e}=N()("jsdom"),{window:t}=new e(k);return t},te=()=>{let e=typeof process<"u"&&process.env?.KNIGHTED_JSX_NODE_SHIM?process.env.KNIGHTED_JSX_NODE_SHIM.toLowerCase():void 0;return e==="linkedom"||e==="jsdom"?e:"auto"},ne=()=>{let e=te();return e==="linkedom"?[y,E]:e==="jsdom"?[E,y]:[y,E]},re=()=>{let e=[];for(let n of ne())try{return n()}catch(r){e.push(r);}let t='Unable to bootstrap a DOM-like environment. Install "linkedom" or "jsdom" (both optional peer dependencies) or set KNIGHTED_JSX_NODE_SHIM to pick one explicitly.';throw new AggregateError(e,t)},T=false,A=()=>{if(Q()||T)return;let e=re();ee(e),T=true;};var oe=/<\s*$/,se=/<\/\s*$/,R="__KX_EXPR__",X=new RegExp(`${R}\\d+_\\d+__`,"g"),ie=0,v={lang:"jsx",sourceType:"module",range:true,preserveParens:true},j=e=>{let t=`[oxc-parser] ${e.message}`;if(e.labels?.length){let n=e.labels[0];n.message&&(t+=`
|
|
2
|
+
${n.message}`);}return e.codeframe&&(t+=`
|
|
3
|
+
${e.codeframe}`),t},P=e=>{for(let t of e.body)if(t.type==="ExpressionStatement"){let n=t.expression;if(n.type==="JSXElement"||n.type==="JSXFragment")return n}throw new Error("The jsx template must contain a single JSX element or fragment.")},x=e=>{switch(e.type){case "JSXIdentifier":return e.name;case "JSXNamespacedName":return `${e.namespace.name}:${e.name.name}`;case "JSXMemberExpression":return `${x(e.object)}.${e.property.name}`;default:return ""}},h=(e,t)=>{if(!e||typeof e!="object")return;let n=e;typeof n.type=="string"&&(t(n),Object.values(n).forEach(r=>{if(r){if(Array.isArray(r)){r.forEach(s=>h(s,t));return}typeof r=="object"&&h(r,t);}}));},O=(e,t)=>{let n=e.replace(/\r/g,"").replace(/\n\s+/g," "),r=e.match(/^\s*/)?.[0]??"",s=e.match(/\s*$/)?.[0]??"",o=/\n/.test(r),i=/\n/.test(s),p=n;if(o&&(p=p.replace(/^\s+/,"")),i&&(p=p.replace(/\s+$/,"")),p.length===0||p.trim().length===0)return [];let a=[];X.lastIndex=0;let c=0,l;for(;l=X.exec(p);){let m=l.index,u=p.slice(c,m);u&&a.push(u);let f=l[0];t.has(f)?a.push(t.get(f)):a.push(f),c=m+f.length;}let d=p.slice(c);return d&&a.push(d),a},ae=(e,t)=>{let n=new Set;return h(e,r=>{r.type==="Identifier"&&t.placeholders.has(r.name)&&n.add(r.name);}),Array.from(n)},L=(e,t,n)=>{if(e.type==="JSXElement"||e.type==="JSXFragment")return n(e);if(!("range"in e)||!e.range)throw new Error("Unable to evaluate expression: missing source range information.");let[r,s]=e.range,o=t.source.slice(r,s),i=ae(e,t);try{let p=new Function(...i,`"use strict"; return (${o});`),a=i.map(c=>t.placeholders.get(c));return p(...a)}catch(p){throw new Error(`Failed to evaluate expression ${o}: ${p.message}`)}},pe=e=>{let t=e.replace(/[^a-zA-Z0-9_$]/g,"");return t?/[A-Za-z_$]/.test(t[0])?t:`Component${t}`:"Component"},ce=(e,t,n)=>{let r=n.get(e);if(r)return r;let s=e.displayName||e.name||`Component${t.length}`,o=pe(s??""),i=o,p=1;for(;t.some(c=>c.name===i);)i=`${o}${p++}`;let a={name:i,value:e};return t.push(a),n.set(e,a),a},_=(e,t)=>{let n=e.raw??e,r=new Map,s=[],o=new Map,i=n[0]??"",p=ie++,a=0;for(let c=0;c<t.length;c++){let l=n[c]??"",d=n[c+1]??"",m=t[c],u=oe.test(l)||se.test(l);if(u&&typeof m=="function"){let U=ce(m,s,o);i+=U.name+d;continue}if(u&&typeof m=="string"){i+=m+d;continue}let f=`${R}${p}_${a++}__`;r.set(f,m),i+=f+d;}return {source:i,placeholders:r,bindings:s}};var I=e=>{let{getIdentifierName:t,evaluateExpressionWithNamespace:n}=e;return (r,s,o)=>{let i={};return r.forEach(p=>{if(p.type==="JSXSpreadAttribute"){let c=n(p.argument,s,o);c&&typeof c=="object"&&!Array.isArray(c)&&Object.assign(i,c);return}let a=t(p.name);if(!p.value){i[a]=true;return}if(p.value.type==="Literal"){i[a]=p.value.value;return}if(p.value.type==="JSXExpressionContainer"){if(p.value.expression.type==="JSXEmptyExpression")return;i[a]=n(p.value.expression,s,o);}}),i}};var M="Capture",D=e=>e.endsWith(M)?{eventName:e.slice(0,-M.length),capture:true}:{eventName:e,capture:false},F=e=>{if(!e.startsWith("on"))return null;if(e.startsWith("on:")){let r=e.slice(3);if(!r)return null;let s=D(r);return s.eventName?s:null}let t=e.slice(2);if(!t)return null;let n=D(t);return n.eventName?{eventName:n.eventName.toLowerCase(),capture:n.capture}:null},$=e=>!e||typeof e!="object"?false:"handleEvent"in e&&typeof e.handleEvent=="function",le=e=>{if(!e||typeof e!="object"||!("handler"in e))return false;let t=e.handler;return typeof t=="function"?true:$(t)},W=e=>{if(typeof e=="function"||$(e))return {listener:e};if(!le(e))return null;let t=e,n=t.options?{...t.options}:void 0,r=(s,o)=>{o!=null&&(n||(n={}),n[s]=o);};return r("capture",t.capture),r("once",t.once),r("passive",t.passive),r("signal",t.signal??void 0),{listener:t.handler,options:n}};var ge=()=>{if(typeof document>"u"||typeof document.createElement!="function")throw new Error("The jsx template tag requires a DOM-like environment (document missing).")},xe=e=>typeof Node>"u"?false:e instanceof Node||e instanceof DocumentFragment,ye=e=>!e||typeof e=="string"?false:typeof e[Symbol.iterator]=="function",H=e=>!e||typeof e!="object"&&typeof e!="function"?false:typeof e.then=="function",Ee={xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},V=e=>{if(!(!e||e==="html"||e==="svg"))return Ee[e]},he=e=>e==="svg"?svg:html,S=(e,t,n)=>{let r=V(t.space),s=String(n);if(r){e.setAttributeNS(r,t.attribute,s);return}e.setAttribute(t.attribute,s);},B=(e,t)=>{let n=V(t.space);if(n){e.removeAttributeNS(n,t.attribute);return}e.removeAttribute(t.attribute);},b=(e,t)=>Array.isArray(e)?e.filter(Boolean).join(t):e,Se=(e,t,n)=>t==="svg"||!n.property||n.property.includes(":")?false:n.property in e,be=(e,t,n,r)=>{if(n==null)return;if(t==="dangerouslySetInnerHTML"&&typeof n=="object"&&n&&"__html"in n){e.innerHTML=String(n.__html??"");return}if(t==="ref"){if(typeof n=="function"){n(e);return}if(n&&typeof n=="object"){n.current=e;return}}if(t==="style"&&typeof n=="object"&&n!==null){let c=n,l=e.style;if(!l)return;let d=l;Object.entries(c).forEach(([m,u])=>{if(u!=null){if(m.startsWith("--")){l.setProperty(m,String(u));return}d[m]=u;}});return}let s=F(t);if(s){let c=W(n);if(c){let l=c.options?{...c.options}:void 0;s.capture&&(l?l.capture=true:l={capture:true}),e.addEventListener(s.eventName,c.listener,l);return}}let o=find(he(r),t),i=e,p=Se(e,r,o);if(o.mustUseProperty){let c=o.boolean?!!n:n;i[o.property]=c;return}if(o.boolean){let c=!!n;p&&(i[o.property]=c),c?S(e,o,""):B(e,o);return}let a=n;if(o.spaceSeparated?a=b(n," "):o.commaSeparated?a=b(n,","):o.commaOrSpaceSeparated&&(a=b(n," ")),o.booleanish&&typeof a=="boolean"&&(a=a?"true":"false"),o.overloadedBoolean){if(a===false){B(e,o);return}if(a===true){S(e,o,"");return}}if(p){i[o.property]=a;return}a!==false&&S(e,o,a);},g=(e,t)=>{if(t!=null&&typeof t!="boolean"){if(H(t))throw new Error("Async values are not supported inside jsx template results.");if(Array.isArray(t)){t.forEach(n=>g(e,n));return}if(ye(t)){for(let n of t)g(e,n);return}if(xe(t)){e.appendChild(t);return}e.appendChild(document.createTextNode(String(t)));}},w=(e,t,n)=>L(e,t,r=>C(r,t,n)),q=I({getIdentifierName:x,evaluateExpressionWithNamespace:w}),we=(e,t,n,r)=>{let s=q(t,n,r);Object.entries(s).forEach(([o,i])=>{if(o!=="key"){if(o==="children"){g(e,i);return}be(e,o,i,r);}});},J=(e,t,n)=>{let r=[];return e.forEach(s=>{switch(s.type){case "JSXText":{O(s.value,t.placeholders).forEach(i=>{r.push(i);});break}case "JSXExpressionContainer":{if(s.expression.type==="JSXEmptyExpression")break;r.push(w(s.expression,t,n));break}case "JSXSpreadChild":{let o=w(s.expression,t,n);o!=null&&r.push(o);break}case "JSXElement":case "JSXFragment":{r.push(C(s,t,n));break}}}),r},Je=(e,t,n,r)=>{let s=q(e.openingElement.attributes,t,r),o=J(e.children,t,r);o.length===1?s.children=o[0]:o.length>1&&(s.children=o);let i=n(s);if(H(i))throw new Error("Async jsx components are not supported.");return i},Ce=(e,t,n)=>{let r=e.openingElement,s=x(r.name),o=t.components.get(s);if(o)return Je(e,t,o,n);if(/[A-Z]/.test(s[0]??""))throw new Error(`Unknown component "${s}". Did you interpolate it with the template literal?`);let i=s==="svg"?"svg":n,p=s==="foreignObject"?null:i,a=i==="svg"?document.createElementNS("http://www.w3.org/2000/svg",s):document.createElement(s);return we(a,r.attributes,t,i),J(e.children,t,p).forEach(l=>g(a,l)),a},C=(e,t,n)=>{if(e.type==="JSXFragment"){let r=document.createDocumentFragment();return J(e.children,t,n).forEach(o=>g(r,o)),r}return Ce(e,t,n)},K=(e,...t)=>{ge();let n=_(e,t),r=parseSync("inline.jsx",n.source,v);if(r.errors.length>0)throw new Error(j(r.errors[0]));let s=P(r.program),o={source:n.source,placeholders:n.placeholders,components:new Map(n.bindings.map(i=>[i.name,i.value]))};return C(s,o,null)};A();var Me=K;
|
|
4
|
+
export{Me as jsx};
|
package/dist/loader/jsx.js
CHANGED
|
@@ -159,6 +159,9 @@ class ReactTemplateBuilder {
|
|
|
159
159
|
throw new Error('[jsx-loader] Unable to inline complex expressions in react mode.');
|
|
160
160
|
}
|
|
161
161
|
/* c8 ignore next */
|
|
162
|
+
/* v8 ignore next */
|
|
163
|
+
/* istanbul ignore next */
|
|
164
|
+
// Should never happen because OXC always annotates expression ranges.
|
|
162
165
|
throw new Error('[jsx-loader] Unable to compile expression for react mode.');
|
|
163
166
|
}
|
|
164
167
|
buildCreateElement(type, props, children) {
|
|
@@ -270,11 +273,15 @@ const shouldInterpolateName = (name) => /^[A-Z]/.test(name.name);
|
|
|
270
273
|
const addSlot = (slots, source, range) => {
|
|
271
274
|
if (!range) {
|
|
272
275
|
/* c8 ignore next */
|
|
276
|
+
/* v8 ignore next */
|
|
277
|
+
// OXC always provides ranges; guard defends against malformed AST nodes.
|
|
273
278
|
return;
|
|
274
279
|
}
|
|
275
280
|
const [start, end] = range;
|
|
276
281
|
if (start === end) {
|
|
277
282
|
/* c8 ignore next */
|
|
283
|
+
/* v8 ignore next */
|
|
284
|
+
// Zero-length ranges indicate parser bugs and would emit empty slices.
|
|
278
285
|
return;
|
|
279
286
|
}
|
|
280
287
|
slots.push({
|
|
@@ -287,6 +294,9 @@ const collectSlots = (program, source) => {
|
|
|
287
294
|
const slots = [];
|
|
288
295
|
const recordComponentName = (name) => {
|
|
289
296
|
if (!name) {
|
|
297
|
+
/* c8 ignore next */
|
|
298
|
+
/* v8 ignore next */
|
|
299
|
+
// JSX elements emitted by OXC always carry a name; this is defensive.
|
|
290
300
|
return;
|
|
291
301
|
}
|
|
292
302
|
switch (name.type) {
|
|
@@ -356,6 +366,8 @@ const renderTemplateWithSlots = (source, slots) => {
|
|
|
356
366
|
slots.forEach(slot => {
|
|
357
367
|
if (slot.start < cursor) {
|
|
358
368
|
/* c8 ignore next */
|
|
369
|
+
/* v8 ignore next */
|
|
370
|
+
// Slots are generated from non-overlapping JSX ranges; this protects against parser regressions.
|
|
359
371
|
throw new Error('Overlapping JSX expressions detected inside template literal.');
|
|
360
372
|
}
|
|
361
373
|
output += escapeTemplateChunk(source.slice(cursor, slot.start));
|
|
@@ -463,6 +475,8 @@ const buildTemplateSource = (quasis, expressions, source, tag) => {
|
|
|
463
475
|
let chunk = quasi.value.cooked;
|
|
464
476
|
if (typeof chunk !== 'string') {
|
|
465
477
|
/* c8 ignore next */
|
|
478
|
+
/* v8 ignore next */
|
|
479
|
+
// Cooked text is always available for valid templates; fall back shields invalid escape sequences.
|
|
466
480
|
chunk = quasi.value.raw ?? '';
|
|
467
481
|
}
|
|
468
482
|
if (trimStartNext > 0) {
|
|
@@ -478,6 +492,8 @@ const buildTemplateSource = (quasis, expressions, source, tag) => {
|
|
|
478
492
|
const end = expression.end ?? null;
|
|
479
493
|
if (start === null || end === null) {
|
|
480
494
|
/* c8 ignore next */
|
|
495
|
+
/* v8 ignore next */
|
|
496
|
+
// Expressions parsed from tagged templates always include start/end ranges.
|
|
481
497
|
throw new Error('Unable to read template expression source range.');
|
|
482
498
|
}
|
|
483
499
|
const nextChunk = quasis[index + 1];
|
|
@@ -548,6 +564,8 @@ const isLoaderPlaceholderIdentifier = (node) => {
|
|
|
548
564
|
(node.type !== 'Identifier' && node.type !== 'JSXIdentifier') ||
|
|
549
565
|
typeof node.name !== 'string') {
|
|
550
566
|
/* c8 ignore next */
|
|
567
|
+
/* v8 ignore next */
|
|
568
|
+
// Visitor only calls this helper with identifier-like nodes; guard prevents crashes on malformed ASTs.
|
|
551
569
|
return false;
|
|
552
570
|
}
|
|
553
571
|
return (node.name.startsWith(TEMPLATE_EXPR_PLACEHOLDER_PREFIX) ||
|
|
@@ -599,6 +617,8 @@ const transformSource = (source, config) => {
|
|
|
599
617
|
return;
|
|
600
618
|
}
|
|
601
619
|
/* c8 ignore next */
|
|
620
|
+
/* v8 ignore next */
|
|
621
|
+
// Modes are validated during option parsing; this fallback guards future extensions.
|
|
602
622
|
throw new Error(`[jsx-loader] Transformation mode "${mode}" not implemented yet for tag "${tagName}".`);
|
|
603
623
|
});
|
|
604
624
|
return {
|
package/dist/node/bootstrap.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export declare const ensureNodeDom: () =>
|
|
1
|
+
export declare const ensureNodeDom: () => void;
|
|
2
|
+
export declare const __setNodeRequireForTesting: (mockRequire: NodeJS.Require | null) => void;
|
package/dist/node/bootstrap.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
const nodeRequire = createRequire(import.meta.url);
|
|
3
|
+
let requireOverride = null;
|
|
4
|
+
const resolveRequire = () => requireOverride ?? nodeRequire;
|
|
1
5
|
const DOM_TEMPLATE = '<!doctype html><html><body></body></html>';
|
|
2
6
|
const GLOBAL_KEYS = [
|
|
3
7
|
'window',
|
|
@@ -23,13 +27,13 @@ const assignGlobalTargets = (windowObj) => {
|
|
|
23
27
|
}
|
|
24
28
|
});
|
|
25
29
|
};
|
|
26
|
-
const loadLinkedom =
|
|
27
|
-
const { parseHTML } =
|
|
30
|
+
const loadLinkedom = () => {
|
|
31
|
+
const { parseHTML } = resolveRequire()('linkedom');
|
|
28
32
|
const { window } = parseHTML(DOM_TEMPLATE);
|
|
29
33
|
return window;
|
|
30
34
|
};
|
|
31
|
-
const loadJsdom =
|
|
32
|
-
const { JSDOM } =
|
|
35
|
+
const loadJsdom = () => {
|
|
36
|
+
const { JSDOM } = resolveRequire()('jsdom');
|
|
33
37
|
const { window } = new JSDOM(DOM_TEMPLATE);
|
|
34
38
|
return window;
|
|
35
39
|
};
|
|
@@ -52,11 +56,11 @@ const selectLoaders = () => {
|
|
|
52
56
|
}
|
|
53
57
|
return [loadLinkedom, loadJsdom];
|
|
54
58
|
};
|
|
55
|
-
const createShimWindow =
|
|
59
|
+
const createShimWindow = () => {
|
|
56
60
|
const errors = [];
|
|
57
61
|
for (const loader of selectLoaders()) {
|
|
58
62
|
try {
|
|
59
|
-
return
|
|
63
|
+
return loader();
|
|
60
64
|
}
|
|
61
65
|
catch (error) {
|
|
62
66
|
errors.push(error);
|
|
@@ -65,19 +69,15 @@ const createShimWindow = async () => {
|
|
|
65
69
|
const help = 'Unable to bootstrap a DOM-like environment. Install "linkedom" or "jsdom" (both optional peer dependencies) or set KNIGHTED_JSX_NODE_SHIM to pick one explicitly.';
|
|
66
70
|
throw new AggregateError(errors, help);
|
|
67
71
|
};
|
|
68
|
-
let
|
|
69
|
-
export const ensureNodeDom =
|
|
70
|
-
if (hasDom()) {
|
|
72
|
+
let bootstrapped = false;
|
|
73
|
+
export const ensureNodeDom = () => {
|
|
74
|
+
if (hasDom() || bootstrapped) {
|
|
71
75
|
return;
|
|
72
76
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
throw error;
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
return bootstrapPromise;
|
|
77
|
+
const windowObj = createShimWindow();
|
|
78
|
+
assignGlobalTargets(windowObj);
|
|
79
|
+
bootstrapped = true;
|
|
80
|
+
};
|
|
81
|
+
export const __setNodeRequireForTesting = (mockRequire) => {
|
|
82
|
+
requireOverride = mockRequire;
|
|
83
83
|
};
|
package/dist/node/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knighted/jsx",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "Runtime JSX tagged template that renders DOM or React trees anywhere without a build step.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jsx runtime",
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
"optionalDependencies": {
|
|
163
163
|
"@oxc-parser/binding-darwin-arm64": "^0.105.0",
|
|
164
164
|
"@oxc-parser/binding-linux-x64-gnu": "^0.105.0",
|
|
165
|
-
"@oxc-parser/binding-wasm32-wasi": "0.105.0"
|
|
165
|
+
"@oxc-parser/binding-wasm32-wasi": "^0.105.0"
|
|
166
166
|
},
|
|
167
167
|
"overrides": {
|
|
168
168
|
"module-lookup-amd": {
|