@tanstack/start-plugin-core 1.143.3 → 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.
- package/dist/esm/plugin.js +11 -46
- package/dist/esm/plugin.js.map +1 -1
- package/dist/esm/{create-server-fn-plugin → start-compiler-plugin}/compiler.d.ts +39 -4
- package/dist/esm/{create-server-fn-plugin → start-compiler-plugin}/compiler.js +82 -24
- package/dist/esm/start-compiler-plugin/compiler.js.map +1 -0
- package/dist/esm/start-compiler-plugin/handleClientOnlyJSX.js.map +1 -0
- package/dist/esm/start-compiler-plugin/handleCreateIsomorphicFn.d.ts +8 -0
- package/dist/esm/start-compiler-plugin/handleCreateIsomorphicFn.js +33 -0
- package/dist/esm/start-compiler-plugin/handleCreateIsomorphicFn.js.map +1 -0
- package/dist/esm/start-compiler-plugin/handleCreateMiddleware.d.ts +8 -0
- package/dist/esm/start-compiler-plugin/handleCreateMiddleware.js +25 -0
- package/dist/esm/start-compiler-plugin/handleCreateMiddleware.js.map +1 -0
- package/dist/esm/start-compiler-plugin/handleCreateServerFn.d.ts +19 -0
- package/dist/esm/start-compiler-plugin/handleCreateServerFn.js +262 -0
- package/dist/esm/start-compiler-plugin/handleCreateServerFn.js.map +1 -0
- package/dist/esm/start-compiler-plugin/handleEnvOnly.d.ts +10 -0
- package/dist/esm/start-compiler-plugin/handleEnvOnly.js +38 -0
- package/dist/esm/start-compiler-plugin/handleEnvOnly.js.map +1 -0
- package/dist/esm/start-compiler-plugin/plugin.d.ts +19 -0
- package/dist/esm/start-compiler-plugin/plugin.js +314 -0
- package/dist/esm/start-compiler-plugin/plugin.js.map +1 -0
- package/dist/esm/start-compiler-plugin/types.d.ts +116 -0
- package/dist/esm/start-compiler-plugin/utils.d.ts +23 -0
- package/dist/esm/start-compiler-plugin/utils.js +34 -0
- package/dist/esm/start-compiler-plugin/utils.js.map +1 -0
- package/dist/esm/types.d.ts +0 -1
- package/package.json +6 -7
- package/src/plugin.ts +10 -50
- package/src/{create-server-fn-plugin → start-compiler-plugin}/compiler.ts +162 -30
- package/src/start-compiler-plugin/handleCreateIsomorphicFn.ts +54 -0
- package/src/start-compiler-plugin/handleCreateMiddleware.ts +39 -0
- package/src/start-compiler-plugin/handleCreateServerFn.ts +491 -0
- package/src/start-compiler-plugin/handleEnvOnly.ts +56 -0
- package/src/start-compiler-plugin/plugin.ts +423 -0
- package/src/start-compiler-plugin/types.ts +133 -0
- package/src/start-compiler-plugin/utils.ts +52 -0
- package/src/types.ts +0 -1
- package/dist/esm/create-server-fn-plugin/compiler.js.map +0 -1
- package/dist/esm/create-server-fn-plugin/handleClientOnlyJSX.js.map +0 -1
- package/dist/esm/create-server-fn-plugin/handleCreateIsomorphicFn.d.ts +0 -4
- package/dist/esm/create-server-fn-plugin/handleCreateIsomorphicFn.js +0 -31
- package/dist/esm/create-server-fn-plugin/handleCreateIsomorphicFn.js.map +0 -1
- package/dist/esm/create-server-fn-plugin/handleCreateMiddleware.d.ts +0 -10
- package/dist/esm/create-server-fn-plugin/handleCreateMiddleware.js +0 -29
- package/dist/esm/create-server-fn-plugin/handleCreateMiddleware.js.map +0 -1
- package/dist/esm/create-server-fn-plugin/handleCreateServerFn.d.ts +0 -17
- package/dist/esm/create-server-fn-plugin/handleCreateServerFn.js +0 -82
- package/dist/esm/create-server-fn-plugin/handleCreateServerFn.js.map +0 -1
- package/dist/esm/create-server-fn-plugin/handleEnvOnly.d.ts +0 -6
- package/dist/esm/create-server-fn-plugin/handleEnvOnly.js +0 -36
- package/dist/esm/create-server-fn-plugin/handleEnvOnly.js.map +0 -1
- package/dist/esm/create-server-fn-plugin/plugin.d.ts +0 -10
- package/dist/esm/create-server-fn-plugin/plugin.js +0 -186
- package/dist/esm/create-server-fn-plugin/plugin.js.map +0 -1
- package/dist/esm/create-server-fn-plugin/types.d.ts +0 -30
- package/dist/esm/create-server-fn-plugin/utils.d.ts +0 -10
- package/dist/esm/create-server-fn-plugin/utils.js +0 -19
- package/dist/esm/create-server-fn-plugin/utils.js.map +0 -1
- package/src/create-server-fn-plugin/handleCreateIsomorphicFn.ts +0 -46
- package/src/create-server-fn-plugin/handleCreateMiddleware.ts +0 -45
- package/src/create-server-fn-plugin/handleCreateServerFn.ts +0 -145
- package/src/create-server-fn-plugin/handleEnvOnly.ts +0 -45
- package/src/create-server-fn-plugin/plugin.ts +0 -234
- package/src/create-server-fn-plugin/types.ts +0 -34
- package/src/create-server-fn-plugin/utils.ts +0 -24
- /package/dist/esm/{create-server-fn-plugin → start-compiler-plugin}/handleClientOnlyJSX.d.ts +0 -0
- /package/dist/esm/{create-server-fn-plugin → start-compiler-plugin}/handleClientOnlyJSX.js +0 -0
- /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,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
|
-
}
|
/package/dist/esm/{create-server-fn-plugin → start-compiler-plugin}/handleClientOnlyJSX.d.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|