@reckona/mreact-compiler 0.0.96 → 0.0.98

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.
Files changed (57) hide show
  1. package/dist/diagnostics.d.ts +1 -0
  2. package/dist/diagnostics.d.ts.map +1 -1
  3. package/dist/diagnostics.js +8 -0
  4. package/dist/diagnostics.js.map +1 -1
  5. package/dist/emit-client.js +14 -9
  6. package/dist/emit-client.js.map +1 -1
  7. package/dist/emit-compat.js +5 -1
  8. package/dist/emit-compat.js.map +1 -1
  9. package/dist/emit-server-stream.d.ts.map +1 -1
  10. package/dist/emit-server-stream.js +70 -6
  11. package/dist/emit-server-stream.js.map +1 -1
  12. package/dist/emit-server.d.ts.map +1 -1
  13. package/dist/emit-server.js +69 -13
  14. package/dist/emit-server.js.map +1 -1
  15. package/dist/internal.d.ts.map +1 -1
  16. package/dist/internal.js +7 -4
  17. package/dist/internal.js.map +1 -1
  18. package/dist/ir.d.ts +1 -0
  19. package/dist/ir.d.ts.map +1 -1
  20. package/dist/ir.js.map +1 -1
  21. package/dist/oxc-child-analysis.d.ts.map +1 -1
  22. package/dist/oxc-child-analysis.js +44 -10
  23. package/dist/oxc-child-analysis.js.map +1 -1
  24. package/dist/oxc-component-detection.d.ts +5 -2
  25. package/dist/oxc-component-detection.d.ts.map +1 -1
  26. package/dist/oxc-component-detection.js +80 -3
  27. package/dist/oxc-component-detection.js.map +1 -1
  28. package/dist/oxc-component-props.d.ts +1 -1
  29. package/dist/oxc-component-props.d.ts.map +1 -1
  30. package/dist/oxc-component-props.js +1 -1
  31. package/dist/oxc-component-props.js.map +1 -1
  32. package/dist/oxc-component-references.d.ts.map +1 -1
  33. package/dist/oxc-component-references.js +247 -12
  34. package/dist/oxc-component-references.js.map +1 -1
  35. package/dist/oxc-runtime-emit.d.ts.map +1 -1
  36. package/dist/oxc-runtime-emit.js +10 -2
  37. package/dist/oxc-runtime-emit.js.map +1 -1
  38. package/dist/oxc.d.ts.map +1 -1
  39. package/dist/oxc.js +109 -20
  40. package/dist/oxc.js.map +1 -1
  41. package/dist/transform.js +29 -11
  42. package/dist/transform.js.map +1 -1
  43. package/package.json +2 -2
  44. package/src/diagnostics.ts +10 -0
  45. package/src/emit-client.ts +20 -10
  46. package/src/emit-compat.ts +6 -1
  47. package/src/emit-server-stream.ts +96 -6
  48. package/src/emit-server.ts +93 -29
  49. package/src/internal.ts +9 -4
  50. package/src/ir.ts +1 -0
  51. package/src/oxc-child-analysis.ts +66 -21
  52. package/src/oxc-component-detection.ts +145 -2
  53. package/src/oxc-component-props.ts +2 -1
  54. package/src/oxc-component-references.ts +366 -11
  55. package/src/oxc-runtime-emit.ts +12 -2
  56. package/src/oxc.ts +167 -5
  57. package/src/transform.ts +42 -10
@@ -3,7 +3,7 @@ import { createCodeBuilder } from "./emit-code-builder.js";
3
3
  import { emitAsyncBoundary as emitLoweredAsyncBoundary, emitOutOfOrderBoundary as emitLoweredOutOfOrderBoundary, emitReactSuspenseBoundary as emitLoweredReactSuspenseBoundary, emitReactSuspenseOutOfOrderBoundary as emitLoweredReactSuspenseOutOfOrderBoundary, } from "./emit-boundary-lowering.js";
4
4
  import { escapeHtmlAttribute as escapeHtml } from "@reckona/mreact-shared/html-escape";
5
5
  import { htmlAttributeName, isDangerousHtmlAttribute, isStaticUrlValueUnsafe, isUrlAttribute, parseStaticStyleObjectLiteral, parseStyleLiteralValue, simpleSideEffectFreeExpression, } from "./emit-server-shared.js";
