@tanstack/start-plugin-core 1.143.4 → 1.143.5

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.
Files changed (68) hide show
  1. package/dist/esm/plugin.js +11 -46
  2. package/dist/esm/plugin.js.map +1 -1
  3. package/dist/esm/{create-server-fn-plugin → start-compiler-plugin}/compiler.d.ts +39 -4
  4. package/dist/esm/{create-server-fn-plugin → start-compiler-plugin}/compiler.js +82 -24
  5. package/dist/esm/start-compiler-plugin/compiler.js.map +1 -0
  6. package/dist/esm/start-compiler-plugin/handleClientOnlyJSX.js.map +1 -0
  7. package/dist/esm/start-compiler-plugin/handleCreateIsomorphicFn.d.ts +8 -0
  8. package/dist/esm/start-compiler-plugin/handleCreateIsomorphicFn.js +33 -0
  9. package/dist/esm/start-compiler-plugin/handleCreateIsomorphicFn.js.map +1 -0
  10. package/dist/esm/start-compiler-plugin/handleCreateMiddleware.d.ts +8 -0
  11. package/dist/esm/start-compiler-plugin/handleCreateMiddleware.js +25 -0
  12. package/dist/esm/start-compiler-plugin/handleCreateMiddleware.js.map +1 -0
  13. package/dist/esm/start-compiler-plugin/handleCreateServerFn.d.ts +19 -0
  14. package/dist/esm/start-compiler-plugin/handleCreateServerFn.js +262 -0
  15. package/dist/esm/start-compiler-plugin/handleCreateServerFn.js.map +1 -0
  16. package/dist/esm/start-compiler-plugin/handleEnvOnly.d.ts +10 -0
  17. package/dist/esm/start-compiler-plugin/handleEnvOnly.js +38 -0
  18. package/dist/esm/start-compiler-plugin/handleEnvOnly.js.map +1 -0
  19. package/dist/esm/start-compiler-plugin/plugin.d.ts +19 -0
  20. package/dist/esm/start-compiler-plugin/plugin.js +314 -0
  21. package/dist/esm/start-compiler-plugin/plugin.js.map +1 -0
  22. package/dist/esm/start-compiler-plugin/types.d.ts +116 -0
  23. package/dist/esm/start-compiler-plugin/utils.d.ts +23 -0
  24. package/dist/esm/start-compiler-plugin/utils.js +34 -0
  25. package/dist/esm/start-compiler-plugin/utils.js.map +1 -0
  26. package/dist/esm/types.d.ts +0 -1
  27. package/package.json +3 -4
  28. package/src/plugin.ts +10 -50
  29. package/src/{create-server-fn-plugin → start-compiler-plugin}/compiler.ts +162 -30
  30. package/src/start-compiler-plugin/handleCreateIsomorphicFn.ts +54 -0
  31. package/src/start-compiler-plugin/handleCreateMiddleware.ts +39 -0
  32. package/src/start-compiler-plugin/handleCreateServerFn.ts +491 -0
  33. package/src/start-compiler-plugin/handleEnvOnly.ts +56 -0
  34. package/src/start-compiler-plugin/plugin.ts +423 -0
  35. package/src/start-compiler-plugin/types.ts +133 -0
  36. package/src/start-compiler-plugin/utils.ts +52 -0
  37. package/src/types.ts +0 -1
  38. package/dist/esm/create-server-fn-plugin/compiler.js.map +0 -1
  39. package/dist/esm/create-server-fn-plugin/handleClientOnlyJSX.js.map +0 -1
  40. package/dist/esm/create-server-fn-plugin/handleCreateIsomorphicFn.d.ts +0 -4
  41. package/dist/esm/create-server-fn-plugin/handleCreateIsomorphicFn.js +0 -31
  42. package/dist/esm/create-server-fn-plugin/handleCreateIsomorphicFn.js.map +0 -1
  43. package/dist/esm/create-server-fn-plugin/handleCreateMiddleware.d.ts +0 -10
  44. package/dist/esm/create-server-fn-plugin/handleCreateMiddleware.js +0 -29
  45. package/dist/esm/create-server-fn-plugin/handleCreateMiddleware.js.map +0 -1
  46. package/dist/esm/create-server-fn-plugin/handleCreateServerFn.d.ts +0 -17
  47. package/dist/esm/create-server-fn-plugin/handleCreateServerFn.js +0 -82
  48. package/dist/esm/create-server-fn-plugin/handleCreateServerFn.js.map +0 -1
  49. package/dist/esm/create-server-fn-plugin/handleEnvOnly.d.ts +0 -6
  50. package/dist/esm/create-server-fn-plugin/handleEnvOnly.js +0 -36
  51. package/dist/esm/create-server-fn-plugin/handleEnvOnly.js.map +0 -1
  52. package/dist/esm/create-server-fn-plugin/plugin.d.ts +0 -10
  53. package/dist/esm/create-server-fn-plugin/plugin.js +0 -186
  54. package/dist/esm/create-server-fn-plugin/plugin.js.map +0 -1
  55. package/dist/esm/create-server-fn-plugin/types.d.ts +0 -30
  56. package/dist/esm/create-server-fn-plugin/utils.d.ts +0 -10
  57. package/dist/esm/create-server-fn-plugin/utils.js +0 -19
  58. package/dist/esm/create-server-fn-plugin/utils.js.map +0 -1
  59. package/src/create-server-fn-plugin/handleCreateIsomorphicFn.ts +0 -46
  60. package/src/create-server-fn-plugin/handleCreateMiddleware.ts +0 -45
  61. package/src/create-server-fn-plugin/handleCreateServerFn.ts +0 -145
  62. package/src/create-server-fn-plugin/handleEnvOnly.ts +0 -45
  63. package/src/create-server-fn-plugin/plugin.ts +0 -234
  64. package/src/create-server-fn-plugin/types.ts +0 -34
  65. package/src/create-server-fn-plugin/utils.ts +0 -24
  66. /package/dist/esm/{create-server-fn-plugin → start-compiler-plugin}/handleClientOnlyJSX.d.ts +0 -0
  67. /package/dist/esm/{create-server-fn-plugin → start-compiler-plugin}/handleClientOnlyJSX.js +0 -0
  68. /package/src/{create-server-fn-plugin → start-compiler-plugin}/handleClientOnlyJSX.ts +0 -0
