@reckona/mreact-compiler 0.0.97 → 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.
- package/dist/diagnostics.d.ts +1 -0
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +8 -0
- package/dist/diagnostics.js.map +1 -1
- package/dist/emit-client.js +14 -9
- package/dist/emit-client.js.map +1 -1
- package/dist/emit-compat.js +5 -1
- package/dist/emit-compat.js.map +1 -1
- package/dist/emit-server-stream.js +52 -3
- package/dist/emit-server-stream.js.map +1 -1
- package/dist/emit-server.js +51 -10
- 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-child-analysis.d.ts.map +1 -1
- package/dist/oxc-child-analysis.js +41 -7
- package/dist/oxc-child-analysis.js.map +1 -1
- package/dist/oxc-component-detection.d.ts +5 -2
- package/dist/oxc-component-detection.d.ts.map +1 -1
- package/dist/oxc-component-detection.js +80 -3
- package/dist/oxc-component-detection.js.map +1 -1
- package/dist/oxc-component-props.d.ts +1 -1
- package/dist/oxc-component-props.d.ts.map +1 -1
- package/dist/oxc-component-props.js +1 -1
- package/dist/oxc-component-props.js.map +1 -1
- package/dist/oxc-component-references.js +2 -2
- package/dist/oxc-component-references.js.map +1 -1
- package/dist/oxc-runtime-emit.d.ts.map +1 -1
- package/dist/oxc-runtime-emit.js +10 -2
- package/dist/oxc-runtime-emit.js.map +1 -1
- package/dist/oxc.d.ts.map +1 -1
- package/dist/oxc.js +109 -20
- package/dist/oxc.js.map +1 -1
- package/dist/transform.js +29 -11
- package/dist/transform.js.map +1 -1
- package/package.json +2 -2
- package/src/diagnostics.ts +10 -0
- package/src/emit-client.ts +20 -10
- package/src/emit-compat.ts +6 -1
- package/src/emit-server-stream.ts +67 -3
- package/src/emit-server.ts +64 -12
- package/src/ir.ts +1 -0
- package/src/oxc-child-analysis.ts +63 -18
- package/src/oxc-component-detection.ts +145 -2
- package/src/oxc-component-props.ts +2 -1
- package/src/oxc-component-references.ts +2 -2
- package/src/oxc-runtime-emit.ts +12 -2
- package/src/oxc.ts +167 -5
- package/src/transform.ts +42 -10
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
invalidJsxExpressionDiagnostic,
|
|
3
3
|
unserializableAwaitValueDiagnostic,
|
|
4
4
|
unsupportedComponentReferenceDiagnostic,
|
|
5
|
+
unsupportedJsxSpreadChildDiagnostic,
|
|
5
6
|
} from "./diagnostics.js";
|
|
6
7
|
import type { AsyncBoundaryIr, JsxElementIr, JsxNodeIr } from "./ir.js";
|
|
7
8
|
import type { OxcBodyStatementJsxMode } from "./oxc-analysis-types.js";
|
|
@@ -135,7 +136,14 @@ export function analyzeOxcJsxNode(
|
|
|
135
136
|
const analyzeJsxNode = (
|
|
136
137
|
child: Record<string, unknown>,
|
|
137
138
|
childBodyStatementJsx: OxcBodyStatementJsxMode = bodyStatementJsx,
|
|
138
|
-
|
|
139
|
+
shadowNames: readonly string[] = [],
|
|
140
|
+
) =>
|
|
141
|
+
analyzeOxcJsxNode(
|
|
142
|
+
code,
|
|
143
|
+
child,
|
|
144
|
+
shadowOxcReactiveAliases(context, shadowNames),
|
|
145
|
+
childBodyStatementJsx,
|
|
146
|
+
);
|
|
139
147
|
const consumerRenderProp = tagName.endsWith(".Consumer")
|
|
140
148
|
? readOxcConsumerRenderProp(
|
|
141
149
|
code,
|
|
@@ -344,6 +352,11 @@ export function analyzeOxcChildren(
|
|
|
344
352
|
);
|
|
345
353
|
}
|
|
346
354
|
|
|
355
|
+
if (object.type === "JSXSpreadChild") {
|
|
356
|
+
context.diagnostics.push(unsupportedJsxSpreadChildDiagnostic(getOxcLocation(code, object)));
|
|
357
|
+
return [];
|
|
358
|
+
}
|
|
359
|
+
|
|
347
360
|
return [];
|
|
348
361
|
});
|
|
349
362
|
}
|
|
@@ -401,17 +414,22 @@ export function analyzeOxcExpressionChild(
|
|
|
401
414
|
bodyStatementJsx,
|
|
402
415
|
);
|
|
403
416
|
|
|
417
|
+
const leftExpression = readObject(unwrappedExpression.left);
|
|
418
|
+
const conditionValueName = logicalConditionValueName(leftExpression);
|
|
419
|
+
|
|
404
420
|
if (unwrappedExpression.operator === "&&") {
|
|
405
421
|
return [
|
|
406
422
|
{
|
|
407
423
|
kind: "conditional",
|
|
408
|
-
conditionCode: readOxcReactiveExpressionCode(
|
|
409
|
-
|
|
410
|
-
readObject(unwrappedExpression.left),
|
|
411
|
-
context,
|
|
412
|
-
),
|
|
424
|
+
conditionCode: readOxcReactiveExpressionCode(code, leftExpression, context),
|
|
425
|
+
conditionValueName,
|
|
413
426
|
whenTrue: rightBranch,
|
|
414
|
-
whenFalse: [
|
|
427
|
+
whenFalse: [
|
|
428
|
+
{
|
|
429
|
+
kind: "expr",
|
|
430
|
+
code: renderableFalsyConditionValueCode(conditionValueName),
|
|
431
|
+
},
|
|
432
|
+
],
|
|
415
433
|
},
|
|
416
434
|
];
|
|
417
435
|
}
|
|
@@ -420,19 +438,12 @@ export function analyzeOxcExpressionChild(
|
|
|
420
438
|
return [
|
|
421
439
|
{
|
|
422
440
|
kind: "conditional",
|
|
423
|
-
conditionCode: readOxcReactiveExpressionCode(
|
|
424
|
-
|
|
425
|
-
readObject(unwrappedExpression.left),
|
|
426
|
-
context,
|
|
427
|
-
),
|
|
441
|
+
conditionCode: readOxcReactiveExpressionCode(code, leftExpression, context),
|
|
442
|
+
conditionValueName,
|
|
428
443
|
whenTrue: [
|
|
429
444
|
{
|
|
430
445
|
kind: "expr",
|
|
431
|
-
code:
|
|
432
|
-
code,
|
|
433
|
-
readObject(unwrappedExpression.left),
|
|
434
|
-
context,
|
|
435
|
-
),
|
|
446
|
+
code: conditionValueName,
|
|
436
447
|
},
|
|
437
448
|
],
|
|
438
449
|
whenFalse: rightBranch,
|
|
@@ -613,7 +624,11 @@ function analyzeOxcListExpression(
|
|
|
613
624
|
const itemName = String(readObject(readArray(renderer.params)[0]).name ?? "_item");
|
|
614
625
|
const indexName = readObject(readArray(renderer.params)[1]).name;
|
|
615
626
|
const arrayName = readObject(readArray(renderer.params)[2]).name;
|
|
616
|
-
const
|
|
627
|
+
const rendererContext = shadowOxcReactiveAliases(
|
|
628
|
+
context,
|
|
629
|
+
[itemName, indexName, arrayName].filter((name): name is string => typeof name === "string"),
|
|
630
|
+
);
|
|
631
|
+
const rendererBody = analyzeOxcListRenderer(code, renderer, rendererContext, bodyStatementJsx);
|
|
617
632
|
|
|
618
633
|
if (rendererBody === undefined) {
|
|
619
634
|
return undefined;
|
|
@@ -802,6 +817,36 @@ function resolveOxcBodyStatementJsx(context: OxcChildAnalysisContext): OxcBodySt
|
|
|
802
817
|
return context.bodyStatementJsx ?? (context.target === "server" ? "server-string" : "dom-node");
|
|
803
818
|
}
|
|
804
819
|
|
|
820
|
+
function logicalConditionValueName(expression: Record<string, unknown>): string {
|
|
821
|
+
return `__mreactLogical_${typeof expression.start === "number" ? expression.start : "value"}`;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
function renderableFalsyConditionValueCode(name: string): string {
|
|
825
|
+
return `((typeof ${name} === "number" || typeof ${name} === "bigint") ? ${name} : null)`;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
function shadowOxcReactiveAliases(
|
|
829
|
+
context: OxcChildAnalysisContext,
|
|
830
|
+
names: readonly string[],
|
|
831
|
+
): OxcChildAnalysisContext {
|
|
832
|
+
if (context.reactiveAliasBindings === undefined || names.length === 0) {
|
|
833
|
+
return context;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
let aliases: Map<string, string> | undefined;
|
|
837
|
+
|
|
838
|
+
for (const name of names) {
|
|
839
|
+
if (!context.reactiveAliasBindings.has(name)) {
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
aliases ??= new Map(context.reactiveAliasBindings);
|
|
844
|
+
aliases.delete(name);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
return aliases === undefined ? context : { ...context, reactiveAliasBindings: aliases };
|
|
848
|
+
}
|
|
849
|
+
|
|
805
850
|
function isOxcJsxCommentExpression(code: string, expression: Record<string, unknown>): boolean {
|
|
806
851
|
if (typeof expression.start !== "number" || typeof expression.end !== "number") {
|
|
807
852
|
return false;
|
|
@@ -34,6 +34,44 @@ export function collectOxcPlainComponentNames(program: unknown): string[] {
|
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
export function collectOxcLocalJsxReturnFunctionNames(program: unknown): Set<string> {
|
|
38
|
+
const names = new Set<string>();
|
|
39
|
+
|
|
40
|
+
for (const statement of readArray(readObject(program).body)) {
|
|
41
|
+
const object = readObject(statement);
|
|
42
|
+
|
|
43
|
+
if (object.type === "FunctionDeclaration" && hasOxcFunctionLikeJsxReturn(object)) {
|
|
44
|
+
const id = readObject(object.id);
|
|
45
|
+
if (typeof id.name === "string") {
|
|
46
|
+
names.add(id.name);
|
|
47
|
+
}
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (object.type !== "VariableDeclaration") {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (const declarator of readArray(object.declarations)) {
|
|
56
|
+
const declaratorObject = readObject(declarator);
|
|
57
|
+
const id = readObject(declaratorObject.id);
|
|
58
|
+
const initializer = unwrapOxcComponentFunctionLikeInitializer(
|
|
59
|
+
readObject(declaratorObject.init),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
typeof id.name === "string" &&
|
|
64
|
+
initializer !== undefined &&
|
|
65
|
+
hasOxcFunctionLikeJsxReturn(initializer)
|
|
66
|
+
) {
|
|
67
|
+
names.add(id.name);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return names;
|
|
73
|
+
}
|
|
74
|
+
|
|
37
75
|
export function collectOxcExportedComponents(program: unknown): string[] {
|
|
38
76
|
const body = readArray(readObject(program).body);
|
|
39
77
|
const components: string[] = [];
|
|
@@ -133,8 +171,15 @@ export function isOxcExportedJsxComponent(statement: unknown): boolean {
|
|
|
133
171
|
);
|
|
134
172
|
}
|
|
135
173
|
|
|
136
|
-
export function isOxcJsxComponentStatement(
|
|
137
|
-
|
|
174
|
+
export function isOxcJsxComponentStatement(
|
|
175
|
+
statement: unknown,
|
|
176
|
+
localJsxReturnFunctionNames: ReadonlySet<string> = new Set(),
|
|
177
|
+
): boolean {
|
|
178
|
+
return (
|
|
179
|
+
isOxcExportedJsxComponent(statement) ||
|
|
180
|
+
isOxcExportedFunctionReturningLocalJsxHelper(statement, localJsxReturnFunctionNames) ||
|
|
181
|
+
readOxcPlainComponent(statement) !== undefined
|
|
182
|
+
);
|
|
138
183
|
}
|
|
139
184
|
|
|
140
185
|
export function isOxcExportedFunctionLike(statement: unknown): boolean {
|
|
@@ -159,6 +204,7 @@ export function isOxcExportedFunctionLike(statement: unknown): boolean {
|
|
|
159
204
|
export function isOxcUnsupportedExportedFunction(
|
|
160
205
|
statement: unknown,
|
|
161
206
|
options?: AnalyzeModuleOptions,
|
|
207
|
+
localJsxReturnFunctionNames: ReadonlySet<string> = new Set(),
|
|
162
208
|
): boolean {
|
|
163
209
|
if (options?.compatReactNodeReturn === true) {
|
|
164
210
|
return false;
|
|
@@ -178,10 +224,29 @@ export function isOxcUnsupportedExportedFunction(
|
|
|
178
224
|
typeof id.name === "string" &&
|
|
179
225
|
/^[A-Z]/.test(id.name) &&
|
|
180
226
|
!hasComponentReturn(declaration.body) &&
|
|
227
|
+
!hasLocalJsxHelperCallReturn(declaration.body, localJsxReturnFunctionNames) &&
|
|
181
228
|
!hasOnlyNullReturns(declaration.body)
|
|
182
229
|
);
|
|
183
230
|
}
|
|
184
231
|
|
|
232
|
+
function isOxcExportedFunctionReturningLocalJsxHelper(
|
|
233
|
+
statement: unknown,
|
|
234
|
+
localJsxReturnFunctionNames: ReadonlySet<string>,
|
|
235
|
+
): boolean {
|
|
236
|
+
const object = readObject(statement);
|
|
237
|
+
|
|
238
|
+
if (object.type !== "ExportNamedDeclaration") {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const declaration = readObject(object.declaration);
|
|
243
|
+
|
|
244
|
+
return (
|
|
245
|
+
declaration.type === "FunctionDeclaration" &&
|
|
246
|
+
hasLocalJsxHelperCallReturn(declaration.body, localJsxReturnFunctionNames)
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
185
250
|
export function readOxcVariableComponentDeclaration(
|
|
186
251
|
declaration: Record<string, unknown>,
|
|
187
252
|
): { name: string; initializer: Record<string, unknown> } | undefined {
|
|
@@ -305,6 +370,45 @@ export function hasComponentCallReturn(body: unknown): boolean {
|
|
|
305
370
|
});
|
|
306
371
|
}
|
|
307
372
|
|
|
373
|
+
export function hasLocalJsxHelperCallReturn(
|
|
374
|
+
body: unknown,
|
|
375
|
+
localJsxReturnFunctionNames: ReadonlySet<string>,
|
|
376
|
+
): boolean {
|
|
377
|
+
if (localJsxReturnFunctionNames.size === 0) {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return readArray(readObject(body).body).some((statement) => {
|
|
382
|
+
const object = readObject(statement);
|
|
383
|
+
|
|
384
|
+
if (object.type === "ReturnStatement") {
|
|
385
|
+
return isOxcLocalJsxHelperCallExpression(
|
|
386
|
+
unwrapOxcParentheses(readObject(object.argument)),
|
|
387
|
+
localJsxReturnFunctionNames,
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return hasNestedLocalJsxHelperCallReturn(object, localJsxReturnFunctionNames);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export function isOxcLocalJsxHelperCallExpression(
|
|
396
|
+
expression: Record<string, unknown>,
|
|
397
|
+
localJsxReturnFunctionNames: ReadonlySet<string>,
|
|
398
|
+
): boolean {
|
|
399
|
+
if (expression.type !== "CallExpression") {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const callee = unwrapOxcParentheses(readObject(expression.callee));
|
|
404
|
+
|
|
405
|
+
return (
|
|
406
|
+
callee.type === "Identifier" &&
|
|
407
|
+
typeof callee.name === "string" &&
|
|
408
|
+
localJsxReturnFunctionNames.has(callee.name)
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
308
412
|
function hasNestedJsxReturn(statement: Record<string, unknown>): boolean {
|
|
309
413
|
if (statement.type === "SwitchStatement") {
|
|
310
414
|
return readArray(statement.cases).some((switchCase) =>
|
|
@@ -359,6 +463,45 @@ function hasNestedComponentCallReturn(statement: Record<string, unknown>): boole
|
|
|
359
463
|
return false;
|
|
360
464
|
}
|
|
361
465
|
|
|
466
|
+
function hasNestedLocalJsxHelperCallReturn(
|
|
467
|
+
statement: Record<string, unknown>,
|
|
468
|
+
localJsxReturnFunctionNames: ReadonlySet<string>,
|
|
469
|
+
): boolean {
|
|
470
|
+
if (statement.type === "SwitchStatement") {
|
|
471
|
+
return readArray(statement.cases).some((switchCase) =>
|
|
472
|
+
readArray(readObject(switchCase).consequent).some((child) => {
|
|
473
|
+
const object = readObject(child);
|
|
474
|
+
return (
|
|
475
|
+
object.type === "ReturnStatement" &&
|
|
476
|
+
isOxcLocalJsxHelperCallExpression(
|
|
477
|
+
unwrapOxcParentheses(readObject(object.argument)),
|
|
478
|
+
localJsxReturnFunctionNames,
|
|
479
|
+
)
|
|
480
|
+
);
|
|
481
|
+
}),
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (statement.type === "IfStatement") {
|
|
486
|
+
return (
|
|
487
|
+
hasLocalJsxHelperCallReturn(
|
|
488
|
+
{ body: [statement.consequent] },
|
|
489
|
+
localJsxReturnFunctionNames,
|
|
490
|
+
) ||
|
|
491
|
+
hasLocalJsxHelperCallReturn(
|
|
492
|
+
{ body: [statement.alternate] },
|
|
493
|
+
localJsxReturnFunctionNames,
|
|
494
|
+
)
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (statement.type === "BlockStatement") {
|
|
499
|
+
return hasLocalJsxHelperCallReturn(statement, localJsxReturnFunctionNames);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
|
|
362
505
|
function collectReturnArguments(statement: Record<string, unknown>): Record<string, unknown>[] {
|
|
363
506
|
if (statement.type === "ReturnStatement") {
|
|
364
507
|
return [readObject(statement.argument)];
|
|
@@ -16,6 +16,7 @@ import type { Diagnostic } from "./types.js";
|
|
|
16
16
|
export type AnalyzeOxcJsxNodeCallback = (
|
|
17
17
|
node: Record<string, unknown>,
|
|
18
18
|
bodyStatementJsx?: OxcBodyStatementJsxMode,
|
|
19
|
+
shadowNames?: readonly string[],
|
|
19
20
|
) => JsxNodeIr;
|
|
20
21
|
|
|
21
22
|
export function analyzeOxcComponentProp(
|
|
@@ -159,7 +160,7 @@ export function analyzeOxcArrowJsxRenderer(
|
|
|
159
160
|
if (body.type === "JSXElement" || body.type === "JSXFragment") {
|
|
160
161
|
return {
|
|
161
162
|
valueName,
|
|
162
|
-
children: [analyzeJsxNode(body, bodyStatementJsx)],
|
|
163
|
+
children: [analyzeJsxNode(body, bodyStatementJsx, [valueName])],
|
|
163
164
|
};
|
|
164
165
|
}
|
|
165
166
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ClientReferenceIr, JsxNodeIr } from "./ir.js";
|
|
2
2
|
import { readArray, readObject } from "./oxc-node-utils.js";
|
|
3
3
|
|
|
4
|
-
const routerEntryCompatRuntimeExports = new Set(
|
|
5
|
-
const routerLinkCompatRuntimeExports = new Set(
|
|
4
|
+
const routerEntryCompatRuntimeExports = new Set<string>();
|
|
5
|
+
const routerLinkCompatRuntimeExports = new Set<string>();
|
|
6
6
|
const unknownCompatReference: ClientReferenceIr = { moduleId: "", exportName: "default" };
|
|
7
7
|
|
|
8
8
|
interface ClientReferenceAliasState {
|
package/src/oxc-runtime-emit.ts
CHANGED
|
@@ -22,7 +22,12 @@ function emitOxcServerStringNode(node: JsxNodeIr): string {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
if (node.kind === "conditional") {
|
|
25
|
-
|
|
25
|
+
const whenTrue = emitOxcServerStringChildren(node.whenTrue);
|
|
26
|
+
const whenFalse = emitOxcServerStringChildren(node.whenFalse);
|
|
27
|
+
|
|
28
|
+
return node.conditionValueName === undefined
|
|
29
|
+
? `((${node.conditionCode}) ? ${whenTrue} : ${whenFalse})`
|
|
30
|
+
: `(() => { const ${node.conditionValueName} = (${node.conditionCode}); return ${node.conditionValueName} ? ${whenTrue} : ${whenFalse}; })()`;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
if (node.kind === "list") {
|
|
@@ -99,7 +104,12 @@ function emitOxcCompatObjectNode(node: JsxNodeIr): string {
|
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
if (node.kind === "conditional") {
|
|
102
|
-
|
|
107
|
+
const whenTrue = emitOxcCompatObjectChildren(node.whenTrue);
|
|
108
|
+
const whenFalse = emitOxcCompatObjectChildren(node.whenFalse);
|
|
109
|
+
|
|
110
|
+
return node.conditionValueName === undefined
|
|
111
|
+
? `(${node.conditionCode}) ? ${whenTrue} : ${whenFalse}`
|
|
112
|
+
: `(() => { const ${node.conditionValueName} = (${node.conditionCode}); return ${node.conditionValueName} ? ${whenTrue} : ${whenFalse}; })()`;
|
|
103
113
|
}
|
|
104
114
|
|
|
105
115
|
if (node.kind === "list") {
|
package/src/oxc.ts
CHANGED
|
@@ -43,11 +43,14 @@ import {
|
|
|
43
43
|
collectOxcAsyncComponentNames,
|
|
44
44
|
collectOxcExportedComponents,
|
|
45
45
|
collectOxcExportedFunctionNames,
|
|
46
|
+
collectOxcLocalJsxReturnFunctionNames,
|
|
46
47
|
collectOxcPlainComponentNames,
|
|
47
48
|
hasComponentReturn,
|
|
49
|
+
hasLocalJsxHelperCallReturn,
|
|
48
50
|
hasOxcFunctionLikeComponentReturn,
|
|
49
51
|
isOxcExportedFunctionLike,
|
|
50
52
|
isOxcComponentCallExpression,
|
|
53
|
+
isOxcLocalJsxHelperCallExpression,
|
|
51
54
|
isJsxRoot,
|
|
52
55
|
isOxcJsxComponentStatement,
|
|
53
56
|
isOxcUnsupportedExportedFunction,
|
|
@@ -242,6 +245,12 @@ function analyzeOxcToIr(
|
|
|
242
245
|
options?.compatReactNodeReturnRenderMode === "react-node"
|
|
243
246
|
? collectOxcCompatReactNodeComponentReferences(program)
|
|
244
247
|
: undefined;
|
|
248
|
+
const localJsxReturnFunctionNames =
|
|
249
|
+
target === "server" ? collectOxcLocalJsxReturnFunctionNames(program) : new Set<string>();
|
|
250
|
+
const localJsxHelperHtmlParameters =
|
|
251
|
+
target === "server"
|
|
252
|
+
? collectLocalJsxHelperHtmlParameters(program, localJsxReturnFunctionNames)
|
|
253
|
+
: new Map<string, Set<number>>();
|
|
245
254
|
const bodyLowerers = createOxcBodyLowerers(compatRuntimeImports);
|
|
246
255
|
const moduleRenderValueBindings = collectOxcBodyJsxBindingNames(body);
|
|
247
256
|
const reactiveDerivedFunctionNames = collectOxcReactiveDerivedFunctionNames(body);
|
|
@@ -263,7 +272,7 @@ function analyzeOxcToIr(
|
|
|
263
272
|
}
|
|
264
273
|
|
|
265
274
|
if (
|
|
266
|
-
isOxcJsxComponentStatement(statement) ||
|
|
275
|
+
isOxcJsxComponentStatement(statement, localJsxReturnFunctionNames) ||
|
|
267
276
|
(options?.compatReactNodeReturn === true && isOxcExportedFunctionLike(statement))
|
|
268
277
|
) {
|
|
269
278
|
const declaration = readObject(readObject(statement).declaration);
|
|
@@ -275,7 +284,7 @@ function analyzeOxcToIr(
|
|
|
275
284
|
}
|
|
276
285
|
continue;
|
|
277
286
|
} else {
|
|
278
|
-
if (isOxcUnsupportedExportedFunction(statement, options)) {
|
|
287
|
+
if (isOxcUnsupportedExportedFunction(statement, options, localJsxReturnFunctionNames)) {
|
|
279
288
|
diagnostics.push({
|
|
280
289
|
level: "error",
|
|
281
290
|
code: "MR_UNSUPPORTED_COMPONENT_RETURN",
|
|
@@ -333,6 +342,8 @@ function analyzeOxcToIr(
|
|
|
333
342
|
componentCallNames,
|
|
334
343
|
bodyLowerers,
|
|
335
344
|
reactiveDerivedFunctionNames,
|
|
345
|
+
localJsxReturnFunctionNames,
|
|
346
|
+
localJsxHelperHtmlParameters,
|
|
336
347
|
),
|
|
337
348
|
);
|
|
338
349
|
|
|
@@ -387,6 +398,88 @@ function componentCallNamesFromProgram(program: unknown): Set<string> {
|
|
|
387
398
|
]);
|
|
388
399
|
}
|
|
389
400
|
|
|
401
|
+
function collectLocalJsxHelperHtmlParameters(
|
|
402
|
+
program: unknown,
|
|
403
|
+
localJsxReturnFunctionNames: ReadonlySet<string>,
|
|
404
|
+
): Map<string, Set<number>> {
|
|
405
|
+
const parameters = new Map<string, Set<number>>();
|
|
406
|
+
|
|
407
|
+
if (localJsxReturnFunctionNames.size === 0) {
|
|
408
|
+
return parameters;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
for (const statement of readArray(readObject(program).body)) {
|
|
412
|
+
const object = readObject(statement);
|
|
413
|
+
const declaration =
|
|
414
|
+
object.type === "ExportNamedDeclaration" || object.type === "ExportDefaultDeclaration"
|
|
415
|
+
? readObject(object.declaration)
|
|
416
|
+
: object;
|
|
417
|
+
const body = readObject(declaration.body);
|
|
418
|
+
|
|
419
|
+
if (body.type !== "BlockStatement") {
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
for (const returnExpression of collectOxcReturnExpressions(body)) {
|
|
424
|
+
const callExpression = unwrapOxcParentheses(returnExpression);
|
|
425
|
+
if (callExpression.type !== "CallExpression") {
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const callee = unwrapOxcParentheses(readObject(callExpression.callee));
|
|
430
|
+
if (
|
|
431
|
+
callee.type !== "Identifier" ||
|
|
432
|
+
typeof callee.name !== "string" ||
|
|
433
|
+
!localJsxReturnFunctionNames.has(callee.name)
|
|
434
|
+
) {
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
const calleeName = callee.name;
|
|
438
|
+
|
|
439
|
+
readArray(callExpression.arguments).forEach((argument, index) => {
|
|
440
|
+
if (!containsOxcJsxSyntax(readObject(argument))) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const indexes = parameters.get(calleeName) ?? new Set<number>();
|
|
445
|
+
indexes.add(index);
|
|
446
|
+
parameters.set(calleeName, indexes);
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return parameters;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function collectOxcReturnExpressions(statement: Record<string, unknown>): Record<string, unknown>[] {
|
|
455
|
+
if (statement.type === "ReturnStatement") {
|
|
456
|
+
return [unwrapOxcParentheses(readObject(statement.argument))];
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (statement.type === "BlockStatement") {
|
|
460
|
+
return readArray(statement.body).flatMap((child) =>
|
|
461
|
+
collectOxcReturnExpressions(readObject(child)),
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (statement.type === "IfStatement") {
|
|
466
|
+
return [
|
|
467
|
+
...collectOxcReturnExpressions(readObject(statement.consequent)),
|
|
468
|
+
...collectOxcReturnExpressions(readObject(statement.alternate)),
|
|
469
|
+
];
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (statement.type === "SwitchStatement") {
|
|
473
|
+
return readArray(statement.cases).flatMap((switchCase) =>
|
|
474
|
+
readArray(readObject(switchCase).consequent).flatMap((child) =>
|
|
475
|
+
collectOxcReturnExpressions(readObject(child)),
|
|
476
|
+
),
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return [];
|
|
481
|
+
}
|
|
482
|
+
|
|
390
483
|
function analyzeOxcComponent(
|
|
391
484
|
code: string,
|
|
392
485
|
statement: unknown,
|
|
@@ -400,6 +493,8 @@ function analyzeOxcComponent(
|
|
|
400
493
|
componentCallNames: Set<string> | undefined,
|
|
401
494
|
bodyLowerers: OxcBodyLowerers,
|
|
402
495
|
reactiveDerivedFunctionNames: ReadonlySet<string>,
|
|
496
|
+
localJsxReturnFunctionNames: ReadonlySet<string>,
|
|
497
|
+
localJsxHelperHtmlParameters: ReadonlyMap<string, ReadonlySet<number>>,
|
|
403
498
|
): ComponentIr[] {
|
|
404
499
|
const object = readObject(statement);
|
|
405
500
|
|
|
@@ -428,6 +523,8 @@ function analyzeOxcComponent(
|
|
|
428
523
|
componentCallNames,
|
|
429
524
|
bodyLowerers,
|
|
430
525
|
reactiveDerivedFunctionNames,
|
|
526
|
+
localJsxReturnFunctionNames,
|
|
527
|
+
localJsxHelperHtmlParameters,
|
|
431
528
|
true,
|
|
432
529
|
),
|
|
433
530
|
];
|
|
@@ -457,6 +554,8 @@ function analyzeOxcComponent(
|
|
|
457
554
|
componentCallNames,
|
|
458
555
|
bodyLowerers,
|
|
459
556
|
reactiveDerivedFunctionNames,
|
|
557
|
+
localJsxReturnFunctionNames,
|
|
558
|
+
localJsxHelperHtmlParameters,
|
|
460
559
|
),
|
|
461
560
|
exported: false,
|
|
462
561
|
},
|
|
@@ -488,13 +587,17 @@ function analyzeOxcComponent(
|
|
|
488
587
|
componentCallNames,
|
|
489
588
|
bodyLowerers,
|
|
490
589
|
reactiveDerivedFunctionNames,
|
|
590
|
+
localJsxReturnFunctionNames,
|
|
591
|
+
localJsxHelperHtmlParameters,
|
|
491
592
|
),
|
|
492
593
|
];
|
|
493
594
|
}
|
|
494
595
|
|
|
495
596
|
if (
|
|
496
597
|
declaration.type !== "FunctionDeclaration" ||
|
|
497
|
-
(!compatReactNodeReturn &&
|
|
598
|
+
(!compatReactNodeReturn &&
|
|
599
|
+
!hasComponentReturn(declaration.body) &&
|
|
600
|
+
!hasLocalJsxHelperCallReturn(declaration.body, localJsxReturnFunctionNames))
|
|
498
601
|
) {
|
|
499
602
|
return [];
|
|
500
603
|
}
|
|
@@ -521,10 +624,40 @@ function analyzeOxcComponent(
|
|
|
521
624
|
componentCallNames,
|
|
522
625
|
bodyLowerers,
|
|
523
626
|
reactiveDerivedFunctionNames,
|
|
627
|
+
localJsxReturnFunctionNames,
|
|
628
|
+
localJsxHelperHtmlParameters,
|
|
524
629
|
),
|
|
525
630
|
];
|
|
526
631
|
}
|
|
527
632
|
|
|
633
|
+
function lowerOxcLocalJsxHelperCallExpressionCode(
|
|
634
|
+
code: string,
|
|
635
|
+
expression: Record<string, unknown>,
|
|
636
|
+
componentNames: Set<string>,
|
|
637
|
+
target: CompileTarget,
|
|
638
|
+
diagnostics: Diagnostic[],
|
|
639
|
+
bodyLowerers: OxcBodyLowerers,
|
|
640
|
+
): string {
|
|
641
|
+
if (expression.type !== "CallExpression") {
|
|
642
|
+
return readSource(code, expression);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const args = readArray(expression.arguments).map((argument) => {
|
|
646
|
+
const object = unwrapOxcParentheses(readObject(argument));
|
|
647
|
+
return containsOxcJsxSyntax(object)
|
|
648
|
+
? (bodyLowerers.lowerServerStringExpression(
|
|
649
|
+
code,
|
|
650
|
+
object,
|
|
651
|
+
componentNames,
|
|
652
|
+
target,
|
|
653
|
+
diagnostics,
|
|
654
|
+
) ?? readSource(code, argument))
|
|
655
|
+
: readSource(code, argument);
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
return `${readSource(code, readObject(expression.callee))}(${args.join(", ")})`;
|
|
659
|
+
}
|
|
660
|
+
|
|
528
661
|
function analyzeOxcFunctionLikeComponent(
|
|
529
662
|
code: string,
|
|
530
663
|
name: string,
|
|
@@ -540,6 +673,8 @@ function analyzeOxcFunctionLikeComponent(
|
|
|
540
673
|
componentCallNames: Set<string> | undefined,
|
|
541
674
|
bodyLowerers: OxcBodyLowerers,
|
|
542
675
|
reactiveDerivedFunctionNames: ReadonlySet<string>,
|
|
676
|
+
localJsxReturnFunctionNames: ReadonlySet<string>,
|
|
677
|
+
localJsxHelperHtmlParameters: ReadonlyMap<string, ReadonlySet<number>>,
|
|
543
678
|
exportDefault = false,
|
|
544
679
|
): ComponentIr {
|
|
545
680
|
const functionBody = readObject(functionLike.body);
|
|
@@ -563,6 +698,15 @@ function analyzeOxcFunctionLikeComponent(
|
|
|
563
698
|
const parameters = readArray(functionLike.params).map((param) =>
|
|
564
699
|
readOxcParameterName(code, param),
|
|
565
700
|
);
|
|
701
|
+
const htmlParameterNames = new Set(
|
|
702
|
+
[...(localJsxHelperHtmlParameters.get(name) ?? [])]
|
|
703
|
+
.map((index) => parameters[index])
|
|
704
|
+
.filter((parameter): parameter is string => parameter !== undefined),
|
|
705
|
+
);
|
|
706
|
+
const bodyComponentNames =
|
|
707
|
+
/^[a-z]/.test(name) && componentNames.has(name)
|
|
708
|
+
? new Set([...componentNames].filter((componentName) => componentName !== name))
|
|
709
|
+
: componentNames;
|
|
566
710
|
const bodyStatements = body
|
|
567
711
|
.filter(
|
|
568
712
|
(bodyStatement) =>
|
|
@@ -576,7 +720,7 @@ function analyzeOxcFunctionLikeComponent(
|
|
|
576
720
|
lowerOxcBodyStatementJsx(
|
|
577
721
|
code,
|
|
578
722
|
bodyStatement,
|
|
579
|
-
|
|
723
|
+
bodyComponentNames,
|
|
580
724
|
target,
|
|
581
725
|
diagnostics,
|
|
582
726
|
bodyStatementJsx,
|
|
@@ -590,7 +734,7 @@ function analyzeOxcFunctionLikeComponent(
|
|
|
590
734
|
reactiveDerivedFunctionNames,
|
|
591
735
|
);
|
|
592
736
|
const childAnalysisContext = createOxcChildAnalysisContext(
|
|
593
|
-
|
|
737
|
+
bodyComponentNames,
|
|
594
738
|
target,
|
|
595
739
|
diagnostics,
|
|
596
740
|
bodyStatementJsx,
|
|
@@ -617,6 +761,23 @@ function analyzeOxcFunctionLikeComponent(
|
|
|
617
761
|
? analyzeOxcJsxNode(code, returnExpression, childAnalysisContext)
|
|
618
762
|
: isOxcComponentCallExpression(returnExpression)
|
|
619
763
|
? analyzeOxcComponentCallExpression(code, returnExpression)
|
|
764
|
+
: isOxcLocalJsxHelperCallExpression(returnExpression, localJsxReturnFunctionNames)
|
|
765
|
+
? {
|
|
766
|
+
kind: "expr" as const,
|
|
767
|
+
code: normalizeOxcExpressionCode(
|
|
768
|
+
bodyStatementJsx === "server-string"
|
|
769
|
+
? lowerOxcLocalJsxHelperCallExpressionCode(
|
|
770
|
+
code,
|
|
771
|
+
returnExpression,
|
|
772
|
+
bodyComponentNames,
|
|
773
|
+
target,
|
|
774
|
+
diagnostics,
|
|
775
|
+
bodyLowerers,
|
|
776
|
+
)
|
|
777
|
+
: readSource(code, returnExpression),
|
|
778
|
+
),
|
|
779
|
+
renderMode: "html" as const,
|
|
780
|
+
}
|
|
620
781
|
: analyzeOxcDynamicRootReturn(
|
|
621
782
|
code,
|
|
622
783
|
returnExpression,
|
|
@@ -654,6 +815,7 @@ function analyzeOxcFunctionLikeComponent(
|
|
|
654
815
|
bodyStatement !== earlyIfRootReturn?.fallthroughStatement,
|
|
655
816
|
),
|
|
656
817
|
),
|
|
818
|
+
...htmlParameterNames,
|
|
657
819
|
]),
|
|
658
820
|
bodyStatementJsx === "server-string" ? "html" : "dynamic",
|
|
659
821
|
);
|