@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.
@@ -20,6 +20,7 @@ interface ClientReferenceAliasState {
20
20
  export function collectOxcClientBoundaryImportComponents(
21
21
  program: unknown,
22
22
  inferredBoundaryImports: ReadonlySet<string>,
23
+ fallbackBoundaryImports: ReadonlySet<string> = new Set(),
23
24
  ): Map<string, ClientReferenceIr> {
24
25
  const names = new Map<string, ClientReferenceIr>();
25
26
 
@@ -45,21 +46,21 @@ export function collectOxcClientBoundaryImportComponents(
45
46
  }
46
47
 
47
48
  if (specifierObject.type === "ImportDefaultSpecifier") {
48
- names.set(localName, { moduleId, exportName: "default" });
49
+ names.set(localName, clientReference(moduleId, "default", fallbackBoundaryImports));
49
50
  continue;
50
51
  }
51
52
 
52
53
  if (specifierObject.type === "ImportNamespaceSpecifier") {
53
- names.set(localName, { moduleId, exportName: "*" });
54
+ names.set(localName, clientReference(moduleId, "*", fallbackBoundaryImports));
54
55
  continue;
55
56
  }
56
57
 
57
58
  if (specifierObject.type === "ImportSpecifier" && specifierObject.importKind !== "type") {
58
59
  const imported = readObject(specifierObject.imported);
59
- names.set(localName, {
60
- moduleId,
61
- exportName: String(imported.name ?? localName),
62
- });
60
+ names.set(
61
+ localName,
62
+ clientReference(moduleId, String(imported.name ?? localName), fallbackBoundaryImports),
63
+ );
63
64
  }
64
65
  }
65
66
  }
@@ -68,6 +69,18 @@ export function collectOxcClientBoundaryImportComponents(
68
69
  return names;
69
70
  }
70
71
 
