@reckona/mreact-compiler 0.0.67 → 0.0.69

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 (43) hide show
  1. package/dist/compiler-module-context.js.map +1 -1
  2. package/dist/diagnostics.js.map +1 -1
  3. package/dist/emit-client.js.map +1 -1
  4. package/dist/emit-compat.js.map +1 -1
  5. package/dist/emit-escape-helper.js.map +1 -1
  6. package/dist/emit-server-shared.js.map +1 -1
  7. package/dist/emit-server-stream.js.map +1 -1
  8. package/dist/emit-server.js.map +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/internal.js.map +1 -1
  11. package/dist/ir.js.map +1 -1
  12. package/dist/oxc-analysis-types.js.map +1 -1
  13. package/dist/oxc-await-analysis.js.map +1 -1
  14. package/dist/oxc-await-ids.js.map +1 -1
  15. package/dist/oxc-await-validation.js.map +1 -1
  16. package/dist/oxc-bindings.js.map +1 -1
  17. package/dist/oxc-body-lowering.js.map +1 -1
  18. package/dist/oxc-child-analysis.js.map +1 -1
  19. package/dist/oxc-code-utils.js.map +1 -1
  20. package/dist/oxc-component-detection.js.map +1 -1
  21. package/dist/oxc-component-props.js.map +1 -1
  22. package/dist/oxc-component-references.js.map +1 -1
  23. package/dist/oxc-dom-lowering.js.map +1 -1
  24. package/dist/oxc-expression-utils.js.map +1 -1
  25. package/dist/oxc-jsx-attributes.js.map +1 -1
  26. package/dist/oxc-jsx-text.js.map +1 -1
  27. package/dist/oxc-nested-lowering.js.map +1 -1
  28. package/dist/oxc-node-utils.js.map +1 -1
  29. package/dist/oxc-raw-jsx.js.map +1 -1
  30. package/dist/oxc-render-values.d.ts +2 -1
  31. package/dist/oxc-render-values.d.ts.map +1 -1
  32. package/dist/oxc-render-values.js +172 -3
  33. package/dist/oxc-render-values.js.map +1 -1
  34. package/dist/oxc-runtime-emit.js.map +1 -1
  35. package/dist/oxc-transform.js.map +1 -1
  36. package/dist/oxc.d.ts.map +1 -1
  37. package/dist/oxc.js +10 -9
  38. package/dist/oxc.js.map +1 -1
  39. package/dist/transform.js.map +1 -1
  40. package/dist/types.js.map +1 -1
  41. package/package.json +2 -2
  42. package/src/oxc-render-values.ts +261 -8
  43. package/src/oxc.ts +14 -1