@@ -1,30 +0,0 @@
1
- import type * as babel from '@babel/core';
2
- import type * as t from '@babel/types';
3
- /**
4
- * Info about a method call in the chain, including the call expression path
5
- * and the path to its first argument (if any).
6
- */
7
- export interface MethodCallInfo {
8
- callPath: babel.NodePath<t.CallExpression>;
9
- /** Path to the first argument, or null if no arguments */
10
- firstArgPath: babel.NodePath | null;
11
- }
12
- /**
13
- * Pre-collected method chain paths for a root call expression.
14
- * This avoids needing to traverse the AST again in handlers.
15
- */
16
- export interface MethodChainPaths {
17
- middleware: MethodCallInfo | null;
18
- inputValidator: MethodCallInfo | null;
19
- handler: MethodCallInfo | null;
20
- server: MethodCallInfo | null;
21
- client: MethodCallInfo | null;
22
- }
23
- export type MethodChainKey = keyof MethodChainPaths;
24
- /**
25
- * Information about a candidate that needs to be rewritten.
26
- */
27
- export interface RewriteCandidate {
28
- path: babel.NodePath<t.CallExpression>;
29
- methodChain: MethodChainPaths;
30
- }
@@ -1,10 +0,0 @@
1
- export declare function codeFrameError(code: string, loc: {
2
- start: {
3
- line: number;
4
- column: number;
5
- };
6
- end: {
7
- line: number;
8
- column: number;
9
- };
10
- }, message: string): Error;
@@ -1,19 +0,0 @@
1
- import { codeFrameColumns } from "@babel/code-frame";
2
- function codeFrameError(code, loc, message) {
3
- const frame = codeFrameColumns(
4
- code,
5
- {
6
- start: loc.start,
7
- end: loc.end
8
- },
9
- {
10
- highlightCode: true,
11
- message
12
- }
13
- );
14
- return new Error(frame);
15
- }
16
- export {
17
- codeFrameError
18
- };
19
- //# sourceMappingURL=utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sources":["../../../src/create-server-fn-plugin/utils.ts"],"sourcesContent":["import { codeFrameColumns } from '@babel/code-frame'\n\nexport function codeFrameError(\n code: string,\n loc: {\n start: { line: number; column: number }\n end: { line: number; column: number }\n },\n message: string,\n) {\n const frame = codeFrameColumns(\n code,\n {\n start: loc.start,\n end: loc.end,\n },\n {\n highlightCode: true,\n message,\n },\n )\n\n return new Error(frame)\n}\n"],"names":[],"mappings":";AAEO,SAAS,eACd,MACA,KAIA,SACA;AACA,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,MACE,OAAO,IAAI;AAAA,MACX,KAAK,IAAI;AAAA,IAAA;AAAA,IAEX;AAAA,MACE,eAAe;AAAA,MACf;AAAA,IAAA;AAAA,EACF;AAGF,SAAO,IAAI,MAAM,KAAK;AACxB;"}
@@ -1,46 +0,0 @@
1
- import * as t from '@babel/types'
2
- import type { RewriteCandidate } from './types'
3
-
4
- export function handleCreateIsomorphicFn(
5
- candidate: RewriteCandidate,
6
- opts: { env: 'client' | 'server' },
7
- ) {
8
- const { path, methodChain } = candidate
9
-
10
- // Get the environment-specific call (.client() or .server())
11
- const envCallInfo =
12
- opts.env === 'client' ? methodChain.client : methodChain.server
13
-
14
- // Check if we have any implementation at all
15
- if (!methodChain.client && !methodChain.server) {
16
- // No implementations provided - warn and replace with no-op
17
- const variableId = path.parentPath.isVariableDeclarator()
18
- ? path.parentPath.node.id
19
- : null
20
- console.warn(
21
- 'createIsomorphicFn called without a client or server implementation!',
22
- 'This will result in a no-op function.',
23
- 'Variable name:',
24
- t.isIdentifier(variableId) ? variableId.name : 'unknown',
25
- )
26
- path.replaceWith(t.arrowFunctionExpression([], t.blockStatement([])))
27
- return
28
- }
29
-
30
- if (!envCallInfo) {
31
- // No implementation for this environment - replace with no-op
32
- path.replaceWith(t.arrowFunctionExpression([], t.blockStatement([])))
33
- return
34
- }
35
-
36
- // Extract the function argument from the environment-specific call
37
- const innerFn = envCallInfo.firstArgPath?.node
38
-
39
- if (!t.isExpression(innerFn)) {
40
- throw new Error(
41
- `createIsomorphicFn().${opts.env}(func) must be called with a function!`,
42
- )
43
- }
44
-
45
- path.replaceWith(innerFn)
46
- }
@@ -1,45 +0,0 @@
1
- import * as t from '@babel/types'
2
- import type { RewriteCandidate } from './types'
3
-
4
- /**
5
- * Handles createMiddleware transformations.
6
- *
7
- * @param candidate - The rewrite candidate containing path and method chain
8
- * @param opts - Options including the environment
9
- */
10
- export function handleCreateMiddleware(
11
- candidate: RewriteCandidate,
12
- opts: {
13
- env: 'client' | 'server'
14
- },
15
- ) {
16
- if (opts.env === 'server') {
17
- throw new Error('handleCreateMiddleware should not be called on the server')
18
- }
19
-
20
- const { inputValidator, server } = candidate.methodChain
21
-
22
- if (inputValidator) {
23
- const innerInputExpression = inputValidator.callPath.node.arguments[0]
24
-
25
- if (!innerInputExpression) {
26
- throw new Error(
27
- 'createMiddleware().inputValidator() must be called with a validator!',
28
- )
29
- }
30
-
31
- // remove the validator call expression
32
- if (t.isMemberExpression(inputValidator.callPath.node.callee)) {
33
- inputValidator.callPath.replaceWith(
34
- inputValidator.callPath.node.callee.object,
35
- )
36
- }
37
- }
38
-
39
- if (server) {
40
- // remove the server call expression
41
- if (t.isMemberExpression(server.callPath.node.callee)) {
42
- server.callPath.replaceWith(server.callPath.node.callee.object)
43
- }
44
- }
45
- }
@@ -1,145 +0,0 @@
1
- import * as t from '@babel/types'
2
- import { codeFrameError } from './utils'
3
- import type { RewriteCandidate } from './types'
4
-
5
- /**
6
- * Handles createServerFn transformations.
7
- *
8
- * @param candidate - The rewrite candidate containing path and method chain
9
- * @param opts - Options including the environment, code, directive, and provider file flag
10
- */
11
- export function handleCreateServerFn(
12
- candidate: RewriteCandidate,
13
- opts: {
14
- env: 'client' | 'server'
15
- code: string
16
- directive: string
17
- /**
18
- * Whether this file is a provider file (extracted server function file).
19
- * Only provider files should have the handler implementation as a second argument.
20
- */
21
- isProviderFile: boolean
22
- },
23
- ) {
24
- const { path, methodChain } = candidate
25
- const { inputValidator, handler } = methodChain
26
-
27
- // Check if the call is assigned to a variable
28
- if (!path.parentPath.isVariableDeclarator()) {
29
- throw new Error('createServerFn must be assigned to a variable!')
30
- }
31
-
32
- // Get the identifier name of the variable
33
- const variableDeclarator = path.parentPath.node
34
- if (!t.isIdentifier(variableDeclarator.id)) {
35
- throw codeFrameError(
36
- opts.code,
37
- variableDeclarator.id.loc!,
38
- 'createServerFn must be assigned to a simple identifier, not a destructuring pattern',
39
- )
40
- }
41
- const existingVariableName = variableDeclarator.id.name
42
-
43
- if (inputValidator) {
44
- const innerInputExpression = inputValidator.callPath.node.arguments[0]
45
-
46
- if (!innerInputExpression) {
47
- throw new Error(
48
- 'createServerFn().inputValidator() must be called with a validator!',
49
- )
50
- }
51
-
52
- // If we're on the client, remove the validator call expression
53
- if (opts.env === 'client') {
54
- if (t.isMemberExpression(inputValidator.callPath.node.callee)) {
55
- inputValidator.callPath.replaceWith(
56
- inputValidator.callPath.node.callee.object,
57
- )
58
- }
59
- }
60
- }
61
-
62
- // First, we need to move the handler function to a nested function call
63
- // that is applied to the arguments passed to the server function.
64
-
65
- const handlerFnPath = handler?.firstArgPath
66
-
67
- if (!handler || !handlerFnPath?.node) {
68
- throw codeFrameError(
69
- opts.code,
70
- path.node.callee.loc!,
71
- `createServerFn must be called with a "handler" property!`,
72
- )
73
- }
74
-
75
- // Validate the handler argument is an expression (not a SpreadElement, etc.)
76
- if (!t.isExpression(handlerFnPath.node)) {
77
- throw codeFrameError(
78
- opts.code,
79
- handlerFnPath.node.loc!,
80
- `handler() must be called with an expression, not a ${handlerFnPath.node.type}`,
81
- )
82
- }
83
-
84
- const handlerFn = handlerFnPath.node
85
-
86
- // So, the way we do this is we give the handler function a way
87
- // to access the serverFn ctx on the server via function scope.
88
- // The 'use server' extracted function will be called with the
89
- // payload from the client, then use the scoped serverFn ctx
90
- // to execute the handler function.
91
- // This way, we can do things like data and middleware validation
92
- // in the __execute function without having to AST transform the
93
- // handler function too much itself.
94
-
95
- // .handler((optsOut, ctx) => {
96
- // return ((optsIn) => {
97
- // 'use server'
98
- // ctx.__execute(handlerFn, optsIn)
99
- // })(optsOut)
100
- // })
101
-
102
- // If the handler function is an identifier and we're on the client, we need to
103
- // remove the bound function from the file.
104
- // If we're on the server, you can leave it, since it will get referenced
105
- // as a second argument.
106
-
107
- if (t.isIdentifier(handlerFn)) {
108
- if (opts.env === 'client') {
109
- // Find the binding for the handler function
110
- const binding = handlerFnPath.scope.getBinding(handlerFn.name)
111
- // Remove it
112
- if (binding) {
113
- binding.path.remove()
114
- }
115
- }
116
- // If the env is server, just leave it alone
117
- }
118
-
119
- handlerFnPath.replaceWith(
120
- t.arrowFunctionExpression(
121
- [t.identifier('opts'), t.identifier('signal')],
122
- t.blockStatement(
123
- // Everything in here is server-only, since the client
124
- // will strip out anything in the 'use server' directive.
125
- [
126
- t.returnStatement(
127
- t.callExpression(
128
- t.identifier(`${existingVariableName}.__executeServer`),
129
- [t.identifier('opts'), t.identifier('signal')],
130
- ),
131
- ),
132
- ],
133
- [t.directive(t.directiveLiteral(opts.directive))],
134
- ),
135
- ),
136
- )
137
-
138
- // Add the serverFn as a second argument on the server side,
139
- // but ONLY for provider files (extracted server function files).
140
- // Caller files must NOT have the second argument because the implementation is already available in the extracted chunk
141
- // and including it would duplicate code
142
- if (opts.env === 'server' && opts.isProviderFile) {
143
- handler.callPath.node.arguments.push(handlerFn)
144
- }
145
- }
@@ -1,45 +0,0 @@
1
- import * as t from '@babel/types'
2
- import type { RewriteCandidate } from './types'
3
- import type { LookupKind } from './compiler'
4
-
5
- function capitalize(str: string) {
6
- if (!str) return ''
7
- return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
8
- }
9
-
10
- export function handleEnvOnlyFn(
11
- candidate: RewriteCandidate,
12
- opts: { env: 'client' | 'server'; kind: LookupKind },
13
- ) {
14
- const { path } = candidate
15
- const targetEnv = opts.kind === 'ClientOnlyFn' ? 'client' : 'server'
16
-
17
- if (opts.env === targetEnv) {
18
- // Matching environment - extract the inner function
19
- const innerFn = path.node.arguments[0]
20
-
21
- if (!t.isExpression(innerFn)) {
22
- throw new Error(
23
- `create${capitalize(targetEnv)}OnlyFn() must be called with a function!`,
24
- )
25
- }
26
-
27
- path.replaceWith(innerFn)
28
- } else {
29
- // Wrong environment - replace with a function that throws an error
30
- path.replaceWith(
31
- t.arrowFunctionExpression(
32
- [],
33
- t.blockStatement([
34
- t.throwStatement(
35
- t.newExpression(t.identifier('Error'), [
36
- t.stringLiteral(
37
- `create${capitalize(targetEnv)}OnlyFn() functions can only be called on the ${targetEnv}!`,
38
- ),
39
- ]),
40
- ),
41
- ]),
42
- ),
43
- )
44
- }
45
- }
@@ -1,234 +0,0 @@
1
- import { TRANSFORM_ID_REGEX } from '../constants'
2
- import {
3
- KindDetectionPatterns,
4
- LookupKindsPerEnv,
5
- ServerFnCompiler,
6
- detectKindsInCode,
7
- } from './compiler'
8
- import type { CompileStartFrameworkOptions } from '../types'
9
- import type { LookupConfig, LookupKind } from './compiler'
10
- import type { PluginOption } from 'vite'
11
-
12
- function cleanId(id: string): string {
13
- // Remove null byte prefix used by Vite/Rollup for virtual modules
14
- if (id.startsWith('\0')) {
15
- id = id.slice(1)
16
- }
17
- const queryIndex = id.indexOf('?')
18
- return queryIndex === -1 ? id : id.substring(0, queryIndex)
19
- }
20
-
21
- // Derive transform code filter from KindDetectionPatterns (single source of truth)
22
- function getTransformCodeFilterForEnv(env: 'client' | 'server'): Array<RegExp> {
23
- const validKinds = LookupKindsPerEnv[env]
24
- const patterns: Array<RegExp> = []
25
- for (const [kind, pattern] of Object.entries(KindDetectionPatterns) as Array<
26
- [LookupKind, RegExp]
27
- >) {
28
- if (validKinds.has(kind)) {
29
- patterns.push(pattern)
30
- }
31
- }
32
- return patterns
33
- }
34
-
35
- const getLookupConfigurationsForEnv = (
36
- env: 'client' | 'server',
37
- framework: CompileStartFrameworkOptions,
38
- ): Array<LookupConfig> => {
39
- // Common configs for all environments
40
- const commonConfigs: Array<LookupConfig> = [
41
- {
42
- libName: `@tanstack/${framework}-start`,
43
- rootExport: 'createServerFn',
44
- kind: 'Root',
45
- },
46
- {
47
- libName: `@tanstack/${framework}-start`,
48
- rootExport: 'createIsomorphicFn',
49
- kind: 'IsomorphicFn',
50
- },
51
- {
52
- libName: `@tanstack/${framework}-start`,
53
- rootExport: 'createServerOnlyFn',
54
- kind: 'ServerOnlyFn',
55
- },
56
- {
57
- libName: `@tanstack/${framework}-start`,
58
- rootExport: 'createClientOnlyFn',
59
- kind: 'ClientOnlyFn',
60
- },
61
- ]
62
-
63
- if (env === 'client') {
64
- return [
65
- {
66
- libName: `@tanstack/${framework}-start`,
67
- rootExport: 'createMiddleware',
68
- kind: 'Root',
69
- },
70
- {
71
- libName: `@tanstack/${framework}-start`,
72
- rootExport: 'createStart',
73
- kind: 'Root',
74
- },
75
- ...commonConfigs,
76
- ]
77
- } else {
78
- // Server-only: add ClientOnly JSX component lookup
79
- return [
80
- ...commonConfigs,
81
- {
82
- libName: `@tanstack/${framework}-router`,
83
- rootExport: 'ClientOnly',
84
- kind: 'ClientOnlyJSX',
85
- },
86
- ]
87
- }
88
- }
89
- const SERVER_FN_LOOKUP = 'server-fn-module-lookup'
90
-
91
- function buildDirectiveSplitParam(directive: string) {
92
- return `tsr-directive-${directive.replace(/[^a-zA-Z0-9]/g, '-')}`
93
- }
94
-
95
- export function createServerFnPlugin(opts: {
96
- framework: CompileStartFrameworkOptions
97
- directive: string
98
- environments: Array<{ name: string; type: 'client' | 'server' }>
99
- }): PluginOption {
100
- const compilers: Record<string /* envName */, ServerFnCompiler> = {}
101
- const directiveSplitParam = buildDirectiveSplitParam(opts.directive)
102
-
103
- function perEnvServerFnPlugin(environment: {
104
- name: string
105
- type: 'client' | 'server'
106
- }): PluginOption {
107
- // Derive transform code filter from KindDetectionPatterns (single source of truth)
108
- const transformCodeFilter = getTransformCodeFilterForEnv(environment.type)
109
-
110
- return {
111
- name: `tanstack-start-core::server-fn:${environment.name}`,
112
- enforce: 'pre',
113
- applyToEnvironment(env) {
114
- return env.name === environment.name
115
- },
116
- transform: {
117
- filter: {
118
- id: {
119
- exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),
120
- include: TRANSFORM_ID_REGEX,
121
- },
122
- code: {
123
- include: transformCodeFilter,
124
- },
125
- },
126
- async handler(code, id) {
127
- let compiler = compilers[this.environment.name]
128
- if (!compiler) {
129
- // Default to 'dev' mode for unknown environments (conservative: no caching)
130
- const mode =
131
- this.environment.mode === 'build' ? 'build' : ('dev' as const)
132
- compiler = new ServerFnCompiler({
133
- env: environment.type,
134
- directive: opts.directive,
135
- lookupKinds: LookupKindsPerEnv[environment.type],
136
- lookupConfigurations: getLookupConfigurationsForEnv(
137
- environment.type,
138
- opts.framework,
139
- ),
140
- mode,
141
- loadModule: async (id: string) => {
142
- if (this.environment.mode === 'build') {
143
- const loaded = await this.load({ id })
144
- // Handle modules with no runtime code (e.g., type-only exports).
145
- // After TypeScript compilation, these become empty modules.
146
- // Create an empty module info instead of throwing.
147
- const code = loaded.code ?? ''
148
- compiler!.ingestModule({ code, id })
149
- } else if (this.environment.mode === 'dev') {
150
- /**
151
- * in dev, vite does not return code from `ctx.load()`
152
- * so instead, we need to take a different approach
153
- * we must force vite to load the module and run it through the vite plugin pipeline
154
- * we can do this by using the `fetchModule` method
155
- * the `captureServerFnModuleLookupPlugin` captures the module code via its transform hook and invokes analyzeModuleAST
156
- */
157
- await this.environment.fetchModule(
158
- id + '?' + SERVER_FN_LOOKUP,
159
- )
160
- } else {
161
- throw new Error(
162
- `could not load module ${id}: unknown environment mode ${this.environment.mode}`,
163
- )
164
- }
165
- },
166
- resolveId: async (source: string, importer?: string) => {
167
- const r = await this.resolve(source, importer)
168
- if (r) {
169
- if (!r.external) {
170
- return cleanId(r.id)
171
- }
172
- }
173
- return null
174
- },
175
- })
176
- compilers[this.environment.name] = compiler
177
- }
178
-
179
- const isProviderFile = id.includes(directiveSplitParam)
180
-
181
- // Detect which kinds are present in this file before parsing
182
- const detectedKinds = detectKindsInCode(code, environment.type)
183
-
184
- id = cleanId(id)
185
- const result = await compiler.compile({
186
- id,
187
- code,
188
- isProviderFile,
189
- detectedKinds,
190
- })
191
- return result
192
- },
193
- },
194
-
195
- hotUpdate(ctx) {
196
- const compiler = compilers[this.environment.name]
197
-
198
- ctx.modules.forEach((m) => {
199
- if (m.id) {
200
- const deleted = compiler?.invalidateModule(m.id)
201
- if (deleted) {
202
- m.importers.forEach((importer) => {
203
- if (importer.id) {
204
- compiler?.invalidateModule(importer.id)
205
- }
206
- })
207
- }
208
- }
209
- })
210
- },
211
- }
212
- }
213
-
214
- return [
215
- ...opts.environments.map(perEnvServerFnPlugin),
216
- {
217
- name: 'tanstack-start-core:capture-server-fn-module-lookup',
218
- // we only need this plugin in dev mode
219
- apply: 'serve',
220
- applyToEnvironment(env) {
221
- return !!opts.environments.find((e) => e.name === env.name)
222
- },
223
- transform: {
224
- filter: {
225
- id: new RegExp(`${SERVER_FN_LOOKUP}$`),
226
- },
227
- handler(code, id) {
228
- const compiler = compilers[this.environment.name]
229
- compiler?.ingestModule({ code, id: cleanId(id) })
230
- },
231
- },
232
- },
233
- ]
234
- }
@@ -1,34 +0,0 @@
1
- import type * as babel from '@babel/core'
2
- import type * as t from '@babel/types'
3
-
4
- /**
5
- * Info about a method call in the chain, including the call expression path
6
- * and the path to its first argument (if any).
7
- */
8
- export interface MethodCallInfo {
9
- callPath: babel.NodePath<t.CallExpression>
10
- /** Path to the first argument, or null if no arguments */
11
- firstArgPath: babel.NodePath | null
12
- }
13
-
14
- /**
15
- * Pre-collected method chain paths for a root call expression.
16
- * This avoids needing to traverse the AST again in handlers.
17
- */
18
- export interface MethodChainPaths {
19
- middleware: MethodCallInfo | null
20
- inputValidator: MethodCallInfo | null
21
- handler: MethodCallInfo | null
22
- server: MethodCallInfo | null
23
- client: MethodCallInfo | null
24
- }
25
-
26
- export type MethodChainKey = keyof MethodChainPaths
27
-
28
- /**
29
- * Information about a candidate that needs to be rewritten.
30
- */
31
- export interface RewriteCandidate {
32
- path: babel.NodePath<t.CallExpression>
33
- methodChain: MethodChainPaths
34
- }
@@ -1,24 +0,0 @@
1
- import { codeFrameColumns } from '@babel/code-frame'
2
-
3
- export function codeFrameError(
4
- code: string,
5
- loc: {
6
- start: { line: number; column: number }
7
- end: { line: number; column: number }
8
- },
9
- message: string,
10
- ) {
11
- const frame = codeFrameColumns(
12
- code,
13
- {
14
- start: loc.start,
15
- end: loc.end,
16
- },
17
- {
18
- highlightCode: true,
19
- message,
20
- },
21
- )
22
-
23
- return new Error(frame)
24
- }