@knighted/jsx 1.6.2 → 1.6.3
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/jsx.cjs +27 -2
- package/dist/cjs/loader/jsx.d.cts +2 -0
- package/dist/cjs/node/bootstrap.cjs +9 -4
- package/dist/cjs/node/debug/index.cjs +9 -6
- package/dist/cjs/node/index.cjs +7 -4
- package/dist/cjs/node/react/index.cjs +5 -1
- package/dist/loader/jsx.d.ts +2 -0
- package/dist/loader/jsx.js +27 -2
- package/package.json +11 -5
package/dist/cjs/loader/jsx.cjs
CHANGED
|
@@ -224,6 +224,8 @@ const TEMPLATE_PARSER_OPTIONS = {
|
|
|
224
224
|
};
|
|
225
225
|
const DEFAULT_TAGS = ['jsx', 'reactJsx'];
|
|
226
226
|
const DEFAULT_MODE = 'runtime';
|
|
227
|
+
const WEB_TARGETS = new Set(['web', 'webworker', 'electron-renderer', 'node-webkit']);
|
|
228
|
+
const isWebTarget = (target) => target ? WEB_TARGETS.has(target) : false;
|
|
227
229
|
const HELPER_SNIPPETS = {
|
|
228
230
|
react: `const __jsxReactMergeProps = (...sources) => Object.assign({}, ...sources)
|
|
229
231
|
const __jsxReact = (type, props, ...children) => React.createElement(type, props, ...children)
|
|
@@ -671,7 +673,14 @@ const transformSource = (source, config, options) => {
|
|
|
671
673
|
.filter(Boolean)
|
|
672
674
|
.join('\n');
|
|
673
675
|
if (helperSource) {
|
|
674
|
-
|
|
676
|
+
const helperBlock = `${helperSource.trimEnd()}\n\n`;
|
|
677
|
+
const shebangIndex = source.startsWith('#!') ? source.indexOf('\n') : -1;
|
|
678
|
+
if (shebangIndex >= 0) {
|
|
679
|
+
magic.appendLeft(shebangIndex + 1, helperBlock);
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
magic.prepend(helperBlock);
|
|
683
|
+
}
|
|
675
684
|
mutated = true;
|
|
676
685
|
}
|
|
677
686
|
const code = mutated ? magic.toString() : source;
|
|
@@ -692,6 +701,8 @@ function jsxLoader(input) {
|
|
|
692
701
|
const callback = this.async();
|
|
693
702
|
try {
|
|
694
703
|
const options = this.getOptions?.() ?? {};
|
|
704
|
+
const warn = this.emitWarning?.bind(this);
|
|
705
|
+
const webTarget = isWebTarget(this.target);
|
|
695
706
|
const explicitTags = Array.isArray(options.tags)
|
|
696
707
|
? options.tags.filter((value) => typeof value === 'string' && value.length > 0)
|
|
697
708
|
: null;
|
|
@@ -705,6 +716,9 @@ function jsxLoader(input) {
|
|
|
705
716
|
const configuredTagModes = options.tagModes && typeof options.tagModes === 'object'
|
|
706
717
|
? options.tagModes
|
|
707
718
|
: undefined;
|
|
719
|
+
const userSpecifiedMode = parseLoaderMode(options.mode);
|
|
720
|
+
const defaultMode = userSpecifiedMode ?? DEFAULT_MODE;
|
|
721
|
+
const userConfiguredTags = new Set();
|
|
708
722
|
if (configuredTagModes) {
|
|
709
723
|
Object.entries(configuredTagModes).forEach(([tagName, mode]) => {
|
|
710
724
|
const parsed = parseLoaderMode(mode);
|
|
@@ -712,15 +726,26 @@ function jsxLoader(input) {
|
|
|
712
726
|
return;
|
|
713
727
|
}
|
|
714
728
|
tagModes.set(tagName, parsed);
|
|
729
|
+
userConfiguredTags.add(tagName);
|
|
715
730
|
});
|
|
716
731
|
}
|
|
717
|
-
const defaultMode = parseLoaderMode(options.mode) ?? DEFAULT_MODE;
|
|
718
732
|
const tags = Array.from(new Set([...tagList, ...tagModes.keys()]));
|
|
719
733
|
tags.forEach(tagName => {
|
|
720
734
|
if (!tagModes.has(tagName)) {
|
|
721
735
|
tagModes.set(tagName, defaultMode);
|
|
722
736
|
}
|
|
723
737
|
});
|
|
738
|
+
/**
|
|
739
|
+
* If targeting the web and runtime mode is only implied (not explicitly requested),
|
|
740
|
+
* keep the runtime output but surface a warning so users can opt into react mode when
|
|
741
|
+
* bundling for the browser.
|
|
742
|
+
*/
|
|
743
|
+
if (webTarget && userSpecifiedMode === null) {
|
|
744
|
+
const hasImplicitRuntime = tags.some(tagName => tagModes.get(tagName) === 'runtime' && !userConfiguredTags.has(tagName));
|
|
745
|
+
if (hasImplicitRuntime) {
|
|
746
|
+
warn?.(new Error('[jsx-loader] Web target detected while defaulting to runtime mode; the shipped parser expects a Node-like environment. Set mode: "react" (or configure per-tag) when bundling client code, or provide a browser-safe runtime parser if you intentionally need runtime output.'));
|
|
747
|
+
}
|
|
748
|
+
}
|
|
724
749
|
const source = typeof input === 'string' ? input : input.toString('utf8');
|
|
725
750
|
const enableSourceMap = options.sourceMap === true;
|
|
726
751
|
const { code, map } = transformSource(source, {
|
|
@@ -2,6 +2,8 @@ import { type SourceMap } from 'magic-string';
|
|
|
2
2
|
type LoaderCallback = (error: Error | null, content?: string, map?: SourceMap | null) => void;
|
|
3
3
|
type LoaderContext<TOptions> = {
|
|
4
4
|
resourcePath: string;
|
|
5
|
+
target?: string;
|
|
6
|
+
emitWarning?: (warning: Error | string) => void;
|
|
5
7
|
async(): LoaderCallback;
|
|
6
8
|
getOptions?: () => Partial<TOptions>;
|
|
7
9
|
};
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.__setNodeRequireForTesting = exports.ensureNodeDom = void 0;
|
|
4
|
+
const node_module_1 = require("node:module");
|
|
5
|
+
const nodeRequire = (0, node_module_1.createRequire)(require("node:url").pathToFileURL(__filename).href);
|
|
3
6
|
let requireOverride = null;
|
|
4
7
|
const resolveRequire = () => requireOverride ?? nodeRequire;
|
|
5
8
|
const DOM_TEMPLATE = '<!doctype html><html><body></body></html>';
|
|
@@ -70,7 +73,7 @@ const createShimWindow = () => {
|
|
|
70
73
|
throw new AggregateError(errors, help);
|
|
71
74
|
};
|
|
72
75
|
let bootstrapped = false;
|
|
73
|
-
|
|
76
|
+
const ensureNodeDom = () => {
|
|
74
77
|
if (hasDom() || bootstrapped) {
|
|
75
78
|
return;
|
|
76
79
|
}
|
|
@@ -78,6 +81,8 @@ export const ensureNodeDom = () => {
|
|
|
78
81
|
assignGlobalTargets(windowObj);
|
|
79
82
|
bootstrapped = true;
|
|
80
83
|
};
|
|
81
|
-
|
|
84
|
+
exports.ensureNodeDom = ensureNodeDom;
|
|
85
|
+
const __setNodeRequireForTesting = (mockRequire) => {
|
|
82
86
|
requireOverride = mockRequire;
|
|
83
87
|
};
|
|
88
|
+
exports.__setNodeRequireForTesting = __setNodeRequireForTesting;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jsx = void 0;
|
|
4
|
+
const diagnostics_js_1 = require("../../debug/diagnostics.cjs");
|
|
5
|
+
const bootstrap_js_1 = require("../bootstrap.cjs");
|
|
6
|
+
const jsx_js_1 = require("../../jsx.cjs");
|
|
7
|
+
(0, diagnostics_js_1.enableJsxDebugDiagnostics)({ mode: 'always' });
|
|
8
|
+
(0, bootstrap_js_1.ensureNodeDom)();
|
|
9
|
+
exports.jsx = jsx_js_1.jsx;
|
package/dist/cjs/node/index.cjs
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jsx = void 0;
|
|
4
|
+
const bootstrap_js_1 = require("./bootstrap.cjs");
|
|
5
|
+
const jsx_js_1 = require("../jsx.cjs");
|
|
6
|
+
(0, bootstrap_js_1.ensureNodeDom)();
|
|
7
|
+
exports.jsx = jsx_js_1.jsx;
|
|
@@ -1 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reactJsx = void 0;
|
|
4
|
+
var react_jsx_js_1 = require("../../react/react-jsx.cjs");
|
|
5
|
+
Object.defineProperty(exports, "reactJsx", { enumerable: true, get: function () { return react_jsx_js_1.reactJsx; } });
|
package/dist/loader/jsx.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { type SourceMap } from 'magic-string';
|
|
|
2
2
|
type LoaderCallback = (error: Error | null, content?: string, map?: SourceMap | null) => void;
|
|
3
3
|
type LoaderContext<TOptions> = {
|
|
4
4
|
resourcePath: string;
|
|
5
|
+
target?: string;
|
|
6
|
+
emitWarning?: (warning: Error | string) => void;
|
|
5
7
|
async(): LoaderCallback;
|
|
6
8
|
getOptions?: () => Partial<TOptions>;
|
|
7
9
|
};
|
package/dist/loader/jsx.js
CHANGED
|
@@ -218,6 +218,8 @@ const TEMPLATE_PARSER_OPTIONS = {
|
|
|
218
218
|
};
|
|
219
219
|
const DEFAULT_TAGS = ['jsx', 'reactJsx'];
|
|
220
220
|
const DEFAULT_MODE = 'runtime';
|
|
221
|
+
const WEB_TARGETS = new Set(['web', 'webworker', 'electron-renderer', 'node-webkit']);
|
|
222
|
+
const isWebTarget = (target) => target ? WEB_TARGETS.has(target) : false;
|
|
221
223
|
const HELPER_SNIPPETS = {
|
|
222
224
|
react: `const __jsxReactMergeProps = (...sources) => Object.assign({}, ...sources)
|
|
223
225
|
const __jsxReact = (type, props, ...children) => React.createElement(type, props, ...children)
|
|
@@ -665,7 +667,14 @@ const transformSource = (source, config, options) => {
|
|
|
665
667
|
.filter(Boolean)
|
|
666
668
|
.join('\n');
|
|
667
669
|
if (helperSource) {
|
|
668
|
-
|
|
670
|
+
const helperBlock = `${helperSource.trimEnd()}\n\n`;
|
|
671
|
+
const shebangIndex = source.startsWith('#!') ? source.indexOf('\n') : -1;
|
|
672
|
+
if (shebangIndex >= 0) {
|
|
673
|
+
magic.appendLeft(shebangIndex + 1, helperBlock);
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
magic.prepend(helperBlock);
|
|
677
|
+
}
|
|
669
678
|
mutated = true;
|
|
670
679
|
}
|
|
671
680
|
const code = mutated ? magic.toString() : source;
|
|
@@ -686,6 +695,8 @@ export default function jsxLoader(input) {
|
|
|
686
695
|
const callback = this.async();
|
|
687
696
|
try {
|
|
688
697
|
const options = this.getOptions?.() ?? {};
|
|
698
|
+
const warn = this.emitWarning?.bind(this);
|
|
699
|
+
const webTarget = isWebTarget(this.target);
|
|
689
700
|
const explicitTags = Array.isArray(options.tags)
|
|
690
701
|
? options.tags.filter((value) => typeof value === 'string' && value.length > 0)
|
|
691
702
|
: null;
|
|
@@ -699,6 +710,9 @@ export default function jsxLoader(input) {
|
|
|
699
710
|
const configuredTagModes = options.tagModes && typeof options.tagModes === 'object'
|
|
700
711
|
? options.tagModes
|
|
701
712
|
: undefined;
|
|
713
|
+
const userSpecifiedMode = parseLoaderMode(options.mode);
|
|
714
|
+
const defaultMode = userSpecifiedMode ?? DEFAULT_MODE;
|
|
715
|
+
const userConfiguredTags = new Set();
|
|
702
716
|
if (configuredTagModes) {
|
|
703
717
|
Object.entries(configuredTagModes).forEach(([tagName, mode]) => {
|
|
704
718
|
const parsed = parseLoaderMode(mode);
|
|
@@ -706,15 +720,26 @@ export default function jsxLoader(input) {
|
|
|
706
720
|
return;
|
|
707
721
|
}
|
|
708
722
|
tagModes.set(tagName, parsed);
|
|
723
|
+
userConfiguredTags.add(tagName);
|
|
709
724
|
});
|
|
710
725
|
}
|
|
711
|
-
const defaultMode = parseLoaderMode(options.mode) ?? DEFAULT_MODE;
|
|
712
726
|
const tags = Array.from(new Set([...tagList, ...tagModes.keys()]));
|
|
713
727
|
tags.forEach(tagName => {
|
|
714
728
|
if (!tagModes.has(tagName)) {
|
|
715
729
|
tagModes.set(tagName, defaultMode);
|
|
716
730
|
}
|
|
717
731
|
});
|
|
732
|
+
/**
|
|
733
|
+
* If targeting the web and runtime mode is only implied (not explicitly requested),
|
|
734
|
+
* keep the runtime output but surface a warning so users can opt into react mode when
|
|
735
|
+
* bundling for the browser.
|
|
736
|
+
*/
|
|
737
|
+
if (webTarget && userSpecifiedMode === null) {
|
|
738
|
+
const hasImplicitRuntime = tags.some(tagName => tagModes.get(tagName) === 'runtime' && !userConfiguredTags.has(tagName));
|
|
739
|
+
if (hasImplicitRuntime) {
|
|
740
|
+
warn?.(new Error('[jsx-loader] Web target detected while defaulting to runtime mode; the shipped parser expects a Node-like environment. Set mode: "react" (or configure per-tag) when bundling client code, or provide a browser-safe runtime parser if you intentionally need runtime output.'));
|
|
741
|
+
}
|
|
742
|
+
}
|
|
718
743
|
const source = typeof input === 'string' ? input : input.toString('utf8');
|
|
719
744
|
const enableSourceMap = options.sourceMap === true;
|
|
720
745
|
const { code, map } = transformSource(source, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knighted/jsx",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
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",
|
|
@@ -112,19 +112,23 @@
|
|
|
112
112
|
},
|
|
113
113
|
"engineStrict": true,
|
|
114
114
|
"scripts": {
|
|
115
|
-
"build": "duel && npm run build:lite && npm run build:cli",
|
|
115
|
+
"build": "duel --mode globals && npm run build:lite && npm run build:cli",
|
|
116
116
|
"prepare": "husky",
|
|
117
117
|
"precheck-types": "npm run build",
|
|
118
118
|
"check-types": "npm run check-types:lib && npm run check-types:demo && npm run check-types:test",
|
|
119
119
|
"check-types:lib": "tsc --noEmit --project tsconfig.json",
|
|
120
120
|
"check-types:demo": "tsc --noEmit --project examples/browser/tsconfig.json",
|
|
121
121
|
"check-types:test": "tsc --noEmit --project tsconfig.vitest.json",
|
|
122
|
+
"clean:deps": "rimraf node_modules",
|
|
123
|
+
"clean:dist": "rimraf dist",
|
|
124
|
+
"clean": "npm run clean:dist && npm run clean:deps",
|
|
122
125
|
"lint": "eslint src test",
|
|
126
|
+
"pretest": "npm run build",
|
|
123
127
|
"cycles": "madge src --circular --extensions ts,tsx,js,jsx --ts-config tsconfig.json",
|
|
124
128
|
"prettier": "prettier -w .",
|
|
125
129
|
"prettier:check": "prettier --check .",
|
|
126
|
-
"test": "KNIGHTED_JSX_CLI_TEST=1 vitest run --coverage",
|
|
127
|
-
"test:watch": "KNIGHTED_JSX_CLI_TEST=1 vitest",
|
|
130
|
+
"test": "cross-env KNIGHTED_JSX_CLI_TEST=1 vitest run --coverage",
|
|
131
|
+
"test:watch": "cross-env KNIGHTED_JSX_CLI_TEST=1 vitest",
|
|
128
132
|
"test:e2e": "npm run build && npm run setup:wasm && npm run build:fixture && playwright test",
|
|
129
133
|
"build:fixture": "node scripts/build-rspack-fixture.mjs",
|
|
130
134
|
"demo:node-ssr": "node test/fixtures/node-ssr/render.mjs",
|
|
@@ -139,7 +143,7 @@
|
|
|
139
143
|
},
|
|
140
144
|
"devDependencies": {
|
|
141
145
|
"@eslint/js": "^9.39.1",
|
|
142
|
-
"@knighted/duel": "^
|
|
146
|
+
"@knighted/duel": "^4.0.0",
|
|
143
147
|
"@oxc-project/types": "^0.105.0",
|
|
144
148
|
"@playwright/test": "^1.57.0",
|
|
145
149
|
"@rspack/core": "^1.0.5",
|
|
@@ -149,6 +153,7 @@
|
|
|
149
153
|
"@types/react-dom": "^19.2.3",
|
|
150
154
|
"@vitest/coverage-v8": "^4.0.14",
|
|
151
155
|
"@vitest/eslint-plugin": "^1.6.4",
|
|
156
|
+
"cross-env": "^10.1.0",
|
|
152
157
|
"eslint": "^9.39.1",
|
|
153
158
|
"eslint-plugin-n": "^17.10.3",
|
|
154
159
|
"eslint-plugin-playwright": "^2.4.0",
|
|
@@ -163,6 +168,7 @@
|
|
|
163
168
|
"prettier": "^3.7.3",
|
|
164
169
|
"react": "^19.0.0",
|
|
165
170
|
"react-dom": "^19.0.0",
|
|
171
|
+
"rimraf": "^6.1.2",
|
|
166
172
|
"tsup": "^8.5.1",
|
|
167
173
|
"typescript": "^5.9.3",
|
|
168
174
|
"typescript-eslint": "^8.48.0",
|