@knighted/jsx 1.6.3 → 1.7.0
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/loader/dom-template-builder.cjs +217 -0
- package/dist/cjs/loader/dom-template-builder.d.cts +12 -0
- package/dist/cjs/loader/helpers/dom-snippets.cjs +149 -0
- package/dist/cjs/loader/helpers/dom-snippets.d.cts +2 -0
- package/dist/cjs/loader/helpers/format-import-specifier.cjs +30 -0
- package/dist/cjs/loader/helpers/format-import-specifier.d.cts +13 -0
- package/dist/cjs/loader/helpers/materialize-slice.cjs +37 -0
- package/dist/cjs/loader/helpers/materialize-slice.d.cts +1 -0
- package/dist/cjs/loader/helpers/parse-range-key.cjs +14 -0
- package/dist/cjs/loader/helpers/parse-range-key.d.cts +1 -0
- package/dist/cjs/loader/helpers/rewrite-imports-without-tags.cjs +62 -0
- package/dist/cjs/loader/helpers/rewrite-imports-without-tags.d.cts +3 -0
- package/dist/cjs/loader/jsx.cjs +32 -33
- package/dist/cjs/loader/jsx.d.cts +1 -1
- package/dist/cjs/loader/modes.cjs +17 -0
- package/dist/cjs/loader/modes.d.cts +3 -0
- package/dist/cjs/runtime/shared.cjs +3 -13
- package/dist/cjs/shared/normalize-text.cjs +22 -0
- package/dist/cjs/shared/normalize-text.d.cts +1 -0
- package/dist/lite/debug/index.js +7 -7
- package/dist/lite/index.js +7 -7
- package/dist/lite/node/debug/index.js +7 -7
- package/dist/lite/node/index.js +7 -7
- package/dist/lite/node/react/index.js +5 -5
- package/dist/lite/react/index.js +5 -5
- package/dist/loader/dom-template-builder.d.ts +12 -0
- package/dist/loader/dom-template-builder.js +213 -0
- package/dist/loader/helpers/dom-snippets.d.ts +2 -0
- package/dist/loader/helpers/dom-snippets.js +146 -0
- package/dist/loader/helpers/format-import-specifier.d.ts +13 -0
- package/dist/loader/helpers/format-import-specifier.js +26 -0
- package/dist/loader/helpers/materialize-slice.d.ts +1 -0
- package/dist/loader/helpers/materialize-slice.js +33 -0
- package/dist/loader/helpers/parse-range-key.d.ts +1 -0
- package/dist/loader/helpers/parse-range-key.js +10 -0
- package/dist/loader/helpers/rewrite-imports-without-tags.d.ts +3 -0
- package/dist/loader/helpers/rewrite-imports-without-tags.js +58 -0
- package/dist/loader/jsx.d.ts +1 -1
- package/dist/loader/jsx.js +28 -29
- package/dist/loader/modes.d.ts +3 -0
- package/dist/loader/modes.js +13 -0
- package/dist/runtime/shared.js +3 -13
- package/dist/shared/normalize-text.d.ts +1 -0
- package/dist/shared/normalize-text.js +18 -0
- package/package.json +2 -2
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DOM_HELPER_SNIPPETS = exports.compileDomTemplate = void 0;
|
|
4
|
+
const oxc_parser_1 = require("oxc-parser");
|
|
5
|
+
const template_diagnostics_js_1 = require("../internal/template-diagnostics.cjs");
|
|
6
|
+
const dom_snippets_js_1 = require("./helpers/dom-snippets.cjs");
|
|
7
|
+
Object.defineProperty(exports, "DOM_HELPER_SNIPPETS", { enumerable: true, get: function () { return dom_snippets_js_1.DOM_HELPER_SNIPPETS; } });
|
|
8
|
+
const normalize_text_js_1 = require("../shared/normalize-text.cjs");
|
|
9
|
+
const TEMPLATE_PARSER_OPTIONS = {
|
|
10
|
+
lang: 'tsx',
|
|
11
|
+
sourceType: 'module',
|
|
12
|
+
range: true,
|
|
13
|
+
preserveParens: true,
|
|
14
|
+
};
|
|
15
|
+
const NAMESPACE_URIS = {
|
|
16
|
+
html: 'http://www.w3.org/1999/xhtml',
|
|
17
|
+
svg: 'http://www.w3.org/2000/svg',
|
|
18
|
+
math: 'http://www.w3.org/1998/Math/MathML',
|
|
19
|
+
};
|
|
20
|
+
const createPlaceholderMap = (placeholders) => new Map(placeholders.map(entry => [entry.marker, entry.code]));
|
|
21
|
+
const isLoaderPlaceholderIdentifier = (node) => {
|
|
22
|
+
const name = node.name;
|
|
23
|
+
return typeof name === 'string' && name.startsWith('__JSX_LOADER');
|
|
24
|
+
};
|
|
25
|
+
class DomTemplateBuilder {
|
|
26
|
+
placeholderMap;
|
|
27
|
+
helpers;
|
|
28
|
+
id = 0;
|
|
29
|
+
constructor(placeholderSource) {
|
|
30
|
+
this.placeholderMap = createPlaceholderMap(placeholderSource);
|
|
31
|
+
this.helpers = new Set();
|
|
32
|
+
}
|
|
33
|
+
compile(root) {
|
|
34
|
+
const code = this.compileNode(root, 'html');
|
|
35
|
+
return { code, helpers: this.helpers };
|
|
36
|
+
}
|
|
37
|
+
nextId(prefix) {
|
|
38
|
+
return `__jsxDom_${prefix}_${this.id++}`;
|
|
39
|
+
}
|
|
40
|
+
compileNode(node, namespace) {
|
|
41
|
+
if (node.type === 'JSXFragment') {
|
|
42
|
+
const fragVar = this.nextId('frag');
|
|
43
|
+
const lines = [`const ${fragVar} = document.createDocumentFragment()`];
|
|
44
|
+
node.children.forEach(child => {
|
|
45
|
+
const childExpr = this.compileChild(child, namespace);
|
|
46
|
+
if (childExpr) {
|
|
47
|
+
this.helpers.add('dom');
|
|
48
|
+
lines.push(`__jsxDomAppend(${fragVar}, ${childExpr})`);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
lines.push(`return ${fragVar}`);
|
|
52
|
+
return `(() => { ${lines.join('; ')} })()`;
|
|
53
|
+
}
|
|
54
|
+
const { tagExpr, namespace: tagNs } = this.compileTagName(node.openingElement.name);
|
|
55
|
+
const resolvedNs = tagNs ?? namespace;
|
|
56
|
+
const creator = resolvedNs === 'html'
|
|
57
|
+
? `document.createElement(${tagExpr})`
|
|
58
|
+
: `document.createElementNS('${NAMESPACE_URIS[resolvedNs]}', ${tagExpr})`;
|
|
59
|
+
const elVar = this.nextId('el');
|
|
60
|
+
const lines = [`const ${elVar} = ${creator}`];
|
|
61
|
+
node.openingElement.attributes.forEach(attr => {
|
|
62
|
+
if (attr.type === 'JSXSpreadAttribute') {
|
|
63
|
+
this.helpers.add('dom');
|
|
64
|
+
const value = this.compileExpression(attr.argument);
|
|
65
|
+
lines.push(`__jsxDomAssignProps(${elVar}, ${value}, '${resolvedNs}')`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const name = this.compileAttributeName(attr.name);
|
|
69
|
+
const valueExpr = this.compileAttributeValue(attr);
|
|
70
|
+
if (!valueExpr) {
|
|
71
|
+
/* c8 ignore next */
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.helpers.add('dom');
|
|
75
|
+
lines.push(`__jsxDomSetProp(${elVar}, ${name}, ${valueExpr}, '${resolvedNs}')`);
|
|
76
|
+
});
|
|
77
|
+
node.children.forEach(child => {
|
|
78
|
+
const childExpr = this.compileChild(child, resolvedNs);
|
|
79
|
+
if (childExpr) {
|
|
80
|
+
this.helpers.add('dom');
|
|
81
|
+
lines.push(`__jsxDomAppend(${elVar}, ${childExpr})`);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
lines.push(`return ${elVar}`);
|
|
85
|
+
return `(() => { ${lines.join('; ')} })()`;
|
|
86
|
+
}
|
|
87
|
+
compileAttributeValue(attr) {
|
|
88
|
+
if (!attr.value) {
|
|
89
|
+
return 'true';
|
|
90
|
+
}
|
|
91
|
+
if (attr.value.type === 'Literal') {
|
|
92
|
+
return JSON.stringify(attr.value.value);
|
|
93
|
+
}
|
|
94
|
+
if (attr.value.type === 'JSXExpressionContainer') {
|
|
95
|
+
const expr = attr.value.expression;
|
|
96
|
+
if (expr.type === 'JSXEmptyExpression') {
|
|
97
|
+
/* c8 ignore next */
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return this.compileExpression(expr);
|
|
101
|
+
}
|
|
102
|
+
/* c8 ignore next */
|
|
103
|
+
return 'undefined';
|
|
104
|
+
}
|
|
105
|
+
compileAttributeName(name) {
|
|
106
|
+
if (name.type === 'JSXIdentifier') {
|
|
107
|
+
return JSON.stringify(name.name);
|
|
108
|
+
}
|
|
109
|
+
if (name.type === 'JSXNamespacedName') {
|
|
110
|
+
return JSON.stringify(`${name.namespace.name}:${name.name.name}`);
|
|
111
|
+
}
|
|
112
|
+
if (name.type === 'JSXMemberExpression') {
|
|
113
|
+
return JSON.stringify(`${this.compileAttributeName(name.object).replace(/"/g, '')}.${name.property.name}`);
|
|
114
|
+
}
|
|
115
|
+
/* c8 ignore next */
|
|
116
|
+
return '""';
|
|
117
|
+
}
|
|
118
|
+
compileChild(child, namespace) {
|
|
119
|
+
switch (child.type) {
|
|
120
|
+
case 'JSXText': {
|
|
121
|
+
const text = (0, normalize_text_js_1.normalizeJsxText)(child.value);
|
|
122
|
+
if (!text)
|
|
123
|
+
return null;
|
|
124
|
+
return JSON.stringify(text);
|
|
125
|
+
}
|
|
126
|
+
case 'JSXExpressionContainer': {
|
|
127
|
+
if (child.expression.type === 'JSXEmptyExpression')
|
|
128
|
+
return null;
|
|
129
|
+
return this.compileExpression(child.expression);
|
|
130
|
+
}
|
|
131
|
+
case 'JSXSpreadChild': {
|
|
132
|
+
return this.compileExpression(child.expression);
|
|
133
|
+
}
|
|
134
|
+
case 'JSXElement':
|
|
135
|
+
case 'JSXFragment': {
|
|
136
|
+
return this.compileNode(child, namespace);
|
|
137
|
+
}
|
|
138
|
+
default:
|
|
139
|
+
/* c8 ignore next */
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
compileTagName(name) {
|
|
144
|
+
if (!name) {
|
|
145
|
+
/* c8 ignore next */
|
|
146
|
+
throw new Error('[jsx-loader] Encountered JSX element without a tag name.');
|
|
147
|
+
}
|
|
148
|
+
if (name.type === 'JSXIdentifier') {
|
|
149
|
+
if (isLoaderPlaceholderIdentifier(name)) {
|
|
150
|
+
const resolved = this.placeholderMap.get(name.name);
|
|
151
|
+
if (!resolved) {
|
|
152
|
+
throw new Error('[jsx-loader] Unable to resolve placeholder for tag expression.');
|
|
153
|
+
}
|
|
154
|
+
return { tagExpr: resolved, namespace: null };
|
|
155
|
+
}
|
|
156
|
+
const tagName = name.name;
|
|
157
|
+
const lower = tagName.toLowerCase();
|
|
158
|
+
if (lower === 'svg')
|
|
159
|
+
return { tagExpr: JSON.stringify(tagName), namespace: 'svg' };
|
|
160
|
+
if (lower === 'math')
|
|
161
|
+
return { tagExpr: JSON.stringify(tagName), namespace: 'math' };
|
|
162
|
+
return { tagExpr: JSON.stringify(tagName), namespace: null };
|
|
163
|
+
}
|
|
164
|
+
if (name.type === 'JSXMemberExpression') {
|
|
165
|
+
const tagExpr = `${this.compileAttributeName(name.object).replace(/"/g, '')}.${name.property.name}`;
|
|
166
|
+
return { tagExpr: JSON.stringify(tagExpr), namespace: null };
|
|
167
|
+
}
|
|
168
|
+
if (name.type === 'JSXNamespacedName') {
|
|
169
|
+
const tagExpr = `${name.namespace.name}:${name.name.name}`;
|
|
170
|
+
return { tagExpr: JSON.stringify(tagExpr), namespace: null };
|
|
171
|
+
}
|
|
172
|
+
/* c8 ignore next */
|
|
173
|
+
throw new Error('[jsx-loader] Unsupported tag expression in dom mode.');
|
|
174
|
+
}
|
|
175
|
+
compileExpression(node) {
|
|
176
|
+
if (node.type === 'JSXElement' || node.type === 'JSXFragment') {
|
|
177
|
+
return this.compileNode(node, 'html');
|
|
178
|
+
}
|
|
179
|
+
if (node.type === 'Identifier') {
|
|
180
|
+
const resolved = this.placeholderMap.get(node.name);
|
|
181
|
+
if (resolved)
|
|
182
|
+
return resolved;
|
|
183
|
+
return node.name;
|
|
184
|
+
}
|
|
185
|
+
if (node.type === 'Literal') {
|
|
186
|
+
return JSON.stringify(node.value);
|
|
187
|
+
}
|
|
188
|
+
if ('range' in node && Array.isArray(node.range)) {
|
|
189
|
+
throw new Error('[jsx-loader] Unable to inline complex expressions in dom mode.');
|
|
190
|
+
}
|
|
191
|
+
/* c8 ignore next */
|
|
192
|
+
throw new Error('[jsx-loader] Unable to compile expression for dom mode.');
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const compileDomTemplate = (templateSource, placeholders, resourcePath, tagName, templates, diagnostics) => {
|
|
196
|
+
const parsed = (0, oxc_parser_1.parseSync)(`${resourcePath}?jsx-dom-template`, templateSource, TEMPLATE_PARSER_OPTIONS);
|
|
197
|
+
if (parsed.errors.length > 0) {
|
|
198
|
+
throw new Error((0, template_diagnostics_js_1.formatTaggedTemplateParserError)(tagName, templates, diagnostics, parsed.errors[0], {
|
|
199
|
+
label: 'jsx-loader',
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
const root = extractJsxRoot(parsed.program);
|
|
203
|
+
const builder = new DomTemplateBuilder(placeholders);
|
|
204
|
+
return builder.compile(root);
|
|
205
|
+
};
|
|
206
|
+
exports.compileDomTemplate = compileDomTemplate;
|
|
207
|
+
const extractJsxRoot = (program) => {
|
|
208
|
+
for (const statement of program.body) {
|
|
209
|
+
if (statement.type === 'ExpressionStatement') {
|
|
210
|
+
const expression = statement.expression;
|
|
211
|
+
if (expression.type === 'JSXElement' || expression.type === 'JSXFragment') {
|
|
212
|
+
return expression;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
throw new Error('[jsx-loader] Expected the template to contain a single JSX root node.');
|
|
217
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type TemplateDiagnostics } from '../internal/template-diagnostics.cjs';
|
|
2
|
+
import { DOM_HELPER_SNIPPETS, type DomHelperKind } from './helpers/dom-snippets.cjs';
|
|
3
|
+
export type TemplatePlaceholder = {
|
|
4
|
+
marker: string;
|
|
5
|
+
code: string;
|
|
6
|
+
};
|
|
7
|
+
type DomCompileResult = {
|
|
8
|
+
code: string;
|
|
9
|
+
helpers: Set<DomHelperKind>;
|
|
10
|
+
};
|
|
11
|
+
export declare const compileDomTemplate: (templateSource: string, placeholders: TemplatePlaceholder[], resourcePath: string, tagName: string, templates: TemplateStringsArray, diagnostics: TemplateDiagnostics) => DomCompileResult;
|
|
12
|
+
export { DOM_HELPER_SNIPPETS };
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DOM_HELPER_SNIPPETS = void 0;
|
|
4
|
+
exports.DOM_HELPER_SNIPPETS = {
|
|
5
|
+
dom: `const __jsxDomAppend = (parent, child) => {
|
|
6
|
+
if (child === null || child === undefined || typeof child === 'boolean') return
|
|
7
|
+
if (Array.isArray(child)) { child.forEach(entry => __jsxDomAppend(parent, entry)); return }
|
|
8
|
+
if (typeof child === 'object' && typeof child[Symbol.iterator] === 'function') {
|
|
9
|
+
for (const entry of child) __jsxDomAppend(parent, entry); return
|
|
10
|
+
}
|
|
11
|
+
if (child instanceof Node) { parent.appendChild(child); return }
|
|
12
|
+
parent.appendChild(document.createTextNode(String(child)))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const __jsxDomClass = (el, value) => {
|
|
16
|
+
if (value === null || value === undefined || value === false) return
|
|
17
|
+
if (typeof value === 'string' || typeof value === 'number') { el.classList.add(...String(value).trim().split(/\\s+/u).filter(Boolean)); return }
|
|
18
|
+
if (Array.isArray(value)) { value.forEach(entry => __jsxDomClass(el, entry)); return }
|
|
19
|
+
if (typeof value === 'object') {
|
|
20
|
+
Object.entries(value).forEach(([key, active]) => {
|
|
21
|
+
if (active) el.classList.add(key)
|
|
22
|
+
else el.classList.remove(key)
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const __jsxDomStyle = (el, value) => {
|
|
28
|
+
if (value === null || value === undefined || value === false) return
|
|
29
|
+
const style = el.style
|
|
30
|
+
if (!style) return
|
|
31
|
+
if (typeof value === 'string') { style.cssText += value; return }
|
|
32
|
+
if (typeof value === 'object') {
|
|
33
|
+
Object.entries(value).forEach(([key, v]) => {
|
|
34
|
+
if (v === null || v === undefined) return
|
|
35
|
+
if (key.startsWith('--')) { style.setProperty(key, String(v)); return }
|
|
36
|
+
style[key] = v
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const __jsxDomResolveHandler = (propName, value) => {
|
|
42
|
+
if (typeof value === 'function' || (value && typeof value === 'object' && typeof value.handleEvent === 'function')) {
|
|
43
|
+
return { listener: value }
|
|
44
|
+
}
|
|
45
|
+
if (!value || typeof value !== 'object' || !('handler' in value)) {
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
const handler = value.handler
|
|
49
|
+
if (typeof handler !== 'function' && !(handler && typeof handler === 'object' && typeof handler.handleEvent === 'function')) {
|
|
50
|
+
return null
|
|
51
|
+
}
|
|
52
|
+
const options = value.options ? { ...value.options } : undefined
|
|
53
|
+
const assign = (key, v) => {
|
|
54
|
+
if (v === undefined || v === null) return
|
|
55
|
+
if (!options) options = {}
|
|
56
|
+
options[key] = v
|
|
57
|
+
}
|
|
58
|
+
assign('capture', value.capture)
|
|
59
|
+
assign('once', value.once)
|
|
60
|
+
assign('passive', value.passive)
|
|
61
|
+
assign('signal', value.signal ?? undefined)
|
|
62
|
+
return { listener: handler, options }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const __jsxDomParseEventName = raw => {
|
|
66
|
+
if (!raw.startsWith('on')) return null
|
|
67
|
+
if (raw.startsWith('on:')) {
|
|
68
|
+
const name = raw.slice(3)
|
|
69
|
+
if (!name) return null
|
|
70
|
+
const capture = name.endsWith('Capture')
|
|
71
|
+
const eventName = capture ? name.slice(0, -7) : name
|
|
72
|
+
if (!eventName) return null
|
|
73
|
+
return { eventName, capture }
|
|
74
|
+
}
|
|
75
|
+
const name = raw.slice(2)
|
|
76
|
+
if (!name) return null
|
|
77
|
+
const capture = name.endsWith('Capture')
|
|
78
|
+
const eventName = (capture ? name.slice(0, -7) : name).toLowerCase()
|
|
79
|
+
if (!eventName) return null
|
|
80
|
+
return { eventName, capture }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const __jsxDomEvent = (el, propName, value) => {
|
|
84
|
+
const parsed = __jsxDomParseEventName(propName)
|
|
85
|
+
if (!parsed) return false
|
|
86
|
+
const resolved = __jsxDomResolveHandler(propName, value)
|
|
87
|
+
if (!resolved) return true
|
|
88
|
+
let options = resolved.options ? { ...resolved.options } : undefined
|
|
89
|
+
if (parsed.capture) {
|
|
90
|
+
if (!options) options = { capture: true }
|
|
91
|
+
else options.capture = true
|
|
92
|
+
}
|
|
93
|
+
el.addEventListener(parsed.eventName, resolved.listener, options)
|
|
94
|
+
return true
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const __jsxDomNamespaceForAttr = (raw, namespace) => {
|
|
98
|
+
if (!raw.includes(':')) return null
|
|
99
|
+
const prefix = raw.split(':', 1)[0]
|
|
100
|
+
if (prefix === 'xml') return 'http://www.w3.org/XML/1998/namespace'
|
|
101
|
+
if (prefix === 'xlink') return 'http://www.w3.org/1999/xlink'
|
|
102
|
+
if (namespace === 'svg') return 'http://www.w3.org/2000/svg'
|
|
103
|
+
if (namespace === 'math') return 'http://www.w3.org/1998/Math/MathML'
|
|
104
|
+
return null
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const __jsxDomSetProp = (el, name, value, namespace) => {
|
|
108
|
+
if (value === null || value === undefined) return
|
|
109
|
+
if (name === 'dangerouslySetInnerHTML' && value && typeof value === 'object' && '__html' in value) {
|
|
110
|
+
el.innerHTML = String(value.__html ?? '')
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
const ns = __jsxDomNamespaceForAttr(name, namespace)
|
|
114
|
+
if (name === 'ref') {
|
|
115
|
+
if (typeof value === 'function') { value(el); return }
|
|
116
|
+
if (value && typeof value === 'object') { value.current = el; return }
|
|
117
|
+
}
|
|
118
|
+
if (name === 'class' || name === 'className') { __jsxDomClass(el, value); return }
|
|
119
|
+
if (name === 'style') { __jsxDomStyle(el, value); return }
|
|
120
|
+
if (__jsxDomEvent(el, name, value)) return
|
|
121
|
+
if (typeof value === 'boolean') {
|
|
122
|
+
if (value) {
|
|
123
|
+
if (ns) el.setAttributeNS(ns, name, '')
|
|
124
|
+
else el.setAttribute(name, '')
|
|
125
|
+
} else {
|
|
126
|
+
if (ns) el.removeAttributeNS(ns, name)
|
|
127
|
+
else el.removeAttribute(name)
|
|
128
|
+
}
|
|
129
|
+
if (name in el) { try { el[name] = value } catch {}
|
|
130
|
+
}
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
if (name.startsWith('data-')) { el.setAttribute(name, value as any); return }
|
|
134
|
+
if (name in el && name !== 'list') {
|
|
135
|
+
try { (el as any)[name] = value } catch {}
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
if (ns) el.setAttributeNS(ns, name, value as any)
|
|
139
|
+
else el.setAttribute(name, value as any)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const __jsxDomAssignProps = (el, props, namespace) => {
|
|
143
|
+
if (!props) return
|
|
144
|
+
Object.entries(props).forEach(([name, value]) => {
|
|
145
|
+
__jsxDomSetProp(el, name, value, namespace)
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
`,
|
|
149
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatImportSpecifier = void 0;
|
|
4
|
+
const formatImportSpecifier = (spec) => {
|
|
5
|
+
const node = spec;
|
|
6
|
+
if (node.type === 'ImportDefaultSpecifier') {
|
|
7
|
+
const name = node.local?.name;
|
|
8
|
+
if (!name) {
|
|
9
|
+
throw new Error('[jsx-loader] Encountered default import without a local name.');
|
|
10
|
+
}
|
|
11
|
+
return name;
|
|
12
|
+
}
|
|
13
|
+
if (node.type === 'ImportNamespaceSpecifier') {
|
|
14
|
+
const name = node.local?.name;
|
|
15
|
+
if (!name) {
|
|
16
|
+
throw new Error('[jsx-loader] Encountered namespace import without a local name.');
|
|
17
|
+
}
|
|
18
|
+
return `* as ${name}`;
|
|
19
|
+
}
|
|
20
|
+
if (node.type === 'ImportSpecifier') {
|
|
21
|
+
const imported = node.imported?.name;
|
|
22
|
+
if (!imported) {
|
|
23
|
+
throw new Error('[jsx-loader] Encountered named import without an imported name.');
|
|
24
|
+
}
|
|
25
|
+
const local = node.local?.name ?? imported;
|
|
26
|
+
return imported === local ? imported : `${imported} as ${local}`;
|
|
27
|
+
}
|
|
28
|
+
return '';
|
|
29
|
+
};
|
|
30
|
+
exports.formatImportSpecifier = formatImportSpecifier;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.materializeSlice = void 0;
|
|
4
|
+
const parse_range_key_js_1 = require("./parse-range-key.cjs");
|
|
5
|
+
const materializeSlice = (start, end, source, replacements) => {
|
|
6
|
+
const exact = replacements.get(`${start}:${end}`);
|
|
7
|
+
if (exact !== undefined) {
|
|
8
|
+
return exact;
|
|
9
|
+
}
|
|
10
|
+
const nested = [];
|
|
11
|
+
replacements.forEach((code, key) => {
|
|
12
|
+
const range = (0, parse_range_key_js_1.parseRangeKey)(key);
|
|
13
|
+
if (!range)
|
|
14
|
+
return;
|
|
15
|
+
const [rStart, rEnd] = range;
|
|
16
|
+
if (rStart >= start && rEnd <= end) {
|
|
17
|
+
nested.push({ start: rStart, end: rEnd, code });
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
if (!nested.length) {
|
|
21
|
+
return source.slice(start, end);
|
|
22
|
+
}
|
|
23
|
+
nested.sort((a, b) => a.start - b.start);
|
|
24
|
+
let cursor = start;
|
|
25
|
+
let output = '';
|
|
26
|
+
nested.forEach(entry => {
|
|
27
|
+
if (entry.start < cursor) {
|
|
28
|
+
throw new Error(`[jsx-loader] Overlapping replacement ranges detected (${entry.start}:${entry.end}) within ${start}:${end}. Nested replacements must not overlap.`);
|
|
29
|
+
}
|
|
30
|
+
output += source.slice(cursor, entry.start);
|
|
31
|
+
output += entry.code;
|
|
32
|
+
cursor = entry.end;
|
|
33
|
+
});
|
|
34
|
+
output += source.slice(cursor, end);
|
|
35
|
+
return output;
|
|
36
|
+
};
|
|
37
|
+
exports.materializeSlice = materializeSlice;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const materializeSlice: (start: number, end: number, source: string, replacements: Map<string, string>) => string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseRangeKey = void 0;
|
|
4
|
+
const parseRangeKey = (key) => {
|
|
5
|
+
const [start, end] = key.split(':').map(entry => Number.parseInt(entry, 10));
|
|
6
|
+
if (!Number.isFinite(start) || !Number.isFinite(end)) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
if (end < start) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
return [start, end];
|
|
13
|
+
};
|
|
14
|
+
exports.parseRangeKey = parseRangeKey;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const parseRangeKey: (key: string) => [number, number] | null;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rewriteImportsWithoutTags = void 0;
|
|
4
|
+
const format_import_specifier_js_1 = require("./format-import-specifier.cjs");
|
|
5
|
+
const rewriteImportsWithoutTags = (program, magic, inlineTagNames, originalSource) => {
|
|
6
|
+
if (!inlineTagNames.size) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
let mutated = false;
|
|
10
|
+
program.body.forEach(node => {
|
|
11
|
+
if (node.type !== 'ImportDeclaration') {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const specifiers = node.specifiers;
|
|
15
|
+
const kept = [];
|
|
16
|
+
let removed = false;
|
|
17
|
+
specifiers.forEach(spec => {
|
|
18
|
+
const localName = spec.local?.name;
|
|
19
|
+
if (!localName) {
|
|
20
|
+
kept.push(spec);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const shouldDrop = inlineTagNames.has(localName);
|
|
24
|
+
if (shouldDrop) {
|
|
25
|
+
removed = true;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
kept.push(spec);
|
|
29
|
+
});
|
|
30
|
+
if (!removed) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (!kept.length) {
|
|
34
|
+
magic.remove(node.start, node.end);
|
|
35
|
+
mutated = true;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const keyword = node.importKind === 'type' ? 'import type' : 'import';
|
|
39
|
+
const bindings = [];
|
|
40
|
+
const defaultSpec = kept.find(spec => spec.type === 'ImportDefaultSpecifier');
|
|
41
|
+
const namespaceSpec = kept.find(spec => spec.type === 'ImportNamespaceSpecifier');
|
|
42
|
+
const namedSpecs = kept.filter(spec => spec.type === 'ImportSpecifier');
|
|
43
|
+
if (defaultSpec) {
|
|
44
|
+
bindings.push((0, format_import_specifier_js_1.formatImportSpecifier)(defaultSpec));
|
|
45
|
+
}
|
|
46
|
+
if (namespaceSpec) {
|
|
47
|
+
bindings.push((0, format_import_specifier_js_1.formatImportSpecifier)(namespaceSpec));
|
|
48
|
+
}
|
|
49
|
+
if (namedSpecs.length) {
|
|
50
|
+
bindings.push(`{ ${namedSpecs.map(format_import_specifier_js_1.formatImportSpecifier).join(', ')} }`);
|
|
51
|
+
}
|
|
52
|
+
const sourceLiteral = node.source;
|
|
53
|
+
const sourceText = sourceLiteral.raw
|
|
54
|
+
? sourceLiteral.raw
|
|
55
|
+
: originalSource.slice(sourceLiteral.start ?? 0, sourceLiteral.end ?? 0);
|
|
56
|
+
const rewritten = `${keyword} ${bindings.join(', ')} from ${sourceText}`;
|
|
57
|
+
magic.overwrite(node.start, node.end, rewritten);
|
|
58
|
+
mutated = true;
|
|
59
|
+
});
|
|
60
|
+
return mutated;
|
|
61
|
+
};
|
|
62
|
+
exports.rewriteImportsWithoutTags = rewriteImportsWithoutTags;
|