@reckona/mreact-compiler 0.0.120 → 0.0.122
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-client.js +73 -1
- package/dist/emit-client.js.map +1 -1
- package/dist/emit-server-stream.d.ts.map +1 -1
- package/dist/emit-server-stream.js +49 -34
- package/dist/emit-server-stream.js.map +1 -1
- package/dist/emit-server.d.ts.map +1 -1
- package/dist/emit-server.js +41 -39
- package/dist/emit-server.js.map +1 -1
- package/dist/ir.d.ts +1 -0
- package/dist/ir.d.ts.map +1 -1
- package/dist/ir.js.map +1 -1
- package/dist/oxc-component-references.d.ts +1 -1
- package/dist/oxc-component-references.d.ts.map +1 -1
- package/dist/oxc-component-references.js +35 -24
- package/dist/oxc-component-references.js.map +1 -1
- package/dist/oxc.d.ts.map +1 -1
- package/dist/oxc.js +13 -16
- package/dist/oxc.js.map +1 -1
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +5 -2
- package/dist/transform.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/emit-client.ts +110 -1
- package/src/emit-server-stream.ts +104 -80
- package/src/emit-server.ts +127 -108
- package/src/ir.ts +1 -0
- package/src/oxc-component-references.ts +86 -34
- package/src/oxc.ts +41 -67
- package/src/transform.ts +51 -49
- package/src/types.ts +2 -0
package/src/emit-server.ts
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AttributeIr,
|
|
3
|
-
ComponentPropIr,
|
|
4
|
-
ComponentIr,
|
|
5
|
-
JsxNodeIr,
|
|
6
|
-
ModuleIr,
|
|
7
|
-
} from "./ir.js";
|
|
1
|
+
import type { AttributeIr, ComponentPropIr, ComponentIr, JsxNodeIr, ModuleIr } from "./ir.js";
|
|
8
2
|
import type { RuntimeImport, ServerEscapeOptions } from "./types.js";
|
|
9
3
|
import { emitEscapeHtmlHelper } from "./emit-escape-helper.js";
|
|
10
4
|
import { createCodeBuilder } from "./emit-code-builder.js";
|
|
@@ -41,14 +35,10 @@ let currentUrlSafeHelperName: string = "_urlAttrSafe";
|
|
|
41
35
|
let currentClientBoundaryHelperName: string | undefined;
|
|
42
36
|
let currentSpreadAttributesHelperName: string = "_renderSpreadAttributes";
|
|
43
37
|
|
|
44
|
-
export function emitServer(
|
|
45
|
-
ir: ModuleIr,
|
|
46
|
-
options: EmitServerOptions = {},
|
|
47
|
-
): EmitResult {
|
|
38
|
+
export function emitServer(ir: ModuleIr, options: EmitServerOptions = {}): EmitResult {
|
|
48
39
|
const escapeHelperName = allocateEscapeHelperName(ir);
|
|
49
|
-
const escapeBatchHelperName =
|
|
50
|
-
? undefined
|
|
51
|
-
: allocateHelperName(ir, "_escapeHtmlBatch");
|
|
40
|
+
const escapeBatchHelperName =
|
|
41
|
+
options.escape === undefined ? undefined : allocateHelperName(ir, "_escapeHtmlBatch");
|
|
52
42
|
const contextProviderHelperName = usesContextProvider(ir)
|
|
53
43
|
? allocateHelperName(ir, "_renderContextProviderToString")
|
|
54
44
|
: undefined;
|
|
@@ -185,17 +175,11 @@ function collectContextImports(
|
|
|
185
175
|
): RuntimeImport[] {
|
|
186
176
|
const specifiers = [
|
|
187
177
|
reactNodeRenderHelperName === undefined ? undefined : "renderToString",
|
|
188
|
-
contextProviderHelperName === undefined
|
|
189
|
-
|
|
190
|
-
: "renderContextProviderToString",
|
|
191
|
-
contextConsumerHelperName === undefined
|
|
192
|
-
? undefined
|
|
193
|
-
: "renderContextConsumerToString",
|
|
178
|
+
contextProviderHelperName === undefined ? undefined : "renderContextProviderToString",
|
|
179
|
+
contextConsumerHelperName === undefined ? undefined : "renderContextConsumerToString",
|
|
194
180
|
].filter((specifier): specifier is string => specifier !== undefined);
|
|
195
181
|
|
|
196
|
-
return specifiers.length === 0
|
|
197
|
-
? []
|
|
198
|
-
: [{ source: "@reckona/mreact-compat", specifiers }];
|
|
182
|
+
return specifiers.length === 0 ? [] : [{ source: "@reckona/mreact-compat", specifiers }];
|
|
199
183
|
}
|
|
200
184
|
|
|
201
185
|
function emitUserImports(ir: ModuleIr): string {
|
|
@@ -218,8 +202,9 @@ function emitComponent(
|
|
|
218
202
|
contextConsumerHelperName?: string,
|
|
219
203
|
reactNodeRenderHelperName?: string,
|
|
220
204
|
): string {
|
|
221
|
-
const body = component.bodyStatements.map(
|
|
222
|
-
|
|
205
|
+
const body = component.bodyStatements.map(
|
|
206
|
+
(statement) =>
|
|
207
|
+
` ${replaceOxcServerStringReactNodeRenderHelper(statement, reactNodeRenderHelperName)}`,
|
|
223
208
|
);
|
|
224
209
|
const parameters = component.parameters.join(", ");
|
|
225
210
|
const htmlStatements = collectHtmlStatements(
|
|
@@ -280,7 +265,7 @@ function emitHtmlExpression(
|
|
|
280
265
|
);
|
|
281
266
|
|
|
282
267
|
if (parts.length === 0) {
|
|
283
|
-
return "
|
|
268
|
+
return '""';
|
|
284
269
|
}
|
|
285
270
|
|
|
286
271
|
return parts.join(" + ");
|
|
@@ -400,10 +385,7 @@ function collectHtmlStatements(
|
|
|
400
385
|
}
|
|
401
386
|
|
|
402
387
|
if (node.kind === "list") {
|
|
403
|
-
const isAsync = containsAsyncServerOperationInChildren(
|
|
404
|
-
node.children,
|
|
405
|
-
asyncComponentNames,
|
|
406
|
-
);
|
|
388
|
+
const isAsync = containsAsyncServerOperationInChildren(node.children, asyncComponentNames);
|
|
407
389
|
|
|
408
390
|
if (isAsync) {
|
|
409
391
|
// Parallel async path keeps the existing renderer + Promise.all + join
|
|
@@ -427,8 +409,7 @@ function collectHtmlStatements(
|
|
|
427
409
|
// Sync list — inline for-loop appending to the caller's accumulator.
|
|
428
410
|
// No inner IIFE wrapper and no intermediate string concat per iteration.
|
|
429
411
|
const itemBinding = `const ${node.itemName} = _arr[_i];`;
|
|
430
|
-
const indexBinding =
|
|
431
|
-
node.indexName === undefined ? undefined : `const ${node.indexName} = _i;`;
|
|
412
|
+
const indexBinding = node.indexName === undefined ? undefined : `const ${node.indexName} = _i;`;
|
|
432
413
|
const arrayBinding =
|
|
433
414
|
node.arrayName === undefined ? undefined : `const ${node.arrayName} = _arr;`;
|
|
434
415
|
const bodyStatements = node.bodyStatements ?? [];
|
|
@@ -521,18 +502,31 @@ function collectHtmlStatements(
|
|
|
521
502
|
if (isClientBoundaryPlaceholder(node)) {
|
|
522
503
|
const helperName = currentClientBoundaryHelperName;
|
|
523
504
|
if (helperName !== undefined) {
|
|
505
|
+
const boundaryProps = emitPropsObject(
|
|
506
|
+
node.props,
|
|
507
|
+
[],
|
|
508
|
+
escapeHelperName,
|
|
509
|
+
escapeBatchHelperName,
|
|
510
|
+
asyncComponentNames,
|
|
511
|
+
dynamicAttributes,
|
|
512
|
+
contextProviderHelperName,
|
|
513
|
+
contextConsumerHelperName,
|
|
514
|
+
reactNodeRenderHelperName,
|
|
515
|
+
);
|
|
516
|
+
const fallbackHtml = shouldRenderClientBoundaryFallback(node)
|
|
517
|
+
? emitComponentCallExpression(node.name, boundaryProps, asyncComponentNames)
|
|
518
|
+
: emitHtmlExpressionFromChildren(
|
|
519
|
+
node.children,
|
|
520
|
+
escapeHelperName,
|
|
521
|
+
escapeBatchHelperName,
|
|
522
|
+
asyncComponentNames,
|
|
523
|
+
dynamicAttributes,
|
|
524
|
+
contextProviderHelperName,
|
|
525
|
+
contextConsumerHelperName,
|
|
526
|
+
reactNodeRenderHelperName,
|
|
527
|
+
);
|
|
524
528
|
return [
|
|
525
|
-
`${outVar} += ${helperName}(${stringLiteral(node.name)}, ${
|
|
526
|
-
node.props,
|
|
527
|
-
[],
|
|
528
|
-
escapeHelperName,
|
|
529
|
-
escapeBatchHelperName,
|
|
530
|
-
asyncComponentNames,
|
|
531
|
-
dynamicAttributes,
|
|
532
|
-
contextProviderHelperName,
|
|
533
|
-
contextConsumerHelperName,
|
|
534
|
-
reactNodeRenderHelperName,
|
|
535
|
-
)}, ${emitHtmlExpressionFromChildren(node.children, escapeHelperName, escapeBatchHelperName, asyncComponentNames, dynamicAttributes, contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName)});`,
|
|
529
|
+
`${outVar} += ${helperName}(${stringLiteral(node.name)}, ${boundaryProps}, ${fallbackHtml});`,
|
|
536
530
|
];
|
|
537
531
|
}
|
|
538
532
|
|
|
@@ -635,9 +629,8 @@ function collectHtmlStatements(
|
|
|
635
629
|
node.children,
|
|
636
630
|
escapeBatchHelperName,
|
|
637
631
|
);
|
|
638
|
-
const childSelectedValueCode =
|
|
639
|
-
? attributeScan.formValueAttributeCode
|
|
640
|
-
: undefined;
|
|
632
|
+
const childSelectedValueCode =
|
|
633
|
+
node.tagName === "select" ? attributeScan.formValueAttributeCode : undefined;
|
|
641
634
|
|
|
642
635
|
if (childrenExpression !== undefined && childSelectedValueCode === undefined) {
|
|
643
636
|
statements.push(`${outVar} += ${childrenExpression};`);
|
|
@@ -693,8 +686,26 @@ function collectHtmlParts(
|
|
|
693
686
|
}
|
|
694
687
|
|
|
695
688
|
if (node.kind === "conditional") {
|
|
696
|
-
const whenTrue = emitHtmlExpressionFromChildren(
|
|
697
|
-
|
|
689
|
+
const whenTrue = emitHtmlExpressionFromChildren(
|
|
690
|
+
node.whenTrue,
|
|
691
|
+
escapeHelperName,
|
|
692
|
+
escapeBatchHelperName,
|
|
693
|
+
asyncComponentNames,
|
|
694
|
+
dynamicAttributes,
|
|
695
|
+
contextProviderHelperName,
|
|
696
|
+
contextConsumerHelperName,
|
|
697
|
+
reactNodeRenderHelperName,
|
|
698
|
+
);
|
|
699
|
+
const whenFalse = emitHtmlExpressionFromChildren(
|
|
700
|
+
node.whenFalse,
|
|
701
|
+
escapeHelperName,
|
|
702
|
+
escapeBatchHelperName,
|
|
703
|
+
asyncComponentNames,
|
|
704
|
+
dynamicAttributes,
|
|
705
|
+
contextProviderHelperName,
|
|
706
|
+
contextConsumerHelperName,
|
|
707
|
+
reactNodeRenderHelperName,
|
|
708
|
+
);
|
|
698
709
|
|
|
699
710
|
return [
|
|
700
711
|
node.conditionValueName === undefined
|
|
@@ -704,10 +715,7 @@ function collectHtmlParts(
|
|
|
704
715
|
}
|
|
705
716
|
|
|
706
717
|
if (node.kind === "list") {
|
|
707
|
-
const isAsync = containsAsyncServerOperationInChildren(
|
|
708
|
-
node.children,
|
|
709
|
-
asyncComponentNames,
|
|
710
|
-
);
|
|
718
|
+
const isAsync = containsAsyncServerOperationInChildren(node.children, asyncComponentNames);
|
|
711
719
|
|
|
712
720
|
if (isAsync) {
|
|
713
721
|
// Async lists rely on Promise.all() for parallel resolution; the
|
|
@@ -732,16 +740,18 @@ function collectHtmlParts(
|
|
|
732
740
|
// Synchronous list — imperative accumulator avoids the per-render
|
|
733
741
|
// callback allocation, the intermediate `.map()` result array, and the
|
|
734
742
|
// trailing `.join("")` call.
|
|
735
|
-
return [
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
743
|
+
return [
|
|
744
|
+
emitSyncListIife(
|
|
745
|
+
node,
|
|
746
|
+
escapeHelperName,
|
|
747
|
+
escapeBatchHelperName,
|
|
748
|
+
asyncComponentNames,
|
|
749
|
+
dynamicAttributes,
|
|
750
|
+
contextProviderHelperName,
|
|
751
|
+
contextConsumerHelperName,
|
|
752
|
+
reactNodeRenderHelperName,
|
|
753
|
+
),
|
|
754
|
+
];
|
|
745
755
|
}
|
|
746
756
|
|
|
747
757
|
if (node.kind === "fragment") {
|
|
@@ -885,9 +895,8 @@ function collectHtmlParts(
|
|
|
885
895
|
escapeBatchHelperName,
|
|
886
896
|
);
|
|
887
897
|
const attributeScan = scanElementAttributes(node.tagName, node.attributes);
|
|
888
|
-
const childSelectedValueCode =
|
|
889
|
-
? attributeScan.formValueAttributeCode
|
|
890
|
-
: undefined;
|
|
898
|
+
const childSelectedValueCode =
|
|
899
|
+
node.tagName === "select" ? attributeScan.formValueAttributeCode : undefined;
|
|
891
900
|
const selectedAttributePart = collectOptionSelectedAttributePart(node, selectedValueCode);
|
|
892
901
|
const dangerousInnerHtml = emitDangerouslySetInnerHtmlExpression(node.attributes);
|
|
893
902
|
const childrenParts =
|
|
@@ -980,7 +989,9 @@ function collectHtmlAttributeParts(
|
|
|
980
989
|
}
|
|
981
990
|
|
|
982
991
|
if (attr.name === "style") {
|
|
983
|
-
return [
|
|
992
|
+
return [
|
|
993
|
+
emitDynamicStyleAttributeExpression(attr.code, escapeHelperName, escapeBatchHelperName),
|
|
994
|
+
];
|
|
984
995
|
}
|
|
985
996
|
|
|
986
997
|
if (isDangerousHtmlAttribute(htmlName)) {
|
|
@@ -988,7 +999,7 @@ function collectHtmlAttributeParts(
|
|
|
988
999
|
// else at runtime so a value computed from a loader cannot inject
|
|
989
1000
|
// executable HTML into the iframe document.
|
|
990
1001
|
return [
|
|
991
|
-
`(() => { const _value = (${attr.code}); if (_value == null || _value === false) return ""; if (typeof _value === "object" && _value !== null && typeof _value.__html === "string") return ${stringLiteral(` ${htmlName}="`)} + ${escapeHelperName}(_value.__html) + ${stringLiteral("
|
|
1002
|
+
`(() => { const _value = (${attr.code}); if (_value == null || _value === false) return ""; if (typeof _value === "object" && _value !== null && typeof _value.__html === "string") return ${stringLiteral(` ${htmlName}="`)} + ${escapeHelperName}(_value.__html) + ${stringLiteral('"')}; return ""; })()`,
|
|
992
1003
|
];
|
|
993
1004
|
}
|
|
994
1005
|
|
|
@@ -1009,11 +1020,11 @@ function collectElementAttributeParts(
|
|
|
1009
1020
|
|
|
1010
1021
|
return attrs.flatMap((attr) =>
|
|
1011
1022
|
attr.kind !== "spread-attr" &&
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1023
|
+
((tagName === "input" &&
|
|
1024
|
+
((attr.name === "defaultValue" && attributeScan.hasExplicitInputValue) ||
|
|
1025
|
+
(attr.name === "defaultChecked" && attributeScan.hasExplicitInputChecked))) ||
|
|
1026
|
+
((tagName === "textarea" || tagName === "select") &&
|
|
1027
|
+
(attr.name === "value" || attr.name === "defaultValue")))
|
|
1017
1028
|
? []
|
|
1018
1029
|
: collectHtmlAttributeParts(
|
|
1019
1030
|
tagName,
|
|
@@ -1087,10 +1098,7 @@ function scanElementAttributes(
|
|
|
1087
1098
|
|
|
1088
1099
|
if ((tagName === "textarea" || tagName === "select") && attr.name === "value") {
|
|
1089
1100
|
valueAttributeCode = readFormValueAttributeCode(attr);
|
|
1090
|
-
} else if (
|
|
1091
|
-
(tagName === "textarea" || tagName === "select") &&
|
|
1092
|
-
attr.name === "defaultValue"
|
|
1093
|
-
) {
|
|
1101
|
+
} else if ((tagName === "textarea" || tagName === "select") && attr.name === "defaultValue") {
|
|
1094
1102
|
defaultValueAttributeCode = readFormValueAttributeCode(attr);
|
|
1095
1103
|
}
|
|
1096
1104
|
}
|
|
@@ -1122,7 +1130,7 @@ function emitDynamicAttributeExpression(
|
|
|
1122
1130
|
// returns the value when safe and `undefined` when the attribute
|
|
1123
1131
|
// should be dropped. Using an IIFE here is necessary because we
|
|
1124
1132
|
// need to capture the value once and branch on the helper output.
|
|
1125
|
-
return `(() => { const _value = (${code}); if (_value == null || _value === false) return ""; const _checked = ${currentUrlSafeHelperName}(${stringLiteral(name)}, _value === true ? "" : _value); return _checked === undefined ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_checked) + ${stringLiteral("
|
|
1133
|
+
return `(() => { const _value = (${code}); if (_value == null || _value === false) return ""; const _checked = ${currentUrlSafeHelperName}(${stringLiteral(name)}, _value === true ? "" : _value); return _checked === undefined ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_checked) + ${stringLiteral('"')}; })()`;
|
|
1126
1134
|
}
|
|
1127
1135
|
|
|
1128
1136
|
const inlineExpr = simpleSideEffectFreeExpression(code);
|
|
@@ -1132,10 +1140,10 @@ function emitDynamicAttributeExpression(
|
|
|
1132
1140
|
// Safe because `simpleSideEffectFreeExpression` only matches expressions
|
|
1133
1141
|
// whose evaluation has no observable side effects (identifier read,
|
|
1134
1142
|
// member chain, literal, this).
|
|
1135
|
-
return `(${inlineExpr} == null || ${inlineExpr} === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(${inlineExpr} === true ? "" : ${inlineExpr}) + ${stringLiteral("
|
|
1143
|
+
return `(${inlineExpr} == null || ${inlineExpr} === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(${inlineExpr} === true ? "" : ${inlineExpr}) + ${stringLiteral('"')})`;
|
|
1136
1144
|
}
|
|
1137
1145
|
|
|
1138
|
-
return `(() => { const _value = (${code}); return _value == null || _value === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_value === true ? "" : _value) + ${stringLiteral("
|
|
1146
|
+
return `(() => { const _value = (${code}); return _value == null || _value === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_value === true ? "" : _value) + ${stringLiteral('"')}; })()`;
|
|
1139
1147
|
}
|
|
1140
1148
|
|
|
1141
1149
|
function emitDynamicStyleAttributeExpression(
|
|
@@ -1149,11 +1157,12 @@ function emitDynamicStyleAttributeExpression(
|
|
|
1149
1157
|
return staticStyleExpression;
|
|
1150
1158
|
}
|
|
1151
1159
|
|
|
1152
|
-
const escapedPair =
|
|
1153
|
-
|
|
1154
|
-
|
|
1160
|
+
const escapedPair =
|
|
1161
|
+
escapeBatchHelperName === undefined
|
|
1162
|
+
? `${escapeHelperName}(_cssName) + ":" + ${escapeHelperName}(_styleValue === true ? "" : _styleValue)`
|
|
1163
|
+
: `(() => { const _escaped = ${escapeBatchHelperName}([_cssName, _styleValue === true ? "" : _styleValue]); return _escaped[0] + ":" + _escaped[1]; })()`;
|
|
1155
1164
|
|
|
1156
|
-
return `(() => { const _value = (${code}); if (_value == null || _value === false) return ""; if (typeof _value === "string") { const _style = ${escapeHelperName}(_value); return _style === "" ? "" : ${stringLiteral(
|
|
1165
|
+
return `(() => { const _value = (${code}); if (_value == null || _value === false) return ""; if (typeof _value === "string") { const _style = ${escapeHelperName}(_value); return _style === "" ? "" : ${stringLiteral(' style="')} + _style + ${stringLiteral('"')}; } const _style = Object.entries(_value).filter(([, _styleValue]) => _styleValue != null && _styleValue !== false).map(([_styleName, _styleValue]) => { const _cssName = String(_styleName).startsWith("--") ? String(_styleName) : String(_styleName).replace(/[A-Z]/g, (_char) => "-" + _char.toLowerCase()); return ${escapedPair}; }).join(";"); return _style === "" ? "" : ${stringLiteral(' style="')} + _style + ${stringLiteral('"')}; })()`;
|
|
1157
1166
|
}
|
|
1158
1167
|
|
|
1159
1168
|
function emitStaticStyleObjectAttributeExpression(
|
|
@@ -1191,11 +1200,12 @@ function emitStaticStyleObjectAttributeExpression(
|
|
|
1191
1200
|
|
|
1192
1201
|
// Stage A — needSep tracking with inline string accumulator, no intermediate
|
|
1193
1202
|
// array allocation and no `.join(";")` per render.
|
|
1194
|
-
const statements = entries.map(
|
|
1195
|
-
|
|
1203
|
+
const statements = entries.map(
|
|
1204
|
+
(entry) =>
|
|
1205
|
+
`{ const _v = (${entry.valueCode}); if (_v != null && _v !== false) _style += (_style === "" ? "" : ";") + ${stringLiteral(`${entry.cssName}:`)} + ${escapeHelperName}(_v === true ? "" : _v); }`,
|
|
1196
1206
|
);
|
|
1197
1207
|
|
|
1198
|
-
return `(() => { let _style = ""; ${statements.join(" ")} return _style === "" ? "" : ${stringLiteral(
|
|
1208
|
+
return `(() => { let _style = ""; ${statements.join(" ")} return _style === "" ? "" : ${stringLiteral(' style="')} + _style + ${stringLiteral('"')}; })()`;
|
|
1199
1209
|
}
|
|
1200
1210
|
|
|
1201
1211
|
function collectTextareaValueParts(
|
|
@@ -1224,7 +1234,7 @@ function collectTextareaValueParts(
|
|
|
1224
1234
|
contextProviderHelperName,
|
|
1225
1235
|
contextConsumerHelperName,
|
|
1226
1236
|
reactNodeRenderHelperName,
|
|
1227
|
-
)
|
|
1237
|
+
),
|
|
1228
1238
|
);
|
|
1229
1239
|
}
|
|
1230
1240
|
|
|
@@ -1245,9 +1255,13 @@ function collectOptionSelectedAttributePart(
|
|
|
1245
1255
|
}
|
|
1246
1256
|
|
|
1247
1257
|
function findOptionValueCode(node: Extract<JsxNodeIr, { kind: "element" }>): string | undefined {
|
|
1248
|
-
const valueAttr = node.attributes.find(
|
|
1258
|
+
const valueAttr = node.attributes.find(
|
|
1259
|
+
(attr) => attr.kind !== "spread-attr" && attr.name === "value",
|
|
1260
|
+
);
|
|
1249
1261
|
if (valueAttr !== undefined && valueAttr.kind !== "event" && valueAttr.kind !== "spread-attr") {
|
|
1250
|
-
return valueAttr.kind === "static-attr"
|
|
1262
|
+
return valueAttr.kind === "static-attr"
|
|
1263
|
+
? stringLiteral(valueAttr.value)
|
|
1264
|
+
: `(${valueAttr.code})`;
|
|
1251
1265
|
}
|
|
1252
1266
|
|
|
1253
1267
|
return node.children.every((child) => child.kind === "text")
|
|
@@ -1282,7 +1296,8 @@ function emitBatchedSimpleChildrenExpression(
|
|
|
1282
1296
|
}
|
|
1283
1297
|
|
|
1284
1298
|
const dynamicChildren = children.filter(
|
|
1285
|
-
(child) =>
|
|
1299
|
+
(child) =>
|
|
1300
|
+
child.kind === "expr" && child.renderMode !== "html" && child.renderMode !== "react-node",
|
|
1286
1301
|
) as Array<Extract<JsxNodeIr, { kind: "expr" }>>;
|
|
1287
1302
|
|
|
1288
1303
|
if (dynamicChildren.length < 2) {
|
|
@@ -1293,7 +1308,11 @@ function emitBatchedSimpleChildrenExpression(
|
|
|
1293
1308
|
children.some(
|
|
1294
1309
|
(child) =>
|
|
1295
1310
|
child.kind !== "text" &&
|
|
1296
|
-
!(
|
|
1311
|
+
!(
|
|
1312
|
+
child.kind === "expr" &&
|
|
1313
|
+
child.renderMode !== "html" &&
|
|
1314
|
+
child.renderMode !== "react-node"
|
|
1315
|
+
),
|
|
1297
1316
|
)
|
|
1298
1317
|
) {
|
|
1299
1318
|
return undefined;
|
|
@@ -1326,7 +1345,7 @@ function emitHtmlExpressionFromChildren(
|
|
|
1326
1345
|
reactNodeRenderHelperName?: string,
|
|
1327
1346
|
): string {
|
|
1328
1347
|
if (children.length === 0) {
|
|
1329
|
-
return "
|
|
1348
|
+
return '""';
|
|
1330
1349
|
}
|
|
1331
1350
|
|
|
1332
1351
|
return emitHtmlExpression(
|
|
@@ -1362,10 +1381,8 @@ function emitSyncListIife(
|
|
|
1362
1381
|
reactNodeRenderHelperName,
|
|
1363
1382
|
);
|
|
1364
1383
|
const itemBinding = `const ${node.itemName} = _arr[_i];`;
|
|
1365
|
-
const indexBinding =
|
|
1366
|
-
|
|
1367
|
-
const arrayBinding =
|
|
1368
|
-
node.arrayName === undefined ? "" : ` const ${node.arrayName} = _arr;`;
|
|
1384
|
+
const indexBinding = node.indexName === undefined ? "" : ` const ${node.indexName} = _i;`;
|
|
1385
|
+
const arrayBinding = node.arrayName === undefined ? "" : ` const ${node.arrayName} = _arr;`;
|
|
1369
1386
|
const bodyStatements =
|
|
1370
1387
|
node.bodyStatements === undefined || node.bodyStatements.length === 0
|
|
1371
1388
|
? ""
|
|
@@ -1395,10 +1412,7 @@ function emitListRenderer(
|
|
|
1395
1412
|
contextConsumerHelperName,
|
|
1396
1413
|
reactNodeRenderHelperName,
|
|
1397
1414
|
);
|
|
1398
|
-
const asyncKeyword = containsAsyncServerOperationInChildren(
|
|
1399
|
-
node.children,
|
|
1400
|
-
asyncComponentNames,
|
|
1401
|
-
)
|
|
1415
|
+
const asyncKeyword = containsAsyncServerOperationInChildren(node.children, asyncComponentNames)
|
|
1402
1416
|
? "async "
|
|
1403
1417
|
: "";
|
|
1404
1418
|
|
|
@@ -1476,22 +1490,30 @@ function emitComponentCallExpression(
|
|
|
1476
1490
|
asyncComponentNames: ReadonlySet<string>,
|
|
1477
1491
|
): string {
|
|
1478
1492
|
const call = `${name}(${propsCode})`;
|
|
1479
|
-
return asyncComponentNames.has(name) ? `(await ${call})` : call;
|
|
1493
|
+
return emitRenderableHtmlExpression(asyncComponentNames.has(name) ? `(await ${call})` : call);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
function emitRenderableHtmlExpression(code: string): string {
|
|
1497
|
+
return `((_value) => _value == null || typeof _value === "boolean" ? "" : _value)(${code})`;
|
|
1480
1498
|
}
|
|
1481
1499
|
|
|
1482
1500
|
function isClientBoundaryPlaceholder(node: Extract<JsxNodeIr, { kind: "component" }>): boolean {
|
|
1483
1501
|
return node.clientReference !== undefined;
|
|
1484
1502
|
}
|
|
1485
1503
|
|
|
1504
|
+
function shouldRenderClientBoundaryFallback(
|
|
1505
|
+
node: Extract<JsxNodeIr, { kind: "component" }>,
|
|
1506
|
+
): boolean {
|
|
1507
|
+
return node.clientReference?.ssrFallback === true;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1486
1510
|
function clientBoundaryPlaceholder(node: Extract<JsxNodeIr, { kind: "component" }>): string {
|
|
1487
1511
|
return `<!--mreact-client-boundary:${escapeHtml(node.name)}-->`;
|
|
1488
1512
|
}
|
|
1489
1513
|
|
|
1490
1514
|
function collectAsyncServerComponentNames(components: readonly ComponentIr[]): Set<string> {
|
|
1491
1515
|
const names = new Set(
|
|
1492
|
-
components
|
|
1493
|
-
.filter((component) => component.async === true)
|
|
1494
|
-
.map((component) => component.name),
|
|
1516
|
+
components.filter((component) => component.async === true).map((component) => component.name),
|
|
1495
1517
|
);
|
|
1496
1518
|
|
|
1497
1519
|
let changed = true;
|
|
@@ -1500,10 +1522,7 @@ function collectAsyncServerComponentNames(components: readonly ComponentIr[]): S
|
|
|
1500
1522
|
changed = false;
|
|
1501
1523
|
|
|
1502
1524
|
for (const component of components) {
|
|
1503
|
-
if (
|
|
1504
|
-
!names.has(component.name) &&
|
|
1505
|
-
containsAsyncServerOperation(component.root, names)
|
|
1506
|
-
) {
|
|
1525
|
+
if (!names.has(component.name) && containsAsyncServerOperation(component.root, names)) {
|
|
1507
1526
|
names.add(component.name);
|
|
1508
1527
|
changed = true;
|
|
1509
1528
|
}
|
package/src/ir.ts
CHANGED