@reckona/mreact-compiler 0.0.72 → 0.0.74

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/src/internal.ts CHANGED
@@ -76,6 +76,14 @@ export interface FormActionReference {
76
76
  start: number;
77
77
  }
78
78
 
79
+ export interface FormActionExpressionReference {
80
+ end: number;
81
+ expression: string;
82
+ expressionEnd: number;
83
+ expressionStart: number;
84
+ start: number;
85
+ }
86
+
79
87
  interface ComponentAliasState {
80
88
  aliases: Map<string, string>;
81
89
  stringConstants: Map<string, string>;
@@ -226,6 +234,21 @@ export function collectFormActionReferences(input: {
226
234
  );
227
235
  }
228
236
 
237
+ export function collectFormActionExpressionReferences(input: {
238
+ code: string;
239
+ filename?: string | undefined;
240
+ }): FormActionExpressionReference[] {
241
+ const parsed = parseModule(input.code, input.filename);
242
+ const references: FormActionExpressionReference[] = [];
243
+
244
+ collectFormActionExpressionReferencesFromNode(input.code, parsed.program, references);
245
+ return references.sort((left, right) =>
246
+ left.start === right.start
247
+ ? left.expression.localeCompare(right.expression)
248
+ : left.start - right.start,
249
+ );
250
+ }
251
+
229
252
  export function collectTopLevelValueExportNames(input: {
230
253
  code: string;
231
254
  filename?: string | undefined;
@@ -1708,6 +1731,78 @@ function collectFormActionReferencesFromNode(
1708
1731
  }
1709
1732
  }
1710
1733
 
1734
+ function collectFormActionExpressionReferencesFromNode(
1735
+ code: string,
1736
+ node: unknown,
1737
+ references: FormActionExpressionReference[],
1738
+ ): void {
1739
+ if (Array.isArray(node)) {
1740
+ for (const child of node) {
1741
+ collectFormActionExpressionReferencesFromNode(code, child, references);
1742
+ }
1743
+ return;
1744
+ }
1745
+
1746
+ const object = readOptionalObject(node);
1747
+ if (object === undefined) {
1748
+ return;
1749
+ }
1750
+
1751
+ if (typeof object.type === "string" && object.type.startsWith("TS")) {
1752
+ return;
1753
+ }
1754
+
1755
+ if (object.type === "ImportDeclaration") {
1756
+ return;
1757
+ }
1758
+
1759
+ if (
1760
+ object.type === "JSXOpeningElement" &&
1761
+ jsxTagName(readOptionalObject(object.name)) === "form"
1762
+ ) {
1763
+ const attributes = Array.isArray(object.attributes) ? object.attributes : [];
1764
+
1765
+ for (const attribute of attributes) {
1766
+ const attr = readObject(attribute);
1767
+
1768
+ if (attr.type !== "JSXAttribute" || readObject(attr.name).name !== "action") {
1769
+ continue;
1770
+ }
1771
+
1772
+ const value = readObject(attr.value);
1773
+ const expression = readObject(value.expression);
1774
+ const start = typeof object.start === "number" ? object.start : undefined;
1775
+ const end = typeof object.end === "number" ? object.end : undefined;
1776
+ const expressionStart = typeof expression.start === "number" ? expression.start : undefined;
1777
+ const expressionEnd = typeof expression.end === "number" ? expression.end : undefined;
1778
+
1779
+ if (
1780
+ value.type === "JSXExpressionContainer" &&
1781
+ start !== undefined &&
1782
+ end !== undefined &&
1783
+ expressionStart !== undefined &&
1784
+ expressionEnd !== undefined
1785
+ ) {
1786
+ references.push({
1787
+ end,
1788
+ expression: code.slice(expressionStart, expressionEnd).trim(),
1789
+ expressionEnd,
1790
+ expressionStart,
1791
+ start,
1792
+ });
1793
+ }
1794
+ }
1795
+ }
1796
+
1797
+ for (const [key, value] of Object.entries(object)) {
1798
+ if (key === "type" || key === "start" || key === "end" || key === "loc") {
1799
+ continue;
1800
+ }
1801
+
1802
+ collectFormActionExpressionReferencesFromNode(code, value, references);
1803
+ }
1804
+ }
1805
+
1711
1806
  function jsxTagName(node: Record<string, unknown> | undefined): string {
1712
1807
  if (node === undefined) {
1713
1808
  return "";
@@ -24,7 +24,6 @@ import {
24
24
  import { normalizeOxcExpressionCode, stripOxcGeneratedImports } from "./oxc-code-utils.js";
25
25
  import {
26
26
  findOxcKeyCodeInChildren,
27
- isOxcJsxBranch,
28
27
  readOxcReturnExpressionFromStatement,
29
28
  } from "./oxc-expression-utils.js";
30
29
  import {
@@ -389,7 +388,7 @@ export function analyzeOxcExpressionChild(
389
388
 
390
389
  if (
391
390
  unwrappedExpression.type === "LogicalExpression" &&
392
- isOxcJsxBranch(readObject(unwrappedExpression.right))
391
+ containsOxcJsxSyntax(readObject(unwrappedExpression.right))
393
392
  ) {
394
393
  const rightBranch = analyzeOxcDynamicBranch(
395
394
  code,
@@ -463,37 +462,44 @@ export function analyzeOxcExpressionChild(
463
462
  const sameModuleComponentCall =
464
463
  sameModuleComponentStreamCall !== undefined ||
465
464
  isOxcSameModuleComponentCallExpression(expression, componentCallNamesForRenderMode);
465
+ const containsNestedJsx = containsOxcJsxSyntax(unwrappedExpression);
466
+ const loweredNestedJsx = containsNestedJsx
467
+ ? context.lowerNestedJsxExpression(
468
+ code,
469
+ expression,
470
+ context.componentNames,
471
+ context.target,
472
+ context.diagnostics,
473
+ bodyStatementJsx,
474
+ )
475
+ : undefined;
476
+ const isKnownRenderValue = isOxcRenderValueExpression(expression) || sameModuleComponentCall;
477
+ const renderMode = sameModuleComponentStreamCall !== undefined
478
+ ? ("stream-node" as const)
479
+ : isKnownRenderValue
480
+ ? bodyStatementJsx === "server-string"
481
+ ? ("html" as const)
482
+ : ("dynamic" as const)
483
+ : loweredNestedJsx !== undefined && bodyStatementJsx === "server-string"
484
+ ? ("html" as const)
485
+ : loweredNestedJsx !== undefined && bodyStatementJsx === "dom-node"
486
+ ? ("dynamic" as const)
487
+ : undefined;
466
488
 
467
489
  return [
468
490
  {
469
491
  kind: "expr",
470
492
  code:
471
493
  sameModuleComponentStreamCall ??
472
- (containsOxcJsxSyntax(unwrappedExpression)
494
+ (containsNestedJsx
473
495
  ? normalizeOxcExpressionCode(
474
- context.lowerNestedJsxExpression(
475
- code,
476
- expression,
477
- context.componentNames,
478
- context.target,
479
- context.diagnostics,
480
- bodyStatementJsx,
481
- ) ??
496
+ loweredNestedJsx ??
482
497
  (bodyStatementJsx === "compat-object"
483
498
  ? stripOxcGeneratedImports(transformJsxWithOxc(readSource(code, expression)))
484
499
  : readOxcReactiveExpressionCode(code, expression, context)),
485
500
  )
486
501
  : readOxcReactiveExpressionCode(code, expression, context)),
487
- ...(isOxcRenderValueExpression(expression) || sameModuleComponentCall
488
- ? {
489
- renderMode:
490
- sameModuleComponentStreamCall !== undefined
491
- ? ("stream-node" as const)
492
- : bodyStatementJsx === "server-string"
493
- ? ("html" as const)
494
- : ("dynamic" as const),
495
- }
496
- : {}),
502
+ ...(renderMode === undefined ? {} : { renderMode }),
497
503
  },
498
504
  ];
499
505
  }
@@ -17,6 +17,28 @@ export function lowerOxcDomNodeExpression(
17
17
  }
18
18
  }
19
19
 
20
+ if (unwrapped.type === "LogicalExpression") {
21
+ const right = lowerOxcDomNodeExpression(code, readObject(unwrapped.right));
22
+
23
+ if (right !== undefined && unwrapped.operator === "&&") {
24
+ return `((${readSource(code, readObject(unwrapped.left))}) ? ${right} : false)`;
25
+ }
26
+
27
+ if (right !== undefined && unwrapped.operator === "||") {
28
+ const left = readSource(code, readObject(unwrapped.left));
29
+ return `((${left}) ? ${left} : ${right})`;
30
+ }
31
+ }
32
+
33
+ if (unwrapped.type === "ArrayExpression") {
34
+ return `[${readArray(unwrapped.elements).map((element) => {
35
+ const object = readObject(element);
36
+ return Object.keys(object).length === 0
37
+ ? "undefined"
38
+ : (lowerOxcDomNodeExpression(code, object) ?? readSource(code, object));
39
+ }).join(", ")}]`;
40
+ }
41
+
20
42
  if (unwrapped.type === "Literal" && (unwrapped.value === null || unwrapped.value === false)) {
21
43
  return 'document.createTextNode("")';
22
44
  }
@@ -561,7 +561,13 @@ function isJsxLikeInitializer(node: Record<string, unknown>): boolean {
561
561
  isJsxLikeInitializer(readObject(node.left)) || isJsxLikeInitializer(readObject(node.right))
562
562
  );
563
563
  }
564
- if (node.type === "ArrayExpression" || node.type === "ObjectExpression") {
564
+ if (node.type === "ArrayExpression") {
565
+ return readArray(node.elements).some((element) => {
566
+ const object = readObject(element);
567
+ return Object.keys(object).length > 0 && isJsxLikeInitializer(object);
568
+ });
569
+ }
570
+ if (node.type === "ObjectExpression") {
565
571
  return false;
566
572
  }
567
573
  return containsOxcJsxSyntax(node);