@tanstack/start-plugin-core 1.142.8 → 1.142.10
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/esm/create-server-fn-plugin/compiler.d.ts +8 -5
- package/dist/esm/create-server-fn-plugin/compiler.js +108 -43
- package/dist/esm/create-server-fn-plugin/compiler.js.map +1 -1
- package/dist/esm/create-server-fn-plugin/handleCreateIsomorphicFn.d.ts +4 -0
- package/dist/esm/create-server-fn-plugin/handleCreateIsomorphicFn.js +31 -0
- package/dist/esm/create-server-fn-plugin/handleCreateIsomorphicFn.js.map +1 -0
- package/dist/esm/create-server-fn-plugin/handleCreateServerFn.js +1 -1
- package/dist/esm/create-server-fn-plugin/handleCreateServerFn.js.map +1 -1
- package/dist/esm/create-server-fn-plugin/handleEnvOnly.d.ts +6 -0
- package/dist/esm/create-server-fn-plugin/handleEnvOnly.js +36 -0
- package/dist/esm/create-server-fn-plugin/handleEnvOnly.js.map +1 -0
- package/dist/esm/create-server-fn-plugin/plugin.d.ts +1 -1
- package/dist/esm/create-server-fn-plugin/plugin.js +50 -12
- package/dist/esm/create-server-fn-plugin/plugin.js.map +1 -1
- package/dist/esm/create-server-fn-plugin/types.d.ts +0 -1
- package/dist/esm/{start-compiler-plugin → create-server-fn-plugin}/utils.d.ts +0 -3
- package/dist/esm/create-server-fn-plugin/utils.js +19 -0
- package/dist/esm/create-server-fn-plugin/utils.js.map +1 -0
- package/dist/esm/plugin.d.ts +2 -30
- package/dist/esm/plugin.js +2 -2
- package/dist/esm/plugin.js.map +1 -1
- package/dist/esm/schema.d.ts +288 -288
- package/dist/esm/schema.js.map +1 -1
- package/dist/esm/start-manifest-plugin/plugin.d.ts +1 -1
- package/dist/esm/start-manifest-plugin/plugin.js.map +1 -1
- package/dist/esm/start-router-plugin/plugin.d.ts +1 -1
- package/dist/esm/start-router-plugin/plugin.js.map +1 -1
- package/dist/esm/types.d.ts +30 -0
- package/package.json +6 -6
- package/src/create-server-fn-plugin/compiler.ts +164 -58
- package/src/create-server-fn-plugin/handleCreateIsomorphicFn.ts +46 -0
- package/src/create-server-fn-plugin/handleCreateServerFn.ts +1 -1
- package/src/create-server-fn-plugin/handleEnvOnly.ts +45 -0
- package/src/create-server-fn-plugin/plugin.ts +58 -14
- package/src/create-server-fn-plugin/types.ts +0 -8
- package/src/create-server-fn-plugin/utils.ts +24 -0
- package/src/plugin.ts +7 -34
- package/src/schema.ts +1 -1
- package/src/start-manifest-plugin/plugin.ts +1 -1
- package/src/start-router-plugin/plugin.ts +1 -1
- package/src/types.ts +34 -0
- package/dist/esm/start-compiler-plugin/compilers.d.ts +0 -15
- package/dist/esm/start-compiler-plugin/compilers.js +0 -114
- package/dist/esm/start-compiler-plugin/compilers.js.map +0 -1
- package/dist/esm/start-compiler-plugin/constants.d.ts +0 -1
- package/dist/esm/start-compiler-plugin/constants.js +0 -9
- package/dist/esm/start-compiler-plugin/constants.js.map +0 -1
- package/dist/esm/start-compiler-plugin/envOnly.d.ts +0 -5
- package/dist/esm/start-compiler-plugin/envOnly.js +0 -41
- package/dist/esm/start-compiler-plugin/envOnly.js.map +0 -1
- package/dist/esm/start-compiler-plugin/isomorphicFn.d.ts +0 -4
- package/dist/esm/start-compiler-plugin/isomorphicFn.js +0 -49
- package/dist/esm/start-compiler-plugin/isomorphicFn.js.map +0 -1
- package/dist/esm/start-compiler-plugin/plugin.d.ts +0 -12
- package/dist/esm/start-compiler-plugin/plugin.js +0 -88
- package/dist/esm/start-compiler-plugin/plugin.js.map +0 -1
- package/dist/esm/start-compiler-plugin/utils.js +0 -30
- package/dist/esm/start-compiler-plugin/utils.js.map +0 -1
- package/src/start-compiler-plugin/compilers.ts +0 -176
- package/src/start-compiler-plugin/constants.ts +0 -5
- package/src/start-compiler-plugin/envOnly.ts +0 -58
- package/src/start-compiler-plugin/isomorphicFn.ts +0 -78
- package/src/start-compiler-plugin/plugin.ts +0 -111
- package/src/start-compiler-plugin/utils.ts +0 -41
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { parseAst } from '@tanstack/router-utils';
|
|
2
1
|
import * as t from '@babel/types';
|
|
3
2
|
type Binding = {
|
|
4
3
|
type: 'import';
|
|
@@ -22,15 +21,14 @@ type ExportEntry = {
|
|
|
22
21
|
targetId: string;
|
|
23
22
|
};
|
|
24
23
|
type Kind = 'None' | `Root` | `Builder` | LookupKind;
|
|
25
|
-
export type LookupKind = 'ServerFn' | 'Middleware';
|
|
24
|
+
export type LookupKind = 'ServerFn' | 'Middleware' | 'IsomorphicFn' | 'ServerOnlyFn' | 'ClientOnlyFn';
|
|
26
25
|
export type LookupConfig = {
|
|
27
26
|
libName: string;
|
|
28
27
|
rootExport: string;
|
|
28
|
+
kind: LookupKind | 'Root';
|
|
29
29
|
};
|
|
30
30
|
interface ModuleInfo {
|
|
31
31
|
id: string;
|
|
32
|
-
code: string;
|
|
33
|
-
ast: ReturnType<typeof parseAst>;
|
|
34
32
|
bindings: Map<string, Binding>;
|
|
35
33
|
exports: Map<string, ExportEntry>;
|
|
36
34
|
reExportAllSources: Array<string>;
|
|
@@ -40,6 +38,8 @@ export declare class ServerFnCompiler {
|
|
|
40
38
|
private moduleCache;
|
|
41
39
|
private initialized;
|
|
42
40
|
private validLookupKinds;
|
|
41
|
+
private hasDirectCallKinds;
|
|
42
|
+
private hasRootAsCandidateKinds;
|
|
43
43
|
private knownRootImports;
|
|
44
44
|
constructor(options: {
|
|
45
45
|
env: 'client' | 'server';
|
|
@@ -53,7 +53,10 @@ export declare class ServerFnCompiler {
|
|
|
53
53
|
ingestModule({ code, id }: {
|
|
54
54
|
code: string;
|
|
55
55
|
id: string;
|
|
56
|
-
}):
|
|
56
|
+
}): {
|
|
57
|
+
info: ModuleInfo;
|
|
58
|
+
ast: import('@tanstack/router-utils').ParseAstResult;
|
|
59
|
+
};
|
|
57
60
|
invalidateModule(id: string): boolean;
|
|
58
61
|
compile({ code, id, isProviderFile, }: {
|
|
59
62
|
code: string;
|
|
@@ -1,47 +1,93 @@
|
|
|
1
1
|
import * as t from "@babel/types";
|
|
2
2
|
import { parseAst, generateFromAst } from "@tanstack/router-utils";
|
|
3
|
-
import
|
|
3
|
+
import babel from "@babel/core";
|
|
4
4
|
import { findReferencedIdentifiers, deadCodeElimination } from "babel-dead-code-elimination";
|
|
5
5
|
import { handleCreateServerFn } from "./handleCreateServerFn.js";
|
|
6
6
|
import { handleCreateMiddleware } from "./handleCreateMiddleware.js";
|
|
7
|
+
import { handleCreateIsomorphicFn } from "./handleCreateIsomorphicFn.js";
|
|
8
|
+
import { handleEnvOnlyFn } from "./handleEnvOnly.js";
|
|
7
9
|
const LookupSetup = {
|
|
8
|
-
ServerFn: {
|
|
10
|
+
ServerFn: {
|
|
11
|
+
type: "methodChain",
|
|
12
|
+
candidateCallIdentifier: /* @__PURE__ */ new Set(["handler"])
|
|
13
|
+
},
|
|
9
14
|
Middleware: {
|
|
15
|
+
type: "methodChain",
|
|
10
16
|
candidateCallIdentifier: /* @__PURE__ */ new Set(["server", "client", "createMiddlewares"])
|
|
11
|
-
}
|
|
17
|
+
},
|
|
18
|
+
IsomorphicFn: {
|
|
19
|
+
type: "methodChain",
|
|
20
|
+
candidateCallIdentifier: /* @__PURE__ */ new Set(["server", "client"]),
|
|
21
|
+
allowRootAsCandidate: true
|
|
22
|
+
// createIsomorphicFn() alone is valid (returns no-op)
|
|
23
|
+
},
|
|
24
|
+
ServerOnlyFn: { type: "directCall" },
|
|
25
|
+
ClientOnlyFn: { type: "directCall" }
|
|
12
26
|
};
|
|
13
|
-
const
|
|
27
|
+
const IdentifierToKinds = /* @__PURE__ */ new Map();
|
|
14
28
|
for (const [kind, setup] of Object.entries(LookupSetup)) {
|
|
15
|
-
|
|
16
|
-
|
|
29
|
+
if (setup.type === "methodChain") {
|
|
30
|
+
for (const id of setup.candidateCallIdentifier) {
|
|
31
|
+
let kinds = IdentifierToKinds.get(id);
|
|
32
|
+
if (!kinds) {
|
|
33
|
+
kinds = /* @__PURE__ */ new Set();
|
|
34
|
+
IdentifierToKinds.set(id, kinds);
|
|
35
|
+
}
|
|
36
|
+
kinds.add(kind);
|
|
37
|
+
}
|
|
17
38
|
}
|
|
18
39
|
}
|
|
19
40
|
class ServerFnCompiler {
|
|
20
41
|
constructor(options) {
|
|
21
42
|
this.options = options;
|
|
22
43
|
this.validLookupKinds = options.lookupKinds;
|
|
44
|
+
this.hasDirectCallKinds = false;
|
|
45
|
+
this.hasRootAsCandidateKinds = false;
|
|
46
|
+
for (const kind of options.lookupKinds) {
|
|
47
|
+
const setup = LookupSetup[kind];
|
|
48
|
+
if (setup.type === "directCall") {
|
|
49
|
+
this.hasDirectCallKinds = true;
|
|
50
|
+
} else if (setup.allowRootAsCandidate) {
|
|
51
|
+
this.hasRootAsCandidateKinds = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
23
54
|
}
|
|
24
55
|
moduleCache = /* @__PURE__ */ new Map();
|
|
25
56
|
initialized = false;
|
|
26
57
|
validLookupKinds;
|
|
58
|
+
// Precomputed flags for candidate detection (avoid recomputing on each collectCandidates call)
|
|
59
|
+
hasDirectCallKinds;
|
|
60
|
+
hasRootAsCandidateKinds;
|
|
27
61
|
// Fast lookup for direct imports from known libraries (e.g., '@tanstack/react-start')
|
|
28
62
|
// Maps: libName → (exportName → Kind)
|
|
29
63
|
// This allows O(1) resolution for the common case without async resolveId calls
|
|
30
64
|
knownRootImports = /* @__PURE__ */ new Map();
|
|
31
|
-
async init(
|
|
65
|
+
async init() {
|
|
66
|
+
this.knownRootImports.set(
|
|
67
|
+
"@tanstack/start-fn-stubs",
|
|
68
|
+
/* @__PURE__ */ new Map([
|
|
69
|
+
["createIsomorphicFn", "IsomorphicFn"],
|
|
70
|
+
["createServerOnlyFn", "ServerOnlyFn"],
|
|
71
|
+
["createClientOnlyFn", "ClientOnlyFn"]
|
|
72
|
+
])
|
|
73
|
+
);
|
|
32
74
|
await Promise.all(
|
|
33
75
|
this.options.lookupConfigurations.map(async (config) => {
|
|
34
|
-
|
|
76
|
+
let libExports = this.knownRootImports.get(config.libName);
|
|
77
|
+
if (!libExports) {
|
|
78
|
+
libExports = /* @__PURE__ */ new Map();
|
|
79
|
+
this.knownRootImports.set(config.libName, libExports);
|
|
80
|
+
}
|
|
81
|
+
libExports.set(config.rootExport, config.kind);
|
|
82
|
+
const libId = await this.options.resolveId(config.libName);
|
|
35
83
|
if (!libId) {
|
|
36
84
|
throw new Error(`could not resolve "${config.libName}"`);
|
|
37
85
|
}
|
|
38
86
|
let rootModule = this.moduleCache.get(libId);
|
|
39
87
|
if (!rootModule) {
|
|
40
88
|
rootModule = {
|
|
41
|
-
ast: null,
|
|
42
89
|
bindings: /* @__PURE__ */ new Map(),
|
|
43
90
|
exports: /* @__PURE__ */ new Map(),
|
|
44
|
-
code: "",
|
|
45
91
|
id: libId,
|
|
46
92
|
reExportAllSources: []
|
|
47
93
|
};
|
|
@@ -58,16 +104,11 @@ class ServerFnCompiler {
|
|
|
58
104
|
});
|
|
59
105
|
rootModule.bindings.set(config.rootExport, {
|
|
60
106
|
type: "var",
|
|
61
|
-
init:
|
|
62
|
-
resolvedKind
|
|
107
|
+
init: null,
|
|
108
|
+
// Not needed since resolvedKind is set
|
|
109
|
+
resolvedKind: config.kind
|
|
63
110
|
});
|
|
64
111
|
this.moduleCache.set(libId, rootModule);
|
|
65
|
-
let libExports = this.knownRootImports.get(config.libName);
|
|
66
|
-
if (!libExports) {
|
|
67
|
-
libExports = /* @__PURE__ */ new Map();
|
|
68
|
-
this.knownRootImports.set(config.libName, libExports);
|
|
69
|
-
}
|
|
70
|
-
libExports.set(config.rootExport, "Root");
|
|
71
112
|
})
|
|
72
113
|
);
|
|
73
114
|
this.initialized = true;
|
|
@@ -152,15 +193,13 @@ class ServerFnCompiler {
|
|
|
152
193
|
}
|
|
153
194
|
}
|
|
154
195
|
const info = {
|
|
155
|
-
code,
|
|
156
196
|
id,
|
|
157
|
-
ast,
|
|
158
197
|
bindings,
|
|
159
198
|
exports,
|
|
160
199
|
reExportAllSources
|
|
161
200
|
};
|
|
162
201
|
this.moduleCache.set(id, info);
|
|
163
|
-
return info;
|
|
202
|
+
return { info, ast };
|
|
164
203
|
}
|
|
165
204
|
invalidateModule(id) {
|
|
166
205
|
return this.moduleCache.delete(id);
|
|
@@ -171,10 +210,10 @@ class ServerFnCompiler {
|
|
|
171
210
|
isProviderFile
|
|
172
211
|
}) {
|
|
173
212
|
if (!this.initialized) {
|
|
174
|
-
await this.init(
|
|
213
|
+
await this.init();
|
|
175
214
|
}
|
|
176
|
-
const {
|
|
177
|
-
const candidates = this.collectCandidates(bindings);
|
|
215
|
+
const { info, ast } = this.ingestModule({ code, id });
|
|
216
|
+
const candidates = this.collectCandidates(info.bindings);
|
|
178
217
|
if (candidates.length === 0) {
|
|
179
218
|
return null;
|
|
180
219
|
}
|
|
@@ -195,7 +234,7 @@ class ServerFnCompiler {
|
|
|
195
234
|
}
|
|
196
235
|
const pathsToRewrite = [];
|
|
197
236
|
const callExprPaths = /* @__PURE__ */ new Map();
|
|
198
|
-
|
|
237
|
+
babel.traverse(ast, {
|
|
199
238
|
CallExpression(path) {
|
|
200
239
|
callExprPaths.set(path.node, path);
|
|
201
240
|
}
|
|
@@ -252,10 +291,19 @@ class ServerFnCompiler {
|
|
|
252
291
|
directive: this.options.directive,
|
|
253
292
|
isProviderFile
|
|
254
293
|
});
|
|
255
|
-
} else {
|
|
294
|
+
} else if (kind === "Middleware") {
|
|
256
295
|
handleCreateMiddleware(candidate, {
|
|
257
296
|
env: this.options.env
|
|
258
297
|
});
|
|
298
|
+
} else if (kind === "IsomorphicFn") {
|
|
299
|
+
handleCreateIsomorphicFn(candidate, {
|
|
300
|
+
env: this.options.env
|
|
301
|
+
});
|
|
302
|
+
} else {
|
|
303
|
+
handleEnvOnlyFn(candidate, {
|
|
304
|
+
env: this.options.env,
|
|
305
|
+
kind
|
|
306
|
+
});
|
|
259
307
|
}
|
|
260
308
|
}
|
|
261
309
|
deadCodeElimination(ast, refIdents);
|
|
@@ -269,13 +317,19 @@ class ServerFnCompiler {
|
|
|
269
317
|
collectCandidates(bindings) {
|
|
270
318
|
const candidates = [];
|
|
271
319
|
for (const binding of bindings.values()) {
|
|
272
|
-
if (binding.type === "var") {
|
|
273
|
-
const
|
|
320
|
+
if (binding.type === "var" && t.isCallExpression(binding.init)) {
|
|
321
|
+
const methodChainCandidate = isCandidateCallExpression(
|
|
274
322
|
binding.init,
|
|
275
323
|
this.validLookupKinds
|
|
276
324
|
);
|
|
277
|
-
if (
|
|
278
|
-
candidates.push(
|
|
325
|
+
if (methodChainCandidate) {
|
|
326
|
+
candidates.push(methodChainCandidate);
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (this.hasDirectCallKinds || this.hasRootAsCandidateKinds) {
|
|
330
|
+
if (t.isIdentifier(binding.init.callee) || t.isMemberExpression(binding.init.callee) && t.isIdentifier(binding.init.callee.property)) {
|
|
331
|
+
candidates.push(binding.init);
|
|
332
|
+
}
|
|
279
333
|
}
|
|
280
334
|
}
|
|
281
335
|
}
|
|
@@ -423,18 +477,25 @@ class ServerFnCompiler {
|
|
|
423
477
|
}
|
|
424
478
|
if (t.isMemberExpression(callee) && t.isIdentifier(callee.property)) {
|
|
425
479
|
const prop = callee.property.name;
|
|
426
|
-
|
|
480
|
+
const possibleKinds = IdentifierToKinds.get(prop);
|
|
481
|
+
if (possibleKinds) {
|
|
427
482
|
const base = await this.resolveExprKind(callee.object, fileId, visited);
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
483
|
+
for (const kind of possibleKinds) {
|
|
484
|
+
if (!this.validLookupKinds.has(kind)) continue;
|
|
485
|
+
if (kind === "ServerFn") {
|
|
486
|
+
if (base === "Root" || base === "Builder") {
|
|
487
|
+
return "ServerFn";
|
|
488
|
+
}
|
|
489
|
+
} else if (kind === "Middleware") {
|
|
490
|
+
if (base === "Root" || base === "Builder" || base === "Middleware") {
|
|
491
|
+
return "Middleware";
|
|
492
|
+
}
|
|
493
|
+
} else if (kind === "IsomorphicFn") {
|
|
494
|
+
if (base === "Root" || base === "Builder" || base === "IsomorphicFn") {
|
|
495
|
+
return "IsomorphicFn";
|
|
496
|
+
}
|
|
497
|
+
}
|
|
436
498
|
}
|
|
437
|
-
return "None";
|
|
438
499
|
}
|
|
439
500
|
if (t.isIdentifier(callee.object)) {
|
|
440
501
|
const info = await this.getModuleInfo(fileId);
|
|
@@ -487,9 +548,13 @@ function isCandidateCallExpression(node, lookupKinds) {
|
|
|
487
548
|
if (!t.isMemberExpression(callee) || !t.isIdentifier(callee.property)) {
|
|
488
549
|
return void 0;
|
|
489
550
|
}
|
|
490
|
-
const
|
|
491
|
-
if (
|
|
492
|
-
|
|
551
|
+
const possibleKinds = IdentifierToKinds.get(callee.property.name);
|
|
552
|
+
if (possibleKinds) {
|
|
553
|
+
for (const kind of possibleKinds) {
|
|
554
|
+
if (lookupKinds.has(kind)) {
|
|
555
|
+
return node;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
493
558
|
}
|
|
494
559
|
return void 0;
|
|
495
560
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.js","sources":["../../../src/create-server-fn-plugin/compiler.ts"],"sourcesContent":["/* eslint-disable import/no-commonjs */\nimport * as t from '@babel/types'\nimport { generateFromAst, parseAst } from '@tanstack/router-utils'\nimport babel from '@babel/core'\nimport {\n deadCodeElimination,\n findReferencedIdentifiers,\n} from 'babel-dead-code-elimination'\nimport { handleCreateServerFn } from './handleCreateServerFn'\nimport { handleCreateMiddleware } from './handleCreateMiddleware'\nimport type { MethodChainPaths, RewriteCandidate } from './types'\n\ntype Binding =\n | {\n type: 'import'\n source: string\n importedName: string\n resolvedKind?: Kind\n }\n | {\n type: 'var'\n init: t.Expression | null\n resolvedKind?: Kind\n }\n\ntype ExportEntry =\n | { tag: 'Normal'; name: string }\n | { tag: 'Default'; name: string }\n | { tag: 'Namespace'; name: string; targetId: string } // for `export * as ns from './x'`\n\ntype Kind = 'None' | `Root` | `Builder` | LookupKind\n\nexport type LookupKind = 'ServerFn' | 'Middleware'\n\nconst LookupSetup: Record<\n LookupKind,\n { candidateCallIdentifier: Set<string> }\n> = {\n ServerFn: { candidateCallIdentifier: new Set(['handler']) },\n Middleware: {\n candidateCallIdentifier: new Set(['server', 'client', 'createMiddlewares']),\n },\n}\n\n// Pre-computed map: identifier name -> LookupKind for fast candidate detection\nconst IdentifierToKind = new Map<string, LookupKind>()\nfor (const [kind, setup] of Object.entries(LookupSetup) as Array<\n [LookupKind, { candidateCallIdentifier: Set<string> }]\n>) {\n for (const id of setup.candidateCallIdentifier) {\n IdentifierToKind.set(id, kind)\n }\n}\n\nexport type LookupConfig = {\n libName: string\n rootExport: string\n}\ninterface ModuleInfo {\n id: string\n code: string\n ast: ReturnType<typeof parseAst>\n bindings: Map<string, Binding>\n exports: Map<string, ExportEntry>\n // Track `export * from './module'` declarations for re-export resolution\n reExportAllSources: Array<string>\n}\n\nexport class ServerFnCompiler {\n private moduleCache = new Map<string, ModuleInfo>()\n private initialized = false\n private validLookupKinds: Set<LookupKind>\n // Fast lookup for direct imports from known libraries (e.g., '@tanstack/react-start')\n // Maps: libName → (exportName → Kind)\n // This allows O(1) resolution for the common case without async resolveId calls\n private knownRootImports = new Map<string, Map<string, Kind>>()\n constructor(\n private options: {\n env: 'client' | 'server'\n directive: string\n lookupConfigurations: Array<LookupConfig>\n lookupKinds: Set<LookupKind>\n loadModule: (id: string) => Promise<void>\n resolveId: (id: string, importer?: string) => Promise<string | null>\n },\n ) {\n this.validLookupKinds = options.lookupKinds\n }\n\n private async init(id: string) {\n await Promise.all(\n this.options.lookupConfigurations.map(async (config) => {\n const libId = await this.options.resolveId(config.libName, id)\n if (!libId) {\n throw new Error(`could not resolve \"${config.libName}\"`)\n }\n let rootModule = this.moduleCache.get(libId)\n if (!rootModule) {\n // insert root binding\n rootModule = {\n ast: null as any,\n bindings: new Map(),\n exports: new Map(),\n code: '',\n id: libId,\n reExportAllSources: [],\n }\n this.moduleCache.set(libId, rootModule)\n }\n\n rootModule.exports.set(config.rootExport, {\n tag: 'Normal',\n name: config.rootExport,\n })\n rootModule.exports.set('*', {\n tag: 'Namespace',\n name: config.rootExport,\n targetId: libId,\n })\n rootModule.bindings.set(config.rootExport, {\n type: 'var',\n init: t.identifier(config.rootExport),\n resolvedKind: `Root` satisfies Kind,\n })\n this.moduleCache.set(libId, rootModule)\n\n // Also populate the fast lookup map for direct imports\n let libExports = this.knownRootImports.get(config.libName)\n if (!libExports) {\n libExports = new Map()\n this.knownRootImports.set(config.libName, libExports)\n }\n libExports.set(config.rootExport, 'Root')\n }),\n )\n\n this.initialized = true\n }\n\n public ingestModule({ code, id }: { code: string; id: string }) {\n const ast = parseAst({ code })\n\n const bindings = new Map<string, Binding>()\n const exports = new Map<string, ExportEntry>()\n const reExportAllSources: Array<string> = []\n\n // we are only interested in top-level bindings, hence we don't traverse the AST\n // instead we only iterate over the program body\n for (const node of ast.program.body) {\n if (t.isImportDeclaration(node)) {\n const source = node.source.value\n for (const s of node.specifiers) {\n if (t.isImportSpecifier(s)) {\n const importedName = t.isIdentifier(s.imported)\n ? s.imported.name\n : s.imported.value\n bindings.set(s.local.name, { type: 'import', source, importedName })\n } else if (t.isImportDefaultSpecifier(s)) {\n bindings.set(s.local.name, {\n type: 'import',\n source,\n importedName: 'default',\n })\n } else if (t.isImportNamespaceSpecifier(s)) {\n bindings.set(s.local.name, {\n type: 'import',\n source,\n importedName: '*',\n })\n }\n }\n } else if (t.isVariableDeclaration(node)) {\n for (const decl of node.declarations) {\n if (t.isIdentifier(decl.id)) {\n bindings.set(decl.id.name, {\n type: 'var',\n init: decl.init ?? null,\n })\n }\n }\n } else if (t.isExportNamedDeclaration(node)) {\n // export const foo = ...\n if (node.declaration) {\n if (t.isVariableDeclaration(node.declaration)) {\n for (const d of node.declaration.declarations) {\n if (t.isIdentifier(d.id)) {\n exports.set(d.id.name, { tag: 'Normal', name: d.id.name })\n bindings.set(d.id.name, { type: 'var', init: d.init ?? null })\n }\n }\n }\n }\n for (const sp of node.specifiers) {\n if (t.isExportNamespaceSpecifier(sp)) {\n exports.set(sp.exported.name, {\n tag: 'Namespace',\n name: sp.exported.name,\n targetId: node.source?.value || '',\n })\n }\n // export { local as exported }\n else if (t.isExportSpecifier(sp)) {\n const local = sp.local.name\n const exported = t.isIdentifier(sp.exported)\n ? sp.exported.name\n : sp.exported.value\n exports.set(exported, { tag: 'Normal', name: local })\n\n // When re-exporting from another module (export { foo } from './module'),\n // create an import binding so the server function can be resolved\n if (node.source) {\n bindings.set(local, {\n type: 'import',\n source: node.source.value,\n importedName: local,\n })\n }\n }\n }\n } else if (t.isExportDefaultDeclaration(node)) {\n const d = node.declaration\n if (t.isIdentifier(d)) {\n exports.set('default', { tag: 'Default', name: d.name })\n } else {\n const synth = '__default_export__'\n bindings.set(synth, { type: 'var', init: d as t.Expression })\n exports.set('default', { tag: 'Default', name: synth })\n }\n } else if (t.isExportAllDeclaration(node)) {\n // Handle `export * from './module'` syntax\n // Track the source so we can look up exports from it when needed\n reExportAllSources.push(node.source.value)\n }\n }\n\n const info: ModuleInfo = {\n code,\n id,\n ast,\n bindings,\n exports,\n reExportAllSources,\n }\n this.moduleCache.set(id, info)\n return info\n }\n\n public invalidateModule(id: string) {\n return this.moduleCache.delete(id)\n }\n\n public async compile({\n code,\n id,\n isProviderFile,\n }: {\n code: string\n id: string\n isProviderFile: boolean\n }) {\n if (!this.initialized) {\n await this.init(id)\n }\n const { bindings, ast } = this.ingestModule({ code, id })\n const candidates = this.collectCandidates(bindings)\n if (candidates.length === 0) {\n // this hook will only be invoked if there is `.handler(` | `.server(` | `.client(` in the code,\n // so not discovering a handler candidate is rather unlikely, but maybe possible?\n return null\n }\n\n // let's find out which of the candidates are actually server functions\n // Resolve all candidates in parallel for better performance\n const resolvedCandidates = await Promise.all(\n candidates.map(async (candidate) => ({\n candidate,\n kind: await this.resolveExprKind(candidate, id),\n })),\n )\n\n // Map from candidate/root node -> kind\n // Note: For top-level variable declarations, candidate === root (the outermost CallExpression)\n const toRewriteMap = new Map<t.CallExpression, LookupKind>()\n for (const { candidate, kind } of resolvedCandidates) {\n if (this.validLookupKinds.has(kind as LookupKind)) {\n toRewriteMap.set(candidate, kind as LookupKind)\n }\n }\n if (toRewriteMap.size === 0) {\n return null\n }\n\n // Single-pass traversal to find NodePaths and collect method chains\n const pathsToRewrite: Array<{\n path: babel.NodePath<t.CallExpression>\n kind: LookupKind\n methodChain: MethodChainPaths\n }> = []\n\n // First, collect all CallExpression paths in the AST for O(1) lookup\n const callExprPaths = new Map<\n t.CallExpression,\n babel.NodePath<t.CallExpression>\n >()\n\n babel.traverse(ast, {\n CallExpression(path) {\n callExprPaths.set(path.node, path)\n },\n })\n\n // Now process candidates - we can look up any CallExpression path in O(1)\n for (const [node, kind] of toRewriteMap) {\n const path = callExprPaths.get(node)\n if (!path) {\n continue\n }\n\n // Collect method chain paths by walking DOWN from root through the chain\n const methodChain: MethodChainPaths = {\n middleware: null,\n inputValidator: null,\n handler: null,\n server: null,\n client: null,\n }\n\n // Walk down the call chain using nodes, look up paths from map\n let currentNode: t.CallExpression = node\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const callee = currentNode.callee\n if (!t.isMemberExpression(callee)) {\n break\n }\n\n // Record method chain path if it's a known method\n if (t.isIdentifier(callee.property)) {\n const name = callee.property.name as keyof MethodChainPaths\n if (name in methodChain) {\n const currentPath = callExprPaths.get(currentNode)!\n // Get first argument path\n const args = currentPath.get('arguments')\n const firstArgPath =\n Array.isArray(args) && args.length > 0 ? (args[0] ?? null) : null\n methodChain[name] = {\n callPath: currentPath,\n firstArgPath,\n }\n }\n }\n\n // Move to the inner call (the object of the member expression)\n if (!t.isCallExpression(callee.object)) {\n break\n }\n currentNode = callee.object\n }\n\n pathsToRewrite.push({ path, kind, methodChain })\n }\n\n // Verify we found all candidates (pathsToRewrite should have same size as toRewriteMap had)\n if (pathsToRewrite.length !== toRewriteMap.size) {\n throw new Error(\n `Internal error: could not find all paths to rewrite. please file an issue`,\n )\n }\n\n const refIdents = findReferencedIdentifiers(ast)\n\n for (const { path, kind, methodChain } of pathsToRewrite) {\n const candidate: RewriteCandidate = { path, methodChain }\n if (kind === 'ServerFn') {\n handleCreateServerFn(candidate, {\n env: this.options.env,\n code,\n directive: this.options.directive,\n isProviderFile,\n })\n } else {\n handleCreateMiddleware(candidate, {\n env: this.options.env,\n })\n }\n }\n\n deadCodeElimination(ast, refIdents)\n\n return generateFromAst(ast, {\n sourceMaps: true,\n sourceFileName: id,\n filename: id,\n })\n }\n\n // collects all candidate CallExpressions at top-level\n private collectCandidates(bindings: Map<string, Binding>) {\n const candidates: Array<t.CallExpression> = []\n\n for (const binding of bindings.values()) {\n if (binding.type === 'var') {\n const candidate = isCandidateCallExpression(\n binding.init,\n this.validLookupKinds,\n )\n if (candidate) {\n candidates.push(candidate)\n }\n }\n }\n return candidates\n }\n\n private async resolveIdentifierKind(\n ident: string,\n id: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n const info = await this.getModuleInfo(id)\n\n const binding = info.bindings.get(ident)\n if (!binding) {\n return 'None'\n }\n if (binding.resolvedKind) {\n return binding.resolvedKind\n }\n\n // TODO improve cycle detection? should we throw here instead of returning 'None'?\n // prevent cycles\n const vKey = `${id}:${ident}`\n if (visited.has(vKey)) {\n return 'None'\n }\n visited.add(vKey)\n\n const resolvedKind = await this.resolveBindingKind(binding, id, visited)\n binding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n /**\n * Recursively find an export in a module, following `export * from` chains.\n * Returns the module info and binding if found, or undefined if not found.\n */\n private async findExportInModule(\n moduleInfo: ModuleInfo,\n exportName: string,\n visitedModules = new Set<string>(),\n ): Promise<{ moduleInfo: ModuleInfo; binding: Binding } | undefined> {\n // Prevent infinite loops in circular re-exports\n if (visitedModules.has(moduleInfo.id)) {\n return undefined\n }\n visitedModules.add(moduleInfo.id)\n\n // First check direct exports\n const directExport = moduleInfo.exports.get(exportName)\n if (directExport) {\n const binding = moduleInfo.bindings.get(directExport.name)\n if (binding) {\n return { moduleInfo, binding }\n }\n }\n\n // If not found, recursively check re-export-all sources in parallel\n // Valid code won't have duplicate exports across chains, so first match wins\n if (moduleInfo.reExportAllSources.length > 0) {\n const results = await Promise.all(\n moduleInfo.reExportAllSources.map(async (reExportSource) => {\n const reExportTarget = await this.options.resolveId(\n reExportSource,\n moduleInfo.id,\n )\n if (reExportTarget) {\n const reExportModule = await this.getModuleInfo(reExportTarget)\n return this.findExportInModule(\n reExportModule,\n exportName,\n visitedModules,\n )\n }\n return undefined\n }),\n )\n // Return the first valid result\n for (const result of results) {\n if (result) {\n return result\n }\n }\n }\n\n return undefined\n }\n\n private async resolveBindingKind(\n binding: Binding,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (binding.resolvedKind) {\n return binding.resolvedKind\n }\n if (binding.type === 'import') {\n // Fast path: check if this is a direct import from a known library\n // (e.g., import { createServerFn } from '@tanstack/react-start')\n // This avoids async resolveId calls for the common case\n const knownExports = this.knownRootImports.get(binding.source)\n if (knownExports) {\n const kind = knownExports.get(binding.importedName)\n if (kind) {\n binding.resolvedKind = kind\n return kind\n }\n }\n\n // Slow path: resolve through the module graph\n const target = await this.options.resolveId(binding.source, fileId)\n if (!target) {\n return 'None'\n }\n\n const importedModule = await this.getModuleInfo(target)\n\n // Find the export, recursively searching through export * from chains\n const found = await this.findExportInModule(\n importedModule,\n binding.importedName,\n )\n\n if (!found) {\n return 'None'\n }\n\n const { moduleInfo: foundModule, binding: foundBinding } = found\n\n if (foundBinding.resolvedKind) {\n return foundBinding.resolvedKind\n }\n\n const resolvedKind = await this.resolveBindingKind(\n foundBinding,\n foundModule.id,\n visited,\n )\n foundBinding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n const resolvedKind = await this.resolveExprKind(\n binding.init,\n fileId,\n visited,\n )\n binding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n private async resolveExprKind(\n expr: t.Expression | null,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (!expr) {\n return 'None'\n }\n\n // Unwrap common TypeScript/parenthesized wrappers first for efficiency\n while (\n t.isTSAsExpression(expr) ||\n t.isTSNonNullExpression(expr) ||\n t.isParenthesizedExpression(expr)\n ) {\n expr = expr.expression\n }\n\n let result: Kind = 'None'\n\n if (t.isCallExpression(expr)) {\n if (!t.isExpression(expr.callee)) {\n return 'None'\n }\n const calleeKind = await this.resolveCalleeKind(\n expr.callee,\n fileId,\n visited,\n )\n if (calleeKind === 'Root' || calleeKind === 'Builder') {\n return 'Builder'\n }\n // Use direct Set.has() instead of iterating\n if (this.validLookupKinds.has(calleeKind as LookupKind)) {\n return calleeKind\n }\n } else if (t.isMemberExpression(expr) && t.isIdentifier(expr.property)) {\n result = await this.resolveCalleeKind(expr.object, fileId, visited)\n }\n\n if (result === 'None' && t.isIdentifier(expr)) {\n result = await this.resolveIdentifierKind(expr.name, fileId, visited)\n }\n\n return result\n }\n\n private async resolveCalleeKind(\n callee: t.Expression,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (t.isIdentifier(callee)) {\n return this.resolveIdentifierKind(callee.name, fileId, visited)\n }\n\n if (t.isMemberExpression(callee) && t.isIdentifier(callee.property)) {\n const prop = callee.property.name\n\n if (\n this.validLookupKinds.has('ServerFn') &&\n LookupSetup['ServerFn'].candidateCallIdentifier.has(prop)\n ) {\n const base = await this.resolveExprKind(callee.object, fileId, visited)\n if (base === 'Root' || base === 'Builder') {\n return 'ServerFn'\n }\n return 'None'\n } else if (\n this.validLookupKinds.has('Middleware') &&\n LookupSetup['Middleware'].candidateCallIdentifier.has(prop)\n ) {\n const base = await this.resolveExprKind(callee.object, fileId, visited)\n if (base === 'Root' || base === 'Builder' || base === 'Middleware') {\n return 'Middleware'\n }\n return 'None'\n }\n // Check if the object is a namespace import\n if (t.isIdentifier(callee.object)) {\n const info = await this.getModuleInfo(fileId)\n const binding = info.bindings.get(callee.object.name)\n if (\n binding &&\n binding.type === 'import' &&\n binding.importedName === '*'\n ) {\n // resolve the property from the target module\n const targetModuleId = await this.options.resolveId(\n binding.source,\n fileId,\n )\n if (targetModuleId) {\n const targetModule = await this.getModuleInfo(targetModuleId)\n const exportEntry = targetModule.exports.get(callee.property.name)\n if (exportEntry) {\n const exportedBinding = targetModule.bindings.get(\n exportEntry.name,\n )\n if (exportedBinding) {\n return await this.resolveBindingKind(\n exportedBinding,\n targetModule.id,\n visited,\n )\n }\n }\n } else {\n return 'None'\n }\n }\n }\n return this.resolveExprKind(callee.object, fileId, visited)\n }\n\n // handle nested expressions\n return this.resolveExprKind(callee, fileId, visited)\n }\n\n private async getModuleInfo(id: string) {\n let cached = this.moduleCache.get(id)\n if (cached) {\n return cached\n }\n\n await this.options.loadModule(id)\n\n cached = this.moduleCache.get(id)\n if (!cached) {\n throw new Error(`could not load module info for ${id}`)\n }\n return cached\n }\n}\n\nfunction isCandidateCallExpression(\n node: t.Node | null | undefined,\n lookupKinds: Set<LookupKind>,\n): t.CallExpression | undefined {\n if (!t.isCallExpression(node)) return undefined\n\n const callee = node.callee\n if (!t.isMemberExpression(callee) || !t.isIdentifier(callee.property)) {\n return undefined\n }\n\n // Use pre-computed map for O(1) lookup instead of iterating over lookupKinds\n const kind = IdentifierToKind.get(callee.property.name)\n if (kind && lookupKinds.has(kind)) {\n return node\n }\n\n return undefined\n}\n"],"names":["babel","resolvedKind"],"mappings":";;;;;;AAkCA,MAAM,cAGF;AAAA,EACF,UAAU,EAAE,yBAAyB,oBAAI,IAAI,CAAC,SAAS,CAAC,EAAA;AAAA,EACxD,YAAY;AAAA,IACV,yBAAyB,oBAAI,IAAI,CAAC,UAAU,UAAU,mBAAmB,CAAC;AAAA,EAAA;AAE9E;AAGA,MAAM,uCAAuB,IAAA;AAC7B,WAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,WAAW,GAEnD;AACD,aAAW,MAAM,MAAM,yBAAyB;AAC9C,qBAAiB,IAAI,IAAI,IAAI;AAAA,EAC/B;AACF;AAgBO,MAAM,iBAAiB;AAAA,EAQ5B,YACU,SAQR;AARQ,SAAA,UAAA;AASR,SAAK,mBAAmB,QAAQ;AAAA,EAClC;AAAA,EAlBQ,kCAAkB,IAAA;AAAA,EAClB,cAAc;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAIA,uCAAuB,IAAA;AAAA,EAc/B,MAAc,KAAK,IAAY;AAC7B,UAAM,QAAQ;AAAA,MACZ,KAAK,QAAQ,qBAAqB,IAAI,OAAO,WAAW;AACtD,cAAM,QAAQ,MAAM,KAAK,QAAQ,UAAU,OAAO,SAAS,EAAE;AAC7D,YAAI,CAAC,OAAO;AACV,gBAAM,IAAI,MAAM,sBAAsB,OAAO,OAAO,GAAG;AAAA,QACzD;AACA,YAAI,aAAa,KAAK,YAAY,IAAI,KAAK;AAC3C,YAAI,CAAC,YAAY;AAEf,uBAAa;AAAA,YACX,KAAK;AAAA,YACL,8BAAc,IAAA;AAAA,YACd,6BAAa,IAAA;AAAA,YACb,MAAM;AAAA,YACN,IAAI;AAAA,YACJ,oBAAoB,CAAA;AAAA,UAAC;AAEvB,eAAK,YAAY,IAAI,OAAO,UAAU;AAAA,QACxC;AAEA,mBAAW,QAAQ,IAAI,OAAO,YAAY;AAAA,UACxC,KAAK;AAAA,UACL,MAAM,OAAO;AAAA,QAAA,CACd;AACD,mBAAW,QAAQ,IAAI,KAAK;AAAA,UAC1B,KAAK;AAAA,UACL,MAAM,OAAO;AAAA,UACb,UAAU;AAAA,QAAA,CACX;AACD,mBAAW,SAAS,IAAI,OAAO,YAAY;AAAA,UACzC,MAAM;AAAA,UACN,MAAM,EAAE,WAAW,OAAO,UAAU;AAAA,UACpC,cAAc;AAAA,QAAA,CACf;AACD,aAAK,YAAY,IAAI,OAAO,UAAU;AAGtC,YAAI,aAAa,KAAK,iBAAiB,IAAI,OAAO,OAAO;AACzD,YAAI,CAAC,YAAY;AACf,2CAAiB,IAAA;AACjB,eAAK,iBAAiB,IAAI,OAAO,SAAS,UAAU;AAAA,QACtD;AACA,mBAAW,IAAI,OAAO,YAAY,MAAM;AAAA,MAC1C,CAAC;AAAA,IAAA;AAGH,SAAK,cAAc;AAAA,EACrB;AAAA,EAEO,aAAa,EAAE,MAAM,MAAoC;AAC9D,UAAM,MAAM,SAAS,EAAE,MAAM;AAE7B,UAAM,+BAAe,IAAA;AACrB,UAAM,8BAAc,IAAA;AACpB,UAAM,qBAAoC,CAAA;AAI1C,eAAW,QAAQ,IAAI,QAAQ,MAAM;AACnC,UAAI,EAAE,oBAAoB,IAAI,GAAG;AAC/B,cAAM,SAAS,KAAK,OAAO;AAC3B,mBAAW,KAAK,KAAK,YAAY;AAC/B,cAAI,EAAE,kBAAkB,CAAC,GAAG;AAC1B,kBAAM,eAAe,EAAE,aAAa,EAAE,QAAQ,IAC1C,EAAE,SAAS,OACX,EAAE,SAAS;AACf,qBAAS,IAAI,EAAE,MAAM,MAAM,EAAE,MAAM,UAAU,QAAQ,cAAc;AAAA,UACrE,WAAW,EAAE,yBAAyB,CAAC,GAAG;AACxC,qBAAS,IAAI,EAAE,MAAM,MAAM;AAAA,cACzB,MAAM;AAAA,cACN;AAAA,cACA,cAAc;AAAA,YAAA,CACf;AAAA,UACH,WAAW,EAAE,2BAA2B,CAAC,GAAG;AAC1C,qBAAS,IAAI,EAAE,MAAM,MAAM;AAAA,cACzB,MAAM;AAAA,cACN;AAAA,cACA,cAAc;AAAA,YAAA,CACf;AAAA,UACH;AAAA,QACF;AAAA,MACF,WAAW,EAAE,sBAAsB,IAAI,GAAG;AACxC,mBAAW,QAAQ,KAAK,cAAc;AACpC,cAAI,EAAE,aAAa,KAAK,EAAE,GAAG;AAC3B,qBAAS,IAAI,KAAK,GAAG,MAAM;AAAA,cACzB,MAAM;AAAA,cACN,MAAM,KAAK,QAAQ;AAAA,YAAA,CACpB;AAAA,UACH;AAAA,QACF;AAAA,MACF,WAAW,EAAE,yBAAyB,IAAI,GAAG;AAE3C,YAAI,KAAK,aAAa;AACpB,cAAI,EAAE,sBAAsB,KAAK,WAAW,GAAG;AAC7C,uBAAW,KAAK,KAAK,YAAY,cAAc;AAC7C,kBAAI,EAAE,aAAa,EAAE,EAAE,GAAG;AACxB,wBAAQ,IAAI,EAAE,GAAG,MAAM,EAAE,KAAK,UAAU,MAAM,EAAE,GAAG,KAAA,CAAM;AACzD,yBAAS,IAAI,EAAE,GAAG,MAAM,EAAE,MAAM,OAAO,MAAM,EAAE,QAAQ,KAAA,CAAM;AAAA,cAC/D;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,mBAAW,MAAM,KAAK,YAAY;AAChC,cAAI,EAAE,2BAA2B,EAAE,GAAG;AACpC,oBAAQ,IAAI,GAAG,SAAS,MAAM;AAAA,cAC5B,KAAK;AAAA,cACL,MAAM,GAAG,SAAS;AAAA,cAClB,UAAU,KAAK,QAAQ,SAAS;AAAA,YAAA,CACjC;AAAA,UACH,WAES,EAAE,kBAAkB,EAAE,GAAG;AAChC,kBAAM,QAAQ,GAAG,MAAM;AACvB,kBAAM,WAAW,EAAE,aAAa,GAAG,QAAQ,IACvC,GAAG,SAAS,OACZ,GAAG,SAAS;AAChB,oBAAQ,IAAI,UAAU,EAAE,KAAK,UAAU,MAAM,OAAO;AAIpD,gBAAI,KAAK,QAAQ;AACf,uBAAS,IAAI,OAAO;AAAA,gBAClB,MAAM;AAAA,gBACN,QAAQ,KAAK,OAAO;AAAA,gBACpB,cAAc;AAAA,cAAA,CACf;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF,WAAW,EAAE,2BAA2B,IAAI,GAAG;AAC7C,cAAM,IAAI,KAAK;AACf,YAAI,EAAE,aAAa,CAAC,GAAG;AACrB,kBAAQ,IAAI,WAAW,EAAE,KAAK,WAAW,MAAM,EAAE,MAAM;AAAA,QACzD,OAAO;AACL,gBAAM,QAAQ;AACd,mBAAS,IAAI,OAAO,EAAE,MAAM,OAAO,MAAM,GAAmB;AAC5D,kBAAQ,IAAI,WAAW,EAAE,KAAK,WAAW,MAAM,OAAO;AAAA,QACxD;AAAA,MACF,WAAW,EAAE,uBAAuB,IAAI,GAAG;AAGzC,2BAAmB,KAAK,KAAK,OAAO,KAAK;AAAA,MAC3C;AAAA,IACF;AAEA,UAAM,OAAmB;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAEF,SAAK,YAAY,IAAI,IAAI,IAAI;AAC7B,WAAO;AAAA,EACT;AAAA,EAEO,iBAAiB,IAAY;AAClC,WAAO,KAAK,YAAY,OAAO,EAAE;AAAA,EACnC;AAAA,EAEA,MAAa,QAAQ;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,EAAA,GAKC;AACD,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,KAAK,KAAK,EAAE;AAAA,IACpB;AACA,UAAM,EAAE,UAAU,QAAQ,KAAK,aAAa,EAAE,MAAM,IAAI;AACxD,UAAM,aAAa,KAAK,kBAAkB,QAAQ;AAClD,QAAI,WAAW,WAAW,GAAG;AAG3B,aAAO;AAAA,IACT;AAIA,UAAM,qBAAqB,MAAM,QAAQ;AAAA,MACvC,WAAW,IAAI,OAAO,eAAe;AAAA,QACnC;AAAA,QACA,MAAM,MAAM,KAAK,gBAAgB,WAAW,EAAE;AAAA,MAAA,EAC9C;AAAA,IAAA;AAKJ,UAAM,mCAAmB,IAAA;AACzB,eAAW,EAAE,WAAW,KAAA,KAAU,oBAAoB;AACpD,UAAI,KAAK,iBAAiB,IAAI,IAAkB,GAAG;AACjD,qBAAa,IAAI,WAAW,IAAkB;AAAA,MAChD;AAAA,IACF;AACA,QAAI,aAAa,SAAS,GAAG;AAC3B,aAAO;AAAA,IACT;AAGA,UAAM,iBAID,CAAA;AAGL,UAAM,oCAAoB,IAAA;AAK1BA,mBAAM,SAAS,KAAK;AAAA,MAClB,eAAe,MAAM;AACnB,sBAAc,IAAI,KAAK,MAAM,IAAI;AAAA,MACnC;AAAA,IAAA,CACD;AAGD,eAAW,CAAC,MAAM,IAAI,KAAK,cAAc;AACvC,YAAM,OAAO,cAAc,IAAI,IAAI;AACnC,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AAGA,YAAM,cAAgC;AAAA,QACpC,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,QAAQ;AAAA,MAAA;AAIV,UAAI,cAAgC;AAEpC,aAAO,MAAM;AACX,cAAM,SAAS,YAAY;AAC3B,YAAI,CAAC,EAAE,mBAAmB,MAAM,GAAG;AACjC;AAAA,QACF;AAGA,YAAI,EAAE,aAAa,OAAO,QAAQ,GAAG;AACnC,gBAAM,OAAO,OAAO,SAAS;AAC7B,cAAI,QAAQ,aAAa;AACvB,kBAAM,cAAc,cAAc,IAAI,WAAW;AAEjD,kBAAM,OAAO,YAAY,IAAI,WAAW;AACxC,kBAAM,eACJ,MAAM,QAAQ,IAAI,KAAK,KAAK,SAAS,IAAK,KAAK,CAAC,KAAK,OAAQ;AAC/D,wBAAY,IAAI,IAAI;AAAA,cAClB,UAAU;AAAA,cACV;AAAA,YAAA;AAAA,UAEJ;AAAA,QACF;AAGA,YAAI,CAAC,EAAE,iBAAiB,OAAO,MAAM,GAAG;AACtC;AAAA,QACF;AACA,sBAAc,OAAO;AAAA,MACvB;AAEA,qBAAe,KAAK,EAAE,MAAM,MAAM,aAAa;AAAA,IACjD;AAGA,QAAI,eAAe,WAAW,aAAa,MAAM;AAC/C,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAEA,UAAM,YAAY,0BAA0B,GAAG;AAE/C,eAAW,EAAE,MAAM,MAAM,YAAA,KAAiB,gBAAgB;AACxD,YAAM,YAA8B,EAAE,MAAM,YAAA;AAC5C,UAAI,SAAS,YAAY;AACvB,6BAAqB,WAAW;AAAA,UAC9B,KAAK,KAAK,QAAQ;AAAA,UAClB;AAAA,UACA,WAAW,KAAK,QAAQ;AAAA,UACxB;AAAA,QAAA,CACD;AAAA,MACH,OAAO;AACL,+BAAuB,WAAW;AAAA,UAChC,KAAK,KAAK,QAAQ;AAAA,QAAA,CACnB;AAAA,MACH;AAAA,IACF;AAEA,wBAAoB,KAAK,SAAS;AAElC,WAAO,gBAAgB,KAAK;AAAA,MAC1B,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,UAAU;AAAA,IAAA,CACX;AAAA,EACH;AAAA;AAAA,EAGQ,kBAAkB,UAAgC;AACxD,UAAM,aAAsC,CAAA;AAE5C,eAAW,WAAW,SAAS,UAAU;AACvC,UAAI,QAAQ,SAAS,OAAO;AAC1B,cAAM,YAAY;AAAA,UAChB,QAAQ;AAAA,UACR,KAAK;AAAA,QAAA;AAEP,YAAI,WAAW;AACb,qBAAW,KAAK,SAAS;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,sBACZ,OACA,IACA,UAAU,oBAAI,OACC;AACf,UAAM,OAAO,MAAM,KAAK,cAAc,EAAE;AAExC,UAAM,UAAU,KAAK,SAAS,IAAI,KAAK;AACvC,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,cAAc;AACxB,aAAO,QAAQ;AAAA,IACjB;AAIA,UAAM,OAAO,GAAG,EAAE,IAAI,KAAK;AAC3B,QAAI,QAAQ,IAAI,IAAI,GAAG;AACrB,aAAO;AAAA,IACT;AACA,YAAQ,IAAI,IAAI;AAEhB,UAAM,eAAe,MAAM,KAAK,mBAAmB,SAAS,IAAI,OAAO;AACvE,YAAQ,eAAe;AACvB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBACZ,YACA,YACA,iBAAiB,oBAAI,OAC8C;AAEnE,QAAI,eAAe,IAAI,WAAW,EAAE,GAAG;AACrC,aAAO;AAAA,IACT;AACA,mBAAe,IAAI,WAAW,EAAE;AAGhC,UAAM,eAAe,WAAW,QAAQ,IAAI,UAAU;AACtD,QAAI,cAAc;AAChB,YAAM,UAAU,WAAW,SAAS,IAAI,aAAa,IAAI;AACzD,UAAI,SAAS;AACX,eAAO,EAAE,YAAY,QAAA;AAAA,MACvB;AAAA,IACF;AAIA,QAAI,WAAW,mBAAmB,SAAS,GAAG;AAC5C,YAAM,UAAU,MAAM,QAAQ;AAAA,QAC5B,WAAW,mBAAmB,IAAI,OAAO,mBAAmB;AAC1D,gBAAM,iBAAiB,MAAM,KAAK,QAAQ;AAAA,YACxC;AAAA,YACA,WAAW;AAAA,UAAA;AAEb,cAAI,gBAAgB;AAClB,kBAAM,iBAAiB,MAAM,KAAK,cAAc,cAAc;AAC9D,mBAAO,KAAK;AAAA,cACV;AAAA,cACA;AAAA,cACA;AAAA,YAAA;AAAA,UAEJ;AACA,iBAAO;AAAA,QACT,CAAC;AAAA,MAAA;AAGH,iBAAW,UAAU,SAAS;AAC5B,YAAI,QAAQ;AACV,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,mBACZ,SACA,QACA,UAAU,oBAAI,OACC;AACf,QAAI,QAAQ,cAAc;AACxB,aAAO,QAAQ;AAAA,IACjB;AACA,QAAI,QAAQ,SAAS,UAAU;AAI7B,YAAM,eAAe,KAAK,iBAAiB,IAAI,QAAQ,MAAM;AAC7D,UAAI,cAAc;AAChB,cAAM,OAAO,aAAa,IAAI,QAAQ,YAAY;AAClD,YAAI,MAAM;AACR,kBAAQ,eAAe;AACvB,iBAAO;AAAA,QACT;AAAA,MACF;AAGA,YAAM,SAAS,MAAM,KAAK,QAAQ,UAAU,QAAQ,QAAQ,MAAM;AAClE,UAAI,CAAC,QAAQ;AACX,eAAO;AAAA,MACT;AAEA,YAAM,iBAAiB,MAAM,KAAK,cAAc,MAAM;AAGtD,YAAM,QAAQ,MAAM,KAAK;AAAA,QACvB;AAAA,QACA,QAAQ;AAAA,MAAA;AAGV,UAAI,CAAC,OAAO;AACV,eAAO;AAAA,MACT;AAEA,YAAM,EAAE,YAAY,aAAa,SAAS,iBAAiB;AAE3D,UAAI,aAAa,cAAc;AAC7B,eAAO,aAAa;AAAA,MACtB;AAEA,YAAMC,gBAAe,MAAM,KAAK;AAAA,QAC9B;AAAA,QACA,YAAY;AAAA,QACZ;AAAA,MAAA;AAEF,mBAAa,eAAeA;AAC5B,aAAOA;AAAAA,IACT;AAEA,UAAM,eAAe,MAAM,KAAK;AAAA,MAC9B,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IAAA;AAEF,YAAQ,eAAe;AACvB,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,gBACZ,MACA,QACA,UAAU,oBAAI,OACC;AACf,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,IACT;AAGA,WACE,EAAE,iBAAiB,IAAI,KACvB,EAAE,sBAAsB,IAAI,KAC5B,EAAE,0BAA0B,IAAI,GAChC;AACA,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,SAAe;AAEnB,QAAI,EAAE,iBAAiB,IAAI,GAAG;AAC5B,UAAI,CAAC,EAAE,aAAa,KAAK,MAAM,GAAG;AAChC,eAAO;AAAA,MACT;AACA,YAAM,aAAa,MAAM,KAAK;AAAA,QAC5B,KAAK;AAAA,QACL;AAAA,QACA;AAAA,MAAA;AAEF,UAAI,eAAe,UAAU,eAAe,WAAW;AACrD,eAAO;AAAA,MACT;AAEA,UAAI,KAAK,iBAAiB,IAAI,UAAwB,GAAG;AACvD,eAAO;AAAA,MACT;AAAA,IACF,WAAW,EAAE,mBAAmB,IAAI,KAAK,EAAE,aAAa,KAAK,QAAQ,GAAG;AACtE,eAAS,MAAM,KAAK,kBAAkB,KAAK,QAAQ,QAAQ,OAAO;AAAA,IACpE;AAEA,QAAI,WAAW,UAAU,EAAE,aAAa,IAAI,GAAG;AAC7C,eAAS,MAAM,KAAK,sBAAsB,KAAK,MAAM,QAAQ,OAAO;AAAA,IACtE;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,kBACZ,QACA,QACA,UAAU,oBAAI,OACC;AACf,QAAI,EAAE,aAAa,MAAM,GAAG;AAC1B,aAAO,KAAK,sBAAsB,OAAO,MAAM,QAAQ,OAAO;AAAA,IAChE;AAEA,QAAI,EAAE,mBAAmB,MAAM,KAAK,EAAE,aAAa,OAAO,QAAQ,GAAG;AACnE,YAAM,OAAO,OAAO,SAAS;AAE7B,UACE,KAAK,iBAAiB,IAAI,UAAU,KACpC,YAAY,UAAU,EAAE,wBAAwB,IAAI,IAAI,GACxD;AACA,cAAM,OAAO,MAAM,KAAK,gBAAgB,OAAO,QAAQ,QAAQ,OAAO;AACtE,YAAI,SAAS,UAAU,SAAS,WAAW;AACzC,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT,WACE,KAAK,iBAAiB,IAAI,YAAY,KACtC,YAAY,YAAY,EAAE,wBAAwB,IAAI,IAAI,GAC1D;AACA,cAAM,OAAO,MAAM,KAAK,gBAAgB,OAAO,QAAQ,QAAQ,OAAO;AACtE,YAAI,SAAS,UAAU,SAAS,aAAa,SAAS,cAAc;AAClE,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT;AAEA,UAAI,EAAE,aAAa,OAAO,MAAM,GAAG;AACjC,cAAM,OAAO,MAAM,KAAK,cAAc,MAAM;AAC5C,cAAM,UAAU,KAAK,SAAS,IAAI,OAAO,OAAO,IAAI;AACpD,YACE,WACA,QAAQ,SAAS,YACjB,QAAQ,iBAAiB,KACzB;AAEA,gBAAM,iBAAiB,MAAM,KAAK,QAAQ;AAAA,YACxC,QAAQ;AAAA,YACR;AAAA,UAAA;AAEF,cAAI,gBAAgB;AAClB,kBAAM,eAAe,MAAM,KAAK,cAAc,cAAc;AAC5D,kBAAM,cAAc,aAAa,QAAQ,IAAI,OAAO,SAAS,IAAI;AACjE,gBAAI,aAAa;AACf,oBAAM,kBAAkB,aAAa,SAAS;AAAA,gBAC5C,YAAY;AAAA,cAAA;AAEd,kBAAI,iBAAiB;AACnB,uBAAO,MAAM,KAAK;AAAA,kBAChB;AAAA,kBACA,aAAa;AAAA,kBACb;AAAA,gBAAA;AAAA,cAEJ;AAAA,YACF;AAAA,UACF,OAAO;AACL,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AACA,aAAO,KAAK,gBAAgB,OAAO,QAAQ,QAAQ,OAAO;AAAA,IAC5D;AAGA,WAAO,KAAK,gBAAgB,QAAQ,QAAQ,OAAO;AAAA,EACrD;AAAA,EAEA,MAAc,cAAc,IAAY;AACtC,QAAI,SAAS,KAAK,YAAY,IAAI,EAAE;AACpC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,UAAM,KAAK,QAAQ,WAAW,EAAE;AAEhC,aAAS,KAAK,YAAY,IAAI,EAAE;AAChC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,kCAAkC,EAAE,EAAE;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,0BACP,MACA,aAC8B;AAC9B,MAAI,CAAC,EAAE,iBAAiB,IAAI,EAAG,QAAO;AAEtC,QAAM,SAAS,KAAK;AACpB,MAAI,CAAC,EAAE,mBAAmB,MAAM,KAAK,CAAC,EAAE,aAAa,OAAO,QAAQ,GAAG;AACrE,WAAO;AAAA,EACT;AAGA,QAAM,OAAO,iBAAiB,IAAI,OAAO,SAAS,IAAI;AACtD,MAAI,QAAQ,YAAY,IAAI,IAAI,GAAG;AACjC,WAAO;AAAA,EACT;AAEA,SAAO;AACT;"}
|
|
1
|
+
{"version":3,"file":"compiler.js","sources":["../../../src/create-server-fn-plugin/compiler.ts"],"sourcesContent":["/* eslint-disable import/no-commonjs */\nimport * as t from '@babel/types'\nimport { generateFromAst, parseAst } from '@tanstack/router-utils'\nimport babel from '@babel/core'\nimport {\n deadCodeElimination,\n findReferencedIdentifiers,\n} from 'babel-dead-code-elimination'\nimport { handleCreateServerFn } from './handleCreateServerFn'\nimport { handleCreateMiddleware } from './handleCreateMiddleware'\nimport { handleCreateIsomorphicFn } from './handleCreateIsomorphicFn'\nimport { handleEnvOnlyFn } from './handleEnvOnly'\nimport type { MethodChainPaths, RewriteCandidate } from './types'\n\ntype Binding =\n | {\n type: 'import'\n source: string\n importedName: string\n resolvedKind?: Kind\n }\n | {\n type: 'var'\n init: t.Expression | null\n resolvedKind?: Kind\n }\n\ntype ExportEntry =\n | { tag: 'Normal'; name: string }\n | { tag: 'Default'; name: string }\n | { tag: 'Namespace'; name: string; targetId: string } // for `export * as ns from './x'`\n\ntype Kind = 'None' | `Root` | `Builder` | LookupKind\n\nexport type LookupKind =\n | 'ServerFn'\n | 'Middleware'\n | 'IsomorphicFn'\n | 'ServerOnlyFn'\n | 'ClientOnlyFn'\n\n// Detection strategy for each kind\ntype MethodChainSetup = {\n type: 'methodChain'\n candidateCallIdentifier: Set<string>\n // If true, a call to the root function (e.g., createIsomorphicFn()) is also a candidate\n // even without chained method calls. This is used for IsomorphicFn which can be\n // called without .client() or .server() (resulting in a no-op function).\n allowRootAsCandidate?: boolean\n}\ntype DirectCallSetup = { type: 'directCall' }\n\nconst LookupSetup: Record<LookupKind, MethodChainSetup | DirectCallSetup> = {\n ServerFn: {\n type: 'methodChain',\n candidateCallIdentifier: new Set(['handler']),\n },\n Middleware: {\n type: 'methodChain',\n candidateCallIdentifier: new Set(['server', 'client', 'createMiddlewares']),\n },\n IsomorphicFn: {\n type: 'methodChain',\n candidateCallIdentifier: new Set(['server', 'client']),\n allowRootAsCandidate: true, // createIsomorphicFn() alone is valid (returns no-op)\n },\n ServerOnlyFn: { type: 'directCall' },\n ClientOnlyFn: { type: 'directCall' },\n}\n\n// Pre-computed map: identifier name -> Set<LookupKind> for fast candidate detection (method chain only)\n// Multiple kinds can share the same identifier (e.g., 'server' and 'client' are used by both Middleware and IsomorphicFn)\nconst IdentifierToKinds = new Map<string, Set<LookupKind>>()\nfor (const [kind, setup] of Object.entries(LookupSetup) as Array<\n [LookupKind, MethodChainSetup | DirectCallSetup]\n>) {\n if (setup.type === 'methodChain') {\n for (const id of setup.candidateCallIdentifier) {\n let kinds = IdentifierToKinds.get(id)\n if (!kinds) {\n kinds = new Set()\n IdentifierToKinds.set(id, kinds)\n }\n kinds.add(kind)\n }\n }\n}\n\nexport type LookupConfig = {\n libName: string\n rootExport: string\n kind: LookupKind | 'Root' // 'Root' for builder pattern, LookupKind for direct call\n}\n\ninterface ModuleInfo {\n id: string\n bindings: Map<string, Binding>\n exports: Map<string, ExportEntry>\n // Track `export * from './module'` declarations for re-export resolution\n reExportAllSources: Array<string>\n}\n\nexport class ServerFnCompiler {\n private moduleCache = new Map<string, ModuleInfo>()\n private initialized = false\n private validLookupKinds: Set<LookupKind>\n // Precomputed flags for candidate detection (avoid recomputing on each collectCandidates call)\n private hasDirectCallKinds: boolean\n private hasRootAsCandidateKinds: boolean\n // Fast lookup for direct imports from known libraries (e.g., '@tanstack/react-start')\n // Maps: libName → (exportName → Kind)\n // This allows O(1) resolution for the common case without async resolveId calls\n private knownRootImports = new Map<string, Map<string, Kind>>()\n constructor(\n private options: {\n env: 'client' | 'server'\n directive: string\n lookupConfigurations: Array<LookupConfig>\n lookupKinds: Set<LookupKind>\n loadModule: (id: string) => Promise<void>\n resolveId: (id: string, importer?: string) => Promise<string | null>\n },\n ) {\n this.validLookupKinds = options.lookupKinds\n\n // Precompute flags for candidate detection\n this.hasDirectCallKinds = false\n this.hasRootAsCandidateKinds = false\n for (const kind of options.lookupKinds) {\n const setup = LookupSetup[kind]\n if (setup.type === 'directCall') {\n this.hasDirectCallKinds = true\n } else if (setup.allowRootAsCandidate) {\n this.hasRootAsCandidateKinds = true\n }\n }\n }\n\n private async init() {\n // Register internal stub package exports for recognition.\n // These don't need module resolution - only the knownRootImports fast path.\n this.knownRootImports.set(\n '@tanstack/start-fn-stubs',\n new Map<string, Kind>([\n ['createIsomorphicFn', 'IsomorphicFn'],\n ['createServerOnlyFn', 'ServerOnlyFn'],\n ['createClientOnlyFn', 'ClientOnlyFn'],\n ]),\n )\n\n await Promise.all(\n this.options.lookupConfigurations.map(async (config) => {\n // Populate the fast lookup map for direct imports (by package name)\n // This allows O(1) recognition of imports from known packages.\n let libExports = this.knownRootImports.get(config.libName)\n if (!libExports) {\n libExports = new Map()\n this.knownRootImports.set(config.libName, libExports)\n }\n libExports.set(config.rootExport, config.kind)\n\n const libId = await this.options.resolveId(config.libName)\n if (!libId) {\n throw new Error(`could not resolve \"${config.libName}\"`)\n }\n let rootModule = this.moduleCache.get(libId)\n if (!rootModule) {\n // insert root binding\n rootModule = {\n bindings: new Map(),\n exports: new Map(),\n id: libId,\n reExportAllSources: [],\n }\n this.moduleCache.set(libId, rootModule)\n }\n\n rootModule.exports.set(config.rootExport, {\n tag: 'Normal',\n name: config.rootExport,\n })\n rootModule.exports.set('*', {\n tag: 'Namespace',\n name: config.rootExport,\n targetId: libId,\n })\n rootModule.bindings.set(config.rootExport, {\n type: 'var',\n init: null, // Not needed since resolvedKind is set\n resolvedKind: config.kind satisfies Kind,\n })\n this.moduleCache.set(libId, rootModule)\n }),\n )\n\n this.initialized = true\n }\n\n public ingestModule({ code, id }: { code: string; id: string }) {\n const ast = parseAst({ code })\n\n const bindings = new Map<string, Binding>()\n const exports = new Map<string, ExportEntry>()\n const reExportAllSources: Array<string> = []\n\n // we are only interested in top-level bindings, hence we don't traverse the AST\n // instead we only iterate over the program body\n for (const node of ast.program.body) {\n if (t.isImportDeclaration(node)) {\n const source = node.source.value\n for (const s of node.specifiers) {\n if (t.isImportSpecifier(s)) {\n const importedName = t.isIdentifier(s.imported)\n ? s.imported.name\n : s.imported.value\n bindings.set(s.local.name, { type: 'import', source, importedName })\n } else if (t.isImportDefaultSpecifier(s)) {\n bindings.set(s.local.name, {\n type: 'import',\n source,\n importedName: 'default',\n })\n } else if (t.isImportNamespaceSpecifier(s)) {\n bindings.set(s.local.name, {\n type: 'import',\n source,\n importedName: '*',\n })\n }\n }\n } else if (t.isVariableDeclaration(node)) {\n for (const decl of node.declarations) {\n if (t.isIdentifier(decl.id)) {\n bindings.set(decl.id.name, {\n type: 'var',\n init: decl.init ?? null,\n })\n }\n }\n } else if (t.isExportNamedDeclaration(node)) {\n // export const foo = ...\n if (node.declaration) {\n if (t.isVariableDeclaration(node.declaration)) {\n for (const d of node.declaration.declarations) {\n if (t.isIdentifier(d.id)) {\n exports.set(d.id.name, { tag: 'Normal', name: d.id.name })\n bindings.set(d.id.name, { type: 'var', init: d.init ?? null })\n }\n }\n }\n }\n for (const sp of node.specifiers) {\n if (t.isExportNamespaceSpecifier(sp)) {\n exports.set(sp.exported.name, {\n tag: 'Namespace',\n name: sp.exported.name,\n targetId: node.source?.value || '',\n })\n }\n // export { local as exported }\n else if (t.isExportSpecifier(sp)) {\n const local = sp.local.name\n const exported = t.isIdentifier(sp.exported)\n ? sp.exported.name\n : sp.exported.value\n exports.set(exported, { tag: 'Normal', name: local })\n\n // When re-exporting from another module (export { foo } from './module'),\n // create an import binding so the server function can be resolved\n if (node.source) {\n bindings.set(local, {\n type: 'import',\n source: node.source.value,\n importedName: local,\n })\n }\n }\n }\n } else if (t.isExportDefaultDeclaration(node)) {\n const d = node.declaration\n if (t.isIdentifier(d)) {\n exports.set('default', { tag: 'Default', name: d.name })\n } else {\n const synth = '__default_export__'\n bindings.set(synth, { type: 'var', init: d as t.Expression })\n exports.set('default', { tag: 'Default', name: synth })\n }\n } else if (t.isExportAllDeclaration(node)) {\n // Handle `export * from './module'` syntax\n // Track the source so we can look up exports from it when needed\n reExportAllSources.push(node.source.value)\n }\n }\n\n const info: ModuleInfo = {\n id,\n bindings,\n exports,\n reExportAllSources,\n }\n this.moduleCache.set(id, info)\n return { info, ast }\n }\n\n public invalidateModule(id: string) {\n return this.moduleCache.delete(id)\n }\n\n public async compile({\n code,\n id,\n isProviderFile,\n }: {\n code: string\n id: string\n isProviderFile: boolean\n }) {\n if (!this.initialized) {\n await this.init()\n }\n const { info, ast } = this.ingestModule({ code, id })\n const candidates = this.collectCandidates(info.bindings)\n if (candidates.length === 0) {\n // this hook will only be invoked if there is `.handler(` | `.server(` | `.client(` in the code,\n // so not discovering a handler candidate is rather unlikely, but maybe possible?\n return null\n }\n\n // let's find out which of the candidates are actually server functions\n // Resolve all candidates in parallel for better performance\n const resolvedCandidates = await Promise.all(\n candidates.map(async (candidate) => ({\n candidate,\n kind: await this.resolveExprKind(candidate, id),\n })),\n )\n\n // Map from candidate/root node -> kind\n // Note: For top-level variable declarations, candidate === root (the outermost CallExpression)\n const toRewriteMap = new Map<t.CallExpression, LookupKind>()\n for (const { candidate, kind } of resolvedCandidates) {\n if (this.validLookupKinds.has(kind as LookupKind)) {\n toRewriteMap.set(candidate, kind as LookupKind)\n }\n }\n if (toRewriteMap.size === 0) {\n return null\n }\n\n // Single-pass traversal to find NodePaths and collect method chains\n const pathsToRewrite: Array<{\n path: babel.NodePath<t.CallExpression>\n kind: LookupKind\n methodChain: MethodChainPaths\n }> = []\n\n // First, collect all CallExpression paths in the AST for O(1) lookup\n const callExprPaths = new Map<\n t.CallExpression,\n babel.NodePath<t.CallExpression>\n >()\n\n babel.traverse(ast, {\n CallExpression(path) {\n callExprPaths.set(path.node, path)\n },\n })\n\n // Now process candidates - we can look up any CallExpression path in O(1)\n for (const [node, kind] of toRewriteMap) {\n const path = callExprPaths.get(node)\n if (!path) {\n continue\n }\n\n // Collect method chain paths by walking DOWN from root through the chain\n const methodChain: MethodChainPaths = {\n middleware: null,\n inputValidator: null,\n handler: null,\n server: null,\n client: null,\n }\n\n // Walk down the call chain using nodes, look up paths from map\n let currentNode: t.CallExpression = node\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n const callee = currentNode.callee\n if (!t.isMemberExpression(callee)) {\n break\n }\n\n // Record method chain path if it's a known method\n if (t.isIdentifier(callee.property)) {\n const name = callee.property.name as keyof MethodChainPaths\n if (name in methodChain) {\n const currentPath = callExprPaths.get(currentNode)!\n // Get first argument path\n const args = currentPath.get('arguments')\n const firstArgPath =\n Array.isArray(args) && args.length > 0 ? (args[0] ?? null) : null\n methodChain[name] = {\n callPath: currentPath,\n firstArgPath,\n }\n }\n }\n\n // Move to the inner call (the object of the member expression)\n if (!t.isCallExpression(callee.object)) {\n break\n }\n currentNode = callee.object\n }\n\n pathsToRewrite.push({ path, kind, methodChain })\n }\n\n // Verify we found all candidates (pathsToRewrite should have same size as toRewriteMap had)\n if (pathsToRewrite.length !== toRewriteMap.size) {\n throw new Error(\n `Internal error: could not find all paths to rewrite. please file an issue`,\n )\n }\n\n const refIdents = findReferencedIdentifiers(ast)\n\n for (const { path, kind, methodChain } of pathsToRewrite) {\n const candidate: RewriteCandidate = { path, methodChain }\n if (kind === 'ServerFn') {\n handleCreateServerFn(candidate, {\n env: this.options.env,\n code,\n directive: this.options.directive,\n isProviderFile,\n })\n } else if (kind === 'Middleware') {\n handleCreateMiddleware(candidate, {\n env: this.options.env,\n })\n } else if (kind === 'IsomorphicFn') {\n handleCreateIsomorphicFn(candidate, {\n env: this.options.env,\n })\n } else {\n // ServerOnlyFn or ClientOnlyFn\n handleEnvOnlyFn(candidate, {\n env: this.options.env,\n kind,\n })\n }\n }\n\n deadCodeElimination(ast, refIdents)\n\n return generateFromAst(ast, {\n sourceMaps: true,\n sourceFileName: id,\n filename: id,\n })\n }\n\n // collects all candidate CallExpressions at top-level\n private collectCandidates(bindings: Map<string, Binding>) {\n const candidates: Array<t.CallExpression> = []\n\n for (const binding of bindings.values()) {\n if (binding.type === 'var' && t.isCallExpression(binding.init)) {\n // Pattern 1: Method chain pattern (.handler(), .server(), etc.)\n const methodChainCandidate = isCandidateCallExpression(\n binding.init,\n this.validLookupKinds,\n )\n if (methodChainCandidate) {\n candidates.push(methodChainCandidate)\n continue\n }\n\n // Pattern 2: Direct call pattern\n // Handles:\n // - createServerOnlyFn(), createClientOnlyFn() (direct call kinds)\n // - createIsomorphicFn() (root-as-candidate kinds)\n // - TanStackStart.createServerOnlyFn() (namespace calls)\n if (this.hasDirectCallKinds || this.hasRootAsCandidateKinds) {\n if (\n t.isIdentifier(binding.init.callee) ||\n (t.isMemberExpression(binding.init.callee) &&\n t.isIdentifier(binding.init.callee.property))\n ) {\n // Include as candidate - kind resolution will verify it's actually a known export\n candidates.push(binding.init)\n }\n }\n }\n }\n return candidates\n }\n\n private async resolveIdentifierKind(\n ident: string,\n id: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n const info = await this.getModuleInfo(id)\n\n const binding = info.bindings.get(ident)\n if (!binding) {\n return 'None'\n }\n if (binding.resolvedKind) {\n return binding.resolvedKind\n }\n\n // TODO improve cycle detection? should we throw here instead of returning 'None'?\n // prevent cycles\n const vKey = `${id}:${ident}`\n if (visited.has(vKey)) {\n return 'None'\n }\n visited.add(vKey)\n\n const resolvedKind = await this.resolveBindingKind(binding, id, visited)\n binding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n /**\n * Recursively find an export in a module, following `export * from` chains.\n * Returns the module info and binding if found, or undefined if not found.\n */\n private async findExportInModule(\n moduleInfo: ModuleInfo,\n exportName: string,\n visitedModules = new Set<string>(),\n ): Promise<{ moduleInfo: ModuleInfo; binding: Binding } | undefined> {\n // Prevent infinite loops in circular re-exports\n if (visitedModules.has(moduleInfo.id)) {\n return undefined\n }\n visitedModules.add(moduleInfo.id)\n\n // First check direct exports\n const directExport = moduleInfo.exports.get(exportName)\n if (directExport) {\n const binding = moduleInfo.bindings.get(directExport.name)\n if (binding) {\n return { moduleInfo, binding }\n }\n }\n\n // If not found, recursively check re-export-all sources in parallel\n // Valid code won't have duplicate exports across chains, so first match wins\n if (moduleInfo.reExportAllSources.length > 0) {\n const results = await Promise.all(\n moduleInfo.reExportAllSources.map(async (reExportSource) => {\n const reExportTarget = await this.options.resolveId(\n reExportSource,\n moduleInfo.id,\n )\n if (reExportTarget) {\n const reExportModule = await this.getModuleInfo(reExportTarget)\n return this.findExportInModule(\n reExportModule,\n exportName,\n visitedModules,\n )\n }\n return undefined\n }),\n )\n // Return the first valid result\n for (const result of results) {\n if (result) {\n return result\n }\n }\n }\n\n return undefined\n }\n\n private async resolveBindingKind(\n binding: Binding,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (binding.resolvedKind) {\n return binding.resolvedKind\n }\n if (binding.type === 'import') {\n // Fast path: check if this is a direct import from a known library\n // (e.g., import { createServerFn } from '@tanstack/react-start')\n // This avoids async resolveId calls for the common case\n const knownExports = this.knownRootImports.get(binding.source)\n if (knownExports) {\n const kind = knownExports.get(binding.importedName)\n if (kind) {\n binding.resolvedKind = kind\n return kind\n }\n }\n\n // Slow path: resolve through the module graph\n const target = await this.options.resolveId(binding.source, fileId)\n if (!target) {\n return 'None'\n }\n\n const importedModule = await this.getModuleInfo(target)\n\n // Find the export, recursively searching through export * from chains\n const found = await this.findExportInModule(\n importedModule,\n binding.importedName,\n )\n\n if (!found) {\n return 'None'\n }\n\n const { moduleInfo: foundModule, binding: foundBinding } = found\n\n if (foundBinding.resolvedKind) {\n return foundBinding.resolvedKind\n }\n\n const resolvedKind = await this.resolveBindingKind(\n foundBinding,\n foundModule.id,\n visited,\n )\n foundBinding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n const resolvedKind = await this.resolveExprKind(\n binding.init,\n fileId,\n visited,\n )\n binding.resolvedKind = resolvedKind\n return resolvedKind\n }\n\n private async resolveExprKind(\n expr: t.Expression | null,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (!expr) {\n return 'None'\n }\n\n // Unwrap common TypeScript/parenthesized wrappers first for efficiency\n while (\n t.isTSAsExpression(expr) ||\n t.isTSNonNullExpression(expr) ||\n t.isParenthesizedExpression(expr)\n ) {\n expr = expr.expression\n }\n\n let result: Kind = 'None'\n\n if (t.isCallExpression(expr)) {\n if (!t.isExpression(expr.callee)) {\n return 'None'\n }\n const calleeKind = await this.resolveCalleeKind(\n expr.callee,\n fileId,\n visited,\n )\n if (calleeKind === 'Root' || calleeKind === 'Builder') {\n return 'Builder'\n }\n // Use direct Set.has() instead of iterating\n if (this.validLookupKinds.has(calleeKind as LookupKind)) {\n return calleeKind\n }\n } else if (t.isMemberExpression(expr) && t.isIdentifier(expr.property)) {\n result = await this.resolveCalleeKind(expr.object, fileId, visited)\n }\n\n if (result === 'None' && t.isIdentifier(expr)) {\n result = await this.resolveIdentifierKind(expr.name, fileId, visited)\n }\n\n return result\n }\n\n private async resolveCalleeKind(\n callee: t.Expression,\n fileId: string,\n visited = new Set<string>(),\n ): Promise<Kind> {\n if (t.isIdentifier(callee)) {\n return this.resolveIdentifierKind(callee.name, fileId, visited)\n }\n\n if (t.isMemberExpression(callee) && t.isIdentifier(callee.property)) {\n const prop = callee.property.name\n\n // Check if this property matches any method chain pattern\n const possibleKinds = IdentifierToKinds.get(prop)\n if (possibleKinds) {\n // Resolve base expression ONCE and reuse for all pattern checks\n const base = await this.resolveExprKind(callee.object, fileId, visited)\n\n // Check each possible kind that uses this identifier\n for (const kind of possibleKinds) {\n if (!this.validLookupKinds.has(kind)) continue\n\n if (kind === 'ServerFn') {\n if (base === 'Root' || base === 'Builder') {\n return 'ServerFn'\n }\n } else if (kind === 'Middleware') {\n if (\n base === 'Root' ||\n base === 'Builder' ||\n base === 'Middleware'\n ) {\n return 'Middleware'\n }\n } else if (kind === 'IsomorphicFn') {\n if (\n base === 'Root' ||\n base === 'Builder' ||\n base === 'IsomorphicFn'\n ) {\n return 'IsomorphicFn'\n }\n }\n }\n }\n\n // Check if the object is a namespace import\n if (t.isIdentifier(callee.object)) {\n const info = await this.getModuleInfo(fileId)\n const binding = info.bindings.get(callee.object.name)\n if (\n binding &&\n binding.type === 'import' &&\n binding.importedName === '*'\n ) {\n // resolve the property from the target module\n const targetModuleId = await this.options.resolveId(\n binding.source,\n fileId,\n )\n if (targetModuleId) {\n const targetModule = await this.getModuleInfo(targetModuleId)\n const exportEntry = targetModule.exports.get(callee.property.name)\n if (exportEntry) {\n const exportedBinding = targetModule.bindings.get(\n exportEntry.name,\n )\n if (exportedBinding) {\n return await this.resolveBindingKind(\n exportedBinding,\n targetModule.id,\n visited,\n )\n }\n }\n } else {\n return 'None'\n }\n }\n }\n return this.resolveExprKind(callee.object, fileId, visited)\n }\n\n // handle nested expressions\n return this.resolveExprKind(callee, fileId, visited)\n }\n\n private async getModuleInfo(id: string) {\n let cached = this.moduleCache.get(id)\n if (cached) {\n return cached\n }\n\n await this.options.loadModule(id)\n\n cached = this.moduleCache.get(id)\n if (!cached) {\n throw new Error(`could not load module info for ${id}`)\n }\n return cached\n }\n}\n\nfunction isCandidateCallExpression(\n node: t.Node | null | undefined,\n lookupKinds: Set<LookupKind>,\n): t.CallExpression | undefined {\n if (!t.isCallExpression(node)) return undefined\n\n const callee = node.callee\n if (!t.isMemberExpression(callee) || !t.isIdentifier(callee.property)) {\n return undefined\n }\n\n // Use pre-computed map for O(1) lookup\n // IdentifierToKinds maps identifier -> Set<LookupKind> to handle shared identifiers\n const possibleKinds = IdentifierToKinds.get(callee.property.name)\n if (possibleKinds) {\n // Check if any of the possible kinds are in the valid lookup kinds\n for (const kind of possibleKinds) {\n if (lookupKinds.has(kind)) {\n return node\n }\n }\n }\n\n return undefined\n}\n"],"names":["resolvedKind"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
function handleCreateIsomorphicFn(candidate, opts) {
|
|
3
|
+
const { path, methodChain } = candidate;
|
|
4
|
+
const envCallInfo = opts.env === "client" ? methodChain.client : methodChain.server;
|
|
5
|
+
if (!methodChain.client && !methodChain.server) {
|
|
6
|
+
const variableId = path.parentPath.isVariableDeclarator() ? path.parentPath.node.id : null;
|
|
7
|
+
console.warn(
|
|
8
|
+
"createIsomorphicFn called without a client or server implementation!",
|
|
9
|
+
"This will result in a no-op function.",
|
|
10
|
+
"Variable name:",
|
|
11
|
+
t.isIdentifier(variableId) ? variableId.name : "unknown"
|
|
12
|
+
);
|
|
13
|
+
path.replaceWith(t.arrowFunctionExpression([], t.blockStatement([])));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!envCallInfo) {
|
|
17
|
+
path.replaceWith(t.arrowFunctionExpression([], t.blockStatement([])));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const innerFn = envCallInfo.firstArgPath?.node;
|
|
21
|
+
if (!t.isExpression(innerFn)) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`createIsomorphicFn().${opts.env}(func) must be called with a function!`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
path.replaceWith(innerFn);
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
handleCreateIsomorphicFn
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=handleCreateIsomorphicFn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handleCreateIsomorphicFn.js","sources":["../../../src/create-server-fn-plugin/handleCreateIsomorphicFn.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport type { RewriteCandidate } from './types'\n\nexport function handleCreateIsomorphicFn(\n candidate: RewriteCandidate,\n opts: { env: 'client' | 'server' },\n) {\n const { path, methodChain } = candidate\n\n // Get the environment-specific call (.client() or .server())\n const envCallInfo =\n opts.env === 'client' ? methodChain.client : methodChain.server\n\n // Check if we have any implementation at all\n if (!methodChain.client && !methodChain.server) {\n // No implementations provided - warn and replace with no-op\n const variableId = path.parentPath.isVariableDeclarator()\n ? path.parentPath.node.id\n : null\n console.warn(\n 'createIsomorphicFn called without a client or server implementation!',\n 'This will result in a no-op function.',\n 'Variable name:',\n t.isIdentifier(variableId) ? variableId.name : 'unknown',\n )\n path.replaceWith(t.arrowFunctionExpression([], t.blockStatement([])))\n return\n }\n\n if (!envCallInfo) {\n // No implementation for this environment - replace with no-op\n path.replaceWith(t.arrowFunctionExpression([], t.blockStatement([])))\n return\n }\n\n // Extract the function argument from the environment-specific call\n const innerFn = envCallInfo.firstArgPath?.node\n\n if (!t.isExpression(innerFn)) {\n throw new Error(\n `createIsomorphicFn().${opts.env}(func) must be called with a function!`,\n )\n }\n\n path.replaceWith(innerFn)\n}\n"],"names":[],"mappings":";AAGO,SAAS,yBACd,WACA,MACA;AACA,QAAM,EAAE,MAAM,YAAA,IAAgB;AAG9B,QAAM,cACJ,KAAK,QAAQ,WAAW,YAAY,SAAS,YAAY;AAG3D,MAAI,CAAC,YAAY,UAAU,CAAC,YAAY,QAAQ;AAE9C,UAAM,aAAa,KAAK,WAAW,qBAAA,IAC/B,KAAK,WAAW,KAAK,KACrB;AACJ,YAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,EAAE,aAAa,UAAU,IAAI,WAAW,OAAO;AAAA,IAAA;AAEjD,SAAK,YAAY,EAAE,wBAAwB,CAAA,GAAI,EAAE,eAAe,CAAA,CAAE,CAAC,CAAC;AACpE;AAAA,EACF;AAEA,MAAI,CAAC,aAAa;AAEhB,SAAK,YAAY,EAAE,wBAAwB,CAAA,GAAI,EAAE,eAAe,CAAA,CAAE,CAAC,CAAC;AACpE;AAAA,EACF;AAGA,QAAM,UAAU,YAAY,cAAc;AAE1C,MAAI,CAAC,EAAE,aAAa,OAAO,GAAG;AAC5B,UAAM,IAAI;AAAA,MACR,wBAAwB,KAAK,GAAG;AAAA,IAAA;AAAA,EAEpC;AAEA,OAAK,YAAY,OAAO;AAC1B;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as t from "@babel/types";
|
|
2
|
-
import { codeFrameError } from "
|
|
2
|
+
import { codeFrameError } from "./utils.js";
|
|
3
3
|
function handleCreateServerFn(candidate, opts) {
|
|
4
4
|
const { path, methodChain } = candidate;
|
|
5
5
|
const { inputValidator, handler } = methodChain;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleCreateServerFn.js","sources":["../../../src/create-server-fn-plugin/handleCreateServerFn.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport { codeFrameError } from '
|
|
1
|
+
{"version":3,"file":"handleCreateServerFn.js","sources":["../../../src/create-server-fn-plugin/handleCreateServerFn.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport { codeFrameError } from './utils'\nimport type { RewriteCandidate } from './types'\n\n/**\n * Handles createServerFn transformations.\n *\n * @param candidate - The rewrite candidate containing path and method chain\n * @param opts - Options including the environment, code, directive, and provider file flag\n */\nexport function handleCreateServerFn(\n candidate: RewriteCandidate,\n opts: {\n env: 'client' | 'server'\n code: string\n directive: string\n /**\n * Whether this file is a provider file (extracted server function file).\n * Only provider files should have the handler implementation as a second argument.\n */\n isProviderFile: boolean\n },\n) {\n const { path, methodChain } = candidate\n const { inputValidator, handler } = methodChain\n\n // Check if the call is assigned to a variable\n if (!path.parentPath.isVariableDeclarator()) {\n throw new Error('createServerFn must be assigned to a variable!')\n }\n\n // Get the identifier name of the variable\n const variableDeclarator = path.parentPath.node\n if (!t.isIdentifier(variableDeclarator.id)) {\n throw codeFrameError(\n opts.code,\n variableDeclarator.id.loc!,\n 'createServerFn must be assigned to a simple identifier, not a destructuring pattern',\n )\n }\n const existingVariableName = variableDeclarator.id.name\n\n if (inputValidator) {\n const innerInputExpression = inputValidator.callPath.node.arguments[0]\n\n if (!innerInputExpression) {\n throw new Error(\n 'createServerFn().inputValidator() must be called with a validator!',\n )\n }\n\n // If we're on the client, remove the validator call expression\n if (opts.env === 'client') {\n if (t.isMemberExpression(inputValidator.callPath.node.callee)) {\n inputValidator.callPath.replaceWith(\n inputValidator.callPath.node.callee.object,\n )\n }\n }\n }\n\n // First, we need to move the handler function to a nested function call\n // that is applied to the arguments passed to the server function.\n\n const handlerFnPath = handler?.firstArgPath\n\n if (!handler || !handlerFnPath?.node) {\n throw codeFrameError(\n opts.code,\n path.node.callee.loc!,\n `createServerFn must be called with a \"handler\" property!`,\n )\n }\n\n // Validate the handler argument is an expression (not a SpreadElement, etc.)\n if (!t.isExpression(handlerFnPath.node)) {\n throw codeFrameError(\n opts.code,\n handlerFnPath.node.loc!,\n `handler() must be called with an expression, not a ${handlerFnPath.node.type}`,\n )\n }\n\n const handlerFn = handlerFnPath.node\n\n // So, the way we do this is we give the handler function a way\n // to access the serverFn ctx on the server via function scope.\n // The 'use server' extracted function will be called with the\n // payload from the client, then use the scoped serverFn ctx\n // to execute the handler function.\n // This way, we can do things like data and middleware validation\n // in the __execute function without having to AST transform the\n // handler function too much itself.\n\n // .handler((optsOut, ctx) => {\n // return ((optsIn) => {\n // 'use server'\n // ctx.__execute(handlerFn, optsIn)\n // })(optsOut)\n // })\n\n // If the handler function is an identifier and we're on the client, we need to\n // remove the bound function from the file.\n // If we're on the server, you can leave it, since it will get referenced\n // as a second argument.\n\n if (t.isIdentifier(handlerFn)) {\n if (opts.env === 'client') {\n // Find the binding for the handler function\n const binding = handlerFnPath.scope.getBinding(handlerFn.name)\n // Remove it\n if (binding) {\n binding.path.remove()\n }\n }\n // If the env is server, just leave it alone\n }\n\n handlerFnPath.replaceWith(\n t.arrowFunctionExpression(\n [t.identifier('opts'), t.identifier('signal')],\n t.blockStatement(\n // Everything in here is server-only, since the client\n // will strip out anything in the 'use server' directive.\n [\n t.returnStatement(\n t.callExpression(\n t.identifier(`${existingVariableName}.__executeServer`),\n [t.identifier('opts'), t.identifier('signal')],\n ),\n ),\n ],\n [t.directive(t.directiveLiteral(opts.directive))],\n ),\n ),\n )\n\n // Add the serverFn as a second argument on the server side,\n // but ONLY for provider files (extracted server function files).\n // Caller files must NOT have the second argument because the implementation is already available in the extracted chunk\n // and including it would duplicate code\n if (opts.env === 'server' && opts.isProviderFile) {\n handler.callPath.node.arguments.push(handlerFn)\n }\n}\n"],"names":[],"mappings":";;AAUO,SAAS,qBACd,WACA,MAUA;AACA,QAAM,EAAE,MAAM,YAAA,IAAgB;AAC9B,QAAM,EAAE,gBAAgB,QAAA,IAAY;AAGpC,MAAI,CAAC,KAAK,WAAW,wBAAwB;AAC3C,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAGA,QAAM,qBAAqB,KAAK,WAAW;AAC3C,MAAI,CAAC,EAAE,aAAa,mBAAmB,EAAE,GAAG;AAC1C,UAAM;AAAA,MACJ,KAAK;AAAA,MACL,mBAAmB,GAAG;AAAA,MACtB;AAAA,IAAA;AAAA,EAEJ;AACA,QAAM,uBAAuB,mBAAmB,GAAG;AAEnD,MAAI,gBAAgB;AAClB,UAAM,uBAAuB,eAAe,SAAS,KAAK,UAAU,CAAC;AAErE,QAAI,CAAC,sBAAsB;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAGA,QAAI,KAAK,QAAQ,UAAU;AACzB,UAAI,EAAE,mBAAmB,eAAe,SAAS,KAAK,MAAM,GAAG;AAC7D,uBAAe,SAAS;AAAA,UACtB,eAAe,SAAS,KAAK,OAAO;AAAA,QAAA;AAAA,MAExC;AAAA,IACF;AAAA,EACF;AAKA,QAAM,gBAAgB,SAAS;AAE/B,MAAI,CAAC,WAAW,CAAC,eAAe,MAAM;AACpC,UAAM;AAAA,MACJ,KAAK;AAAA,MACL,KAAK,KAAK,OAAO;AAAA,MACjB;AAAA,IAAA;AAAA,EAEJ;AAGA,MAAI,CAAC,EAAE,aAAa,cAAc,IAAI,GAAG;AACvC,UAAM;AAAA,MACJ,KAAK;AAAA,MACL,cAAc,KAAK;AAAA,MACnB,sDAAsD,cAAc,KAAK,IAAI;AAAA,IAAA;AAAA,EAEjF;AAEA,QAAM,YAAY,cAAc;AAuBhC,MAAI,EAAE,aAAa,SAAS,GAAG;AAC7B,QAAI,KAAK,QAAQ,UAAU;AAEzB,YAAM,UAAU,cAAc,MAAM,WAAW,UAAU,IAAI;AAE7D,UAAI,SAAS;AACX,gBAAQ,KAAK,OAAA;AAAA,MACf;AAAA,IACF;AAAA,EAEF;AAEA,gBAAc;AAAA,IACZ,EAAE;AAAA,MACA,CAAC,EAAE,WAAW,MAAM,GAAG,EAAE,WAAW,QAAQ,CAAC;AAAA,MAC7C,EAAE;AAAA;AAAA;AAAA,QAGA;AAAA,UACE,EAAE;AAAA,YACA,EAAE;AAAA,cACA,EAAE,WAAW,GAAG,oBAAoB,kBAAkB;AAAA,cACtD,CAAC,EAAE,WAAW,MAAM,GAAG,EAAE,WAAW,QAAQ,CAAC;AAAA,YAAA;AAAA,UAC/C;AAAA,QACF;AAAA,QAEF,CAAC,EAAE,UAAU,EAAE,iBAAiB,KAAK,SAAS,CAAC,CAAC;AAAA,MAAA;AAAA,IAClD;AAAA,EACF;AAOF,MAAI,KAAK,QAAQ,YAAY,KAAK,gBAAgB;AAChD,YAAQ,SAAS,KAAK,UAAU,KAAK,SAAS;AAAA,EAChD;AACF;"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
function capitalize(str) {
|
|
3
|
+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
4
|
+
}
|
|
5
|
+
function handleEnvOnlyFn(candidate, opts) {
|
|
6
|
+
const { path } = candidate;
|
|
7
|
+
const targetEnv = opts.kind === "ClientOnlyFn" ? "client" : "server";
|
|
8
|
+
if (opts.env === targetEnv) {
|
|
9
|
+
const innerFn = path.node.arguments[0];
|
|
10
|
+
if (!t.isExpression(innerFn)) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
`create${capitalize(targetEnv)}OnlyFn() must be called with a function!`
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
path.replaceWith(innerFn);
|
|
16
|
+
} else {
|
|
17
|
+
path.replaceWith(
|
|
18
|
+
t.arrowFunctionExpression(
|
|
19
|
+
[],
|
|
20
|
+
t.blockStatement([
|
|
21
|
+
t.throwStatement(
|
|
22
|
+
t.newExpression(t.identifier("Error"), [
|
|
23
|
+
t.stringLiteral(
|
|
24
|
+
`create${capitalize(targetEnv)}OnlyFn() functions can only be called on the ${targetEnv}!`
|
|
25
|
+
)
|
|
26
|
+
])
|
|
27
|
+
)
|
|
28
|
+
])
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
handleEnvOnlyFn
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=handleEnvOnly.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handleEnvOnly.js","sources":["../../../src/create-server-fn-plugin/handleEnvOnly.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport type { RewriteCandidate } from './types'\nimport type { LookupKind } from './compiler'\n\nfunction capitalize(str: string) {\n if (!str) return ''\n return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()\n}\n\nexport function handleEnvOnlyFn(\n candidate: RewriteCandidate,\n opts: { env: 'client' | 'server'; kind: LookupKind },\n) {\n const { path } = candidate\n const targetEnv = opts.kind === 'ClientOnlyFn' ? 'client' : 'server'\n\n if (opts.env === targetEnv) {\n // Matching environment - extract the inner function\n const innerFn = path.node.arguments[0]\n\n if (!t.isExpression(innerFn)) {\n throw new Error(\n `create${capitalize(targetEnv)}OnlyFn() must be called with a function!`,\n )\n }\n\n path.replaceWith(innerFn)\n } else {\n // Wrong environment - replace with a function that throws an error\n path.replaceWith(\n t.arrowFunctionExpression(\n [],\n t.blockStatement([\n t.throwStatement(\n t.newExpression(t.identifier('Error'), [\n t.stringLiteral(\n `create${capitalize(targetEnv)}OnlyFn() functions can only be called on the ${targetEnv}!`,\n ),\n ]),\n ),\n ]),\n ),\n )\n }\n}\n"],"names":[],"mappings":";AAIA,SAAS,WAAW,KAAa;AAE/B,SAAO,IAAI,OAAO,CAAC,EAAE,gBAAgB,IAAI,MAAM,CAAC,EAAE,YAAA;AACpD;AAEO,SAAS,gBACd,WACA,MACA;AACA,QAAM,EAAE,SAAS;AACjB,QAAM,YAAY,KAAK,SAAS,iBAAiB,WAAW;AAE5D,MAAI,KAAK,QAAQ,WAAW;AAE1B,UAAM,UAAU,KAAK,KAAK,UAAU,CAAC;AAErC,QAAI,CAAC,EAAE,aAAa,OAAO,GAAG;AAC5B,YAAM,IAAI;AAAA,QACR,SAAS,WAAW,SAAS,CAAC;AAAA,MAAA;AAAA,IAElC;AAEA,SAAK,YAAY,OAAO;AAAA,EAC1B,OAAO;AAEL,SAAK;AAAA,MACH,EAAE;AAAA,QACA,CAAA;AAAA,QACA,EAAE,eAAe;AAAA,UACf,EAAE;AAAA,YACA,EAAE,cAAc,EAAE,WAAW,OAAO,GAAG;AAAA,cACrC,EAAE;AAAA,gBACA,SAAS,WAAW,SAAS,CAAC,gDAAgD,SAAS;AAAA,cAAA;AAAA,YACzF,CACD;AAAA,UAAA;AAAA,QACH,CACD;AAAA,MAAA;AAAA,IACH;AAAA,EAEJ;AACF;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CompileStartFrameworkOptions } from '../
|
|
1
|
+
import { CompileStartFrameworkOptions } from '../types.js';
|
|
2
2
|
import { PluginOption } from 'vite';
|
|
3
3
|
export declare function createServerFnPlugin(opts: {
|
|
4
4
|
framework: CompileStartFrameworkOptions;
|