@reckona/mreact-compiler 0.0.65 → 0.0.67
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/package.json +4 -3
- package/src/compiler-module-context.ts +31 -0
- package/src/diagnostics.ts +184 -0
- package/src/emit-client.ts +837 -0
- package/src/emit-compat.ts +567 -0
- package/src/emit-escape-helper.ts +45 -0
- package/src/emit-server-shared.ts +384 -0
- package/src/emit-server-stream.ts +2558 -0
- package/src/emit-server.ts +1827 -0
- package/src/index.ts +44 -0
- package/src/internal.ts +1905 -0
- package/src/ir.ts +151 -0
- package/src/oxc-analysis-types.ts +5 -0
- package/src/oxc-await-analysis.ts +165 -0
- package/src/oxc-await-ids.ts +62 -0
- package/src/oxc-await-validation.ts +117 -0
- package/src/oxc-bindings.ts +70 -0
- package/src/oxc-body-lowering.ts +430 -0
- package/src/oxc-child-analysis.ts +791 -0
- package/src/oxc-code-utils.ts +19 -0
- package/src/oxc-component-detection.ts +459 -0
- package/src/oxc-component-props.ts +170 -0
- package/src/oxc-component-references.ts +613 -0
- package/src/oxc-dom-lowering.ts +127 -0
- package/src/oxc-expression-utils.ts +42 -0
- package/src/oxc-jsx-attributes.ts +110 -0
- package/src/oxc-jsx-text.ts +84 -0
- package/src/oxc-nested-lowering.ts +319 -0
- package/src/oxc-node-utils.ts +65 -0
- package/src/oxc-raw-jsx.ts +239 -0
- package/src/oxc-render-values.ts +620 -0
- package/src/oxc-runtime-emit.ts +212 -0
- package/src/oxc-transform.ts +77 -0
- package/src/oxc.ts +932 -0
- package/src/transform.ts +634 -0
- package/src/types.ts +117 -0
package/src/transform.ts
ADDED
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
import { emitClient } from "./emit-client.js";
|
|
2
|
+
import { emitCompat } from "./emit-compat.js";
|
|
3
|
+
import { emitServer } from "./emit-server.js";
|
|
4
|
+
import { emitServerStream } from "./emit-server-stream.js";
|
|
5
|
+
import { analyzeCompilerModuleContextWithOxc, analyzeWithOxc } from "./oxc.js";
|
|
6
|
+
import type { ComponentIr, JsxNodeIr } from "./ir.js";
|
|
7
|
+
import type { AnalyzeToIrInput, AnalyzeToIrOutput, CompilerModuleContext } from "./internal.js";
|
|
8
|
+
import type { AnalyzeModuleOptions } from "./types.js";
|
|
9
|
+
import type {
|
|
10
|
+
ClientReferenceMetadata,
|
|
11
|
+
EventHydrationEntryMetadata,
|
|
12
|
+
ModuleMetadata,
|
|
13
|
+
TransformInput,
|
|
14
|
+
TransformOutput,
|
|
15
|
+
} from "./types.js";
|
|
16
|
+
|
|
17
|
+
export function transform(input: TransformInput): TransformOutput {
|
|
18
|
+
return transformWithAnalyzer(input, (analyzeTarget, analyzeOptions) =>
|
|
19
|
+
analyzeWithOxc({
|
|
20
|
+
code: input.code,
|
|
21
|
+
filename: input.filename,
|
|
22
|
+
target: analyzeTarget,
|
|
23
|
+
options: analyzeOptions,
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function transformCompilerModuleContext(
|
|
29
|
+
input: TransformInput & { moduleContext: CompilerModuleContext },
|
|
30
|
+
): TransformOutput {
|
|
31
|
+
if (
|
|
32
|
+
(input.moduleContext.code !== input.code || input.moduleContext.filename !== input.filename)
|
|
33
|
+
) {
|
|
34
|
+
throw new Error("Transform input moduleContext must match the input code and filename.");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return transformWithAnalyzer(input, (analyzeTarget, analyzeOptions) =>
|
|
38
|
+
analyzeCompilerModuleContextWithOxc(input.moduleContext, {
|
|
39
|
+
target: analyzeTarget,
|
|
40
|
+
options: analyzeOptions,
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function transformWithAnalyzer(
|
|
46
|
+
input: TransformInput,
|
|
47
|
+
analyze: (
|
|
48
|
+
target: AnalyzeToIrInput["target"],
|
|
49
|
+
options: AnalyzeModuleOptions,
|
|
50
|
+
) => AnalyzeToIrOutput,
|
|
51
|
+
): TransformOutput {
|
|
52
|
+
const mode = input.mode ?? "reactive";
|
|
53
|
+
const serverOutput = input.serverOutput ?? "string";
|
|
54
|
+
const serverBootstrap = input.serverBootstrap ?? "none";
|
|
55
|
+
const analyzeTarget = mode === "compat" ? "client" : input.target;
|
|
56
|
+
const bodyStatementJsx =
|
|
57
|
+
input.target === "server"
|
|
58
|
+
? "server-string"
|
|
59
|
+
: mode === "compat" && input.target === "client"
|
|
60
|
+
? "compat-object"
|
|
61
|
+
: "dom-node";
|
|
62
|
+
const analyzeOptions = {
|
|
63
|
+
topLevelJsx:
|
|
64
|
+
mode === "compat" && input.target === "client"
|
|
65
|
+
? "compat-object"
|
|
66
|
+
: input.target === "server"
|
|
67
|
+
? "server-string"
|
|
68
|
+
: "diagnostic",
|
|
69
|
+
bodyStatementJsx,
|
|
70
|
+
...(input.target === "server" ? { serverOutput } : {}),
|
|
71
|
+
awaitCompatComponents:
|
|
72
|
+
input.target === "server" && serverOutput === "stream" ? "lower" : "diagnostic",
|
|
73
|
+
clientBoundaryImports: input.clientBoundaryImports ?? [],
|
|
74
|
+
compatReactNodeReturn: mode === "compat",
|
|
75
|
+
...(mode === "compat" && input.target === "server"
|
|
76
|
+
? { compatReactNodeReturnRenderMode: "react-node" as const }
|
|
77
|
+
: {}),
|
|
78
|
+
} as const;
|
|
79
|
+
const analyzed = analyze(analyzeTarget, analyzeOptions);
|
|
80
|
+
const diagnostics = [...analyzed.diagnostics];
|
|
81
|
+
const emitted =
|
|
82
|
+
mode === "compat" && input.target === "client"
|
|
83
|
+
? emitCompat(analyzed.ir, { dev: input.dev })
|
|
84
|
+
: input.target === "server"
|
|
85
|
+
? 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
|
+
)
|
|
116
|
+
: emitClient(analyzed.ir);
|
|
117
|
+
|
|
118
|
+
const metadata: ModuleMetadata = {
|
|
119
|
+
filename: input.filename,
|
|
120
|
+
target: input.target,
|
|
121
|
+
compiler: {
|
|
122
|
+
frontend: "oxc",
|
|
123
|
+
typescriptFallback: false,
|
|
124
|
+
},
|
|
125
|
+
components: analyzed.ir.components.map((component) => ({
|
|
126
|
+
name: component.name,
|
|
127
|
+
exportName: component.exportName,
|
|
128
|
+
})),
|
|
129
|
+
imports: emitted.imports,
|
|
130
|
+
};
|
|
131
|
+
const events = collectEventHydrationEntries(analyzed.ir.components);
|
|
132
|
+
|
|
133
|
+
if (events.length > 0) {
|
|
134
|
+
metadata.eventHydrationManifest = {
|
|
135
|
+
version: 1,
|
|
136
|
+
events,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const clientReferences = collectClientReferences(analyzed.ir.components);
|
|
140
|
+
|
|
141
|
+
if (clientReferences.length > 0) {
|
|
142
|
+
metadata.clientReferences = clientReferences;
|
|
143
|
+
}
|
|
144
|
+
const clientReferenceManifest = collectClientReferenceManifest(analyzed.ir.components);
|
|
145
|
+
|
|
146
|
+
if (clientReferenceManifest.length > 0) {
|
|
147
|
+
metadata.clientReferenceManifest = clientReferenceManifest;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (input.target === "server") {
|
|
151
|
+
metadata.serverOutput = serverOutput;
|
|
152
|
+
|
|
153
|
+
if (serverBootstrap !== "none") {
|
|
154
|
+
metadata.serverBootstrap = serverBootstrap;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (input.serverBootstrapNonce !== undefined) {
|
|
158
|
+
metadata.serverBootstrapNonce = input.serverBootstrapNonce;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (input.serverBootstrapSrc !== undefined) {
|
|
162
|
+
metadata.serverBootstrapSrc = input.serverBootstrapSrc;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (input.serverHydration === true) {
|
|
166
|
+
metadata.serverHydration = true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (input.reactSuspenseRevealScriptSrc !== undefined) {
|
|
170
|
+
metadata.reactSuspenseRevealScriptSrc = input.reactSuspenseRevealScriptSrc;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
code: emitted.code,
|
|
176
|
+
map: input.sourceMap === true ? createSourceMap(input, emitted.code) : null,
|
|
177
|
+
diagnostics,
|
|
178
|
+
metadata,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function createSourceMap(input: TransformInput, outputCode: string): string {
|
|
183
|
+
const generatedMap = createSegmentMappings(outputCode, input.code);
|
|
184
|
+
|
|
185
|
+
return JSON.stringify({
|
|
186
|
+
version: 3,
|
|
187
|
+
file: `${input.filename}.js`,
|
|
188
|
+
sources: [input.filename],
|
|
189
|
+
sourcesContent: [input.code],
|
|
190
|
+
names: generatedMap.names,
|
|
191
|
+
mappings: generatedMap.mappings,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
interface GeneratedSourceMap {
|
|
196
|
+
mappings: string;
|
|
197
|
+
names: string[];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function createSegmentMappings(outputCode: string, sourceCode: string): GeneratedSourceMap {
|
|
201
|
+
const generatedLines = outputCode.split("\n");
|
|
202
|
+
const sourceLines = sourceCode.split("\n");
|
|
203
|
+
const lines: string[] = [];
|
|
204
|
+
const names: string[] = [];
|
|
205
|
+
const nameIndexes = new Map<string, number>();
|
|
206
|
+
let previousSourceIndex = 0;
|
|
207
|
+
let previousSourceLine = 0;
|
|
208
|
+
let previousSourceColumn = 0;
|
|
209
|
+
let previousNameIndex = 0;
|
|
210
|
+
|
|
211
|
+
for (const [lineIndex, generatedLine] of generatedLines.entries()) {
|
|
212
|
+
let previousGeneratedColumn = 0;
|
|
213
|
+
const segments = collectSourceMapSegments(generatedLine, lineIndex, sourceLines);
|
|
214
|
+
|
|
215
|
+
lines.push(
|
|
216
|
+
segments
|
|
217
|
+
.map((segment) => {
|
|
218
|
+
const fields = [
|
|
219
|
+
encodeVlq(segment.generatedColumn - previousGeneratedColumn),
|
|
220
|
+
encodeVlq(0 - previousSourceIndex),
|
|
221
|
+
encodeVlq(segment.sourceLine - previousSourceLine),
|
|
222
|
+
encodeVlq(segment.sourceColumn - previousSourceColumn),
|
|
223
|
+
];
|
|
224
|
+
|
|
225
|
+
if (segment.name !== undefined) {
|
|
226
|
+
const nameIndex = getSourceMapNameIndex(segment.name, names, nameIndexes);
|
|
227
|
+
fields.push(encodeVlq(nameIndex - previousNameIndex));
|
|
228
|
+
previousNameIndex = nameIndex;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const encoded = fields.join("");
|
|
232
|
+
previousGeneratedColumn = segment.generatedColumn;
|
|
233
|
+
previousSourceIndex = 0;
|
|
234
|
+
previousSourceLine = segment.sourceLine;
|
|
235
|
+
previousSourceColumn = segment.sourceColumn;
|
|
236
|
+
return encoded;
|
|
237
|
+
})
|
|
238
|
+
.join(","),
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return { mappings: lines.join(";"), names };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
interface SourceMapSegment {
|
|
246
|
+
generatedColumn: number;
|
|
247
|
+
sourceLine: number;
|
|
248
|
+
sourceColumn: number;
|
|
249
|
+
name?: string;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function collectSourceMapSegments(
|
|
253
|
+
generatedLine: string,
|
|
254
|
+
generatedLineIndex: number,
|
|
255
|
+
sourceLines: readonly string[],
|
|
256
|
+
): SourceMapSegment[] {
|
|
257
|
+
const fallbackSourceLine = findFallbackSourceLine(generatedLine, generatedLineIndex, sourceLines);
|
|
258
|
+
const segments: SourceMapSegment[] = [
|
|
259
|
+
{
|
|
260
|
+
generatedColumn: 0,
|
|
261
|
+
sourceLine: fallbackSourceLine,
|
|
262
|
+
sourceColumn: 0,
|
|
263
|
+
},
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
const functionMatch = /function\s+([A-Za-z_$][\w$]*)/.exec(generatedLine);
|
|
267
|
+
if (functionMatch !== null && functionMatch.index !== undefined) {
|
|
268
|
+
const token = `function ${functionMatch[1]}`;
|
|
269
|
+
const sourceLocation = findSourceLocation(sourceLines, token);
|
|
270
|
+
|
|
271
|
+
if (sourceLocation !== undefined) {
|
|
272
|
+
segments.push({
|
|
273
|
+
generatedColumn: functionMatch.index,
|
|
274
|
+
sourceLine: sourceLocation.line,
|
|
275
|
+
sourceColumn: sourceLocation.column,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const returnColumn = generatedLine.indexOf("return");
|
|
281
|
+
if (returnColumn >= 0) {
|
|
282
|
+
const sourceLocation = findSourceLocation(sourceLines, "return");
|
|
283
|
+
|
|
284
|
+
if (sourceLocation !== undefined) {
|
|
285
|
+
segments.push({
|
|
286
|
+
generatedColumn: returnColumn,
|
|
287
|
+
sourceLine: sourceLocation.line,
|
|
288
|
+
sourceColumn: sourceLocation.column,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const templateStart = generatedLine.indexOf('createTemplate("');
|
|
294
|
+
const templateTag =
|
|
295
|
+
templateStart < 0
|
|
296
|
+
? undefined
|
|
297
|
+
: generatedLine.slice(templateStart).match(/<[A-Za-z][\w:-]*/)?.[0];
|
|
298
|
+
if (templateTag !== undefined) {
|
|
299
|
+
const generatedColumn = generatedLine.indexOf(templateTag);
|
|
300
|
+
const sourceLocation = findSourceLocation(sourceLines, templateTag);
|
|
301
|
+
|
|
302
|
+
if (generatedColumn >= 0 && sourceLocation !== undefined) {
|
|
303
|
+
segments.push({
|
|
304
|
+
generatedColumn,
|
|
305
|
+
sourceLine: sourceLocation.line,
|
|
306
|
+
sourceColumn: sourceLocation.column,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const dynamicExpression = /=> \(([^)]+)\)/.exec(generatedLine)?.[1]?.trim();
|
|
312
|
+
if (dynamicExpression !== undefined && dynamicExpression !== "") {
|
|
313
|
+
const generatedColumn = generatedLine.indexOf(dynamicExpression);
|
|
314
|
+
const bindPropAttribute = /bindProp\([^,]+,\s+"([^"]+)"/.exec(generatedLine)?.[1];
|
|
315
|
+
const sourceLocation =
|
|
316
|
+
bindPropAttribute === undefined
|
|
317
|
+
? undefined
|
|
318
|
+
: (findSourceLocation(sourceLines, `${bindPropAttribute}={${dynamicExpression}}`) ??
|
|
319
|
+
findSourceLocation(sourceLines, `${bindPropAttribute}="${dynamicExpression}"`));
|
|
320
|
+
const fallbackSourceLocation =
|
|
321
|
+
findSourceLocation(sourceLines, `{${dynamicExpression}}`) ??
|
|
322
|
+
findJsxExpressionTokenLocation(sourceLines, dynamicExpression) ??
|
|
323
|
+
findSourceLocation(sourceLines, dynamicExpression);
|
|
324
|
+
const resolvedSourceLocation = sourceLocation ?? fallbackSourceLocation;
|
|
325
|
+
|
|
326
|
+
if (generatedColumn >= 0 && resolvedSourceLocation !== undefined) {
|
|
327
|
+
const sourceColumnOffset =
|
|
328
|
+
bindPropAttribute !== undefined && sourceLocation !== undefined
|
|
329
|
+
? bindPropAttribute.length + 2
|
|
330
|
+
: sourceLines[resolvedSourceLocation.line]?.startsWith("{", resolvedSourceLocation.column)
|
|
331
|
+
? 1
|
|
332
|
+
: 0;
|
|
333
|
+
|
|
334
|
+
segments.push({
|
|
335
|
+
generatedColumn,
|
|
336
|
+
sourceLine: resolvedSourceLocation.line,
|
|
337
|
+
sourceColumn: resolvedSourceLocation.column + sourceColumnOffset,
|
|
338
|
+
...(isIdentifierName(dynamicExpression) ? { name: dynamicExpression } : {}),
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
for (const identifier of collectIdentifierReferences(dynamicExpression)) {
|
|
342
|
+
segments.push({
|
|
343
|
+
generatedColumn: generatedColumn + identifier.column,
|
|
344
|
+
sourceLine: resolvedSourceLocation.line,
|
|
345
|
+
sourceColumn: resolvedSourceLocation.column + sourceColumnOffset + identifier.column,
|
|
346
|
+
name: identifier.name,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return dedupeAndSortSegments(segments);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function getSourceMapNameIndex(
|
|
356
|
+
name: string,
|
|
357
|
+
names: string[],
|
|
358
|
+
indexes: Map<string, number>,
|
|
359
|
+
): number {
|
|
360
|
+
const existing = indexes.get(name);
|
|
361
|
+
|
|
362
|
+
if (existing !== undefined) {
|
|
363
|
+
return existing;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const index = names.length;
|
|
367
|
+
names.push(name);
|
|
368
|
+
indexes.set(name, index);
|
|
369
|
+
return index;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function isIdentifierName(value: string): boolean {
|
|
373
|
+
return /^[A-Za-z_$][\w$]*$/.test(value);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function collectIdentifierReferences(expression: string): { name: string; column: number }[] {
|
|
377
|
+
const references: { name: string; column: number }[] = [];
|
|
378
|
+
const seen = new Set<string>();
|
|
379
|
+
const identifierPattern = /\b[A-Za-z_$][\w$]*\b/g;
|
|
380
|
+
|
|
381
|
+
for (const match of expression.matchAll(identifierPattern)) {
|
|
382
|
+
const name = match[0];
|
|
383
|
+
const column = match.index ?? 0;
|
|
384
|
+
|
|
385
|
+
if (sourceMapIgnoredIdentifiers.has(name) || seen.has(`${name}:${column}`)) {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
references.push({ name, column });
|
|
390
|
+
seen.add(`${name}:${column}`);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return references;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const sourceMapIgnoredIdentifiers = new Set(["false", "null", "true", "undefined"]);
|
|
397
|
+
|
|
398
|
+
function findFallbackSourceLine(
|
|
399
|
+
generatedLine: string,
|
|
400
|
+
generatedLineIndex: number,
|
|
401
|
+
sourceLines: readonly string[],
|
|
402
|
+
): number {
|
|
403
|
+
const functionName = /function\s+([A-Za-z_$][\w$]*)/.exec(generatedLine)?.[1];
|
|
404
|
+
|
|
405
|
+
if (functionName !== undefined) {
|
|
406
|
+
return findSourceLocation(sourceLines, `function ${functionName}`)?.line ?? 0;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (generatedLine.includes("createTemplate")) {
|
|
410
|
+
const jsxLine = sourceLines.findIndex((line) => line.includes("<"));
|
|
411
|
+
return jsxLine < 0 ? 0 : jsxLine;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (generatedLine.includes("return")) {
|
|
415
|
+
return findSourceLocation(sourceLines, "return")?.line ?? 0;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return Math.min(generatedLineIndex, Math.max(0, sourceLines.length - 1));
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function findSourceLocation(
|
|
422
|
+
sourceLines: readonly string[],
|
|
423
|
+
token: string,
|
|
424
|
+
): { line: number; column: number } | undefined {
|
|
425
|
+
for (const [line, sourceLine] of sourceLines.entries()) {
|
|
426
|
+
const column = sourceLine.indexOf(token);
|
|
427
|
+
|
|
428
|
+
if (column >= 0) {
|
|
429
|
+
return { line, column };
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function findJsxExpressionTokenLocation(
|
|
437
|
+
sourceLines: readonly string[],
|
|
438
|
+
token: string,
|
|
439
|
+
): { line: number; column: number } | undefined {
|
|
440
|
+
let insideJsxExpression = false;
|
|
441
|
+
|
|
442
|
+
for (const [line, sourceLine] of sourceLines.entries()) {
|
|
443
|
+
if (sourceLine.includes("<") && sourceLine.includes("{")) {
|
|
444
|
+
insideJsxExpression = true;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (insideJsxExpression) {
|
|
448
|
+
const column = sourceLine.indexOf(token);
|
|
449
|
+
|
|
450
|
+
if (column >= 0) {
|
|
451
|
+
return { line, column };
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (sourceLine.includes("}")) {
|
|
456
|
+
insideJsxExpression = false;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return undefined;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function dedupeAndSortSegments(segments: readonly SourceMapSegment[]): SourceMapSegment[] {
|
|
464
|
+
const byGeneratedColumn = new Map<number, SourceMapSegment>();
|
|
465
|
+
|
|
466
|
+
for (const segment of segments) {
|
|
467
|
+
byGeneratedColumn.set(segment.generatedColumn, segment);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return Array.from(byGeneratedColumn.values()).sort(
|
|
471
|
+
(left, right) => left.generatedColumn - right.generatedColumn,
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const sourceMapBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
476
|
+
|
|
477
|
+
function encodeVlq(value: number): string {
|
|
478
|
+
let vlq = value < 0 ? (-value << 1) + 1 : value << 1;
|
|
479
|
+
let encoded = "";
|
|
480
|
+
|
|
481
|
+
do {
|
|
482
|
+
let digit = vlq & 31;
|
|
483
|
+
vlq >>>= 5;
|
|
484
|
+
|
|
485
|
+
if (vlq > 0) {
|
|
486
|
+
digit |= 32;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
encoded += sourceMapBase64[digit] ?? "";
|
|
490
|
+
} while (vlq > 0);
|
|
491
|
+
|
|
492
|
+
return encoded;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function collectEventHydrationEntries(
|
|
496
|
+
components: readonly ComponentIr[],
|
|
497
|
+
): EventHydrationEntryMetadata[] {
|
|
498
|
+
return components.flatMap((component) => {
|
|
499
|
+
const entries: EventHydrationEntryMetadata[] = [];
|
|
500
|
+
collectEventsFromNode(component.root, component.name, "0", entries);
|
|
501
|
+
return entries;
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function collectClientReferences(components: readonly ComponentIr[]): string[] {
|
|
506
|
+
const references = new Set<string>();
|
|
507
|
+
|
|
508
|
+
for (const component of components) {
|
|
509
|
+
collectClientReferencesFromNode(component.root, references);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return Array.from(references);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function collectClientReferenceManifest(
|
|
516
|
+
components: readonly ComponentIr[],
|
|
517
|
+
): ClientReferenceMetadata[] {
|
|
518
|
+
const references = new Map<string, ClientReferenceMetadata>();
|
|
519
|
+
|
|
520
|
+
for (const component of components) {
|
|
521
|
+
collectClientReferenceManifestFromNode(component.root, references);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return Array.from(references.values());
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function collectClientReferenceManifestFromNode(
|
|
528
|
+
node: JsxNodeIr,
|
|
529
|
+
references: Map<string, ClientReferenceMetadata>,
|
|
530
|
+
): void {
|
|
531
|
+
if (node.kind === "component" && node.clientReference !== undefined) {
|
|
532
|
+
references.set(`${node.name}:${node.clientReference.moduleId}:${node.clientReference.exportName}`, {
|
|
533
|
+
name: node.name,
|
|
534
|
+
moduleId: node.clientReference.moduleId,
|
|
535
|
+
exportName: node.clientReference.exportName,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
for (const child of getNodeChildren(node)) {
|
|
540
|
+
collectClientReferenceManifestFromNode(child, references);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (node.kind === "component") {
|
|
544
|
+
for (const prop of node.props) {
|
|
545
|
+
if (prop.kind === "render-prop") {
|
|
546
|
+
for (const child of prop.children) {
|
|
547
|
+
collectClientReferenceManifestFromNode(child, references);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function collectClientReferencesFromNode(
|
|
555
|
+
node: JsxNodeIr,
|
|
556
|
+
references: Set<string>,
|
|
557
|
+
): void {
|
|
558
|
+
if (node.kind === "component" && node.runtime === "compat" && node.clientReference !== undefined) {
|
|
559
|
+
references.add(node.name);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
for (const child of getNodeChildren(node)) {
|
|
563
|
+
collectClientReferencesFromNode(child, references);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (node.kind === "component") {
|
|
567
|
+
for (const prop of node.props) {
|
|
568
|
+
if (prop.kind === "render-prop") {
|
|
569
|
+
for (const child of prop.children) {
|
|
570
|
+
collectClientReferencesFromNode(child, references);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function collectEventsFromNode(
|
|
578
|
+
node: JsxNodeIr,
|
|
579
|
+
componentName: string,
|
|
580
|
+
path: string,
|
|
581
|
+
entries: EventHydrationEntryMetadata[],
|
|
582
|
+
): void {
|
|
583
|
+
if (node.kind === "element") {
|
|
584
|
+
for (const attr of node.attributes) {
|
|
585
|
+
if (attr.kind === "event") {
|
|
586
|
+
entries.push({
|
|
587
|
+
id: `${componentName}:${path}`,
|
|
588
|
+
event: attr.eventName,
|
|
589
|
+
handler: attr.code,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
for (const [index, child] of getNodeChildren(node).entries()) {
|
|
596
|
+
collectEventsFromNode(child, componentName, `${path}.${index}`, entries);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
function getNodeChildren(node: JsxNodeIr): readonly JsxNodeIr[] {
|
|
601
|
+
if (node.kind === "element" || node.kind === "fragment") {
|
|
602
|
+
return node.children;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (node.kind === "conditional") {
|
|
606
|
+
return [...node.whenTrue, ...node.whenFalse];
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (node.kind === "list") {
|
|
610
|
+
return node.children;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (node.kind === "async-boundary") {
|
|
614
|
+
return [...node.children, ...(node.placeholderChildren ?? []), ...(node.catchChildren ?? [])];
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return [];
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
function createServerOptions(
|
|
621
|
+
serverBootstrap: NonNullable<TransformInput["serverBootstrap"]>,
|
|
622
|
+
serverBootstrapNonce?: string,
|
|
623
|
+
serverBootstrapSrc?: string,
|
|
624
|
+
serverHydration?: boolean,
|
|
625
|
+
reactSuspenseRevealScriptSrc?: string,
|
|
626
|
+
) {
|
|
627
|
+
return {
|
|
628
|
+
serverBootstrap,
|
|
629
|
+
...(serverBootstrapNonce === undefined ? {} : { serverBootstrapNonce }),
|
|
630
|
+
...(serverBootstrapSrc === undefined ? {} : { serverBootstrapSrc }),
|
|
631
|
+
...(serverHydration === undefined ? {} : { serverHydration }),
|
|
632
|
+
...(reactSuspenseRevealScriptSrc === undefined ? {} : { reactSuspenseRevealScriptSrc }),
|
|
633
|
+
};
|
|
634
|
+
}
|