@reckona/mreact-compiler 0.0.120 → 0.0.121
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-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-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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit-server.d.ts","sourceRoot":"","sources":["../src/emit-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"emit-server.d.ts","sourceRoot":"","sources":["../src/emit-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAwD,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC9F,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAkBrE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,MAAM,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACzC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AASD,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAE,iBAAsB,GAAG,UAAU,CA6GpF"}
|
package/dist/emit-server.js
CHANGED
|
@@ -11,9 +11,7 @@ let currentClientBoundaryHelperName;
|
|
|
11
11
|
let currentSpreadAttributesHelperName = "_renderSpreadAttributes";
|
|
12
12
|
export function emitServer(ir, options = {}) {
|
|
13
13
|
const escapeHelperName = allocateEscapeHelperName(ir);
|
|
14
|
-
const escapeBatchHelperName = options.escape === undefined
|
|
15
|
-
? undefined
|
|
16
|
-
: allocateHelperName(ir, "_escapeHtmlBatch");
|
|
14
|
+
const escapeBatchHelperName = options.escape === undefined ? undefined : allocateHelperName(ir, "_escapeHtmlBatch");
|
|
17
15
|
const contextProviderHelperName = usesContextProvider(ir)
|
|
18
16
|
? allocateHelperName(ir, "_renderContextProviderToString")
|
|
19
17
|
: undefined;
|
|
@@ -114,16 +112,10 @@ function emitContextImport(contextProviderHelperName, contextConsumerHelperName,
|
|
|
114
112
|
function collectContextImports(contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName) {
|
|
115
113
|
const specifiers = [
|
|
116
114
|
reactNodeRenderHelperName === undefined ? undefined : "renderToString",
|
|
117
|
-
contextProviderHelperName === undefined
|
|
118
|
-
|
|
119
|
-
: "renderContextProviderToString",
|
|
120
|
-
contextConsumerHelperName === undefined
|
|
121
|
-
? undefined
|
|
122
|
-
: "renderContextConsumerToString",
|
|
115
|
+
contextProviderHelperName === undefined ? undefined : "renderContextProviderToString",
|
|
116
|
+
contextConsumerHelperName === undefined ? undefined : "renderContextConsumerToString",
|
|
123
117
|
].filter((specifier) => specifier !== undefined);
|
|
124
|
-
return specifiers.length === 0
|
|
125
|
-
? []
|
|
126
|
-
: [{ source: "@reckona/mreact-compat", specifiers }];
|
|
118
|
+
return specifiers.length === 0 ? [] : [{ source: "@reckona/mreact-compat", specifiers }];
|
|
127
119
|
}
|
|
128
120
|
function emitUserImports(ir) {
|
|
129
121
|
return ir.userImports.join("\n");
|
|
@@ -154,7 +146,7 @@ function emitComponent(component, escapeHelperName, escapeBatchHelperName, outAc
|
|
|
154
146
|
function emitHtmlExpression(node, escapeHelperName, escapeBatchHelperName, asyncComponentNames, dynamicAttributes, contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName) {
|
|
155
147
|
const parts = collectHtmlParts(node, escapeHelperName, escapeBatchHelperName, asyncComponentNames, dynamicAttributes, contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName);
|
|
156
148
|
if (parts.length === 0) {
|
|
157
|
-
return "
|
|
149
|
+
return '""';
|
|
158
150
|
}
|
|
159
151
|
return parts.join(" + ");
|
|
160
152
|
}
|
|
@@ -291,8 +283,12 @@ function collectHtmlStatements(node, outVar, escapeHelperName, escapeBatchHelper
|
|
|
291
283
|
if (isClientBoundaryPlaceholder(node)) {
|
|
292
284
|
const helperName = currentClientBoundaryHelperName;
|
|
293
285
|
if (helperName !== undefined) {
|
|
286
|
+
const boundaryProps = emitPropsObject(node.props, [], escapeHelperName, escapeBatchHelperName, asyncComponentNames, dynamicAttributes, contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName);
|
|
287
|
+
const fallbackHtml = shouldRenderClientBoundaryFallback(node)
|
|
288
|
+
? emitComponentCallExpression(node.name, boundaryProps, asyncComponentNames)
|
|
289
|
+
: emitHtmlExpressionFromChildren(node.children, escapeHelperName, escapeBatchHelperName, asyncComponentNames, dynamicAttributes, contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName);
|
|
294
290
|
return [
|
|
295
|
-
`${outVar} += ${helperName}(${stringLiteral(node.name)}, ${
|
|
291
|
+
`${outVar} += ${helperName}(${stringLiteral(node.name)}, ${boundaryProps}, ${fallbackHtml});`,
|
|
296
292
|
];
|
|
297
293
|
}
|
|
298
294
|
return [`${outVar} += ${stringLiteral(clientBoundaryPlaceholder(node))};`];
|
|
@@ -341,9 +337,7 @@ function collectHtmlStatements(node, outVar, escapeHelperName, escapeBatchHelper
|
|
|
341
337
|
return statements;
|
|
342
338
|
}
|
|
343
339
|
const childrenExpression = emitBatchedSimpleChildrenExpression(node.children, escapeBatchHelperName);
|
|
344
|
-
const childSelectedValueCode = node.tagName === "select"
|
|
345
|
-
? attributeScan.formValueAttributeCode
|
|
346
|
-
: undefined;
|
|
340
|
+
const childSelectedValueCode = node.tagName === "select" ? attributeScan.formValueAttributeCode : undefined;
|
|
347
341
|
if (childrenExpression !== undefined && childSelectedValueCode === undefined) {
|
|
348
342
|
statements.push(`${outVar} += ${childrenExpression};`);
|
|
349
343
|
}
|
|
@@ -391,7 +385,9 @@ function collectHtmlParts(node, escapeHelperName, escapeBatchHelperName, asyncCo
|
|
|
391
385
|
// Synchronous list — imperative accumulator avoids the per-render
|
|
392
386
|
// callback allocation, the intermediate `.map()` result array, and the
|
|
393
387
|
// trailing `.join("")` call.
|
|
394
|
-
return [
|
|
388
|
+
return [
|
|
389
|
+
emitSyncListIife(node, escapeHelperName, escapeBatchHelperName, asyncComponentNames, dynamicAttributes, contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName),
|
|
390
|
+
];
|
|
395
391
|
}
|
|
396
392
|
if (node.kind === "fragment") {
|
|
397
393
|
return node.children.flatMap((child) => collectHtmlParts(child, escapeHelperName, escapeBatchHelperName, asyncComponentNames, dynamicAttributes, contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName));
|
|
@@ -453,9 +449,7 @@ function collectHtmlParts(node, escapeHelperName, escapeBatchHelperName, asyncCo
|
|
|
453
449
|
}
|
|
454
450
|
const childrenExpression = emitBatchedSimpleChildrenExpression(node.children, escapeBatchHelperName);
|
|
455
451
|
const attributeScan = scanElementAttributes(node.tagName, node.attributes);
|
|
456
|
-
const childSelectedValueCode = node.tagName === "select"
|
|
457
|
-
? attributeScan.formValueAttributeCode
|
|
458
|
-
: undefined;
|
|
452
|
+
const childSelectedValueCode = node.tagName === "select" ? attributeScan.formValueAttributeCode : undefined;
|
|
459
453
|
const selectedAttributePart = collectOptionSelectedAttributePart(node, selectedValueCode);
|
|
460
454
|
const dangerousInnerHtml = emitDangerouslySetInnerHtmlExpression(node.attributes);
|
|
461
455
|
const childrenParts = dangerousInnerHtml !== undefined
|
|
@@ -509,14 +503,16 @@ function collectHtmlAttributeParts(tagName, attr, escapeHelperName, escapeBatchH
|
|
|
509
503
|
return [];
|
|
510
504
|
}
|
|
511
505
|
if (attr.name === "style") {
|
|
512
|
-
return [
|
|
506
|
+
return [
|
|
507
|
+
emitDynamicStyleAttributeExpression(attr.code, escapeHelperName, escapeBatchHelperName),
|
|
508
|
+
];
|
|
513
509
|
}
|
|
514
510
|
if (isDangerousHtmlAttribute(htmlName)) {
|
|
515
511
|
// Dynamic srcdoc must arrive as `{ __html: "..." }`. Drop anything
|
|
516
512
|
// else at runtime so a value computed from a loader cannot inject
|
|
517
513
|
// executable HTML into the iframe document.
|
|
518
514
|
return [
|
|
519
|
-
`(() => { 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("
|
|
515
|
+
`(() => { 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 ""; })()`,
|
|
520
516
|
];
|
|
521
517
|
}
|
|
522
518
|
return [emitDynamicAttributeExpression(htmlName, attr.code, escapeHelperName)];
|
|
@@ -575,8 +571,7 @@ function scanElementAttributes(tagName, attrs) {
|
|
|
575
571
|
if ((tagName === "textarea" || tagName === "select") && attr.name === "value") {
|
|
576
572
|
valueAttributeCode = readFormValueAttributeCode(attr);
|
|
577
573
|
}
|
|
578
|
-
else if ((tagName === "textarea" || tagName === "select") &&
|
|
579
|
-
attr.name === "defaultValue") {
|
|
574
|
+
else if ((tagName === "textarea" || tagName === "select") && attr.name === "defaultValue") {
|
|
580
575
|
defaultValueAttributeCode = readFormValueAttributeCode(attr);
|
|
581
576
|
}
|
|
582
577
|
}
|
|
@@ -598,7 +593,7 @@ function emitDynamicAttributeExpression(name, code, escapeHelperName) {
|
|
|
598
593
|
// returns the value when safe and `undefined` when the attribute
|
|
599
594
|
// should be dropped. Using an IIFE here is necessary because we
|
|
600
595
|
// need to capture the value once and branch on the helper output.
|
|
601
|
-
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("
|
|
596
|
+
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('"')}; })()`;
|
|
602
597
|
}
|
|
603
598
|
const inlineExpr = simpleSideEffectFreeExpression(code);
|
|
604
599
|
if (inlineExpr !== undefined) {
|
|
@@ -606,9 +601,9 @@ function emitDynamicAttributeExpression(name, code, escapeHelperName) {
|
|
|
606
601
|
// Safe because `simpleSideEffectFreeExpression` only matches expressions
|
|
607
602
|
// whose evaluation has no observable side effects (identifier read,
|
|
608
603
|
// member chain, literal, this).
|
|
609
|
-
return `(${inlineExpr} == null || ${inlineExpr} === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(${inlineExpr} === true ? "" : ${inlineExpr}) + ${stringLiteral("
|
|
604
|
+
return `(${inlineExpr} == null || ${inlineExpr} === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(${inlineExpr} === true ? "" : ${inlineExpr}) + ${stringLiteral('"')})`;
|
|
610
605
|
}
|
|
611
|
-
return `(() => { const _value = (${code}); return _value == null || _value === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_value === true ? "" : _value) + ${stringLiteral("
|
|
606
|
+
return `(() => { const _value = (${code}); return _value == null || _value === false ? "" : ${stringLiteral(` ${name}="`)} + ${escapeHelperName}(_value === true ? "" : _value) + ${stringLiteral('"')}; })()`;
|
|
612
607
|
}
|
|
613
608
|
function emitDynamicStyleAttributeExpression(code, escapeHelperName, escapeBatchHelperName) {
|
|
614
609
|
const staticStyleExpression = emitStaticStyleObjectAttributeExpression(code, escapeHelperName);
|
|
@@ -618,7 +613,7 @@ function emitDynamicStyleAttributeExpression(code, escapeHelperName, escapeBatch
|
|
|
618
613
|
const escapedPair = escapeBatchHelperName === undefined
|
|
619
614
|
? `${escapeHelperName}(_cssName) + ":" + ${escapeHelperName}(_styleValue === true ? "" : _styleValue)`
|
|
620
615
|
: `(() => { const _escaped = ${escapeBatchHelperName}([_cssName, _styleValue === true ? "" : _styleValue]); return _escaped[0] + ":" + _escaped[1]; })()`;
|
|
621
|
-
return `(() => { const _value = (${code}); if (_value == null || _value === false) return ""; if (typeof _value === "string") { const _style = ${escapeHelperName}(_value); return _style === "" ? "" : ${stringLiteral(
|
|
616
|
+
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('"')}; })()`;
|
|
622
617
|
}
|
|
623
618
|
function emitStaticStyleObjectAttributeExpression(code, escapeHelperName) {
|
|
624
619
|
const entries = parseStaticStyleObjectLiteral(code);
|
|
@@ -646,7 +641,7 @@ function emitStaticStyleObjectAttributeExpression(code, escapeHelperName) {
|
|
|
646
641
|
// Stage A — needSep tracking with inline string accumulator, no intermediate
|
|
647
642
|
// array allocation and no `.join(";")` per render.
|
|
648
643
|
const statements = entries.map((entry) => `{ const _v = (${entry.valueCode}); if (_v != null && _v !== false) _style += (_style === "" ? "" : ";") + ${stringLiteral(`${entry.cssName}:`)} + ${escapeHelperName}(_v === true ? "" : _v); }`);
|
|
649
|
-
return `(() => { let _style = ""; ${statements.join(" ")} return _style === "" ? "" : ${stringLiteral(
|
|
644
|
+
return `(() => { let _style = ""; ${statements.join(" ")} return _style === "" ? "" : ${stringLiteral(' style="')} + _style + ${stringLiteral('"')}; })()`;
|
|
650
645
|
}
|
|
651
646
|
function collectTextareaValueParts(node, escapeHelperName, escapeBatchHelperName, asyncComponentNames, dynamicAttributes, contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName, attributeScan = scanElementAttributes(node.tagName, node.attributes)) {
|
|
652
647
|
const valueCode = attributeScan.formValueAttributeCode;
|
|
@@ -668,7 +663,9 @@ function collectOptionSelectedAttributePart(node, selectedValueCode) {
|
|
|
668
663
|
function findOptionValueCode(node) {
|
|
669
664
|
const valueAttr = node.attributes.find((attr) => attr.kind !== "spread-attr" && attr.name === "value");
|
|
670
665
|
if (valueAttr !== undefined && valueAttr.kind !== "event" && valueAttr.kind !== "spread-attr") {
|
|
671
|
-
return valueAttr.kind === "static-attr"
|
|
666
|
+
return valueAttr.kind === "static-attr"
|
|
667
|
+
? stringLiteral(valueAttr.value)
|
|
668
|
+
: `(${valueAttr.code})`;
|
|
672
669
|
}
|
|
673
670
|
return node.children.every((child) => child.kind === "text")
|
|
674
671
|
? stringLiteral(node.children.map((child) => child.value).join(""))
|
|
@@ -697,7 +694,9 @@ function emitBatchedSimpleChildrenExpression(children, escapeBatchHelperName) {
|
|
|
697
694
|
return undefined;
|
|
698
695
|
}
|
|
699
696
|
if (children.some((child) => child.kind !== "text" &&
|
|
700
|
-
!(child.kind === "expr" &&
|
|
697
|
+
!(child.kind === "expr" &&
|
|
698
|
+
child.renderMode !== "html" &&
|
|
699
|
+
child.renderMode !== "react-node"))) {
|
|
701
700
|
return undefined;
|
|
702
701
|
}
|
|
703
702
|
const values = dynamicChildren.map((child) => child.code);
|
|
@@ -714,7 +713,7 @@ function emitBatchedSimpleChildrenExpression(children, escapeBatchHelperName) {
|
|
|
714
713
|
}
|
|
715
714
|
function emitHtmlExpressionFromChildren(children, escapeHelperName, escapeBatchHelperName, asyncComponentNames, dynamicAttributes, contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName) {
|
|
716
715
|
if (children.length === 0) {
|
|
717
|
-
return "
|
|
716
|
+
return '""';
|
|
718
717
|
}
|
|
719
718
|
return emitHtmlExpression({ kind: "fragment", children }, escapeHelperName, escapeBatchHelperName, asyncComponentNames, dynamicAttributes, contextProviderHelperName, contextConsumerHelperName, reactNodeRenderHelperName);
|
|
720
719
|
}
|
|
@@ -775,24 +774,27 @@ function emitCompatRuntimePropsObject(props, children = []) {
|
|
|
775
774
|
}
|
|
776
775
|
function emitComponentCallExpression(name, propsCode, asyncComponentNames) {
|
|
777
776
|
const call = `${name}(${propsCode})`;
|
|
778
|
-
return asyncComponentNames.has(name) ? `(await ${call})` : call;
|
|
777
|
+
return emitRenderableHtmlExpression(asyncComponentNames.has(name) ? `(await ${call})` : call);
|
|
778
|
+
}
|
|
779
|
+
function emitRenderableHtmlExpression(code) {
|
|
780
|
+
return `((_value) => _value == null || typeof _value === "boolean" ? "" : _value)(${code})`;
|
|
779
781
|
}
|
|
780
782
|
function isClientBoundaryPlaceholder(node) {
|
|
781
783
|
return node.clientReference !== undefined;
|
|
782
784
|
}
|
|
785
|
+
function shouldRenderClientBoundaryFallback(node) {
|
|
786
|
+
return node.clientReference?.ssrFallback === true;
|
|
787
|
+
}
|
|
783
788
|
function clientBoundaryPlaceholder(node) {
|
|
784
789
|
return `<!--mreact-client-boundary:${escapeHtml(node.name)}-->`;
|
|
785
790
|
}
|
|
786
791
|
function collectAsyncServerComponentNames(components) {
|
|
787
|
-
const names = new Set(components
|
|
788
|
-
.filter((component) => component.async === true)
|
|
789
|
-
.map((component) => component.name));
|
|
792
|
+
const names = new Set(components.filter((component) => component.async === true).map((component) => component.name));
|
|
790
793
|
let changed = true;
|
|
791
794
|
while (changed) {
|
|
792
795
|
changed = false;
|
|
793
796
|
for (const component of components) {
|
|
794
|
-
if (!names.has(component.name) &&
|
|
795
|
-
containsAsyncServerOperation(component.root, names)) {
|
|
797
|
+
if (!names.has(component.name) && containsAsyncServerOperation(component.root, names)) {
|
|
796
798
|
names.add(component.name);
|
|
797
799
|
changed = true;
|
|
798
800
|
}
|