72
+ function clientReference(
73
+ moduleId: string,
74
+ exportName: string,
75
+ fallbackBoundaryImports: ReadonlySet<string>,
76
+ ): ClientReferenceIr {
77
+ return {
78
+ moduleId,
79
+ exportName,
80
+ ...(fallbackBoundaryImports.has(moduleId) ? { ssrFallback: true } : {}),
81
+ };
82
+ }
83
+
71
84
  export function collectOxcCompatRuntimeImportComponents(
72
85
  program: unknown,
73
86
  ): Map<string, ClientReferenceIr> {
@@ -207,7 +220,9 @@ function isOxcClientBoundaryImport(
207
220
  inferredBoundaryImports: ReadonlySet<string>,
208
221
  ): boolean {
209
222
  const moduleId = String(readObject(statement.source).value ?? "");
210
- return inferredBoundaryImports.has(moduleId) || /\.(?:client|compat)\.[cm]?[jt]sx?$/.test(moduleId);
223
+ return (
224
+ inferredBoundaryImports.has(moduleId) || /\.(?:client|compat)\.[cm]?[jt]sx?$/.test(moduleId)
225
+ );
211
226
  }
212
227
 
213
228
  function findOxcClientReference(
@@ -295,9 +310,7 @@ function collectOxcCompatReactNodeClassReferences(
295
310
  }
296
311
  }
297
312
 
298
- function readOxcClassComponentName(
299
- node: Record<string, unknown> | undefined,
300
- ): string | undefined {
313
+ function readOxcClassComponentName(node: Record<string, unknown> | undefined): string | undefined {
301
314
  if (node?.type === "ClassDeclaration" || node?.type === "ClassExpression") {
302
315
  const id = readOptionalObject(node.id);
303
316
  const name = typeof id?.name === "string" ? id.name : undefined;
@@ -451,7 +464,11 @@ function collectOxcObjectLiteralClientReferenceAliases(
451
464
  continue;
452
465
  }
453
466
 
454
- const keyName = propertyName(readOptionalObject(property.key), property.computed === true, state);
467
+ const keyName = propertyName(
468
+ readOptionalObject(property.key),
469
+ property.computed === true,
470
+ state,
471
+ );
455
472
  const value = readOptionalObject(property.value);
456
473
  if (keyName !== undefined) {
457
474
  addObjectMemberKey(state, objectName, keyName);
@@ -561,9 +578,12 @@ function expressionClientReference(
561
578
 
562
579
  if (node.type === "MemberExpression") {
563
580
  const objectName = expressionObjectName(readOptionalObject(node.object), state);
564
- const memberName = propertyName(readOptionalObject(node.property), node.computed === true, state);
565
- const objectReference =
566
- objectName === undefined ? undefined : state.references.get(objectName);
581
+ const memberName = propertyName(
582
+ readOptionalObject(node.property),
583
+ node.computed === true,
584
+ state,
585
+ );
586
+ const objectReference = objectName === undefined ? undefined : state.references.get(objectName);
567
587
 
568
588
  if (objectName !== undefined && memberName !== undefined) {
569
589
  const objectMember = state.objectMembers.get(objectName)?.get(memberName);
@@ -587,15 +607,19 @@ function expressionClientReference(
587
607
 
588
608
  if (objectName !== undefined && memberName === undefined) {
589
609
  return selectClientReference(
590
- [...objectMemberReferences(state, objectName), ...dynamicObjectMemberReferences(state, objectName)],
610
+ [
611
+ ...objectMemberReferences(state, objectName),
612
+ ...dynamicObjectMemberReferences(state, objectName),
613
+ ],
591
614
  state.allowAmbiguousAliases,
592
615
  );
593
616
  }
594
617
 
595
618
  if (objectName === undefined && memberName !== undefined) {
596
619
  const references = [
597
- ...expressionObjectNameCandidates(readOptionalObject(node.object), state)
598
- .map((candidate) => state.objectMembers.get(candidate)?.get(memberName)),
620
+ ...expressionObjectNameCandidates(readOptionalObject(node.object), state).map((candidate) =>
621
+ state.objectMembers.get(candidate)?.get(memberName),
622
+ ),
599
623
  ...expressionDynamicObjectNestedMemberReferences(
600
624
  readOptionalObject(node.object),
601
625
  memberName,
@@ -643,12 +667,17 @@ function objectEntryMemberReference(
643
667
  return undefined;
644
668
  }
645
669
 
646
- if (state.allowAmbiguousAliases && state.globModuleMaps.has(sourceName) && memberName === "default") {
670
+ if (
671
+ state.allowAmbiguousAliases &&
672
+ state.globModuleMaps.has(sourceName) &&
673
+ memberName === "default"
674
+ ) {
647
675
  return unknownCompatReference;
648
676
  }
649
677
 
650
- const references = Array.from(state.objectMemberKeys.get(sourceName) ?? [])
651
- .map((key) => state.objectMembers.get(`${sourceName}.${key}`)?.get(memberName));
678
+ const references = Array.from(state.objectMemberKeys.get(sourceName) ?? []).map((key) =>
679
+ state.objectMembers.get(`${sourceName}.${key}`)?.get(memberName),
680
+ );
652
681
  return selectClientReference(references, state.allowAmbiguousAliases);
653
682
  }
654
683
 
@@ -693,7 +722,11 @@ function expressionObjectName(
693
722
 
694
723
  if (node?.type === "MemberExpression") {
695
724
  const objectName = expressionObjectName(readOptionalObject(node.object), state);
696
- const memberName = propertyName(readOptionalObject(node.property), node.computed === true, state);
725
+ const memberName = propertyName(
726
+ readOptionalObject(node.property),
727
+ node.computed === true,
728
+ state,
729
+ );
697
730
 
698
731
  return objectName !== undefined && memberName !== undefined
699
732
  ? `${objectName}.${memberName}`
@@ -791,7 +824,11 @@ function collectDynamicObjectNestedMemberReferences(
791
824
  continue;
792
825
  }
793
826
 
794
- const keyName = propertyName(readOptionalObject(property.key), property.computed === true, state);
827
+ const keyName = propertyName(
828
+ readOptionalObject(property.key),
829
+ property.computed === true,
830
+ state,
831
+ );
795
832
  const reference = expressionClientReference(readOptionalObject(property.value), state);
796
833
  if (keyName !== undefined && reference !== undefined) {
797
834
  addDynamicObjectNestedMemberReference(state, objectName, keyName, reference);
@@ -805,7 +842,8 @@ function addDynamicObjectNestedMemberReference(
805
842
  memberName: string,
806
843
  reference: ClientReferenceIr,
807
844
  ): void {
808
- const members = state.dynamicObjectNestedMembers.get(objectName) ?? new Map<string, ClientReferenceIr[]>();
845
+ const members =
846
+ state.dynamicObjectNestedMembers.get(objectName) ?? new Map<string, ClientReferenceIr[]>();
809
847
  const references = members.get(memberName) ?? [];
810
848
  references.push(reference);
811
849
  members.set(memberName, references);
@@ -830,8 +868,12 @@ function isObjectAssignCall(node: Record<string, unknown>): boolean {
830
868
 
831
869
  const object = readOptionalObject(callee.object);
832
870
  const property = readOptionalObject(callee.property);
833
- return object?.type === "Identifier" && object.name === "Object" &&
834
- property?.type === "Identifier" && property.name === "assign";
871
+ return (
872
+ object?.type === "Identifier" &&
873
+ object.name === "Object" &&
874
+ property?.type === "Identifier" &&
875
+ property.name === "assign"
876
+ );
835
877
  }
836
878
 
837
879
  function isObjectEntriesCall(node: Record<string, unknown> | undefined): boolean {
@@ -842,8 +884,12 @@ function isObjectEntriesCall(node: Record<string, unknown> | undefined): boolean
842
884
 
843
885
  const object = readOptionalObject(callee.object);
844
886
  const property = readOptionalObject(callee.property);
845
- return object?.type === "Identifier" && object.name === "Object" &&
846
- property?.type === "Identifier" && property.name === "entries";
887
+ return (
888
+ object?.type === "Identifier" &&
889
+ object.name === "Object" &&
890
+ property?.type === "Identifier" &&
891
+ property.name === "entries"
892
+ );
847
893
  }
848
894
 
849
895
  function isImportMetaGlobEagerCall(node: Record<string, unknown> | undefined): boolean {
@@ -861,8 +907,13 @@ function isImportMetaGlobEagerCall(node: Record<string, unknown> | undefined): b
861
907
  const meta = readOptionalObject(metaProperty?.meta);
862
908
  const metaName = meta?.type === "Identifier" ? meta.name : undefined;
863
909
  const propertyName = readOptionalObject(metaProperty?.property);
864
- const importMetaPropertyName = propertyName?.type === "Identifier" ? propertyName.name : undefined;
865
- if (metaProperty?.type !== "MetaProperty" || metaName !== "import" || importMetaPropertyName !== "meta") {
910
+ const importMetaPropertyName =
911
+ propertyName?.type === "Identifier" ? propertyName.name : undefined;
912
+ if (
913
+ metaProperty?.type !== "MetaProperty" ||
914
+ metaName !== "import" ||
915
+ importMetaPropertyName !== "meta"
916
+ ) {
866
917
  return false;
867
918
  }
868
919
 
@@ -875,12 +926,14 @@ function isImportMetaGlobEagerCall(node: Record<string, unknown> | undefined): b
875
926
  const property = readOptionalObject(propertyValue);
876
927
  const key = readOptionalObject(property?.key);
877
928
  const value = readOptionalObject(property?.value);
878
- return property?.type === "Property" &&
929
+ return (
930
+ property?.type === "Property" &&
879
931
  property.computed !== true &&
880
932
  key?.type === "Identifier" &&
881
933
  key.name === "eager" &&
882
934
  value?.type === "Literal" &&
883
- value.value === true;
935
+ value.value === true
936
+ );
884
937
  });
885
938
  }
886
939
 
@@ -972,9 +1025,8 @@ function forOfObjectEntriesValueBindingName(
972
1025
  node?.type === "VariableDeclaration"
973
1026
  ? readOptionalObject(readArray(node.declarations)[0])
974
1027
  : undefined;
975
- const pattern = declaration?.type === "VariableDeclarator"
976
- ? readOptionalObject(declaration.id)
977
- : node;
1028
+ const pattern =
1029
+ declaration?.type === "VariableDeclarator" ? readOptionalObject(declaration.id) : node;
978
1030
 
979
1031
  if (pattern?.type !== "ArrayPattern") {
980
1032
  return undefined;
package/src/oxc.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import { parseSync } from "oxc-parser";
2
2
  import { unsupportedTopLevelJsxInitializerDiagnostic } from "./diagnostics.js";
3
- import {
4
- type AnalyzeToIrInput,
5
- type AnalyzeToIrOutput,
6
- } from "./internal.js";
3
+ import { type AnalyzeToIrInput, type AnalyzeToIrOutput } from "./internal.js";
7
4
  import {
8
5
  createCompilerModuleContextWithOxc,
9
6
  type CompilerModuleContext,
@@ -80,10 +77,7 @@ import {
80
77
  lowerOxcNestedJsxExpression,
81
78
  lowerOxcServerStringExpression,
82
79
  } from "./oxc-nested-lowering.js";
83
- import {
84
- isOxcJsxBranch,
85
- readOxcReturnExpressionFromStatement,
86
- } from "./oxc-expression-utils.js";
80
+ import { isOxcJsxBranch, readOxcReturnExpressionFromStatement } from "./oxc-expression-utils.js";
87
81
  import {
88
82
  collectOxcBodyJsxBindingNames,
89
83
  collectOxcReactiveDerivedFunctionNames,
@@ -183,13 +177,10 @@ export function analyzeOxcParity(input: AnalyzeToIrInput): OxcParityResult {
183
177
  }
184
178
 
185
179
  export function analyzeWithOxc(input: AnalyzeToIrInput): AnalyzeToIrOutput {
186
- return analyzeCompilerModuleContextWithOxc(
187
- createCompilerModuleContextWithOxc(input),
188
- {
189
- target: input.target,
190
- ...(input.options === undefined ? {} : { options: input.options }),
191
- },
192
- );
180
+ return analyzeCompilerModuleContextWithOxc(createCompilerModuleContextWithOxc(input), {
181
+ target: input.target,
182
+ ...(input.options === undefined ? {} : { options: input.options }),
183
+ });
193
184
  }
194
185
 
195
186
  export function analyzeCompilerModuleContextWithOxc(
@@ -239,6 +230,7 @@ function analyzeOxcToIr(
239
230
  const clientBoundaryImports = collectOxcClientBoundaryImportComponents(
240
231
  program,
241
232
  new Set(options?.clientBoundaryImports ?? []),
233
+ new Set(options?.clientBoundaryFallbackImports ?? []),
242
234
  );
243
235
  const compatRuntimeImports = collectOxcCompatRuntimeImportComponents(program);
244
236
  const compatReactNodeReferences =
@@ -376,7 +368,9 @@ function analyzeOxcToIr(
376
368
  }
377
369
 
378
370
  function isCssImportSource(source: unknown): boolean {
379
- return typeof source === "string" && /\.(?:css|pcss|postcss|scss|sass|less|styl|stylus)$/u.test(source);
371
+ return (
372
+ typeof source === "string" && /\.(?:css|pcss|postcss|scss|sass|less|styl|stylus)$/u.test(source)
373
+ );
380
374
  }
381
375
 
382
376
  function componentNamesFromProgram(
@@ -451,7 +445,9 @@ function collectLocalJsxHelperHtmlParameters(
451
445
  return parameters;
452
446
  }
453
447
 
454
- function collectOxcReturnExpressions(statement: Record<string, unknown>): Record<string, unknown>[] {
448
+ function collectOxcReturnExpressions(
449
+ statement: Record<string, unknown>,
450
+ ): Record<string, unknown>[] {
455
451
  if (statement.type === "ReturnStatement") {
456
452
  return [unwrapOxcParentheses(readObject(statement.argument))];
457
453
  }
@@ -745,18 +741,8 @@ function analyzeOxcFunctionLikeComponent(
745
741
  bodyLowerers,
746
742
  );
747
743
  const root =
748
- analyzeOxcEarlyIfRootReturn(
749
- code,
750
- earlyIfRootReturn,
751
- childAnalysisContext,
752
- bodyStatementJsx,
753
- ) ??
754
- analyzeOxcSwitchRootReturn(
755
- code,
756
- rootStatement,
757
- childAnalysisContext,
758
- bodyStatementJsx,
759
- ) ??
744
+ analyzeOxcEarlyIfRootReturn(code, earlyIfRootReturn, childAnalysisContext, bodyStatementJsx) ??
745
+ analyzeOxcSwitchRootReturn(code, rootStatement, childAnalysisContext, bodyStatementJsx) ??
760
746
  (isJsxRoot(returnExpression.type) || returnExpression.type === "JSXFragment"
761
747
  ? analyzeOxcJsxNode(code, returnExpression, childAnalysisContext)
762
748
  : isOxcComponentCallExpression(returnExpression)
@@ -778,30 +764,29 @@ function analyzeOxcFunctionLikeComponent(
778
764
  ),
779
765
  renderMode: "html" as const,
780
766
  }
781
- : analyzeOxcDynamicRootReturn(
782
- code,
783
- returnExpression,
784
- childAnalysisContext,
785
- bodyStatementJsx,
786
- ) ??
787
- {
788
- kind: "expr" as const,
789
- code: normalizeOxcExpressionCode(
790
- compatReactNodeReturn
791
- ? (lowerOxcCompatReactNodeExpression(
792
- code,
793
- returnExpression,
794
- componentNames,
795
- target,
796
- diagnostics,
797
- ) ??
798
- stripOxcGeneratedImports(
799
- transformJsxToCreateElementWithOxc(readSource(code, returnExpression)),
800
- ))
801
- : readSource(code, returnExpression),
802
- ),
803
- ...(compatReactNodeReturn ? { renderMode: "react-node" as const } : {}),
804
- });
767
+ : (analyzeOxcDynamicRootReturn(
768
+ code,
769
+ returnExpression,
770
+ childAnalysisContext,
771
+ bodyStatementJsx,
772
+ ) ?? {
773
+ kind: "expr" as const,
774
+ code: normalizeOxcExpressionCode(
775
+ compatReactNodeReturn
776
+ ? (lowerOxcCompatReactNodeExpression(
777
+ code,
778
+ returnExpression,
779
+ componentNames,
780
+ target,
781
+ diagnostics,
782
+ ) ??
783
+ stripOxcGeneratedImports(
784
+ transformJsxToCreateElementWithOxc(readSource(code, returnExpression)),
785
+ ))
786
+ : readSource(code, returnExpression),
787
+ ),
788
+ ...(compatReactNodeReturn ? { renderMode: "react-node" as const } : {}),
789
+ }));
805
790
  markOxcRenderValueExpressions(
806
791
  [root],
807
792
  new Set([
@@ -946,10 +931,7 @@ function isOxcRootReturnExpression(expression: Record<string, unknown>): boolean
946
931
  }
947
932
 
948
933
  function isOxcEmptyRootReturn(expression: Record<string, unknown>): boolean {
949
- return (
950
- expression.type === "Literal" &&
951
- (expression.value === null || expression.value === false)
952
- );
934
+ return expression.type === "Literal" && (expression.value === null || expression.value === false);
953
935
  }
954
936
 
955
937
  function isOxcRenderableRootReturn(expression: Record<string, unknown>): boolean {
@@ -966,10 +948,7 @@ function analyzeOxcDynamicRootReturnShape(expression: Record<string, unknown>):
966
948
  return true;
967
949
  }
968
950
 
969
- return (
970
- expression.type === "LogicalExpression" &&
971
- isOxcJsxBranch(readObject(expression.right))
972
- );
951
+ return expression.type === "LogicalExpression" && isOxcJsxBranch(readObject(expression.right));
973
952
  }
974
953
 
975
954
  function findOxcRootStatement(body: readonly unknown[]): unknown | undefined {
@@ -1091,12 +1070,7 @@ function analyzeOxcEarlyIfRootReturn(
1091
1070
  {
1092
1071
  kind: "conditional",
1093
1072
  conditionCode: readOxcReactiveRootConditionCode(code, branch.test, context),
1094
- whenTrue: analyzeOxcDynamicRootBranch(
1095
- code,
1096
- branch.consequent,
1097
- context,
1098
- bodyStatementJsx,
1099
- ),
1073
+ whenTrue: analyzeOxcDynamicRootBranch(code, branch.consequent, context, bodyStatementJsx),
1100
1074
  whenFalse: fallback,
1101
1075
  },
1102
1076
  ];
package/src/transform.ts CHANGED
@@ -28,9 +28,7 @@ export function transform(input: TransformInput): TransformOutput {
28
28
  export function transformCompilerModuleContext(
29
29
  input: TransformInput & { moduleContext: CompilerModuleContext },
30
30
  ): TransformOutput {
31
- if (
32
- (input.moduleContext.code !== input.code || input.moduleContext.filename !== input.filename)
33
- ) {
31
+ if (input.moduleContext.code !== input.code || input.moduleContext.filename !== input.filename) {
34
32
  throw new Error("Transform input moduleContext must match the input code and filename.");
35
33
  }
36
34
 
@@ -44,10 +42,7 @@ export function transformCompilerModuleContext(
44
42
 
45
43
  function transformWithAnalyzer(
46
44
  input: TransformInput,
47
- analyze: (
48
- target: AnalyzeToIrInput["target"],
49
- options: AnalyzeModuleOptions,
50
- ) => AnalyzeToIrOutput,
45
+ analyze: (target: AnalyzeToIrInput["target"], options: AnalyzeModuleOptions) => AnalyzeToIrOutput,
51
46
  ): TransformOutput {
52
47
  const mode = input.mode ?? "reactive";
53
48
  const serverOutput = input.serverOutput ?? "string";
@@ -71,6 +66,7 @@ function transformWithAnalyzer(
71
66
  awaitCompatComponents:
72
67
  input.target === "server" && serverOutput === "stream" ? "lower" : "diagnostic",
73
68
  clientBoundaryImports: input.clientBoundaryImports ?? [],
69
+ clientBoundaryFallbackImports: input.clientBoundaryFallbackImports ?? [],
74
70
  compatReactNodeReturn: mode === "compat",
75
71
  ...(mode === "compat" && input.target === "server"
76
72
  ? { compatReactNodeReturnRenderMode: "react-node" as const }
@@ -83,36 +79,30 @@ function transformWithAnalyzer(
83
79
  ? emitCompat(analyzed.ir, { dev: input.dev })
84
80
  : input.target === "server"
85
81
  ? serverOutput === "stream"
86
- ? emitServerStream(
87
- analyzed.ir,
88
- {
89
- ...createServerOptions(
90
- serverBootstrap,
91
- input.serverBootstrapNonce,
92
- input.serverBootstrapSrc,
93
- input.serverHydration,
94
- input.reactSuspenseRevealScriptSrc,
95
- ),
96
- ...(input.serverAwaitHydration === true
97
- ? { serverAwaitHydration: true as const }
98
- : {}),
99
- dynamicAttributes: mode === "compat" ? "drop" : "emit",
100
- escape: input.serverEscape,
101
- },
102
- )
103
- : emitServer(
104
- analyzed.ir,
105
- {
106
- ...createServerOptions(
107
- serverBootstrap,
108
- input.serverBootstrapNonce,
109
- input.serverBootstrapSrc,
110
- input.serverHydration,
111
- ),
112
- dynamicAttributes: mode === "compat" ? "drop" : "emit",
113
- escape: input.serverEscape,
114
- },
115
- )
82
+ ? emitServerStream(analyzed.ir, {
83
+ ...createServerOptions(
84
+ serverBootstrap,
85
+ input.serverBootstrapNonce,
86
+ input.serverBootstrapSrc,
87
+ input.serverHydration,
88
+ input.reactSuspenseRevealScriptSrc,
89
+ ),
90
+ ...(input.serverAwaitHydration === true
91
+ ? { serverAwaitHydration: true as const }
92
+ : {}),
93
+ dynamicAttributes: mode === "compat" ? "drop" : "emit",
94
+ escape: input.serverEscape,
95
+ })
96
+ : emitServer(analyzed.ir, {
97
+ ...createServerOptions(
98
+ serverBootstrap,
99
+ input.serverBootstrapNonce,
100
+ input.serverBootstrapSrc,
101
+ input.serverHydration,
102
+ ),
103
+ dynamicAttributes: mode === "compat" ? "drop" : "emit",
104
+ escape: input.serverEscape,
105
+ })
116
106
  : emitClient(analyzed.ir);
117
107
 
118
108
  const metadata: ModuleMetadata = {
@@ -321,8 +311,16 @@ function collectSourceMapSegments(
321
311
  const sourceLocation =
322
312
  bindPropAttribute === undefined
323
313
  ? undefined
324
- : (findSourceLocation(sourceLines, `${bindPropAttribute}={${dynamicExpression}}`, searchState) ??
325
- findSourceLocation(sourceLines, `${bindPropAttribute}="${dynamicExpression}"`, searchState));
314
+ : (findSourceLocation(
315
+ sourceLines,
316
+ `${bindPropAttribute}={${dynamicExpression}}`,
317
+ searchState,
318
+ ) ??
319
+ findSourceLocation(
320
+ sourceLines,
321
+ `${bindPropAttribute}="${dynamicExpression}"`,
322
+ searchState,
323
+ ));
326
324
  const fallbackSourceLocation =
327
325
  findSourceLocation(sourceLines, `{${dynamicExpression}}`, searchState) ??
328
326
  findJsxExpressionTokenLocation(sourceLines, dynamicExpression) ??
@@ -561,11 +559,14 @@ function collectClientReferenceManifestFromNode(
561
559
  references: Map<string, ClientReferenceMetadata>,
562
560
  ): void {
563
561
  if (node.kind === "component" && node.clientReference !== undefined) {
564
- references.set(`${node.name}:${node.clientReference.moduleId}:${node.clientReference.exportName}`, {
565
- name: node.name,
566
- moduleId: node.clientReference.moduleId,
567
- exportName: node.clientReference.exportName,
568
- });
562
+ references.set(
563
+ `${node.name}:${node.clientReference.moduleId}:${node.clientReference.exportName}`,
564
+ {
565
+ name: node.name,
566
+ moduleId: node.clientReference.moduleId,
567
+ exportName: node.clientReference.exportName,
568
+ },
569
+ );
569
570
  }
570
571
 
571
572
  for (const child of getNodeChildren(node)) {
@@ -583,11 +584,12 @@ function collectClientReferenceManifestFromNode(
583
584
  }
584
585
  }
585
586
 
586
- function collectClientReferencesFromNode(
587
- node: JsxNodeIr,
588
- references: Set<string>,
589
- ): void {
590
- if (node.kind === "component" && node.runtime === "compat" && node.clientReference !== undefined) {
587
+ function collectClientReferencesFromNode(node: JsxNodeIr, references: Set<string>): void {
588
+ if (
589
+ node.kind === "component" &&
590
+ node.runtime === "compat" &&
591
+ node.clientReference !== undefined
592
+ ) {
591
593
  references.add(node.name);
592
594
  }
593
595
 
package/src/types.ts CHANGED
@@ -29,6 +29,7 @@ export interface AnalyzeModuleOptions {
29
29
  serverOutput?: ServerOutputMode;
30
30
  awaitCompatComponents?: "diagnostic" | "lower";
31
31
  clientBoundaryImports?: readonly string[];
32
+ clientBoundaryFallbackImports?: readonly string[];
32
33
  compatReactNodeReturn?: boolean;
33
34
  compatReactNodeReturnRenderMode?: "react-node";
34
35
  }
@@ -48,6 +49,7 @@ export interface TransformInput {
48
49
  serverHydration?: boolean;
49
50
  serverAwaitHydration?: boolean;
50
51
  clientBoundaryImports?: readonly string[];
52
+ clientBoundaryFallbackImports?: readonly string[];
51
53
  serverEscape?: ServerEscapeOptions;
52
54
  reactSuspenseRevealScriptSrc?: string;
53
55
  }