@@ -51,6 +51,7 @@ export function collectOxcBodyJsxBindingNames(statements: readonly unknown[]): S
51
51
  export function collectOxcReactiveReadAliases(
52
52
  code: string,
53
53
  statements: readonly unknown[],
54
+ reactiveDerivedFunctions: ReadonlySet<string> = new Set(),
54
55
  ): Map<string, string> {
55
56
  const aliases = new Map<string, string>();
56
57
 
@@ -67,7 +68,12 @@ export function collectOxcReactiveReadAliases(
67
68
  const initializer = unwrapOxcParentheses(readObject(declaration.init));
68
69
 
69
70
  if (typeof id.name !== "string") continue;
70
- if (!isOxcReactiveAliasExpression(initializer)) continue;
71
+ if (
72
+ !isOxcReactiveAliasExpression(initializer) &&
73
+ !isOxcReactiveDerivedAliasExpression(initializer, reactiveDerivedFunctions)
74
+ ) {
75
+ continue;
76
+ }
71
77
 
72
78
  aliases.set(id.name, readSource(code, initializer));
73
79
  }
@@ -76,6 +82,45 @@ export function collectOxcReactiveReadAliases(
76
82
  return aliases;
77
83
  }
78
84
 
85
+ export function collectOxcReactiveDerivedFunctionNames(
86
+ statements: readonly unknown[],
87
+ ): Set<string> {
88
+ const names = new Set<string>();
89
+
90
+ for (const statementValue of statements) {
91
+ const statement = readObject(statementValue);
92
+
93
+ if (statement.type === "FunctionDeclaration") {
94
+ const id = readObject(statement.id);
95
+ if (typeof id.name === "string" && isOxcReactiveDerivedFunction(statement)) {
96
+ names.add(id.name);
97
+ }
98
+ continue;
99
+ }
100
+
101
+ if (statement.type !== "VariableDeclaration" || statement.kind !== "const") {
102
+ continue;
103
+ }
104
+
105
+ for (const declarationValue of readArray(statement.declarations)) {
106
+ const declaration = readObject(declarationValue);
107
+ const id = readObject(declaration.id);
108
+ const initializer = unwrapOxcParentheses(readObject(declaration.init));
109
+
110
+ if (
111
+ typeof id.name === "string" &&
112
+ (initializer.type === "FunctionExpression" ||
113
+ initializer.type === "ArrowFunctionExpression") &&
114
+ isOxcReactiveDerivedFunction(initializer)
115
+ ) {
116
+ names.add(id.name);
117
+ }
118
+ }
119
+ }
120
+
121
+ return names;
122
+ }
123
+
79
124
  export function rewriteOxcReactiveAliasExpressionCode(
80
125
  code: string,
81
126
  expression: Record<string, unknown>,
@@ -93,7 +138,14 @@ export function rewriteOxcReactiveAliasExpressionCode(
93
138
  }
94
139
 
95
140
  const replacements: ReactiveAliasReplacement[] = [];
96
- collectOxcReactiveAliasReplacements(expression, undefined, undefined, aliases, new Set(), replacements);
141
+ collectOxcReactiveAliasReplacements(
142
+ expression,
143
+ undefined,
144
+ undefined,
145
+ aliases,
146
+ new Set(),
147
+ replacements,
148
+ );
97
149
 
98
150
  if (replacements.length === 0) {
99
151
  return undefined;
@@ -147,7 +199,9 @@ function collectOxcReactiveAliasReplacements(
147
199
  replacements.push({
148
200
  end,
149
201
  start,
150
- text: isOxcShorthandPropertyValue(object, parent) ? `${object.name}: (${replacement})` : `(${replacement})`,
202
+ text: isOxcShorthandPropertyValue(object, parent)
203
+ ? `${object.name}: (${replacement})`
204
+ : `(${replacement})`,
151
205
  });
152
206
  }
153
207
  return;
@@ -194,7 +248,14 @@ function collectOxcReactiveAliasReplacements(
194
248
 
195
249
  if (Array.isArray(value)) {
196
250
  for (const item of value) {
197
- collectOxcReactiveAliasReplacements(item, object, key, aliases, childShadowed, replacements);
251
+ collectOxcReactiveAliasReplacements(
252
+ item,
253
+ object,
254
+ key,
255
+ aliases,
256
+ childShadowed,
257
+ replacements,
258
+ );
198
259
  }
199
260
  continue;
200
261
  }
@@ -285,10 +346,7 @@ function isOxcFunctionNode(node: Record<string, unknown>): boolean {
285
346
  );
286
347
  }
287
348
 
288
- function addOxcBlockBindingNames(
289
- node: unknown,
290
- shadowed: Set<string>,
291
- ): ReadonlySet<string> {
349
+ function addOxcBlockBindingNames(node: unknown, shadowed: Set<string>): ReadonlySet<string> {
292
350
  const object = readObject(node);
293
351
  const body = readArray(object.body);
294
352
 
@@ -350,6 +408,64 @@ function collectOxcBindingNames(node: unknown, names: Set<string>): void {
350
408
  }
351
409
  }
352
410
 
411
+ function collectOxcFunctionLocalBindings(
412
+ functionNode: Record<string, unknown>,
413
+ names: Set<string>,
414
+ ): void {
415
+ collectOxcBindingNames(functionNode.id, names);
416
+
417
+ for (const parameter of readArray(functionNode.params)) {
418
+ collectOxcBindingNames(parameter, names);
419
+ }
420
+
421
+ collectOxcLocalBindingsFromNode(readObject(functionNode.body), names);
422
+ }
423
+
424
+ function collectOxcLocalBindingsFromNode(node: unknown, names: Set<string>): void {
425
+ const object = readObject(node);
426
+
427
+ if (typeof object.type !== "string" || object.type.startsWith("TS")) {
428
+ return;
429
+ }
430
+
431
+ if (object.type === "VariableDeclaration") {
432
+ for (const declaration of readArray(object.declarations)) {
433
+ collectOxcBindingNames(readObject(declaration).id, names);
434
+ }
435
+ } else if (object.type === "FunctionDeclaration" || object.type === "ClassDeclaration") {
436
+ collectOxcBindingNames(object.id, names);
437
+ return;
438
+ } else if (object.type === "ForOfStatement" || object.type === "ForInStatement") {
439
+ const left = readObject(object.left);
440
+ const declarations = readArray(left.declarations);
441
+ collectOxcBindingNames(
442
+ declarations.length > 0 ? readObject(declarations[0]).id : object.left,
443
+ names,
444
+ );
445
+ } else if (object.type === "ForStatement") {
446
+ collectOxcLocalBindingsFromNode(object.init, names);
447
+ } else if (isOxcFunctionNode(object)) {
448
+ return;
449
+ }
450
+
451
+ for (const [key, value] of Object.entries(object)) {
452
+ if (key === "type" || key === "start" || key === "end" || key === "loc") {
453
+ continue;
454
+ }
455
+
456
+ if (Array.isArray(value)) {
457
+ for (const item of value) {
458
+ collectOxcLocalBindingsFromNode(item, names);
459
+ }
460
+ continue;
461
+ }
462
+
463
+ if (typeof value === "object" && value !== null) {
464
+ collectOxcLocalBindingsFromNode(value, names);
465
+ }
466
+ }
467
+ }
468
+
353
469
  function readNumber(value: unknown): number | undefined {
354
470
  return typeof value === "number" ? value : undefined;
355
471
  }
@@ -479,6 +595,143 @@ function isOxcReactiveAliasExpression(expression: Record<string, unknown>): bool
479
595
  return state.safe && state.reactive;
480
596
  }
481
597
 
598
+ function isOxcReactiveDerivedAliasExpression(
599
+ expression: Record<string, unknown>,
600
+ reactiveDerivedFunctions: ReadonlySet<string>,
601
+ ): boolean {
602
+ if (reactiveDerivedFunctions.size === 0) {
603
+ return false;
604
+ }
605
+
606
+ const unwrappedExpression = unwrapOxcParentheses(expression);
607
+
608
+ if (unwrappedExpression.type !== "CallExpression") {
609
+ return false;
610
+ }
611
+
612
+ if (readArray(unwrappedExpression.arguments).length !== 0) {
613
+ return false;
614
+ }
615
+
616
+ const callee = readObject(unwrappedExpression.callee);
617
+
618
+ return (
619
+ callee.type === "Identifier" &&
620
+ typeof callee.name === "string" &&
621
+ reactiveDerivedFunctions.has(callee.name)
622
+ );
623
+ }
624
+
625
+ function isOxcReactiveDerivedFunction(functionNode: Record<string, unknown>): boolean {
626
+ if (readArray(functionNode.params).length !== 0) {
627
+ return false;
628
+ }
629
+
630
+ const localBindings = new Set<string>();
631
+ collectOxcFunctionLocalBindings(functionNode, localBindings);
632
+ const usage = analyzeOxcReactiveDerivedFunctionUsage(
633
+ readObject(functionNode.body),
634
+ localBindings,
635
+ );
636
+
637
+ return usage.reactive && usage.safe;
638
+ }
639
+
640
+ function analyzeOxcReactiveDerivedFunctionUsage(
641
+ node: unknown,
642
+ localBindings: ReadonlySet<string>,
643
+ ): ReactiveAliasExpressionState {
644
+ const object = readObject(node);
645
+
646
+ if (typeof object.type !== "string" || object.type.startsWith("TS")) {
647
+ return { reactive: false, safe: true };
648
+ }
649
+
650
+ if (isOxcFunctionNode(object)) {
651
+ return { reactive: false, safe: true };
652
+ }
653
+
654
+ if (object.type === "CallExpression") {
655
+ const callee = readObject(object.callee);
656
+ const member = callee.type === "MemberExpression" ? callee : undefined;
657
+ const property = readObject(member?.property);
658
+ const owner = readObject(member?.object);
659
+ const propertyName =
660
+ member?.computed === true
661
+ ? undefined
662
+ : typeof property.name === "string"
663
+ ? property.name
664
+ : undefined;
665
+ const ownerName = owner.type === "Identifier" ? owner.name : undefined;
666
+
667
+ if (propertyName === "get" && typeof ownerName === "string" && !localBindings.has(ownerName)) {
668
+ return mergeReactiveAliasStates([
669
+ { reactive: true, safe: true },
670
+ ...readArray(object.arguments).map((argument) =>
671
+ analyzeOxcReactiveDerivedFunctionUsage(argument, localBindings),
672
+ ),
673
+ ]);
674
+ }
675
+
676
+ if (
677
+ propertyName !== undefined &&
678
+ typeof ownerName === "string" &&
679
+ !localBindings.has(ownerName) &&
680
+ isLikelyMutatingMethodName(propertyName)
681
+ ) {
682
+ return { reactive: false, safe: false };
683
+ }
684
+ }
685
+
686
+ const states: ReactiveAliasExpressionState[] = [];
687
+
688
+ for (const [key, value] of Object.entries(object)) {
689
+ if (key === "type" || key === "start" || key === "end" || key === "loc") {
690
+ continue;
691
+ }
692
+
693
+ if (Array.isArray(value)) {
694
+ states.push(
695
+ ...value.map((item) => analyzeOxcReactiveDerivedFunctionUsage(item, localBindings)),
696
+ );
697
+ continue;
698
+ }
699
+
700
+ if (typeof value === "object" && value !== null) {
701
+ states.push(analyzeOxcReactiveDerivedFunctionUsage(value, localBindings));
702
+ }
703
+ }
704
+
705
+ return mergeReactiveAliasStates(states);
706
+ }
707
+
708
+ function mergeReactiveAliasStates(
709
+ states: readonly ReactiveAliasExpressionState[],
710
+ ): ReactiveAliasExpressionState {
711
+ return states.reduce<ReactiveAliasExpressionState>(
712
+ (merged, state) => ({
713
+ reactive: merged.reactive || state.reactive,
714
+ safe: merged.safe && state.safe,
715
+ }),
716
+ { reactive: false, safe: true },
717
+ );
718
+ }
719
+
720
+ function isLikelyMutatingMethodName(name: string): boolean {
721
+ return (
722
+ name === "set" ||
723
+ name === "delete" ||
724
+ name === "clear" ||
725
+ name === "push" ||
726
+ name === "pop" ||
727
+ name === "shift" ||
728
+ name === "unshift" ||
729
+ name === "splice" ||
730
+ name === "sort" ||
731
+ name === "reverse"
732
+ );
733
+ }
734
+
482
735
  function analyzeOxcReactiveAliasExpression(
483
736
  expression: Record<string, unknown>,
484
737
  ): ReactiveAliasExpressionState {
package/src/oxc.ts CHANGED
@@ -81,6 +81,7 @@ import {
81
81
  } from "./oxc-expression-utils.js";
82
82
  import {
83
83
  collectOxcBodyJsxBindingNames,
84
+ collectOxcReactiveDerivedFunctionNames,
84
85
  collectOxcReactiveReadAliases,
85
86
  containsOxcJsxSyntax,
86
87
  markOxcRenderValueExpressions,
@@ -237,6 +238,7 @@ function analyzeOxcToIr(
237
238
  const compatRuntimeImports = collectOxcCompatRuntimeImportComponents(program);
238
239
  const bodyLowerers = createOxcBodyLowerers(compatRuntimeImports);
239
240
  const moduleRenderValueBindings = collectOxcBodyJsxBindingNames(body);
241
+ const reactiveDerivedFunctionNames = collectOxcReactiveDerivedFunctionNames(body);
240
242
 
241
243
  for (const statement of body) {
242
244
  const object = readObject(statement);
@@ -324,6 +326,7 @@ function analyzeOxcToIr(
324
326
  options?.serverOutput,
325
327
  componentCallNames,
326
328
  bodyLowerers,
329
+ reactiveDerivedFunctionNames,
327
330
  ),
328
331
  );
329
332
 
@@ -387,6 +390,7 @@ function analyzeOxcComponent(
387
390
  serverOutput: AnalyzeModuleOptions["serverOutput"],
388
391
  componentCallNames: Set<string> | undefined,
389
392
  bodyLowerers: OxcBodyLowerers,
393
+ reactiveDerivedFunctionNames: ReadonlySet<string>,
390
394
  ): ComponentIr[] {
391
395
  const object = readObject(statement);
392
396
 
@@ -414,6 +418,7 @@ function analyzeOxcComponent(
414
418
  serverOutput,
415
419
  componentCallNames,
416
420
  bodyLowerers,
421
+ reactiveDerivedFunctionNames,
417
422
  true,
418
423
  ),
419
424
  ];
@@ -442,6 +447,7 @@ function analyzeOxcComponent(
442
447
  serverOutput,
443
448
  componentCallNames,
444
449
  bodyLowerers,
450
+ reactiveDerivedFunctionNames,
445
451
  ),
446
452
  exported: false,
447
453
  },
@@ -472,6 +478,7 @@ function analyzeOxcComponent(
472
478
  serverOutput,
473
479
  componentCallNames,
474
480
  bodyLowerers,
481
+ reactiveDerivedFunctionNames,
475
482
  ),
476
483
  ];
477
484
  }
@@ -504,6 +511,7 @@ function analyzeOxcComponent(
504
511
  serverOutput,
505
512
  componentCallNames,
506
513
  bodyLowerers,
514
+ reactiveDerivedFunctionNames,
507
515
  ),
508
516
  ];
509
517
  }
@@ -522,6 +530,7 @@ function analyzeOxcFunctionLikeComponent(
522
530
  serverOutput: AnalyzeModuleOptions["serverOutput"],
523
531
  componentCallNames: Set<string> | undefined,
524
532
  bodyLowerers: OxcBodyLowerers,
533
+ reactiveDerivedFunctionNames: ReadonlySet<string>,
525
534
  exportDefault = false,
526
535
  ): ComponentIr {
527
536
  const functionBody = readObject(functionLike.body);
@@ -563,7 +572,11 @@ function analyzeOxcFunctionLikeComponent(
563
572
  ) ?? formatOxcBodyStatement(code, bodyStatement, bodyStatementJsx),
564
573
  );
565
574
  const componentBodyBindings = collectOxcVariableInitializers(body);
566
- const reactiveAliasBindings = collectOxcReactiveReadAliases(code, body);
575
+ const reactiveAliasBindings = collectOxcReactiveReadAliases(
576
+ code,
577
+ body,
578
+ reactiveDerivedFunctionNames,
579
+ );
567
580
  const childAnalysisContext = createOxcChildAnalysisContext(
568
581
  componentNames,
569
582
  target,