6
- import { oxcServerStringReactNodeRenderHelperPlaceholder } from "./oxc-runtime-emit.js";
6
+ import { emitOxcCompatObjectChildren, oxcServerStringReactNodeRenderHelperPlaceholder, } from "./oxc-runtime-emit.js";
7
7
  let currentUrlSafeHelperName = "_urlAttrSafe";
8
8
  let currentClientBoundaryHelperName;
9
9
  let currentSpreadAttributesHelperName = "_renderSpreadAttributes";
@@ -348,10 +348,23 @@ function emitAppendStatements(node, sinkName, escapeHelperName, asyncBoundaryHel
348
348
  if (whenTrue.length === 0 && whenFalse.length === 0) {
349
349
  return [];
350
350
  }
351
+ const conditionCode = node.conditionValueName ?? node.conditionCode;
352
+ let statements;
351
353
  if (whenFalse.length === 0) {
352
- return [` if (${node.conditionCode}) {`, ...whenTrue, ` }`];
354
+ statements = [` if (${conditionCode}) {`, ...whenTrue, ` }`];
353
355
  }
354
- return [` if (${node.conditionCode}) {`, ...whenTrue, ` } else {`, ...whenFalse, ` }`];
356
+ else {
357
+ statements = [` if (${conditionCode}) {`, ...whenTrue, ` } else {`, ...whenFalse, ` }`];
358
+ }
359
+ if (node.conditionValueName === undefined) {
360
+ return statements;
361
+ }
362
+ return [
363
+ ` {`,
364
+ ` const ${node.conditionValueName} = (${node.conditionCode});`,
365
+ ...statements.map((statement) => ` ${statement}`),
366
+ ` }`,
367
+ ];
355
368
  }
