octane 0.1.12 → 0.1.16
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/compiler/bundler.js +39 -56
- package/dist/compiler/client-only-server.js +195 -54
- package/dist/compiler/compile-renderer-boundaries.js +448 -536
- package/dist/compiler/compile-universal.js +2220 -1500
- package/dist/compiler/compile.js +7188 -2959
- package/dist/compiler/fat-segments.js +196 -0
- package/dist/compiler/hook-deps.js +115 -24
- package/dist/compiler/hydrate-boundaries.js +695 -444
- package/dist/compiler/native-change-diagnostics.js +2 -1
- package/dist/compiler/renderer-boundaries.js +2 -2
- package/dist/compiler/renderers.js +16 -1
- package/dist/compiler/slot-hooks.js +11 -7
- package/dist/compiler/vite.d.ts +8 -2
- package/dist/compiler/vite.js +36 -3
- package/dist/compiler/volar.js +245 -18
- package/dist/constants.d.ts +7 -1
- package/dist/constants.js +7 -1
- package/dist/devtools-hook.d.ts +64 -0
- package/dist/devtools-hook.js +162 -0
- package/dist/dom-tables.d.ts +2 -0
- package/dist/dom-tables.js +145 -0
- package/dist/head-ownership.d.ts +12 -0
- package/dist/head-ownership.js +31 -0
- package/dist/hydration/event-capture.d.ts +4 -1
- package/dist/hydration/event-capture.js +9 -2
- package/dist/hydration/types.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -0
- package/dist/jsx-runtime.d.ts +570 -0
- package/dist/runtime.d.ts +19 -1
- package/dist/runtime.js +1081 -265
- package/dist/runtime.server.d.ts +1 -14
- package/dist/runtime.server.js +124 -29
- package/dist/server/rpc.js +16 -1
- package/dist/stream-protocol.d.ts +20 -0
- package/dist/stream-protocol.js +68 -0
- package/dist/universal-core.d.ts +13 -3
- package/dist/universal-core.js +1135 -124
- package/dist/universal-dom-boundary.js +49 -6
- package/package.json +25 -11
package/dist/compiler/bundler.js
CHANGED
|
@@ -14,17 +14,14 @@ import * as nodeFs from 'node:fs';
|
|
|
14
14
|
import * as nodeModule from 'node:module';
|
|
15
15
|
import * as nodePath from 'node:path';
|
|
16
16
|
import { parseModule } from '@tsrx/core';
|
|
17
|
-
import { compile, hasOnlyLowerableNullishExits, isVoidJsxCodeBlockFunction } from './compile.js';
|
|
18
17
|
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
prepareServerHydrateBoundaries,
|
|
27
|
-
} from './hydrate-boundaries.js';
|
|
18
|
+
compile,
|
|
19
|
+
compileForBundler,
|
|
20
|
+
hasOnlyLowerableNullishExits,
|
|
21
|
+
isVoidJsxCodeBlockFunction,
|
|
22
|
+
} from './compile.js';
|
|
23
|
+
import { validateRendererModuleSource } from './compile-universal.js';
|
|
24
|
+
import { HYDRATE_QUERY_PARAM, hydrateBoundaryPathFromId } from './hydrate-boundaries.js';
|
|
28
25
|
import {
|
|
29
26
|
DOM_RENDERER_MODULE,
|
|
30
27
|
normalizeRendererConfig,
|
|
@@ -32,10 +29,7 @@ import {
|
|
|
32
29
|
} from './renderers.js';
|
|
33
30
|
import { findLeadingJsxImportSourcePragma } from './pragma.js';
|
|
34
31
|
import { normalizeUniversalRuntime } from './universal-runtime.js';
|
|
35
|
-
import {
|
|
36
|
-
analyzeNativeChangeDiagnostics,
|
|
37
|
-
formatCompileDiagnostic,
|
|
38
|
-
} from './native-change-diagnostics.js';
|
|
32
|
+
import { formatCompileDiagnostic } from './native-change-diagnostics.js';
|
|
39
33
|
import { findVoidComponentImports, findVoidRootImports, slotHooks } from './slot-hooks.js';
|
|
40
34
|
import {
|
|
41
35
|
assertNoLiveClientOnlyImports,
|
|
@@ -199,10 +193,14 @@ function normalizeHmrDialect(value) {
|
|
|
199
193
|
*/
|
|
200
194
|
export function findVoidComponentExports(source, id) {
|
|
201
195
|
let ast;
|
|
202
|
-
|
|
203
|
-
ast =
|
|
204
|
-
}
|
|
205
|
-
|
|
196
|
+
if (source && typeof source === 'object' && source.type === 'Program') {
|
|
197
|
+
ast = source;
|
|
198
|
+
} else {
|
|
199
|
+
try {
|
|
200
|
+
ast = parseModule(source, id);
|
|
201
|
+
} catch {
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
206
204
|
}
|
|
207
205
|
const memoLocals = new Set();
|
|
208
206
|
const declarations = [];
|
|
@@ -873,8 +871,9 @@ class OctaneBundlerCompiler {
|
|
|
873
871
|
if (environment === 'server' && clientReference !== null) {
|
|
874
872
|
const stub = createClientOnlyServerStub(code, filename, renderer.id);
|
|
875
873
|
return {
|
|
874
|
+
ast: stub.ast,
|
|
876
875
|
code: stub.code,
|
|
877
|
-
map:
|
|
876
|
+
map: stub.map,
|
|
878
877
|
kind: 'client-only-stub',
|
|
879
878
|
renderer,
|
|
880
879
|
clientReference,
|
|
@@ -883,36 +882,11 @@ class OctaneBundlerCompiler {
|
|
|
883
882
|
};
|
|
884
883
|
}
|
|
885
884
|
const hasRendererBoundaries = Object.keys(this.renderers.boundaries).length > 0;
|
|
886
|
-
const
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
dom: renderer.target === 'dom',
|
|
892
|
-
renderer,
|
|
893
|
-
rendererBoundaries: this.renderers.boundaries,
|
|
894
|
-
rendererRegistry: this.renderers.registry,
|
|
895
|
-
},
|
|
896
|
-
);
|
|
897
|
-
const nativeChangeDiagnostics = nativeChangeAnalysis.diagnostics;
|
|
898
|
-
const hydratePreparation =
|
|
899
|
-
environment === 'client'
|
|
900
|
-
? prepareHydrateBoundaries(code, filename, hydrateBoundaryPath)
|
|
901
|
-
: prepareServerHydrateBoundaries(code, filename);
|
|
902
|
-
const compileSource = hydratePreparation?.source ?? code;
|
|
903
|
-
const out = compile(compileSource, filename, {
|
|
904
|
-
__hydratePrepared: true,
|
|
905
|
-
__hydrateBoundaryModule: typeof hydratePreparation?.boundaryPath === 'string',
|
|
906
|
-
__nativeChangeDiagnostics: nativeChangeDiagnostics,
|
|
907
|
-
...(hydratePreparation === null && !hasRendererBoundaries
|
|
908
|
-
? { __nativeChangeAnalysis: nativeChangeAnalysis }
|
|
909
|
-
: null),
|
|
910
|
-
// Scoped-style hashes are position-derived; after the extraction
|
|
911
|
-
// rewrite the compiler restamps them from these authored
|
|
912
|
-
// coordinates so client and server compiles agree (compile.js).
|
|
913
|
-
...(hydratePreparation?.origins != null
|
|
914
|
-
? { __styleRemap: { authored: code, origins: hydratePreparation.origins } }
|
|
915
|
-
: null),
|
|
885
|
+
const compileFilename =
|
|
886
|
+
hydrateBoundaryPath === null
|
|
887
|
+
? filename
|
|
888
|
+
: `${filename}?${HYDRATE_QUERY_PARAM}=${encodeURIComponent(hydrateBoundaryPath)}`;
|
|
889
|
+
const compileOptions = {
|
|
916
890
|
hmr,
|
|
917
891
|
mode: environment,
|
|
918
892
|
dev,
|
|
@@ -933,10 +907,17 @@ class OctaneBundlerCompiler {
|
|
|
933
907
|
...(environment === 'client' && typeof options.isVoidComponentImport === 'function'
|
|
934
908
|
? { isVoidComponentImport: options.isVoidComponentImport }
|
|
935
909
|
: null),
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
910
|
+
};
|
|
911
|
+
const collectVoidComponentExports =
|
|
912
|
+
environment === 'client' && options.collectVoidComponentExports === true;
|
|
913
|
+
let out;
|
|
914
|
+
let voidComponentAst = null;
|
|
915
|
+
if (collectVoidComponentExports) {
|
|
916
|
+
const compilation = compileForBundler(code, compileFilename, compileOptions);
|
|
917
|
+
out = compilation.result;
|
|
918
|
+
voidComponentAst = compilation.hydrateAst;
|
|
919
|
+
} else {
|
|
920
|
+
out = compile(code, compileFilename, compileOptions);
|
|
940
921
|
}
|
|
941
922
|
this._forwardCompileDiagnostics(out.diagnostics);
|
|
942
923
|
return {
|
|
@@ -947,9 +928,11 @@ class OctaneBundlerCompiler {
|
|
|
947
928
|
renderer,
|
|
948
929
|
...(out.universalRuntime === undefined ? null : { universalRuntime: out.universalRuntime }),
|
|
949
930
|
...(clientReference === null ? null : { clientReference }),
|
|
950
|
-
...(
|
|
951
|
-
?
|
|
952
|
-
: {
|
|
931
|
+
...(voidComponentAst === null
|
|
932
|
+
? null
|
|
933
|
+
: {
|
|
934
|
+
voidComponentExports: findVoidComponentExports(voidComponentAst, filename),
|
|
935
|
+
}),
|
|
953
936
|
...finishMetadata(collected),
|
|
954
937
|
};
|
|
955
938
|
}
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* regions have been omitted, so any remaining reference receives a source
|
|
9
9
|
* diagnostic before a sentinel can affect server behavior.
|
|
10
10
|
*/
|
|
11
|
-
import { parseModule } from '@tsrx/core';
|
|
11
|
+
import { builders as b, parseModule } from '@tsrx/core';
|
|
12
|
+
import { print as esrapPrint } from 'esrap';
|
|
13
|
+
import esrapTsx from 'esrap/languages/tsx';
|
|
12
14
|
|
|
13
15
|
const CLIENT_REFERENCE_VERSION = 1;
|
|
14
16
|
export const CLIENT_REFERENCE_MANIFEST_FILENAME = 'octane-client-references.json';
|
|
@@ -26,10 +28,6 @@ function astName(node) {
|
|
|
26
28
|
return typeof node?.value === 'string' ? node.value : null;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
function printExportName(name) {
|
|
30
|
-
return /^[$A-Z_a-z][$\w]*$/u.test(name) || name === 'default' ? name : JSON.stringify(name);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
31
|
function addPatternNames(pattern, output) {
|
|
34
32
|
if (!pattern) return;
|
|
35
33
|
if (pattern.type === 'TSParameterProperty') {
|
|
@@ -182,7 +180,10 @@ export function findStaticRuntimeImportRequests(source, filename = 'unknown') {
|
|
|
182
180
|
}
|
|
183
181
|
|
|
184
182
|
function collectRuntimeExports(ast, filename) {
|
|
185
|
-
const exports = new
|
|
183
|
+
const exports = new Map();
|
|
184
|
+
const addExport = (name, origin) => {
|
|
185
|
+
if (!exports.has(name)) exports.set(name, origin);
|
|
186
|
+
};
|
|
186
187
|
for (const statement of ast.body ?? []) {
|
|
187
188
|
if (statement.type === 'ExportDefaultDeclaration') {
|
|
188
189
|
if (
|
|
@@ -190,7 +191,7 @@ function collectRuntimeExports(ast, filename) {
|
|
|
190
191
|
statement.declaration?.declare !== true &&
|
|
191
192
|
statement.declaration?.type !== 'TSInterfaceDeclaration'
|
|
192
193
|
) {
|
|
193
|
-
|
|
194
|
+
addExport('default', statement);
|
|
194
195
|
}
|
|
195
196
|
continue;
|
|
196
197
|
}
|
|
@@ -208,14 +209,14 @@ function collectRuntimeExports(ast, filename) {
|
|
|
208
209
|
statement.importKind !== 'type' &&
|
|
209
210
|
statement.id?.name
|
|
210
211
|
) {
|
|
211
|
-
|
|
212
|
+
addExport(statement.id.name, statement.id);
|
|
212
213
|
continue;
|
|
213
214
|
}
|
|
214
215
|
if (statement.type === 'ExportAllDeclaration') {
|
|
215
216
|
if (statement.exportKind === 'type') continue;
|
|
216
217
|
const exported = astName(statement.exported);
|
|
217
218
|
if (exported !== null) {
|
|
218
|
-
|
|
219
|
+
addExport(exported, statement.exported ?? statement);
|
|
219
220
|
continue;
|
|
220
221
|
}
|
|
221
222
|
throw diagnosticError(
|
|
@@ -230,7 +231,11 @@ function collectRuntimeExports(ast, filename) {
|
|
|
230
231
|
const declaration = statement.declaration;
|
|
231
232
|
if (declaration?.declare === true) continue;
|
|
232
233
|
if (declaration?.type === 'VariableDeclaration') {
|
|
233
|
-
for (const item of declaration.declarations ?? [])
|
|
234
|
+
for (const item of declaration.declarations ?? []) {
|
|
235
|
+
const names = new Set();
|
|
236
|
+
addPatternNames(item.id, names);
|
|
237
|
+
for (const name of names) addExport(name, item.id);
|
|
238
|
+
}
|
|
234
239
|
} else if (
|
|
235
240
|
declaration?.id &&
|
|
236
241
|
(declaration.type === 'FunctionDeclaration' ||
|
|
@@ -238,15 +243,92 @@ function collectRuntimeExports(ast, filename) {
|
|
|
238
243
|
declaration.type === 'TSEnumDeclaration' ||
|
|
239
244
|
declaration.type === 'TSModuleDeclaration')
|
|
240
245
|
) {
|
|
241
|
-
|
|
246
|
+
addExport(declaration.id.name, declaration.id);
|
|
242
247
|
}
|
|
243
248
|
for (const specifier of statement.specifiers ?? []) {
|
|
244
249
|
if (specifier.exportKind === 'type') continue;
|
|
245
250
|
const exported = astName(specifier.exported);
|
|
246
|
-
if (exported !== null)
|
|
251
|
+
if (exported !== null) addExport(exported, specifier.exported ?? specifier);
|
|
247
252
|
}
|
|
248
253
|
}
|
|
249
|
-
return [...exports]
|
|
254
|
+
return [...exports]
|
|
255
|
+
.map(([name, origin]) => ({ name, origin }))
|
|
256
|
+
.sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Generated stub scaffolding has no authored syntax of its own, but every
|
|
261
|
+
* printed node still inherits a source origin so the auxiliary module carries
|
|
262
|
+
* a useful esrap map. The tree is compiler-owned; parsed nodes are never
|
|
263
|
+
* embedded or mutated.
|
|
264
|
+
*/
|
|
265
|
+
function inheritGeneratedOrigin(root, origin) {
|
|
266
|
+
const seen = new WeakSet();
|
|
267
|
+
const visit = (value) => {
|
|
268
|
+
if (!value || typeof value !== 'object' || seen.has(value)) return;
|
|
269
|
+
seen.add(value);
|
|
270
|
+
if (Array.isArray(value)) {
|
|
271
|
+
for (const item of value) visit(item);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (typeof value.type === 'string' && value.loc == null && origin?.loc != null) {
|
|
275
|
+
value.start = origin.start;
|
|
276
|
+
value.end = origin.end;
|
|
277
|
+
value.loc = origin.loc;
|
|
278
|
+
}
|
|
279
|
+
for (const [key, child] of Object.entries(value)) {
|
|
280
|
+
if (key !== 'loc' && key !== 'metadata') visit(child);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
visit(root);
|
|
284
|
+
return root;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function createProgram(body, origin) {
|
|
288
|
+
return inheritGeneratedOrigin(
|
|
289
|
+
{
|
|
290
|
+
type: 'Program',
|
|
291
|
+
sourceType: 'module',
|
|
292
|
+
body,
|
|
293
|
+
metadata: { path: [] },
|
|
294
|
+
},
|
|
295
|
+
origin,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const jsonStringifyCall = (expression) => b.call(b.member(b.id('JSON'), 'stringify'), expression);
|
|
300
|
+
|
|
301
|
+
function clientOnlyStubVisitors() {
|
|
302
|
+
const visitors = esrapTsx();
|
|
303
|
+
const printExportSpecifier = visitors.ExportSpecifier;
|
|
304
|
+
return {
|
|
305
|
+
...visitors,
|
|
306
|
+
ExportSpecifier(node, context) {
|
|
307
|
+
// ESTree represents quoted export names as Literals. esrap 2.3's TS
|
|
308
|
+
// visitor currently prints only Identifier→Identifier aliases; retain
|
|
309
|
+
// the standard AST and teach this one print the missing literal arm.
|
|
310
|
+
if (node.exported.type === 'Literal') {
|
|
311
|
+
context.visit(node.local);
|
|
312
|
+
context.write(' as ');
|
|
313
|
+
context.visit(node.exported);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
printExportSpecifier(node, context);
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function printClientOnlyServerStub(program, source, filename, exports) {
|
|
322
|
+
const printed = esrapPrint(program, clientOnlyStubVisitors(), {
|
|
323
|
+
sourceMapSource: filename,
|
|
324
|
+
sourceMapContent: source,
|
|
325
|
+
});
|
|
326
|
+
return {
|
|
327
|
+
ast: program,
|
|
328
|
+
code: printed.code,
|
|
329
|
+
map: printed.map,
|
|
330
|
+
exports,
|
|
331
|
+
};
|
|
250
332
|
}
|
|
251
333
|
|
|
252
334
|
/**
|
|
@@ -255,48 +337,102 @@ function collectRuntimeExports(ast, filename) {
|
|
|
255
337
|
*/
|
|
256
338
|
export function createClientOnlyServerStub(source, filename, renderer) {
|
|
257
339
|
const ast = parseModule(source, filename);
|
|
258
|
-
const
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
'function __octaneClientOnlyExport(name) {',
|
|
263
|
-
'\tconst fail = () => {',
|
|
264
|
-
'\t\tconst error = new Error(`Client-only export ${JSON.stringify(name)} from ${JSON.stringify(__octaneClientOnlyModule)} (renderer ${JSON.stringify(__octaneClientOnlyRenderer)}) was used by the server graph.`);',
|
|
265
|
-
"\t\terror.code = 'OCTANE_CLIENT_ONLY_SERVER_USE';",
|
|
266
|
-
'\t\terror.filename = __octaneClientOnlyModule;',
|
|
267
|
-
'\t\tthrow error;',
|
|
268
|
-
'\t};',
|
|
269
|
-
'\treturn new Proxy(fail, {',
|
|
270
|
-
'\t\tapply: fail,',
|
|
271
|
-
'\t\tconstruct: fail,',
|
|
272
|
-
'\t\tdefineProperty: fail,',
|
|
273
|
-
'\t\tdeleteProperty: fail,',
|
|
274
|
-
'\t\tget: fail,',
|
|
275
|
-
'\t\tgetOwnPropertyDescriptor: fail,',
|
|
276
|
-
'\t\tgetPrototypeOf: fail,',
|
|
277
|
-
'\t\thas: fail,',
|
|
278
|
-
'\t\tisExtensible: fail,',
|
|
279
|
-
'\t\townKeys: fail,',
|
|
280
|
-
'\t\tpreventExtensions: fail,',
|
|
281
|
-
'\t\tset: fail,',
|
|
282
|
-
'\t\tsetPrototypeOf: fail,',
|
|
283
|
-
'\t});',
|
|
284
|
-
'}',
|
|
285
|
-
];
|
|
286
|
-
for (let index = 0; index < exports.length; index++) {
|
|
287
|
-
lines.push(
|
|
288
|
-
`const __octaneClientOnlyExport${index} = __octaneClientOnlyExport(${JSON.stringify(exports[index])});`,
|
|
289
|
-
);
|
|
340
|
+
const exportEntries = collectRuntimeExports(ast, filename);
|
|
341
|
+
const exports = exportEntries.map((entry) => entry.name);
|
|
342
|
+
if (exportEntries.length === 0) {
|
|
343
|
+
return printClientOnlyServerStub(createProgram([], ast), source, filename, exports);
|
|
290
344
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
345
|
+
const message = b.template(
|
|
346
|
+
[
|
|
347
|
+
b.quasi('Client-only export '),
|
|
348
|
+
b.quasi(' from '),
|
|
349
|
+
b.quasi(' (renderer '),
|
|
350
|
+
b.quasi(') was used by the server graph.', true),
|
|
351
|
+
],
|
|
352
|
+
[
|
|
353
|
+
jsonStringifyCall(b.id('name')),
|
|
354
|
+
jsonStringifyCall(b.id('__octaneClientOnlyModule')),
|
|
355
|
+
jsonStringifyCall(b.id('__octaneClientOnlyRenderer')),
|
|
356
|
+
],
|
|
357
|
+
);
|
|
358
|
+
const fail = b.arrow(
|
|
359
|
+
[],
|
|
360
|
+
b.block([
|
|
361
|
+
b.const('error', b.new('Error', undefined, message)),
|
|
362
|
+
b.stmt(
|
|
363
|
+
b.assignment(
|
|
364
|
+
'=',
|
|
365
|
+
b.member(b.id('error'), 'code'),
|
|
366
|
+
b.literal('OCTANE_CLIENT_ONLY_SERVER_USE'),
|
|
367
|
+
),
|
|
368
|
+
),
|
|
369
|
+
b.stmt(
|
|
370
|
+
b.assignment('=', b.member(b.id('error'), 'filename'), b.id('__octaneClientOnlyModule')),
|
|
371
|
+
),
|
|
372
|
+
{ type: 'ThrowStatement', argument: b.id('error'), metadata: { path: [] } },
|
|
373
|
+
]),
|
|
374
|
+
);
|
|
375
|
+
const traps = [
|
|
376
|
+
'apply',
|
|
377
|
+
'construct',
|
|
378
|
+
'defineProperty',
|
|
379
|
+
'deleteProperty',
|
|
380
|
+
'get',
|
|
381
|
+
'getOwnPropertyDescriptor',
|
|
382
|
+
'getPrototypeOf',
|
|
383
|
+
'has',
|
|
384
|
+
'isExtensible',
|
|
385
|
+
'ownKeys',
|
|
386
|
+
'preventExtensions',
|
|
387
|
+
'set',
|
|
388
|
+
'setPrototypeOf',
|
|
389
|
+
];
|
|
390
|
+
const body = [
|
|
391
|
+
b.const('__octaneClientOnlyModule', b.literal(filename)),
|
|
392
|
+
b.const('__octaneClientOnlyRenderer', b.literal(renderer)),
|
|
393
|
+
b.function_declaration(
|
|
394
|
+
b.id('__octaneClientOnlyExport'),
|
|
395
|
+
[b.id('name')],
|
|
396
|
+
b.block([
|
|
397
|
+
b.const('fail', fail),
|
|
398
|
+
b.return(
|
|
399
|
+
b.new(
|
|
400
|
+
'Proxy',
|
|
401
|
+
undefined,
|
|
402
|
+
b.id('fail'),
|
|
403
|
+
b.object(traps.map((name) => b.init(name, b.id('fail')))),
|
|
404
|
+
),
|
|
405
|
+
),
|
|
406
|
+
]),
|
|
407
|
+
),
|
|
408
|
+
];
|
|
409
|
+
for (let index = 0; index < exportEntries.length; index++) {
|
|
410
|
+
body.push(
|
|
411
|
+
inheritGeneratedOrigin(
|
|
412
|
+
b.const(
|
|
413
|
+
`__octaneClientOnlyExport${index}`,
|
|
414
|
+
b.call('__octaneClientOnlyExport', b.literal(exportEntries[index].name)),
|
|
415
|
+
),
|
|
416
|
+
exportEntries[index].origin,
|
|
417
|
+
),
|
|
297
418
|
);
|
|
298
419
|
}
|
|
299
|
-
|
|
420
|
+
const exportSpecifiers = exportEntries.map((entry, index) =>
|
|
421
|
+
inheritGeneratedOrigin(
|
|
422
|
+
b.export_specifier(
|
|
423
|
+
`__octaneClientOnlyExport${index}`,
|
|
424
|
+
/^[$A-Z_a-z][$\w]*$/u.test(entry.name) ? b.id(entry.name) : b.literal(entry.name),
|
|
425
|
+
),
|
|
426
|
+
entry.origin,
|
|
427
|
+
),
|
|
428
|
+
);
|
|
429
|
+
body.push(b.export(null, exportSpecifiers));
|
|
430
|
+
// A Program can end at column zero when the source has a trailing newline.
|
|
431
|
+
// Structural nodes need an authored syntax range whose end is a real token:
|
|
432
|
+
// esrap anchors a generated closing delimiter immediately before `loc.end`.
|
|
433
|
+
const scaffoldOrigin = exportEntries[0].origin;
|
|
434
|
+
const program = createProgram(body, scaffoldOrigin);
|
|
435
|
+
return printClientOnlyServerStub(program, source, filename, exports);
|
|
300
436
|
}
|
|
301
437
|
|
|
302
438
|
function bindingNames(pattern) {
|
|
@@ -371,10 +507,15 @@ function importedName(specifier) {
|
|
|
371
507
|
* rewrite. Side-effect imports and unused bindings are safe because their
|
|
372
508
|
* target compiles to a no-op stub.
|
|
373
509
|
*/
|
|
374
|
-
export function assertNoLiveClientOnlyImports(
|
|
510
|
+
export function assertNoLiveClientOnlyImports(
|
|
511
|
+
source,
|
|
512
|
+
filename,
|
|
513
|
+
clientOnlyImports = [],
|
|
514
|
+
parsedAst = null,
|
|
515
|
+
) {
|
|
375
516
|
if (!Array.isArray(clientOnlyImports) || clientOnlyImports.length === 0) return;
|
|
376
517
|
const byRequest = new Map(clientOnlyImports.map((entry) => [entry.request, entry]));
|
|
377
|
-
const ast = parseModule(source, filename);
|
|
518
|
+
const ast = parsedAst ?? parseModule(source, filename);
|
|
378
519
|
const imported = new Map();
|
|
379
520
|
|
|
380
521
|
for (const statement of ast.body ?? []) {
|