@knighted/jsx 1.4.1 → 1.5.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/README.md +21 -1
- package/dist/cjs/cli/init.cjs +92 -5
- package/dist/cjs/cli/init.d.cts +14 -1
- package/dist/cjs/jsx-runtime.d.cts +18 -1
- package/dist/cjs/jsx.cjs +188 -16
- package/dist/cli/init.d.ts +14 -1
- package/dist/cli/init.js +86 -4
- package/dist/jsx-runtime.d.ts +18 -1
- package/dist/jsx.js +188 -16
- package/dist/lite/index.js +3 -3
- package/dist/lite/node/index.js +3 -3
- package/package.json +17 -6
package/README.md
CHANGED
|
@@ -99,7 +99,7 @@ The React runtime shares the same template semantics as `jsx`, except it returns
|
|
|
99
99
|
|
|
100
100
|
- `style` accepts either a string or an object. Object values handle CSS custom properties (`--token`) automatically.
|
|
101
101
|
- `class` and `className` both work and can be strings or arrays.
|
|
102
|
-
- Event handlers use the `on<Event>` naming convention (e.g. `onClick`).
|
|
102
|
+
- Event handlers use the `on<Event>` naming convention (e.g. `onClick`), support capture-phase variants via `on<Event>Capture`, and allow custom events with the `on:custom-event` syntax (descriptor objects with `{ handler, once, capture }` are also accepted).
|
|
103
103
|
- `ref` supports callback refs as well as mutable `{ current }` objects.
|
|
104
104
|
- `dangerouslySetInnerHTML` expects an object with an `__html` field, mirroring React.
|
|
105
105
|
|
|
@@ -286,6 +286,26 @@ import { reactJsx as nodeReactJsx } from '@knighted/jsx/node/react/lite'
|
|
|
286
286
|
|
|
287
287
|
Each lite subpath ships the same API as its standard counterpart but is pre-minified and scoped to just that runtime (DOM, React, Node DOM, or Node React). Swap them in when you want the smallest possible bundles; otherwise the default exports keep working as-is.
|
|
288
288
|
|
|
289
|
+
## Common gotchas
|
|
290
|
+
|
|
291
|
+
### DocumentFragment reuse (DOM helper)
|
|
292
|
+
|
|
293
|
+
`jsx` returns actual DOM nodes, so fragments compile down to real `DocumentFragment` instances. The browser treats those fragments as one-time transport containers: append them to a parent, and the fragment empties itself as it moves its children. Unlike VDOM libraries (React, Preact, Solid), we do not clone fragments on your behalf, so storing a fragment and reusing it later will not work the way a React developer might expect.
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
const header = jsx`
|
|
297
|
+
<>
|
|
298
|
+
<h1>Title</h1>
|
|
299
|
+
<p>Reusable? Only if you clone.</p>
|
|
300
|
+
</>
|
|
301
|
+
`
|
|
302
|
+
|
|
303
|
+
document.querySelector('header')!.append(header)
|
|
304
|
+
document.querySelector('footer')!.append(header) // footer stays empty
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
When you need multiple copies, call the template again, wrap it in a helper (``const makeHeader = () => jsx`<...>`; makeHeader()``), or clone the fragment before reusing it (`footer.append(header.cloneNode(true))`). Components that return fragments are unaffected because every invocation produces a fresh fragment.
|
|
308
|
+
|
|
289
309
|
## Limitations
|
|
290
310
|
|
|
291
311
|
- Requires a DOM-like environment (it throws when `document` is missing).
|
package/dist/cjs/cli/init.cjs
CHANGED
|
@@ -8,6 +8,9 @@ exports.detectPackageManager = detectPackageManager;
|
|
|
8
8
|
exports.ensurePackageJson = ensurePackageJson;
|
|
9
9
|
exports.runNpmPack = runNpmPack;
|
|
10
10
|
exports.parsePackageName = parsePackageName;
|
|
11
|
+
exports.resolveBindingSpec = resolveBindingSpec;
|
|
12
|
+
exports.fetchLatestBindingVersion = fetchLatestBindingVersion;
|
|
13
|
+
exports.readLocalOxcParserVersion = readLocalOxcParserVersion;
|
|
11
14
|
exports.installBinding = installBinding;
|
|
12
15
|
exports.installRuntimeDeps = installRuntimeDeps;
|
|
13
16
|
exports.isDependencyInstalled = isDependencyInstalled;
|
|
@@ -23,7 +26,10 @@ const promises_1 = __importDefault(require("node:readline/promises"));
|
|
|
23
26
|
const node_module_1 = require("node:module");
|
|
24
27
|
const node_url_1 = require("node:url");
|
|
25
28
|
const tar_1 = require("tar");
|
|
26
|
-
const
|
|
29
|
+
const CLI_REQUIRE = (0, node_module_1.createRequire)(typeof __filename !== 'undefined' ? __filename : node_path_1.default.join(process.cwd(), 'noop.js'));
|
|
30
|
+
const DEFAULT_BINDING_PACKAGE_NAME = '@oxc-parser/binding-wasm32-wasi';
|
|
31
|
+
const DEFAULT_BINDING_PACKAGE = process.env.WASM_BINDING_PACKAGE ?? DEFAULT_BINDING_PACKAGE_NAME;
|
|
32
|
+
const DEFAULT_BINDING_SOURCE = process.env.WASM_BINDING_PACKAGE ? 'env' : 'default';
|
|
27
33
|
const RUNTIME_DEPS = ['@napi-rs/wasm-runtime', '@emnapi/runtime', '@emnapi/core'];
|
|
28
34
|
const SUPPORTED_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun'];
|
|
29
35
|
// Node emits a noisy ExperimentalWarning whenever the WASI shim loads; silence just that message.
|
|
@@ -48,7 +54,9 @@ function parseArgs(argv) {
|
|
|
48
54
|
verbose: false,
|
|
49
55
|
force: false,
|
|
50
56
|
skipConfig: true,
|
|
51
|
-
wasmPackage:
|
|
57
|
+
wasmPackage: DEFAULT_BINDING_PACKAGE,
|
|
58
|
+
wasmVersion: undefined,
|
|
59
|
+
wasmPackageSource: DEFAULT_BINDING_SOURCE,
|
|
52
60
|
};
|
|
53
61
|
for (let i = 0; i < argv.length; i += 1) {
|
|
54
62
|
const arg = argv[i];
|
|
@@ -82,6 +90,14 @@ function parseArgs(argv) {
|
|
|
82
90
|
if (!pkg)
|
|
83
91
|
throw new Error('Missing value for --wasm-package');
|
|
84
92
|
options.wasmPackage = pkg;
|
|
93
|
+
options.wasmPackageSource = 'flag';
|
|
94
|
+
i += 1;
|
|
95
|
+
}
|
|
96
|
+
else if (arg === '--wasm-version') {
|
|
97
|
+
const version = argv[i + 1];
|
|
98
|
+
if (!version)
|
|
99
|
+
throw new Error('Missing value for --wasm-version');
|
|
100
|
+
options.wasmVersion = version;
|
|
85
101
|
i += 1;
|
|
86
102
|
}
|
|
87
103
|
else if (arg === '--help' || arg === '-h') {
|
|
@@ -92,7 +108,7 @@ function parseArgs(argv) {
|
|
|
92
108
|
return options;
|
|
93
109
|
}
|
|
94
110
|
function printHelp() {
|
|
95
|
-
console.log(`\nUsage: npx @knighted/jsx init [options]\n\nOptions:\n --package-manager, --pm <name> Choose npm | pnpm | yarn | bun\n --wasm-package <spec> Override binding package spec\n --config Prompt to help with loader config\n --skip-config Skip any loader config prompts (default)\n --dry-run Print actions without executing\n --force, --yes Assume yes for prompts\n --verbose Log extra detail\n -h, --help Show this help message\n`);
|
|
111
|
+
console.log(`\nUsage: npx @knighted/jsx init [options]\n\nOptions:\n --package-manager, --pm <name> Choose npm | pnpm | yarn | bun\n --wasm-package <spec> Override binding package spec\n --wasm-version <version> Pin version for the default binding\n --config Prompt to help with loader config\n --skip-config Skip any loader config prompts (default)\n --dry-run Print actions without executing\n --force, --yes Assume yes for prompts\n --verbose Log extra detail\n -h, --help Show this help message\n`);
|
|
96
112
|
}
|
|
97
113
|
function log(message) {
|
|
98
114
|
console.log(message);
|
|
@@ -148,6 +164,73 @@ function parsePackageName(spec) {
|
|
|
148
164
|
const [, name, version] = match;
|
|
149
165
|
return { name, version };
|
|
150
166
|
}
|
|
167
|
+
function readLocalOxcParserVersion(resolver = CLI_REQUIRE) {
|
|
168
|
+
try {
|
|
169
|
+
const pkg = resolver('oxc-parser/package.json');
|
|
170
|
+
if (pkg && typeof pkg.version === 'string') {
|
|
171
|
+
return pkg.version;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Ignore resolution failures and fall back to registry lookup later.
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
function isRegistryResolvablePackage(name) {
|
|
180
|
+
if (!name)
|
|
181
|
+
return false;
|
|
182
|
+
if (name.startsWith('.') || name.startsWith('/'))
|
|
183
|
+
return false;
|
|
184
|
+
if (node_path_1.default.isAbsolute(name))
|
|
185
|
+
return false;
|
|
186
|
+
const blockedPrefixes = [
|
|
187
|
+
'file:',
|
|
188
|
+
'link:',
|
|
189
|
+
'git+',
|
|
190
|
+
'github:',
|
|
191
|
+
'workspace:',
|
|
192
|
+
'http://',
|
|
193
|
+
'https://',
|
|
194
|
+
];
|
|
195
|
+
return !blockedPrefixes.some(prefix => name.startsWith(prefix));
|
|
196
|
+
}
|
|
197
|
+
function fetchLatestBindingVersion(pkgName, execFn = node_child_process_1.execFileSync) {
|
|
198
|
+
const output = execFn('npm', ['view', pkgName, 'version', '--json'], {
|
|
199
|
+
encoding: 'utf8',
|
|
200
|
+
stdio: ['ignore', 'pipe', 'inherit'],
|
|
201
|
+
}).trim();
|
|
202
|
+
if (!output) {
|
|
203
|
+
throw new Error(`Unable to determine latest version for ${pkgName}`);
|
|
204
|
+
}
|
|
205
|
+
const parsed = JSON.parse(output);
|
|
206
|
+
if (typeof parsed === 'string')
|
|
207
|
+
return parsed;
|
|
208
|
+
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
209
|
+
const last = parsed[parsed.length - 1];
|
|
210
|
+
if (typeof last === 'string')
|
|
211
|
+
return last;
|
|
212
|
+
}
|
|
213
|
+
throw new Error(`Unable to determine latest version for ${pkgName}`);
|
|
214
|
+
}
|
|
215
|
+
function resolveBindingSpec(spec, explicitVersion, fetchLatest = fetchLatestBindingVersion) {
|
|
216
|
+
let combinedSpec = spec;
|
|
217
|
+
if (explicitVersion) {
|
|
218
|
+
const { name } = parsePackageName(spec);
|
|
219
|
+
if (!name) {
|
|
220
|
+
throw new Error(`Unable to parse binding package spec: ${spec}`);
|
|
221
|
+
}
|
|
222
|
+
combinedSpec = `${name}@${explicitVersion}`;
|
|
223
|
+
}
|
|
224
|
+
const { name, version } = parsePackageName(combinedSpec);
|
|
225
|
+
if (!name) {
|
|
226
|
+
throw new Error(`Unable to parse binding package spec: ${spec}`);
|
|
227
|
+
}
|
|
228
|
+
if (version || !isRegistryResolvablePackage(name)) {
|
|
229
|
+
return { spec: combinedSpec, name, version };
|
|
230
|
+
}
|
|
231
|
+
const latest = fetchLatest(name);
|
|
232
|
+
return { spec: `${name}@${latest}`, name, version: latest };
|
|
233
|
+
}
|
|
151
234
|
async function installBinding(spec, cwd, dryRun, verbose, pack = runNpmPack) {
|
|
152
235
|
const { name, version } = parsePackageName(spec);
|
|
153
236
|
const tarballName = pack(spec, cwd, dryRun, verbose);
|
|
@@ -248,13 +331,17 @@ async function maybeHandleConfigPrompt(skipConfig, force) {
|
|
|
248
331
|
console.log(LOADER_CONFIG_EXAMPLE);
|
|
249
332
|
}
|
|
250
333
|
async function main(overrides = {}) {
|
|
251
|
-
const { parseArgs: parseArgsImpl = parseArgs, ensurePackageJson: ensurePackageJsonImpl = ensurePackageJson, detectPackageManager: detectPackageManagerImpl = detectPackageManager, installRuntimeDeps: installRuntimeDepsImpl = installRuntimeDeps, installBinding: installBindingImpl = installBinding, persistBindingSpec: persistBindingSpecImpl = persistBindingSpec, verifyBinding: verifyBindingImpl = verifyBinding, maybeHandleConfigPrompt: maybeHandleConfigPromptImpl = maybeHandleConfigPrompt, log: logImpl = log, } = overrides;
|
|
334
|
+
const { parseArgs: parseArgsImpl = parseArgs, ensurePackageJson: ensurePackageJsonImpl = ensurePackageJson, detectPackageManager: detectPackageManagerImpl = detectPackageManager, installRuntimeDeps: installRuntimeDepsImpl = installRuntimeDeps, installBinding: installBindingImpl = installBinding, persistBindingSpec: persistBindingSpecImpl = persistBindingSpec, verifyBinding: verifyBindingImpl = verifyBinding, maybeHandleConfigPrompt: maybeHandleConfigPromptImpl = maybeHandleConfigPrompt, resolveBindingSpec: resolveBindingSpecImpl = resolveBindingSpec, readLocalOxcParserVersion: readLocalOxcParserVersionImpl = readLocalOxcParserVersion, log: logImpl = log, } = overrides;
|
|
252
335
|
const options = parseArgsImpl(process.argv.slice(2));
|
|
253
336
|
ensurePackageJsonImpl(options.cwd);
|
|
337
|
+
const bundledParserVersion = readLocalOxcParserVersionImpl();
|
|
338
|
+
const desiredBindingVersion = options.wasmVersion ??
|
|
339
|
+
(options.wasmPackageSource === 'default' ? bundledParserVersion : undefined);
|
|
340
|
+
const resolvedBinding = resolveBindingSpecImpl(options.wasmPackage, desiredBindingVersion);
|
|
254
341
|
const packageManager = detectPackageManagerImpl(options.cwd, options.packageManager);
|
|
255
342
|
logImpl(`> Using package manager: ${packageManager}`);
|
|
256
343
|
const installedRuntimeDeps = installRuntimeDepsImpl(packageManager, RUNTIME_DEPS, options.cwd, options.dryRun, options.verbose);
|
|
257
|
-
const binding = await installBindingImpl(
|
|
344
|
+
const binding = await installBindingImpl(resolvedBinding.spec, options.cwd, options.dryRun, options.verbose);
|
|
258
345
|
persistBindingSpecImpl(options.cwd, binding.name, binding.version, options.dryRun, options.verbose);
|
|
259
346
|
let resolvedPath;
|
|
260
347
|
if (!options.dryRun) {
|
package/dist/cjs/cli/init.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
2
3
|
declare const SUPPORTED_PACKAGE_MANAGERS: readonly ["npm", "pnpm", "yarn", "bun"];
|
|
3
4
|
type PackageManager = (typeof SUPPORTED_PACKAGE_MANAGERS)[number];
|
|
4
5
|
type CliOptions = {
|
|
@@ -9,6 +10,8 @@ type CliOptions = {
|
|
|
9
10
|
skipConfig: boolean;
|
|
10
11
|
packageManager?: PackageManager;
|
|
11
12
|
wasmPackage: string;
|
|
13
|
+
wasmVersion?: string;
|
|
14
|
+
wasmPackageSource: 'default' | 'env' | 'flag';
|
|
12
15
|
};
|
|
13
16
|
declare function parseArgs(argv: string[]): CliOptions;
|
|
14
17
|
declare function log(message: string): void;
|
|
@@ -22,6 +25,14 @@ declare function parsePackageName(spec: string): {
|
|
|
22
25
|
name: string;
|
|
23
26
|
version: string;
|
|
24
27
|
};
|
|
28
|
+
type NodeRequireFn = ReturnType<typeof createRequire>;
|
|
29
|
+
declare function readLocalOxcParserVersion(resolver?: NodeRequireFn): string | undefined;
|
|
30
|
+
declare function fetchLatestBindingVersion(pkgName: string, execFn?: typeof execFileSync): string;
|
|
31
|
+
declare function resolveBindingSpec(spec: string, explicitVersion?: string, fetchLatest?: typeof fetchLatestBindingVersion): {
|
|
32
|
+
spec: string;
|
|
33
|
+
name: string;
|
|
34
|
+
version: string | undefined;
|
|
35
|
+
};
|
|
25
36
|
type PackFunction = (spec: string, cwd: string, dryRun: boolean, verbose: boolean) => string;
|
|
26
37
|
declare function installBinding(spec: string, cwd: string, dryRun: boolean, verbose: boolean, pack?: PackFunction): Promise<{
|
|
27
38
|
targetDir: string;
|
|
@@ -45,7 +56,9 @@ type MainDeps = {
|
|
|
45
56
|
persistBindingSpec: typeof persistBindingSpec;
|
|
46
57
|
verifyBinding: typeof verifyBinding;
|
|
47
58
|
maybeHandleConfigPrompt: typeof maybeHandleConfigPrompt;
|
|
59
|
+
resolveBindingSpec: typeof resolveBindingSpec;
|
|
60
|
+
readLocalOxcParserVersion: typeof readLocalOxcParserVersion;
|
|
48
61
|
log: typeof log;
|
|
49
62
|
};
|
|
50
63
|
declare function main(overrides?: Partial<MainDeps>): Promise<void>;
|
|
51
|
-
export { parseArgs, detectPackageManager, ensurePackageJson, runNpmPack, parsePackageName, installBinding, installRuntimeDeps, isDependencyInstalled, persistBindingSpec, verifyBinding, promptYesNo, maybeHandleConfigPrompt, main, };
|
|
64
|
+
export { parseArgs, detectPackageManager, ensurePackageJson, runNpmPack, parsePackageName, resolveBindingSpec, fetchLatestBindingVersion, readLocalOxcParserVersion, installBinding, installRuntimeDeps, isDependencyInstalled, persistBindingSpec, verifyBinding, promptYesNo, maybeHandleConfigPrompt, main, };
|
|
@@ -9,8 +9,25 @@ type DataAttributes = {
|
|
|
9
9
|
type AriaAttributes = {
|
|
10
10
|
[K in `aria-${string}`]?: string | number | boolean | null | undefined;
|
|
11
11
|
};
|
|
12
|
+
type JsxEventListener<EV extends Event> = ((event: EV) => void) | {
|
|
13
|
+
handleEvent(event: EV): void;
|
|
14
|
+
};
|
|
15
|
+
type JsxEventDescriptor<EV extends Event> = {
|
|
16
|
+
handler: JsxEventListener<EV>;
|
|
17
|
+
capture?: boolean;
|
|
18
|
+
once?: boolean;
|
|
19
|
+
passive?: boolean;
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
};
|
|
22
|
+
type JsxEventProp<EV extends Event> = JsxEventListener<EV> | JsxEventDescriptor<EV>;
|
|
12
23
|
type EventHandlers<T extends EventTarget> = {
|
|
13
|
-
[K in keyof GlobalEventHandlersEventMap as `on${Capitalize<string & K>}`]?:
|
|
24
|
+
[K in keyof GlobalEventHandlersEventMap as `on${Capitalize<string & K>}`]?: JsxEventProp<GlobalEventHandlersEventMap[K]>;
|
|
25
|
+
} & {
|
|
26
|
+
[K in keyof GlobalEventHandlersEventMap as `on${Capitalize<string & K>}Capture`]?: JsxEventProp<GlobalEventHandlersEventMap[K]>;
|
|
27
|
+
} & {
|
|
28
|
+
[K in string as K extends '' ? never : `on:${K}`]?: JsxEventProp<CustomEvent<unknown>>;
|
|
29
|
+
} & {
|
|
30
|
+
[K in string as K extends '' ? never : `on:${K}Capture`]?: JsxEventProp<CustomEvent<unknown>>;
|
|
14
31
|
};
|
|
15
32
|
type ElementProps<Tag extends keyof HTMLElementTagNameMap> = Omit<Partial<HTMLElementTagNameMap[Tag]>, 'children'> & EventHandlers<HTMLElementTagNameMap[Tag]> & DataAttributes & AriaAttributes & {
|
|
16
33
|
class?: string;
|
package/dist/cjs/jsx.cjs
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.jsx = void 0;
|
|
4
4
|
const oxc_parser_1 = require("oxc-parser");
|
|
5
5
|
const shared_js_1 = require("./runtime/shared.cjs");
|
|
6
|
+
const property_information_1 = require("property-information");
|
|
6
7
|
const ensureDomAvailable = () => {
|
|
7
8
|
if (typeof document === 'undefined' || typeof document.createElement !== 'function') {
|
|
8
9
|
throw new Error('The jsx template tag requires a DOM-like environment (document missing).');
|
|
@@ -26,8 +27,131 @@ const isPromiseLike = (value) => {
|
|
|
26
27
|
}
|
|
27
28
|
return typeof value.then === 'function';
|
|
28
29
|
};
|
|
29
|
-
const
|
|
30
|
-
|
|
30
|
+
const ATTRIBUTE_NAMESPACE_URIS = {
|
|
31
|
+
xlink: 'http://www.w3.org/1999/xlink',
|
|
32
|
+
xml: 'http://www.w3.org/XML/1998/namespace',
|
|
33
|
+
xmlns: 'http://www.w3.org/2000/xmlns/',
|
|
34
|
+
};
|
|
35
|
+
const getAttributeNamespace = (space) => {
|
|
36
|
+
if (!space || space === 'html' || space === 'svg') {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
return ATTRIBUTE_NAMESPACE_URIS[space];
|
|
40
|
+
};
|
|
41
|
+
const getSchemaForNamespace = (namespace) => namespace === 'svg' ? property_information_1.svg : property_information_1.html;
|
|
42
|
+
const setAttributeValue = (element, info, value) => {
|
|
43
|
+
const namespaceUri = getAttributeNamespace(info.space);
|
|
44
|
+
const attrValue = String(value);
|
|
45
|
+
if (namespaceUri) {
|
|
46
|
+
element.setAttributeNS(namespaceUri, info.attribute, attrValue);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
element.setAttribute(info.attribute, attrValue);
|
|
50
|
+
};
|
|
51
|
+
const removeAttributeValue = (element, info) => {
|
|
52
|
+
const namespaceUri = getAttributeNamespace(info.space);
|
|
53
|
+
if (namespaceUri) {
|
|
54
|
+
element.removeAttributeNS(namespaceUri, info.attribute);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
element.removeAttribute(info.attribute);
|
|
58
|
+
};
|
|
59
|
+
const joinTokenList = (value, delimiter) => {
|
|
60
|
+
if (!Array.isArray(value)) {
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
return value.filter(Boolean).join(delimiter);
|
|
64
|
+
};
|
|
65
|
+
const shouldAssignProperty = (element, namespace, info) => {
|
|
66
|
+
if (namespace === 'svg') {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
if (!info.property || info.property.includes(':')) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return info.property in element;
|
|
73
|
+
};
|
|
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
|
+
const setDomProp = (element, name, value, namespace) => {
|
|
154
|
+
if (value === null || value === undefined) {
|
|
31
155
|
return;
|
|
32
156
|
}
|
|
33
157
|
if (name === 'dangerouslySetInnerHTML' &&
|
|
@@ -67,27 +191,75 @@ const setDomProp = (element, name, value) => {
|
|
|
67
191
|
});
|
|
68
192
|
return;
|
|
69
193
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
194
|
+
const eventBinding = parseEventPropName(name);
|
|
195
|
+
if (eventBinding) {
|
|
196
|
+
const handlerValue = resolveEventHandlerValue(value);
|
|
197
|
+
if (handlerValue) {
|
|
198
|
+
let options = handlerValue.options ? { ...handlerValue.options } : undefined;
|
|
199
|
+
if (eventBinding.capture) {
|
|
200
|
+
if (!options) {
|
|
201
|
+
options = { capture: true };
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
options.capture = true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
element.addEventListener(eventBinding.eventName, handlerValue.listener, options);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const info = (0, property_information_1.find)(getSchemaForNamespace(namespace), name);
|
|
212
|
+
const elementWithIndex = element;
|
|
213
|
+
const canAssignProperty = shouldAssignProperty(element, namespace, info);
|
|
214
|
+
if (info.mustUseProperty) {
|
|
215
|
+
const nextValue = info.boolean ? Boolean(value) : value;
|
|
216
|
+
elementWithIndex[info.property] = nextValue;
|
|
73
217
|
return;
|
|
74
218
|
}
|
|
75
|
-
if (
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
219
|
+
if (info.boolean) {
|
|
220
|
+
const boolValue = Boolean(value);
|
|
221
|
+
if (canAssignProperty) {
|
|
222
|
+
elementWithIndex[info.property] = boolValue;
|
|
223
|
+
}
|
|
224
|
+
if (boolValue) {
|
|
225
|
+
setAttributeValue(element, info, '');
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
removeAttributeValue(element, info);
|
|
229
|
+
}
|
|
80
230
|
return;
|
|
81
231
|
}
|
|
82
|
-
|
|
83
|
-
|
|
232
|
+
let normalizedValue = value;
|
|
233
|
+
if (info.spaceSeparated) {
|
|
234
|
+
normalizedValue = joinTokenList(value, ' ');
|
|
235
|
+
}
|
|
236
|
+
else if (info.commaSeparated) {
|
|
237
|
+
normalizedValue = joinTokenList(value, ',');
|
|
238
|
+
}
|
|
239
|
+
else if (info.commaOrSpaceSeparated) {
|
|
240
|
+
normalizedValue = joinTokenList(value, ' ');
|
|
241
|
+
}
|
|
242
|
+
if (info.booleanish && typeof normalizedValue === 'boolean') {
|
|
243
|
+
normalizedValue = normalizedValue ? 'true' : 'false';
|
|
244
|
+
}
|
|
245
|
+
if (info.overloadedBoolean) {
|
|
246
|
+
if (normalizedValue === false) {
|
|
247
|
+
removeAttributeValue(element, info);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (normalizedValue === true) {
|
|
251
|
+
setAttributeValue(element, info, '');
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (canAssignProperty) {
|
|
256
|
+
elementWithIndex[info.property] = normalizedValue;
|
|
84
257
|
return;
|
|
85
258
|
}
|
|
86
|
-
if (
|
|
87
|
-
element[name] = value;
|
|
259
|
+
if (normalizedValue === false) {
|
|
88
260
|
return;
|
|
89
261
|
}
|
|
90
|
-
element
|
|
262
|
+
setAttributeValue(element, info, normalizedValue);
|
|
91
263
|
};
|
|
92
264
|
const appendChildValue = (parent, value) => {
|
|
93
265
|
if (value === null || value === undefined) {
|
|
@@ -154,7 +326,7 @@ const applyDomAttributes = (element, attributes, ctx, namespace) => {
|
|
|
154
326
|
appendChildValue(element, value);
|
|
155
327
|
return;
|
|
156
328
|
}
|
|
157
|
-
setDomProp(element, name, value);
|
|
329
|
+
setDomProp(element, name, value, namespace);
|
|
158
330
|
});
|
|
159
331
|
};
|
|
160
332
|
const evaluateJsxChildren = (children, ctx, namespace) => {
|
package/dist/cli/init.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
2
3
|
declare const SUPPORTED_PACKAGE_MANAGERS: readonly ["npm", "pnpm", "yarn", "bun"];
|
|
3
4
|
type PackageManager = (typeof SUPPORTED_PACKAGE_MANAGERS)[number];
|
|
4
5
|
type CliOptions = {
|
|
@@ -9,6 +10,8 @@ type CliOptions = {
|
|
|
9
10
|
skipConfig: boolean;
|
|
10
11
|
packageManager?: PackageManager;
|
|
11
12
|
wasmPackage: string;
|
|
13
|
+
wasmVersion?: string;
|
|
14
|
+
wasmPackageSource: 'default' | 'env' | 'flag';
|
|
12
15
|
};
|
|
13
16
|
declare function parseArgs(argv: string[]): CliOptions;
|
|
14
17
|
declare function log(message: string): void;
|
|
@@ -22,6 +25,14 @@ declare function parsePackageName(spec: string): {
|
|
|
22
25
|
name: string;
|
|
23
26
|
version: string;
|
|
24
27
|
};
|
|
28
|
+
type NodeRequireFn = ReturnType<typeof createRequire>;
|
|
29
|
+
declare function readLocalOxcParserVersion(resolver?: NodeRequireFn): string | undefined;
|
|
30
|
+
declare function fetchLatestBindingVersion(pkgName: string, execFn?: typeof execFileSync): string;
|
|
31
|
+
declare function resolveBindingSpec(spec: string, explicitVersion?: string, fetchLatest?: typeof fetchLatestBindingVersion): {
|
|
32
|
+
spec: string;
|
|
33
|
+
name: string;
|
|
34
|
+
version: string | undefined;
|
|
35
|
+
};
|
|
25
36
|
type PackFunction = (spec: string, cwd: string, dryRun: boolean, verbose: boolean) => string;
|
|
26
37
|
declare function installBinding(spec: string, cwd: string, dryRun: boolean, verbose: boolean, pack?: PackFunction): Promise<{
|
|
27
38
|
targetDir: string;
|
|
@@ -45,7 +56,9 @@ type MainDeps = {
|
|
|
45
56
|
persistBindingSpec: typeof persistBindingSpec;
|
|
46
57
|
verifyBinding: typeof verifyBinding;
|
|
47
58
|
maybeHandleConfigPrompt: typeof maybeHandleConfigPrompt;
|
|
59
|
+
resolveBindingSpec: typeof resolveBindingSpec;
|
|
60
|
+
readLocalOxcParserVersion: typeof readLocalOxcParserVersion;
|
|
48
61
|
log: typeof log;
|
|
49
62
|
};
|
|
50
63
|
declare function main(overrides?: Partial<MainDeps>): Promise<void>;
|
|
51
|
-
export { parseArgs, detectPackageManager, ensurePackageJson, runNpmPack, parsePackageName, installBinding, installRuntimeDeps, isDependencyInstalled, persistBindingSpec, verifyBinding, promptYesNo, maybeHandleConfigPrompt, main, };
|
|
64
|
+
export { parseArgs, detectPackageManager, ensurePackageJson, runNpmPack, parsePackageName, resolveBindingSpec, fetchLatestBindingVersion, readLocalOxcParserVersion, installBinding, installRuntimeDeps, isDependencyInstalled, persistBindingSpec, verifyBinding, promptYesNo, maybeHandleConfigPrompt, main, };
|
package/dist/cli/init.js
CHANGED
|
@@ -7,7 +7,12 @@ import { createRequire } from 'module';
|
|
|
7
7
|
import { pathToFileURL } from 'url';
|
|
8
8
|
import { extract } from 'tar';
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var CLI_REQUIRE = createRequire(
|
|
11
|
+
typeof __filename !== "undefined" ? __filename : path.join(process.cwd(), "noop.js")
|
|
12
|
+
);
|
|
13
|
+
var DEFAULT_BINDING_PACKAGE_NAME = "@oxc-parser/binding-wasm32-wasi";
|
|
14
|
+
var DEFAULT_BINDING_PACKAGE = process.env.WASM_BINDING_PACKAGE ?? DEFAULT_BINDING_PACKAGE_NAME;
|
|
15
|
+
var DEFAULT_BINDING_SOURCE = process.env.WASM_BINDING_PACKAGE ? "env" : "default";
|
|
11
16
|
var RUNTIME_DEPS = ["@napi-rs/wasm-runtime", "@emnapi/runtime", "@emnapi/core"];
|
|
12
17
|
var SUPPORTED_PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
13
18
|
var WASI_WARNING_SNIPPET = "WASI is an experimental feature";
|
|
@@ -31,7 +36,9 @@ function parseArgs(argv) {
|
|
|
31
36
|
verbose: false,
|
|
32
37
|
force: false,
|
|
33
38
|
skipConfig: true,
|
|
34
|
-
wasmPackage:
|
|
39
|
+
wasmPackage: DEFAULT_BINDING_PACKAGE,
|
|
40
|
+
wasmVersion: void 0,
|
|
41
|
+
wasmPackageSource: DEFAULT_BINDING_SOURCE
|
|
35
42
|
};
|
|
36
43
|
for (let i = 0; i < argv.length; i += 1) {
|
|
37
44
|
const arg = argv[i];
|
|
@@ -57,6 +64,12 @@ function parseArgs(argv) {
|
|
|
57
64
|
const pkg = argv[i + 1];
|
|
58
65
|
if (!pkg) throw new Error("Missing value for --wasm-package");
|
|
59
66
|
options.wasmPackage = pkg;
|
|
67
|
+
options.wasmPackageSource = "flag";
|
|
68
|
+
i += 1;
|
|
69
|
+
} else if (arg === "--wasm-version") {
|
|
70
|
+
const version = argv[i + 1];
|
|
71
|
+
if (!version) throw new Error("Missing value for --wasm-version");
|
|
72
|
+
options.wasmVersion = version;
|
|
60
73
|
i += 1;
|
|
61
74
|
} else if (arg === "--help" || arg === "-h") {
|
|
62
75
|
printHelp();
|
|
@@ -73,6 +86,7 @@ Usage: npx @knighted/jsx init [options]
|
|
|
73
86
|
Options:
|
|
74
87
|
--package-manager, --pm <name> Choose npm | pnpm | yarn | bun
|
|
75
88
|
--wasm-package <spec> Override binding package spec
|
|
89
|
+
--wasm-version <version> Pin version for the default binding
|
|
76
90
|
--config Prompt to help with loader config
|
|
77
91
|
--skip-config Skip any loader config prompts (default)
|
|
78
92
|
--dry-run Print actions without executing
|
|
@@ -128,6 +142,66 @@ function parsePackageName(spec) {
|
|
|
128
142
|
const [, name, version] = match;
|
|
129
143
|
return { name, version };
|
|
130
144
|
}
|
|
145
|
+
function readLocalOxcParserVersion(resolver = CLI_REQUIRE) {
|
|
146
|
+
try {
|
|
147
|
+
const pkg = resolver("oxc-parser/package.json");
|
|
148
|
+
if (pkg && typeof pkg.version === "string") {
|
|
149
|
+
return pkg.version;
|
|
150
|
+
}
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
function isRegistryResolvablePackage(name) {
|
|
156
|
+
if (!name) return false;
|
|
157
|
+
if (name.startsWith(".") || name.startsWith("/")) return false;
|
|
158
|
+
if (path.isAbsolute(name)) return false;
|
|
159
|
+
const blockedPrefixes = [
|
|
160
|
+
"file:",
|
|
161
|
+
"link:",
|
|
162
|
+
"git+",
|
|
163
|
+
"github:",
|
|
164
|
+
"workspace:",
|
|
165
|
+
"http://",
|
|
166
|
+
"https://"
|
|
167
|
+
];
|
|
168
|
+
return !blockedPrefixes.some((prefix) => name.startsWith(prefix));
|
|
169
|
+
}
|
|
170
|
+
function fetchLatestBindingVersion(pkgName, execFn = execFileSync) {
|
|
171
|
+
const output = execFn("npm", ["view", pkgName, "version", "--json"], {
|
|
172
|
+
encoding: "utf8",
|
|
173
|
+
stdio: ["ignore", "pipe", "inherit"]
|
|
174
|
+
}).trim();
|
|
175
|
+
if (!output) {
|
|
176
|
+
throw new Error(`Unable to determine latest version for ${pkgName}`);
|
|
177
|
+
}
|
|
178
|
+
const parsed = JSON.parse(output);
|
|
179
|
+
if (typeof parsed === "string") return parsed;
|
|
180
|
+
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
181
|
+
const last = parsed[parsed.length - 1];
|
|
182
|
+
if (typeof last === "string") return last;
|
|
183
|
+
}
|
|
184
|
+
throw new Error(`Unable to determine latest version for ${pkgName}`);
|
|
185
|
+
}
|
|
186
|
+
function resolveBindingSpec(spec, explicitVersion, fetchLatest = fetchLatestBindingVersion) {
|
|
187
|
+
let combinedSpec = spec;
|
|
188
|
+
if (explicitVersion) {
|
|
189
|
+
const { name: name2 } = parsePackageName(spec);
|
|
190
|
+
if (!name2) {
|
|
191
|
+
throw new Error(`Unable to parse binding package spec: ${spec}`);
|
|
192
|
+
}
|
|
193
|
+
combinedSpec = `${name2}@${explicitVersion}`;
|
|
194
|
+
}
|
|
195
|
+
const { name, version } = parsePackageName(combinedSpec);
|
|
196
|
+
if (!name) {
|
|
197
|
+
throw new Error(`Unable to parse binding package spec: ${spec}`);
|
|
198
|
+
}
|
|
199
|
+
if (version || !isRegistryResolvablePackage(name)) {
|
|
200
|
+
return { spec: combinedSpec, name, version };
|
|
201
|
+
}
|
|
202
|
+
const latest = fetchLatest(name);
|
|
203
|
+
return { spec: `${name}@${latest}`, name, version: latest };
|
|
204
|
+
}
|
|
131
205
|
async function installBinding(spec, cwd, dryRun, verbose, pack = runNpmPack) {
|
|
132
206
|
const { name, version } = parsePackageName(spec);
|
|
133
207
|
const tarballName = pack(spec, cwd, dryRun, verbose);
|
|
@@ -240,10 +314,18 @@ async function main(overrides = {}) {
|
|
|
240
314
|
persistBindingSpec: persistBindingSpecImpl = persistBindingSpec,
|
|
241
315
|
verifyBinding: verifyBindingImpl = verifyBinding,
|
|
242
316
|
maybeHandleConfigPrompt: maybeHandleConfigPromptImpl = maybeHandleConfigPrompt,
|
|
317
|
+
resolveBindingSpec: resolveBindingSpecImpl = resolveBindingSpec,
|
|
318
|
+
readLocalOxcParserVersion: readLocalOxcParserVersionImpl = readLocalOxcParserVersion,
|
|
243
319
|
log: logImpl = log
|
|
244
320
|
} = overrides;
|
|
245
321
|
const options = parseArgsImpl(process.argv.slice(2));
|
|
246
322
|
ensurePackageJsonImpl(options.cwd);
|
|
323
|
+
const bundledParserVersion = readLocalOxcParserVersionImpl();
|
|
324
|
+
const desiredBindingVersion = options.wasmVersion ?? (options.wasmPackageSource === "default" ? bundledParserVersion : void 0);
|
|
325
|
+
const resolvedBinding = resolveBindingSpecImpl(
|
|
326
|
+
options.wasmPackage,
|
|
327
|
+
desiredBindingVersion
|
|
328
|
+
);
|
|
247
329
|
const packageManager = detectPackageManagerImpl(options.cwd, options.packageManager);
|
|
248
330
|
logImpl(`> Using package manager: ${packageManager}`);
|
|
249
331
|
const installedRuntimeDeps = installRuntimeDepsImpl(
|
|
@@ -254,7 +336,7 @@ async function main(overrides = {}) {
|
|
|
254
336
|
options.verbose
|
|
255
337
|
);
|
|
256
338
|
const binding = await installBindingImpl(
|
|
257
|
-
|
|
339
|
+
resolvedBinding.spec,
|
|
258
340
|
options.cwd,
|
|
259
341
|
options.dryRun,
|
|
260
342
|
options.verbose
|
|
@@ -303,4 +385,4 @@ function suppressExperimentalWasiWarning() {
|
|
|
303
385
|
});
|
|
304
386
|
}
|
|
305
387
|
|
|
306
|
-
export { detectPackageManager, ensurePackageJson, installBinding, installRuntimeDeps, isDependencyInstalled, main, maybeHandleConfigPrompt, parseArgs, parsePackageName, persistBindingSpec, promptYesNo, runNpmPack, verifyBinding };
|
|
388
|
+
export { detectPackageManager, ensurePackageJson, fetchLatestBindingVersion, installBinding, installRuntimeDeps, isDependencyInstalled, main, maybeHandleConfigPrompt, parseArgs, parsePackageName, persistBindingSpec, promptYesNo, readLocalOxcParserVersion, resolveBindingSpec, runNpmPack, verifyBinding };
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -9,8 +9,25 @@ type DataAttributes = {
|
|
|
9
9
|
type AriaAttributes = {
|
|
10
10
|
[K in `aria-${string}`]?: string | number | boolean | null | undefined;
|
|
11
11
|
};
|
|
12
|
+
type JsxEventListener<EV extends Event> = ((event: EV) => void) | {
|
|
13
|
+
handleEvent(event: EV): void;
|
|
14
|
+
};
|
|
15
|
+
type JsxEventDescriptor<EV extends Event> = {
|
|
16
|
+
handler: JsxEventListener<EV>;
|
|
17
|
+
capture?: boolean;
|
|
18
|
+
once?: boolean;
|
|
19
|
+
passive?: boolean;
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
};
|
|
22
|
+
type JsxEventProp<EV extends Event> = JsxEventListener<EV> | JsxEventDescriptor<EV>;
|
|
12
23
|
type EventHandlers<T extends EventTarget> = {
|
|
13
|
-
[K in keyof GlobalEventHandlersEventMap as `on${Capitalize<string & K>}`]?:
|
|
24
|
+
[K in keyof GlobalEventHandlersEventMap as `on${Capitalize<string & K>}`]?: JsxEventProp<GlobalEventHandlersEventMap[K]>;
|
|
25
|
+
} & {
|
|
26
|
+
[K in keyof GlobalEventHandlersEventMap as `on${Capitalize<string & K>}Capture`]?: JsxEventProp<GlobalEventHandlersEventMap[K]>;
|
|
27
|
+
} & {
|
|
28
|
+
[K in string as K extends '' ? never : `on:${K}`]?: JsxEventProp<CustomEvent<unknown>>;
|
|
29
|
+
} & {
|
|
30
|
+
[K in string as K extends '' ? never : `on:${K}Capture`]?: JsxEventProp<CustomEvent<unknown>>;
|
|
14
31
|
};
|
|
15
32
|
type ElementProps<Tag extends keyof HTMLElementTagNameMap> = Omit<Partial<HTMLElementTagNameMap[Tag]>, 'children'> & EventHandlers<HTMLElementTagNameMap[Tag]> & DataAttributes & AriaAttributes & {
|
|
16
33
|
class?: string;
|
package/dist/jsx.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { parseSync } from 'oxc-parser';
|
|
2
2
|
import { buildTemplate, evaluateExpression, extractRootNode, formatParserError, getIdentifierName, normalizeJsxTextSegments, parserOptions, } from './runtime/shared.js';
|
|
3
|
+
import { find as findPropertyInfo, html as htmlProperties, svg as svgProperties, } from 'property-information';
|
|
3
4
|
const ensureDomAvailable = () => {
|
|
4
5
|
if (typeof document === 'undefined' || typeof document.createElement !== 'function') {
|
|
5
6
|
throw new Error('The jsx template tag requires a DOM-like environment (document missing).');
|
|
@@ -23,8 +24,131 @@ const isPromiseLike = (value) => {
|
|
|
23
24
|
}
|
|
24
25
|
return typeof value.then === 'function';
|
|
25
26
|
};
|
|
26
|
-
const
|
|
27
|
-
|
|
27
|
+
const ATTRIBUTE_NAMESPACE_URIS = {
|
|
28
|
+
xlink: 'http://www.w3.org/1999/xlink',
|
|
29
|
+
xml: 'http://www.w3.org/XML/1998/namespace',
|
|
30
|
+
xmlns: 'http://www.w3.org/2000/xmlns/',
|
|
31
|
+
};
|
|
32
|
+
const getAttributeNamespace = (space) => {
|
|
33
|
+
if (!space || space === 'html' || space === 'svg') {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
return ATTRIBUTE_NAMESPACE_URIS[space];
|
|
37
|
+
};
|
|
38
|
+
const getSchemaForNamespace = (namespace) => namespace === 'svg' ? svgProperties : htmlProperties;
|
|
39
|
+
const setAttributeValue = (element, info, value) => {
|
|
40
|
+
const namespaceUri = getAttributeNamespace(info.space);
|
|
41
|
+
const attrValue = String(value);
|
|
42
|
+
if (namespaceUri) {
|
|
43
|
+
element.setAttributeNS(namespaceUri, info.attribute, attrValue);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
element.setAttribute(info.attribute, attrValue);
|
|
47
|
+
};
|
|
48
|
+
const removeAttributeValue = (element, info) => {
|
|
49
|
+
const namespaceUri = getAttributeNamespace(info.space);
|
|
50
|
+
if (namespaceUri) {
|
|
51
|
+
element.removeAttributeNS(namespaceUri, info.attribute);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
element.removeAttribute(info.attribute);
|
|
55
|
+
};
|
|
56
|
+
const joinTokenList = (value, delimiter) => {
|
|
57
|
+
if (!Array.isArray(value)) {
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
return value.filter(Boolean).join(delimiter);
|
|
61
|
+
};
|
|
62
|
+
const shouldAssignProperty = (element, namespace, info) => {
|
|
63
|
+
if (namespace === 'svg') {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (!info.property || info.property.includes(':')) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return info.property in element;
|
|
70
|
+
};
|
|
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
|
+
const setDomProp = (element, name, value, namespace) => {
|
|
151
|
+
if (value === null || value === undefined) {
|
|
28
152
|
return;
|
|
29
153
|
}
|
|
30
154
|
if (name === 'dangerouslySetInnerHTML' &&
|
|
@@ -64,27 +188,75 @@ const setDomProp = (element, name, value) => {
|
|
|
64
188
|
});
|
|
65
189
|
return;
|
|
66
190
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
191
|
+
const eventBinding = parseEventPropName(name);
|
|
192
|
+
if (eventBinding) {
|
|
193
|
+
const handlerValue = resolveEventHandlerValue(value);
|
|
194
|
+
if (handlerValue) {
|
|
195
|
+
let options = handlerValue.options ? { ...handlerValue.options } : undefined;
|
|
196
|
+
if (eventBinding.capture) {
|
|
197
|
+
if (!options) {
|
|
198
|
+
options = { capture: true };
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
options.capture = true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
element.addEventListener(eventBinding.eventName, handlerValue.listener, options);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const info = findPropertyInfo(getSchemaForNamespace(namespace), name);
|
|
209
|
+
const elementWithIndex = element;
|
|
210
|
+
const canAssignProperty = shouldAssignProperty(element, namespace, info);
|
|
211
|
+
if (info.mustUseProperty) {
|
|
212
|
+
const nextValue = info.boolean ? Boolean(value) : value;
|
|
213
|
+
elementWithIndex[info.property] = nextValue;
|
|
70
214
|
return;
|
|
71
215
|
}
|
|
72
|
-
if (
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
216
|
+
if (info.boolean) {
|
|
217
|
+
const boolValue = Boolean(value);
|
|
218
|
+
if (canAssignProperty) {
|
|
219
|
+
elementWithIndex[info.property] = boolValue;
|
|
220
|
+
}
|
|
221
|
+
if (boolValue) {
|
|
222
|
+
setAttributeValue(element, info, '');
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
removeAttributeValue(element, info);
|
|
226
|
+
}
|
|
77
227
|
return;
|
|
78
228
|
}
|
|
79
|
-
|
|
80
|
-
|
|
229
|
+
let normalizedValue = value;
|
|
230
|
+
if (info.spaceSeparated) {
|
|
231
|
+
normalizedValue = joinTokenList(value, ' ');
|
|
232
|
+
}
|
|
233
|
+
else if (info.commaSeparated) {
|
|
234
|
+
normalizedValue = joinTokenList(value, ',');
|
|
235
|
+
}
|
|
236
|
+
else if (info.commaOrSpaceSeparated) {
|
|
237
|
+
normalizedValue = joinTokenList(value, ' ');
|
|
238
|
+
}
|
|
239
|
+
if (info.booleanish && typeof normalizedValue === 'boolean') {
|
|
240
|
+
normalizedValue = normalizedValue ? 'true' : 'false';
|
|
241
|
+
}
|
|
242
|
+
if (info.overloadedBoolean) {
|
|
243
|
+
if (normalizedValue === false) {
|
|
244
|
+
removeAttributeValue(element, info);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (normalizedValue === true) {
|
|
248
|
+
setAttributeValue(element, info, '');
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (canAssignProperty) {
|
|
253
|
+
elementWithIndex[info.property] = normalizedValue;
|
|
81
254
|
return;
|
|
82
255
|
}
|
|
83
|
-
if (
|
|
84
|
-
element[name] = value;
|
|
256
|
+
if (normalizedValue === false) {
|
|
85
257
|
return;
|
|
86
258
|
}
|
|
87
|
-
element
|
|
259
|
+
setAttributeValue(element, info, normalizedValue);
|
|
88
260
|
};
|
|
89
261
|
const appendChildValue = (parent, value) => {
|
|
90
262
|
if (value === null || value === undefined) {
|
|
@@ -151,7 +323,7 @@ const applyDomAttributes = (element, attributes, ctx, namespace) => {
|
|
|
151
323
|
appendChildValue(element, value);
|
|
152
324
|
return;
|
|
153
325
|
}
|
|
154
|
-
setDomProp(element, name, value);
|
|
326
|
+
setDomProp(element, name, value, namespace);
|
|
155
327
|
});
|
|
156
328
|
};
|
|
157
329
|
const evaluateJsxChildren = (children, ctx, namespace) => {
|
package/dist/lite/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {parseSync}from'oxc-parser';var
|
|
1
|
+
import {parseSync}from'oxc-parser';import {find,svg,html}from'property-information';var F=/<\s*$/,B=/<\/\s*$/,T="__KX_EXPR__",C=new RegExp(`${T}\\d+_\\d+__`,"g"),M=0,N={lang:"jsx",sourceType:"module",range:true,preserveParens:true},A=e=>{let n=`[oxc-parser] ${e.message}`;if(e.labels?.length){let t=e.labels[0];t.message&&(n+=`
|
|
2
2
|
${t.message}`);}return e.codeframe&&(n+=`
|
|
3
|
-
${e.codeframe}`),n},
|
|
4
|
-
export{
|
|
3
|
+
${e.codeframe}`),n},k=e=>{for(let n of e.body)if(n.type==="ExpressionStatement"){let t=n.expression;if(t.type==="JSXElement"||t.type==="JSXFragment")return t}throw new Error("The jsx template must contain a single JSX element or fragment.")},y=e=>{switch(e.type){case "JSXIdentifier":return e.name;case "JSXNamespacedName":return `${e.namespace.name}:${e.name.name}`;case "JSXMemberExpression":return `${y(e.object)}.${e.property.name}`;default:return ""}},E=(e,n)=>{if(!e||typeof e!="object")return;let t=e;typeof t.type=="string"&&(n(t),Object.values(t).forEach(r=>{if(r){if(Array.isArray(r)){r.forEach(o=>E(o,n));return}typeof r=="object"&&E(r,n);}}));},X=(e,n)=>{let t=e.replace(/\r/g,"").replace(/\n\s+/g," "),r=e.match(/^\s*/)?.[0]??"",o=e.match(/\s*$/)?.[0]??"",s=/\n/.test(r),a=/\n/.test(o),c=t;if(s&&(c=c.replace(/^\s+/,"")),a&&(c=c.replace(/\s+$/,"")),c.length===0||c.trim().length===0)return [];let i=[];C.lastIndex=0;let p=0,l;for(;l=C.exec(c);){let u=l.index,m=c.slice(p,u);m&&i.push(m);let f=l[0];n.has(f)?i.push(n.get(f)):i.push(f),p=u+f.length;}let d=c.slice(p);return d&&i.push(d),i},D=(e,n)=>{let t=new Set;return E(e,r=>{r.type==="Identifier"&&n.placeholders.has(r.name)&&t.add(r.name);}),Array.from(t)},P=(e,n,t)=>{if(e.type==="JSXElement"||e.type==="JSXFragment")return t(e);if(!("range"in e)||!e.range)throw new Error("Unable to evaluate expression: missing source range information.");let[r,o]=e.range,s=n.source.slice(r,o),a=D(e,n);try{let c=new Function(...a,`"use strict"; return (${s});`),i=a.map(p=>n.placeholders.get(p));return c(...i)}catch(c){throw new Error(`Failed to evaluate expression ${s}: ${c.message}`)}},W=e=>{let n=e.replace(/[^a-zA-Z0-9_$]/g,"");return n?/[A-Za-z_$]/.test(n[0])?n:`Component${n}`:"Component"},H=(e,n,t)=>{let r=t.get(e);if(r)return r;let o=e.displayName||e.name||`Component${n.length}`,s=W(o??""),a=s,c=1;for(;n.some(p=>p.name===a);)a=`${s}${c++}`;let i={name:a,value:e};return n.push(i),t.set(e,i),i},R=(e,n)=>{let t=e.raw??e,r=new Map,o=[],s=new Map,a=t[0]??"",c=M++,i=0;for(let p=0;p<n.length;p++){let l=t[p]??"",d=t[p+1]??"",u=n[p],m=F.test(l)||B.test(l);if(m&&typeof u=="function"){let $=H(u,o,s);a+=$.name+d;continue}if(m&&typeof u=="string"){a+=u+d;continue}let f=`${T}${c}_${i++}__`;r.set(f,u),a+=f+d;}return {source:a,placeholders:r,bindings:o}};var Z=()=>{if(typeof document>"u"||typeof document.createElement!="function")throw new Error("The jsx template tag requires a DOM-like environment (document missing).")},G=e=>typeof Node>"u"?false:e instanceof Node||e instanceof DocumentFragment,q=e=>!e||typeof e=="string"?false:typeof e[Symbol.iterator]=="function",v=e=>!e||typeof e!="object"&&typeof e!="function"?false:typeof e.then=="function",Q={xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},I=e=>{if(!(!e||e==="html"||e==="svg"))return Q[e]},Y=e=>e==="svg"?svg:html,h=(e,n,t)=>{let r=I(n.space),o=String(t);if(r){e.setAttributeNS(r,n.attribute,o);return}e.setAttribute(n.attribute,o);},j=(e,n)=>{let t=I(n.space);if(t){e.removeAttributeNS(t,n.attribute);return}e.removeAttribute(n.attribute);},b=(e,n)=>Array.isArray(e)?e.filter(Boolean).join(n):e,ee=(e,n,t)=>n==="svg"||!t.property||t.property.includes(":")?false:t.property in e,S="Capture",O=e=>e.endsWith(S)&&e.length>S.length?{eventName:e.slice(0,-S.length),capture:true}:{eventName:e,capture:false},ne=e=>{if(!e.startsWith("on"))return null;if(e.startsWith("on:")){let r=e.slice(3);if(!r)return null;let o=O(r);return o.eventName?o:null}let n=e.slice(2);if(!n)return null;let t=O(n);return t.eventName?{eventName:t.eventName.toLowerCase(),capture:t.capture}:null},L=e=>!e||typeof e!="object"?false:"handleEvent"in e&&typeof e.handleEvent=="function",te=e=>{if(!e||typeof e!="object"||!("handler"in e))return false;let n=e.handler;return typeof n=="function"?true:L(n)},re=e=>{if(typeof e=="function"||L(e))return {listener:e};if(!te(e))return null;let n=e,t=n.options?{...n.options}:void 0,r=(o,s)=>{s!=null&&(t||(t={}),t[o]=s);};return r("capture",n.capture),r("once",n.once),r("passive",n.passive),r("signal",n.signal??void 0),{listener:n.handler,options:t}},oe=(e,n,t,r)=>{if(t==null)return;if(n==="dangerouslySetInnerHTML"&&typeof t=="object"&&t&&"__html"in t){e.innerHTML=String(t.__html??"");return}if(n==="ref"){if(typeof t=="function"){t(e);return}if(t&&typeof t=="object"){t.current=e;return}}if(n==="style"&&typeof t=="object"&&t!==null){let p=t,l=e.style;if(!l)return;let d=l;Object.entries(p).forEach(([u,m])=>{if(m!=null){if(u.startsWith("--")){l.setProperty(u,String(m));return}d[u]=m;}});return}let o=ne(n);if(o){let p=re(t);if(p){let l=p.options?{...p.options}:void 0;o.capture&&(l?l.capture=true:l={capture:true}),e.addEventListener(o.eventName,p.listener,l);return}}let s=find(Y(r),n),a=e,c=ee(e,r,s);if(s.mustUseProperty){let p=s.boolean?!!t:t;a[s.property]=p;return}if(s.boolean){let p=!!t;c&&(a[s.property]=p),p?h(e,s,""):j(e,s);return}let i=t;if(s.spaceSeparated?i=b(t," "):s.commaSeparated?i=b(t,","):s.commaOrSpaceSeparated&&(i=b(t," ")),s.booleanish&&typeof i=="boolean"&&(i=i?"true":"false"),s.overloadedBoolean){if(i===false){j(e,s);return}if(i===true){h(e,s,"");return}}if(c){a[s.property]=i;return}i!==false&&h(e,s,i);},g=(e,n)=>{if(n!=null&&typeof n!="boolean"){if(v(n))throw new Error("Async values are not supported inside jsx template results.");if(Array.isArray(n)){n.forEach(t=>g(e,t));return}if(q(n)){for(let t of n)g(e,t);return}if(G(n)){e.appendChild(n);return}e.appendChild(document.createTextNode(String(n)));}},x=(e,n,t)=>P(e,n,r=>w(r,n,t)),_=(e,n,t)=>{let r={};return e.forEach(o=>{if(o.type==="JSXSpreadAttribute"){let a=x(o.argument,n,t);a&&typeof a=="object"&&!Array.isArray(a)&&Object.assign(r,a);return}let s=y(o.name);if(!o.value){r[s]=true;return}if(o.value.type==="Literal"){r[s]=o.value.value;return}if(o.value.type==="JSXExpressionContainer"){if(o.value.expression.type==="JSXEmptyExpression")return;r[s]=x(o.value.expression,n,t);}}),r},se=(e,n,t,r)=>{let o=_(n,t,r);Object.entries(o).forEach(([s,a])=>{if(s!=="key"){if(s==="children"){g(e,a);return}oe(e,s,a,r);}});},J=(e,n,t)=>{let r=[];return e.forEach(o=>{switch(o.type){case "JSXText":{X(o.value,n.placeholders).forEach(a=>{r.push(a);});break}case "JSXExpressionContainer":{if(o.expression.type==="JSXEmptyExpression")break;r.push(x(o.expression,n,t));break}case "JSXSpreadChild":{let s=x(o.expression,n,t);s!=null&&r.push(s);break}case "JSXElement":case "JSXFragment":{r.push(w(o,n,t));break}}}),r},ae=(e,n,t,r)=>{let o=_(e.openingElement.attributes,n,r),s=J(e.children,n,r);s.length===1?o.children=s[0]:s.length>1&&(o.children=s);let a=t(o);if(v(a))throw new Error("Async jsx components are not supported.");return a},ie=(e,n,t)=>{let r=e.openingElement,o=y(r.name),s=n.components.get(o);if(s)return ae(e,n,s,t);if(/[A-Z]/.test(o[0]??""))throw new Error(`Unknown component "${o}". Did you interpolate it with the template literal?`);let a=o==="svg"?"svg":t,c=o==="foreignObject"?null:a,i=a==="svg"?document.createElementNS("http://www.w3.org/2000/svg",o):document.createElement(o);return se(i,r.attributes,n,a),J(e.children,n,c).forEach(l=>g(i,l)),i},w=(e,n,t)=>{if(e.type==="JSXFragment"){let r=document.createDocumentFragment();return J(e.children,n,t).forEach(s=>g(r,s)),r}return ie(e,n,t)},pe=(e,...n)=>{Z();let t=R(e,n),r=parseSync("inline.jsx",t.source,N);if(r.errors.length>0)throw new Error(A(r.errors[0]));let o=k(r.program),s={source:t.source,placeholders:t.placeholders,components:new Map(t.bindings.map(a=>[a.name,a.value]))};return w(o,s,null)};
|
|
4
|
+
export{pe as jsx};
|
package/dist/lite/node/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {parseSync}from'oxc-parser';var
|
|
1
|
+
import {parseSync}from'oxc-parser';import {find,svg,html}from'property-information';var k="<!doctype html><html><body></body></html>",V=["window","self","document","HTMLElement","Element","Node","DocumentFragment","customElements","Text","Comment","MutationObserver","navigator"],K=()=>typeof document<"u"&&typeof document.createElement=="function",U=e=>{let n=globalThis,t=e;V.forEach(r=>{n[r]===void 0&&t[r]!==void 0&&(n[r]=t[r]);});},E=async()=>{let{parseHTML:e}=await import('linkedom'),{window:n}=e(k);return n},S=async()=>{let{JSDOM:e}=await import('jsdom'),{window:n}=new e(k);return n},z=()=>{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"},G=()=>{let e=z();return e==="linkedom"?[E,S]:e==="jsdom"?[S,E]:[E,S]},Z=async()=>{let e=[];for(let t of G())try{return await t()}catch(r){e.push(r);}let n='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,n)},y=null,A=async()=>{if(!K())return y||(y=(async()=>{let e=await Z();U(e);})().catch(e=>{throw y=null,e})),y};var q=/<\s*$/,Y=/<\/\s*$/,P="__KX_EXPR__",X=new RegExp(`${P}\\d+_\\d+__`,"g"),Q=0,O={lang:"jsx",sourceType:"module",range:true,preserveParens:true},R=e=>{let n=`[oxc-parser] ${e.message}`;if(e.labels?.length){let t=e.labels[0];t.message&&(n+=`
|
|
2
2
|
${t.message}`);}return e.codeframe&&(n+=`
|
|
3
|
-
${e.codeframe}`),n},
|
|
4
|
-
export{
|
|
3
|
+
${e.codeframe}`),n},j=e=>{for(let n of e.body)if(n.type==="ExpressionStatement"){let t=n.expression;if(t.type==="JSXElement"||t.type==="JSXFragment")return t}throw new Error("The jsx template must contain a single JSX element or fragment.")},h=e=>{switch(e.type){case "JSXIdentifier":return e.name;case "JSXNamespacedName":return `${e.namespace.name}:${e.name.name}`;case "JSXMemberExpression":return `${h(e.object)}.${e.property.name}`;default:return ""}},w=(e,n)=>{if(!e||typeof e!="object")return;let t=e;typeof t.type=="string"&&(n(t),Object.values(t).forEach(r=>{if(r){if(Array.isArray(r)){r.forEach(o=>w(o,n));return}typeof r=="object"&&w(r,n);}}));},v=(e,n)=>{let t=e.replace(/\r/g,"").replace(/\n\s+/g," "),r=e.match(/^\s*/)?.[0]??"",o=e.match(/\s*$/)?.[0]??"",s=/\n/.test(r),i=/\n/.test(o),p=t;if(s&&(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];n.has(f)?a.push(n.get(f)):a.push(f),c=m+f.length;}let d=p.slice(c);return d&&a.push(d),a},ee=(e,n)=>{let t=new Set;return w(e,r=>{r.type==="Identifier"&&n.placeholders.has(r.name)&&t.add(r.name);}),Array.from(t)},L=(e,n,t)=>{if(e.type==="JSXElement"||e.type==="JSXFragment")return t(e);if(!("range"in e)||!e.range)throw new Error("Unable to evaluate expression: missing source range information.");let[r,o]=e.range,s=n.source.slice(r,o),i=ee(e,n);try{let p=new Function(...i,`"use strict"; return (${s});`),a=i.map(c=>n.placeholders.get(c));return p(...a)}catch(p){throw new Error(`Failed to evaluate expression ${s}: ${p.message}`)}},ne=e=>{let n=e.replace(/[^a-zA-Z0-9_$]/g,"");return n?/[A-Za-z_$]/.test(n[0])?n:`Component${n}`:"Component"},te=(e,n,t)=>{let r=t.get(e);if(r)return r;let o=e.displayName||e.name||`Component${n.length}`,s=ne(o??""),i=s,p=1;for(;n.some(c=>c.name===i);)i=`${s}${p++}`;let a={name:i,value:e};return n.push(a),t.set(e,a),a},_=(e,n)=>{let t=e.raw??e,r=new Map,o=[],s=new Map,i=t[0]??"",p=Q++,a=0;for(let c=0;c<n.length;c++){let l=t[c]??"",d=t[c+1]??"",m=n[c],u=q.test(l)||Y.test(l);if(u&&typeof m=="function"){let W=te(m,o,s);i+=W.name+d;continue}if(u&&typeof m=="string"){i+=m+d;continue}let f=`${P}${p}_${a++}__`;r.set(f,m),i+=f+d;}return {source:i,placeholders:r,bindings:o}};var ae=()=>{if(typeof document>"u"||typeof document.createElement!="function")throw new Error("The jsx template tag requires a DOM-like environment (document missing).")},ce=e=>typeof Node>"u"?false:e instanceof Node||e instanceof DocumentFragment,pe=e=>!e||typeof e=="string"?false:typeof e[Symbol.iterator]=="function",M=e=>!e||typeof e!="object"&&typeof e!="function"?false:typeof e.then=="function",le={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 le[e]},me=e=>e==="svg"?svg:html,b=(e,n,t)=>{let r=$(n.space),o=String(t);if(r){e.setAttributeNS(r,n.attribute,o);return}e.setAttribute(n.attribute,o);},I=(e,n)=>{let t=$(n.space);if(t){e.removeAttributeNS(t,n.attribute);return}e.removeAttribute(n.attribute);},J=(e,n)=>Array.isArray(e)?e.filter(Boolean).join(n):e,ue=(e,n,t)=>n==="svg"||!t.property||t.property.includes(":")?false:t.property in e,C="Capture",D=e=>e.endsWith(C)&&e.length>C.length?{eventName:e.slice(0,-C.length),capture:true}:{eventName:e,capture:false},de=e=>{if(!e.startsWith("on"))return null;if(e.startsWith("on:")){let r=e.slice(3);if(!r)return null;let o=D(r);return o.eventName?o:null}let n=e.slice(2);if(!n)return null;let t=D(n);return t.eventName?{eventName:t.eventName.toLowerCase(),capture:t.capture}:null},F=e=>!e||typeof e!="object"?false:"handleEvent"in e&&typeof e.handleEvent=="function",fe=e=>{if(!e||typeof e!="object"||!("handler"in e))return false;let n=e.handler;return typeof n=="function"?true:F(n)},ge=e=>{if(typeof e=="function"||F(e))return {listener:e};if(!fe(e))return null;let n=e,t=n.options?{...n.options}:void 0,r=(o,s)=>{s!=null&&(t||(t={}),t[o]=s);};return r("capture",n.capture),r("once",n.once),r("passive",n.passive),r("signal",n.signal??void 0),{listener:n.handler,options:t}},ye=(e,n,t,r)=>{if(t==null)return;if(n==="dangerouslySetInnerHTML"&&typeof t=="object"&&t&&"__html"in t){e.innerHTML=String(t.__html??"");return}if(n==="ref"){if(typeof t=="function"){t(e);return}if(t&&typeof t=="object"){t.current=e;return}}if(n==="style"&&typeof t=="object"&&t!==null){let c=t,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 o=de(n);if(o){let c=ge(t);if(c){let l=c.options?{...c.options}:void 0;o.capture&&(l?l.capture=true:l={capture:true}),e.addEventListener(o.eventName,c.listener,l);return}}let s=find(me(r),n),i=e,p=ue(e,r,s);if(s.mustUseProperty){let c=s.boolean?!!t:t;i[s.property]=c;return}if(s.boolean){let c=!!t;p&&(i[s.property]=c),c?b(e,s,""):I(e,s);return}let a=t;if(s.spaceSeparated?a=J(t," "):s.commaSeparated?a=J(t,","):s.commaOrSpaceSeparated&&(a=J(t," ")),s.booleanish&&typeof a=="boolean"&&(a=a?"true":"false"),s.overloadedBoolean){if(a===false){I(e,s);return}if(a===true){b(e,s,"");return}}if(p){i[s.property]=a;return}a!==false&&b(e,s,a);},g=(e,n)=>{if(n!=null&&typeof n!="boolean"){if(M(n))throw new Error("Async values are not supported inside jsx template results.");if(Array.isArray(n)){n.forEach(t=>g(e,t));return}if(pe(n)){for(let t of n)g(e,t);return}if(ce(n)){e.appendChild(n);return}e.appendChild(document.createTextNode(String(n)));}},x=(e,n,t)=>L(e,n,r=>N(r,n,t)),B=(e,n,t)=>{let r={};return e.forEach(o=>{if(o.type==="JSXSpreadAttribute"){let i=x(o.argument,n,t);i&&typeof i=="object"&&!Array.isArray(i)&&Object.assign(r,i);return}let s=h(o.name);if(!o.value){r[s]=true;return}if(o.value.type==="Literal"){r[s]=o.value.value;return}if(o.value.type==="JSXExpressionContainer"){if(o.value.expression.type==="JSXEmptyExpression")return;r[s]=x(o.value.expression,n,t);}}),r},he=(e,n,t,r)=>{let o=B(n,t,r);Object.entries(o).forEach(([s,i])=>{if(s!=="key"){if(s==="children"){g(e,i);return}ye(e,s,i,r);}});},T=(e,n,t)=>{let r=[];return e.forEach(o=>{switch(o.type){case "JSXText":{v(o.value,n.placeholders).forEach(i=>{r.push(i);});break}case "JSXExpressionContainer":{if(o.expression.type==="JSXEmptyExpression")break;r.push(x(o.expression,n,t));break}case "JSXSpreadChild":{let s=x(o.expression,n,t);s!=null&&r.push(s);break}case "JSXElement":case "JSXFragment":{r.push(N(o,n,t));break}}}),r},xe=(e,n,t,r)=>{let o=B(e.openingElement.attributes,n,r),s=T(e.children,n,r);s.length===1?o.children=s[0]:s.length>1&&(o.children=s);let i=t(o);if(M(i))throw new Error("Async jsx components are not supported.");return i},Ee=(e,n,t)=>{let r=e.openingElement,o=h(r.name),s=n.components.get(o);if(s)return xe(e,n,s,t);if(/[A-Z]/.test(o[0]??""))throw new Error(`Unknown component "${o}". Did you interpolate it with the template literal?`);let i=o==="svg"?"svg":t,p=o==="foreignObject"?null:i,a=i==="svg"?document.createElementNS("http://www.w3.org/2000/svg",o):document.createElement(o);return he(a,r.attributes,n,i),T(e.children,n,p).forEach(l=>g(a,l)),a},N=(e,n,t)=>{if(e.type==="JSXFragment"){let r=document.createDocumentFragment();return T(e.children,n,t).forEach(s=>g(r,s)),r}return Ee(e,n,t)},H=(e,...n)=>{ae();let t=_(e,n),r=parseSync("inline.jsx",t.source,O);if(r.errors.length>0)throw new Error(R(r.errors[0]));let o=j(r.program),s={source:t.source,placeholders:t.placeholders,components:new Map(t.bindings.map(i=>[i.name,i.value]))};return N(o,s,null)};await A();var Ae=H;
|
|
4
|
+
export{Ae as jsx};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knighted/jsx",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
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",
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"check-types:lib": "tsc --noEmit --project tsconfig.json",
|
|
90
90
|
"check-types:demo": "tsc --noEmit --project examples/browser/tsconfig.json",
|
|
91
91
|
"lint": "eslint src test",
|
|
92
|
+
"cycles": "madge src --circular --extensions ts,tsx,js,jsx --ts-config tsconfig.json",
|
|
92
93
|
"prettier": "prettier -w .",
|
|
93
94
|
"prettier:check": "prettier --check .",
|
|
94
95
|
"test": "KNIGHTED_JSX_CLI_TEST=1 vitest run --coverage",
|
|
@@ -107,7 +108,7 @@
|
|
|
107
108
|
"devDependencies": {
|
|
108
109
|
"@eslint/js": "^9.39.1",
|
|
109
110
|
"@knighted/duel": "^2.1.6",
|
|
110
|
-
"@oxc-project/types": "^0.
|
|
111
|
+
"@oxc-project/types": "^0.105.0",
|
|
111
112
|
"@playwright/test": "^1.57.0",
|
|
112
113
|
"@rspack/core": "^1.0.5",
|
|
113
114
|
"@types/jsdom": "^27.0.0",
|
|
@@ -115,14 +116,17 @@
|
|
|
115
116
|
"@types/react": "^19.2.7",
|
|
116
117
|
"@types/react-dom": "^19.2.3",
|
|
117
118
|
"@vitest/coverage-v8": "^4.0.14",
|
|
119
|
+
"@vitest/eslint-plugin": "^1.6.4",
|
|
118
120
|
"eslint": "^9.39.1",
|
|
119
121
|
"eslint-plugin-n": "^17.10.3",
|
|
120
122
|
"eslint-plugin-playwright": "^2.4.0",
|
|
123
|
+
"eslint-plugin-unicorn": "^62.0.0",
|
|
121
124
|
"http-server": "^14.1.1",
|
|
122
125
|
"husky": "^9.1.7",
|
|
123
126
|
"jsdom": "^27.2.0",
|
|
124
127
|
"lint-staged": "^16.2.7",
|
|
125
128
|
"lit": "^3.2.1",
|
|
129
|
+
"madge": "^8.0.0",
|
|
126
130
|
"next": "^16.0.0",
|
|
127
131
|
"prettier": "^3.7.3",
|
|
128
132
|
"react": "^19.0.0",
|
|
@@ -135,7 +139,8 @@
|
|
|
135
139
|
},
|
|
136
140
|
"dependencies": {
|
|
137
141
|
"magic-string": "^0.30.21",
|
|
138
|
-
"oxc-parser": "^0.
|
|
142
|
+
"oxc-parser": "^0.105.0",
|
|
143
|
+
"property-information": "^7.1.0",
|
|
139
144
|
"tar": "^7.4.3"
|
|
140
145
|
},
|
|
141
146
|
"peerDependencies": {
|
|
@@ -155,9 +160,14 @@
|
|
|
155
160
|
}
|
|
156
161
|
},
|
|
157
162
|
"optionalDependencies": {
|
|
158
|
-
"@oxc-parser/binding-darwin-arm64": "^0.
|
|
159
|
-
"@oxc-parser/binding-linux-x64-gnu": "^0.
|
|
160
|
-
"@oxc-parser/binding-wasm32-wasi": "
|
|
163
|
+
"@oxc-parser/binding-darwin-arm64": "^0.105.0",
|
|
164
|
+
"@oxc-parser/binding-linux-x64-gnu": "^0.105.0",
|
|
165
|
+
"@oxc-parser/binding-wasm32-wasi": "0.105.0"
|
|
166
|
+
},
|
|
167
|
+
"overrides": {
|
|
168
|
+
"module-lookup-amd": {
|
|
169
|
+
"glob": "^9.0.0"
|
|
170
|
+
}
|
|
161
171
|
},
|
|
162
172
|
"files": [
|
|
163
173
|
"dist"
|
|
@@ -178,6 +188,7 @@
|
|
|
178
188
|
"singleQuote": true
|
|
179
189
|
},
|
|
180
190
|
"lint-staged": {
|
|
191
|
+
"src/**/*.{ts,tsx,js,jsx}": "npm run cycles",
|
|
181
192
|
"*.{js,jsx,ts,tsx,mjs,cjs,cts,mts}": "eslint --max-warnings=0",
|
|
182
193
|
"*.{js,jsx,ts,tsx,mjs,cjs,cts,mts,json,md,css,scss,html}": "prettier --check"
|
|
183
194
|
}
|