@reckona/mreact-compiler 0.0.153 → 0.0.154
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/emit-server.d.ts.map +1 -1
- package/dist/emit-server.js +81 -8
- package/dist/emit-server.js.map +1 -1
- package/dist/ir.d.ts +2 -1
- package/dist/ir.d.ts.map +1 -1
- package/dist/ir.js.map +1 -1
- package/dist/oxc-compat-create-element.d.ts +11 -0
- package/dist/oxc-compat-create-element.d.ts.map +1 -0
- package/dist/oxc-compat-create-element.js +489 -0
- package/dist/oxc-compat-create-element.js.map +1 -0
- package/dist/oxc.d.ts.map +1 -1
- package/dist/oxc.js +79 -11
- package/dist/oxc.js.map +1 -1
- package/package.json +2 -2
- package/src/emit-server.ts +103 -4
- package/src/ir.ts +4 -1
- package/src/oxc-compat-create-element.ts +705 -0
- package/src/oxc.ts +130 -4
package/src/emit-server.ts
CHANGED
|
@@ -36,6 +36,7 @@ export interface EmitServerOptions {
|
|
|
36
36
|
// name through every signature. Reset at the top of `emitServer`.
|
|
37
37
|
let currentUrlSafeHelperName: string = "_urlAttrSafe";
|
|
38
38
|
let currentClientBoundaryHelperName: string | undefined;
|
|
39
|
+
let currentCompatChildHelperName: string | undefined;
|
|
39
40
|
let currentSpreadAttributesHelperName: string = "_renderSpreadAttributes";
|
|
40
41
|
|
|
41
42
|
export function emitServer(ir: ModuleIr, options: EmitServerOptions = {}): EmitResult {
|
|
@@ -54,12 +55,16 @@ export function emitServer(ir: ModuleIr, options: EmitServerOptions = {}): EmitR
|
|
|
54
55
|
const clientBoundaryHelperName = usesClientBoundary(ir)
|
|
55
56
|
? allocateHelperName(ir, "_renderClientBoundary")
|
|
56
57
|
: undefined;
|
|
58
|
+
const compatChildHelperName = usesCompatChildRender(ir)
|
|
59
|
+
? allocateHelperName(ir, "_renderCompatChild")
|
|
60
|
+
: undefined;
|
|
57
61
|
const spreadAttributesHelperName = allocateHelperName(ir, "_renderSpreadAttributes");
|
|
58
62
|
const outAccumulatorName = allocateHelperName(ir, "_out");
|
|
59
63
|
const urlSafeHelperName = allocateHelperName(ir, "_urlAttrSafe");
|
|
60
64
|
currentUrlSafeHelperName = urlSafeHelperName;
|
|
61
65
|
setOxcServerStringUrlSafeHelperName(urlSafeHelperName);
|
|
62
66
|
currentClientBoundaryHelperName = clientBoundaryHelperName;
|
|
67
|
+
currentCompatChildHelperName = compatChildHelperName;
|
|
63
68
|
currentSpreadAttributesHelperName = spreadAttributesHelperName;
|
|
64
69
|
const helper = emitEscapeHtmlHelper(escapeHelperName);
|
|
65
70
|
// Inline URL-scheme guard mirroring packages/server/src/url-safety.ts.
|
|
@@ -127,6 +132,7 @@ export function emitServer(ir: ModuleIr, options: EmitServerOptions = {}): EmitR
|
|
|
127
132
|
contextProviderHelperName,
|
|
128
133
|
contextConsumerHelperName,
|
|
129
134
|
reactNodeRenderHelperName,
|
|
135
|
+
compatChildHelperName,
|
|
130
136
|
);
|
|
131
137
|
const moduleStatements = emitModuleStatements(ir);
|
|
132
138
|
const code = createCodeBuilder();
|
|
@@ -146,6 +152,7 @@ export function emitServer(ir: ModuleIr, options: EmitServerOptions = {}): EmitR
|
|
|
146
152
|
contextProviderHelperName,
|
|
147
153
|
contextConsumerHelperName,
|
|
148
154
|
reactNodeRenderHelperName,
|
|
155
|
+
compatChildHelperName,
|
|
149
156
|
),
|
|
150
157
|
};
|
|
151
158
|
}
|
|
@@ -154,11 +161,15 @@ function emitContextImport(
|
|
|
154
161
|
contextProviderHelperName: string | undefined,
|
|
155
162
|
contextConsumerHelperName: string | undefined,
|
|
156
163
|
reactNodeRenderHelperName: string | undefined,
|
|
164
|
+
compatChildHelperName?: string | undefined,
|
|
157
165
|
): string {
|
|
158
166
|
const specifiers = [
|
|
159
167
|
reactNodeRenderHelperName === undefined
|
|
160
168
|
? undefined
|
|
161
169
|
: `renderToString as ${reactNodeRenderHelperName}`,
|
|
170
|
+
compatChildHelperName === undefined
|
|
171
|
+
? undefined
|
|
172
|
+
: `renderChildToString as ${compatChildHelperName}`,
|
|
162
173
|
contextProviderHelperName === undefined
|
|
163
174
|
? undefined
|
|
164
175
|
: `renderContextProviderToString as ${contextProviderHelperName}`,
|
|
@@ -176,11 +187,13 @@ function collectContextImports(
|
|
|
176
187
|
contextProviderHelperName: string | undefined,
|
|
177
188
|
contextConsumerHelperName: string | undefined,
|
|
178
189
|
reactNodeRenderHelperName?: string,
|
|
190
|
+
compatChildHelperName?: string,
|
|
179
191
|
): RuntimeImport[] {
|
|
180
192
|
const specifiers = [
|
|
181
193
|
reactNodeRenderHelperName === undefined ? undefined : "renderToString",
|
|
182
194
|
contextProviderHelperName === undefined ? undefined : "renderContextProviderToString",
|
|
183
195
|
contextConsumerHelperName === undefined ? undefined : "renderContextConsumerToString",
|
|
196
|
+
compatChildHelperName === undefined ? undefined : "renderChildToString",
|
|
184
197
|
].filter((specifier): specifier is string => specifier !== undefined);
|
|
185
198
|
|
|
186
199
|
return specifiers.length === 0 ? [] : [{ source: "@reckona/mreact-compat", specifiers }];
|
|
@@ -317,6 +330,10 @@ function collectHtmlStatements(
|
|
|
317
330
|
return [`${outVar} += ${reactNodeRenderHelperName}(() => (${node.code}));`];
|
|
318
331
|
}
|
|
319
332
|
|
|
333
|
+
if (node.renderMode === "compat-child" && currentCompatChildHelperName !== undefined) {
|
|
334
|
+
return [`${outVar} += ${currentCompatChildHelperName}(${node.code});`];
|
|
335
|
+
}
|
|
336
|
+
|
|
320
337
|
return [`${outVar} += ${escapeHelperName}(${node.code});`];
|
|
321
338
|
}
|
|
322
339
|
|
|
@@ -691,6 +708,10 @@ function collectHtmlParts(
|
|
|
691
708
|
return [`${reactNodeRenderHelperName}(() => (${node.code}))`];
|
|
692
709
|
}
|
|
693
710
|
|
|
711
|
+
if (node.renderMode === "compat-child" && currentCompatChildHelperName !== undefined) {
|
|
712
|
+
return [`${currentCompatChildHelperName}(${node.code})`];
|
|
713
|
+
}
|
|
714
|
+
|
|
694
715
|
return [`${escapeHelperName}(${node.code})`];
|
|
695
716
|
}
|
|
696
717
|
|
|
@@ -1013,7 +1034,9 @@ function collectHtmlAttributeParts(
|
|
|
1013
1034
|
|
|
1014
1035
|
if (attr.name === "style") {
|
|
1015
1036
|
return [
|
|
1016
|
-
|
|
1037
|
+
attr.serialization === "compat"
|
|
1038
|
+
? emitCompatDynamicStyleAttributeExpression(attr.code, escapeHelperName)
|
|
1039
|
+
: emitDynamicStyleAttributeExpression(attr.code, escapeHelperName, escapeBatchHelperName),
|
|
1017
1040
|
];
|
|
1018
1041
|
}
|
|
1019
1042
|
|
|
@@ -1026,7 +1049,11 @@ function collectHtmlAttributeParts(
|
|
|
1026
1049
|
];
|
|
1027
1050
|
}
|
|
1028
1051
|
|
|
1029
|
-
return [
|
|
1052
|
+
return [
|
|
1053
|
+
attr.serialization === "compat" && !isUrlAttribute(htmlName)
|
|
1054
|
+
? emitCompatDynamicAttributeExpression(htmlName, attr.code, escapeHelperName)
|
|
1055
|
+
: emitDynamicAttributeExpression(htmlName, attr.code, escapeHelperName),
|
|
1056
|
+
];
|
|
1030
1057
|
}
|
|
1031
1058
|
|
|
1032
1059
|
function collectElementAttributeParts(
|
|
@@ -1175,6 +1202,42 @@ function emitDynamicAttributeExpression(
|
|
|
1175
1202
|
: `(() => { const _value = (${code}); return _value == null || _value === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_value === true ? "" : _value) + ${stringLiteral('"')}; })()`;
|
|
1176
1203
|
}
|
|
1177
1204
|
|
|
1205
|
+
// Mirrors packages/react-compat/src/server-render.ts renderHtmlAttribute for
|
|
1206
|
+
// dynamic values: functions and objects drop, booleans serialize as
|
|
1207
|
+
// "true"/"false" for booleanish-string and data attributes, and false drops
|
|
1208
|
+
// elsewhere. Byte parity with the interpreter is pinned by tests.
|
|
1209
|
+
function emitCompatDynamicAttributeExpression(
|
|
1210
|
+
name: string,
|
|
1211
|
+
code: string,
|
|
1212
|
+
escapeHelperName: string,
|
|
1213
|
+
): string {
|
|
1214
|
+
const lowerCased = name.toLowerCase();
|
|
1215
|
+
const booleanishOrData =
|
|
1216
|
+
lowerCased.startsWith("aria-") ||
|
|
1217
|
+
lowerCased.startsWith("data-") ||
|
|
1218
|
+
lowerCased === "contenteditable" ||
|
|
1219
|
+
lowerCased === "draggable" ||
|
|
1220
|
+
lowerCased === "spellcheck";
|
|
1221
|
+
const booleanBranch = booleanishOrData
|
|
1222
|
+
? `return ${stringLiteral(` ${name}="`)} + (_value ? "true" : "false") + ${stringLiteral('"')};`
|
|
1223
|
+
: `return _value ? ${stringLiteral(` ${name}=""`)} : "";`;
|
|
1224
|
+
|
|
1225
|
+
return `(() => { const _value = (${code}); if (_value == null || typeof _value === "function") return ""; if (typeof _value === "boolean") { ${booleanBranch} } if (typeof _value === "object") return ""; return ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_value) + ${stringLiteral('"')}; })()`;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// Mirrors packages/react-compat/src/server-render.ts renderStyleAttribute and
|
|
1229
|
+
// renderCssValue: skips null/boolean/empty entries and appends px to nonzero
|
|
1230
|
+
// numeric values outside the react unitless list.
|
|
1231
|
+
function emitCompatDynamicStyleAttributeExpression(
|
|
1232
|
+
code: string,
|
|
1233
|
+
escapeHelperName: string,
|
|
1234
|
+
): string {
|
|
1235
|
+
const unitlessCheck =
|
|
1236
|
+
'_styleName === "flex" || _styleName === "fontWeight" || _styleName === "lineHeight" || _styleName === "opacity" || _styleName === "order" || _styleName === "zIndex" || _styleName === "zoom"';
|
|
1237
|
+
|
|
1238
|
+
return `(() => { const _value = (${code}); if (_value == null || typeof _value !== "object") return ""; let _style = ""; for (const _styleName in _value) { const _styleValue = _value[_styleName]; if (_styleValue == null || typeof _styleValue === "boolean" || _styleValue === "") continue; const _cssName = _styleName.startsWith("--") ? _styleName : _styleName.replace(/[A-Z]/g, (_char) => "-" + _char.toLowerCase()); const _css = typeof _styleValue !== "number" || _styleValue === 0 || (${unitlessCheck}) ? String(_styleValue) : _styleValue + "px"; _style += (_style === "" ? "" : ";") + ${escapeHelperName}(_cssName) + ":" + ${escapeHelperName}(_css); } return _style === "" ? "" : ${stringLiteral(' style="')} + _style + ${stringLiteral('"')}; })()`;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1178
1241
|
function emitDynamicStyleAttributeExpression(
|
|
1179
1242
|
code: string,
|
|
1180
1243
|
escapeHelperName: string,
|
|
@@ -1326,7 +1389,10 @@ function emitBatchedSimpleChildrenExpression(
|
|
|
1326
1389
|
|
|
1327
1390
|
const dynamicChildren = children.filter(
|
|
1328
1391
|
(child) =>
|
|
1329
|
-
child.kind === "expr" &&
|
|
1392
|
+
child.kind === "expr" &&
|
|
1393
|
+
child.renderMode !== "html" &&
|
|
1394
|
+
child.renderMode !== "react-node" &&
|
|
1395
|
+
child.renderMode !== "compat-child",
|
|
1330
1396
|
) as Array<Extract<JsxNodeIr, { kind: "expr" }>>;
|
|
1331
1397
|
|
|
1332
1398
|
if (dynamicChildren.length < 2) {
|
|
@@ -1340,7 +1406,8 @@ function emitBatchedSimpleChildrenExpression(
|
|
|
1340
1406
|
!(
|
|
1341
1407
|
child.kind === "expr" &&
|
|
1342
1408
|
child.renderMode !== "html" &&
|
|
1343
|
-
child.renderMode !== "react-node"
|
|
1409
|
+
child.renderMode !== "react-node" &&
|
|
1410
|
+
child.renderMode !== "compat-child"
|
|
1344
1411
|
),
|
|
1345
1412
|
)
|
|
1346
1413
|
) {
|
|
@@ -1682,6 +1749,38 @@ function usesClientBoundary(ir: ModuleIr): boolean {
|
|
|
1682
1749
|
return ir.components.some((component) => containsClientBoundary(component.root));
|
|
1683
1750
|
}
|
|
1684
1751
|
|
|
1752
|
+
function usesCompatChildRender(ir: ModuleIr): boolean {
|
|
1753
|
+
return ir.components.some((component) => containsCompatChildRender(component.root));
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
function containsCompatChildRender(node: JsxNodeIr): boolean {
|
|
1757
|
+
if (node.kind === "expr") {
|
|
1758
|
+
return node.renderMode === "compat-child";
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
if (node.kind === "conditional") {
|
|
1762
|
+
return [...node.whenTrue, ...node.whenFalse].some(containsCompatChildRender);
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
if (node.kind === "list" || node.kind === "element" || node.kind === "fragment") {
|
|
1766
|
+
return node.children.some(containsCompatChildRender);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
if (node.kind === "async-boundary") {
|
|
1770
|
+
return [
|
|
1771
|
+
...node.children,
|
|
1772
|
+
...(node.placeholderChildren ?? []),
|
|
1773
|
+
...(node.catchChildren ?? []),
|
|
1774
|
+
].some(containsCompatChildRender);
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
if (node.kind === "component") {
|
|
1778
|
+
return node.children.some(containsCompatChildRender);
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
return false;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1685
1784
|
function emitClientBoundaryHelper(name: string): string {
|
|
1686
1785
|
const propsHelperName = `${name}$hasNonSerializableProps`;
|
|
1687
1786
|
|
package/src/ir.ts
CHANGED
|
@@ -108,7 +108,7 @@ export interface TextIr {
|
|
|
108
108
|
export interface ExprIr {
|
|
109
109
|
kind: "expr";
|
|
110
110
|
code: string;
|
|
111
|
-
renderMode?: "dynamic" | "html" | "react-node" | "stream-node";
|
|
111
|
+
renderMode?: "dynamic" | "html" | "react-node" | "stream-node" | "compat-child";
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
export interface AsyncBoundaryIr {
|
|
@@ -140,6 +140,9 @@ export interface DynamicAttributeIr {
|
|
|
140
140
|
kind: "dynamic-attr";
|
|
141
141
|
name: string;
|
|
142
142
|
code: string;
|
|
143
|
+
// "compat" applies react-compat serialization semantics (px suffix for
|
|
144
|
+
// numeric style values, interpreter-equivalent filtering).
|
|
145
|
+
serialization?: "compat";
|
|
143
146
|
}
|
|
144
147
|
|
|
145
148
|
export interface EventAttributeIr {
|