356
369
  const collectState = {
357
370
  dynamicAttributes,
@@ -571,12 +584,15 @@ function tryEmitPartAsStringExpression(part, compatRenderToStringHelperName) {
571
584
  return emitListPartAsStringExpression(part, compatRenderToStringHelperName);
572
585
  }
573
586
  if (part.kind === "component" && part.runtime === "compat") {
574
- const rendered = `${compatRenderToStringHelperName}(${part.name}, ${emitPropsObject(part.props, part.children, part.escapeHelperName)})`;
587
+ const rendered = `${compatRenderToStringHelperName}(${part.name}, ${emitCompatRuntimePropsObject(part.props, part.children)})`;
575
588
  if (part.hydrationId === undefined) {
576
589
  return rendered;
577
590
  }
578
591
  return `${stringLiteral(`<!--mreact-h:start:${encodeURIComponent(part.hydrationId)}-->`)} + ${rendered} + ${stringLiteral(`<!--mreact-h:end:${encodeURIComponent(part.hydrationId)}-->`)}`;
579
592
  }
593
+ if (part.kind === "component" && part.hydrationId === undefined) {
594
+ return `${part.name}(${emitPropsObject(part.props, part.children, part.escapeHelperName)})`;
595
+ }
580
596
  // Non-compat component parts require `await sink-write`; lists with
581
597
  // sink-needing children also can't collapse. Signal fallback.
582
598
  return undefined;
@@ -638,7 +654,7 @@ function emitNestedStreamAppendStatements(parts, sinkName, compatRenderToStringH
638
654
  .join("\n");
639
655
  }
640
656
  function emitCompatComponentAppendStatements(part, sinkName, compatRenderToStringHelperName, indent) {
641
- const rendered = `${compatRenderToStringHelperName}(${part.name}, ${emitPropsObject(part.props, part.children, part.escapeHelperName)})`;
657
+ const rendered = `${compatRenderToStringHelperName}(${part.name}, ${emitCompatRuntimePropsObject(part.props, part.children)})`;
642
658
  const statements = part.hydrationId === undefined
643
659
  ? [`${sinkName}.append(${rendered});`]
644
660
  : [
@@ -672,10 +688,14 @@ function collectHtmlParts(node, escapeHelperName, asyncBoundaryHelperName, outOf
672
688
  return [{ kind: "dynamic", code: node.code, escapeHelperName }];
673
689
  }
674
690
  if (node.kind === "conditional") {
691
+ const whenTrue = emitHtmlExpressionFromChildren(node.whenTrue, escapeHelperName);
692
+ const whenFalse = emitHtmlExpressionFromChildren(node.whenFalse, escapeHelperName);
675
693
  return [
676
694
  {
677
695
  kind: "raw-dynamic",
678
- code: `((${node.conditionCode}) ? ${emitHtmlExpressionFromChildren(node.whenTrue, escapeHelperName)} : ${emitHtmlExpressionFromChildren(node.whenFalse, escapeHelperName)})`,
696
+ code: node.conditionValueName === undefined
697
+ ? `((${node.conditionCode}) ? ${whenTrue} : ${whenFalse})`
698
+ : `(() => { const ${node.conditionValueName} = (${node.conditionCode}); return ${node.conditionValueName} ? ${whenTrue} : ${whenFalse}; })()`,
679
699
  },
680
700
  ];
681
701
  }
@@ -945,6 +965,14 @@ function collectHtmlAttributeParts(tagName, attr, escapeHelperName, escapeBatchH
945
965
  }
946
966
  function collectElementAttributeParts(tagName, attrs, escapeHelperName, state, attributeScan = scanElementAttributes(tagName, attrs)) {
947
967
  const escapeBatchHelperName = state.escapeBatchHelperName;
968
+ if (state.dynamicAttributes === "emit" && attrs.some((attr) => attr.kind === "spread-attr")) {
969
+ return [
970
+ {
971
+ kind: "raw-dynamic",
972
+ code: emitMergedSpreadAttributeExpression(tagName, attrs, attributeScan),
973
+ },
974
+ ];
975
+ }
948
976
  return attrs.flatMap((attr) => attr.kind !== "spread-attr" &&
949
977
  ((tagName === "input" &&
950
978
  ((attr.name === "defaultValue" && attributeScan.hasExplicitInputValue) ||
@@ -954,6 +982,27 @@ function collectElementAttributeParts(tagName, attrs, escapeHelperName, state, a
954
982
  ? []
955
983
  : collectHtmlAttributeParts(tagName, attr, escapeHelperName, escapeBatchHelperName, state.dynamicAttributes));
956
984
  }
985
+ function emitMergedSpreadAttributeExpression(tagName, attrs, attributeScan) {
986
+ const statements = attrs.flatMap((attr) => {
987
+ if (attr.kind !== "spread-attr" &&
988
+ ((tagName === "input" &&
989
+ ((attr.name === "defaultValue" && attributeScan.hasExplicitInputValue) ||
990
+ (attr.name === "defaultChecked" && attributeScan.hasExplicitInputChecked))) ||
991
+ ((tagName === "textarea" || tagName === "select") &&
992
+ (attr.name === "value" || attr.name === "defaultValue")))) {
993
+ return [];
994
+ }
995
+ if (attr.kind === "spread-attr") {
996
+ return [`Object.assign(_props, (${attr.code}) ?? {});`];
997
+ }
998
+ if (attr.kind === "event" || attr.name === "key" || attr.name === "dangerouslySetInnerHTML") {
999
+ return [];
1000
+ }
1001
+ const valueCode = attr.kind === "static-attr" ? stringLiteral(attr.value) : `(${attr.code})`;
1002
+ return [`_props[${stringLiteral(attr.name)}] = ${valueCode};`];
1003
+ });
1004
+ return `(() => { const _props = {}; ${statements.join(" ")} return ${currentSpreadAttributesHelperName}(${stringLiteral(tagName)}, _props); })()`;
1005
+ }
957
1006
  function scanElementAttributes(tagName, attrs) {
958
1007
  let hasExplicitInputValue = false;
959
1008
  let hasExplicitInputChecked = false;
@@ -1486,6 +1535,21 @@ function emitPropsObject(props, children = [], escapeHelperName = "_escapeHtml")
1486
1535
  }
1487
1536
  return `{ ${entries.join(", ")} }`;
1488
1537
  }
1538
+ function emitCompatRuntimePropsObject(props, children = []) {
1539
+ const entries = props.map((prop) => {
1540
+ if (prop.kind === "spread-prop") {
1541
+ return `...(${prop.code})`;
1542
+ }
1543
+ if (prop.kind === "render-prop") {
1544
+ return `${emitPropName(prop.name)}: ${emitOxcCompatObjectChildren(prop.children)}`;
1545
+ }
1546
+ return `${emitPropName(prop.name)}: (${prop.code})`;
1547
+ });
1548
+ if (children.length > 0) {
1549
+ entries.push(`children: ${emitOxcCompatObjectChildren(children)}`);
1550
+ }
1551
+ return `{ ${entries.join(", ")} }`;
1552
+ }
1489
1553
  function emitPropName(name) {
1490
1554
  return /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name);
1491
1555
  }