@tanstack/start-plugin-core 1.167.35 → 1.169.0

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 (187) hide show
  1. package/dist/esm/import-protection/adapterUtils.d.ts +27 -0
  2. package/dist/esm/import-protection/adapterUtils.js +31 -0
  3. package/dist/esm/import-protection/adapterUtils.js.map +1 -0
  4. package/dist/esm/import-protection/analysis.d.ts +36 -0
  5. package/dist/esm/import-protection/analysis.js +407 -0
  6. package/dist/esm/import-protection/analysis.js.map +1 -0
  7. package/dist/esm/{import-protection-plugin → import-protection}/ast.js +1 -1
  8. package/dist/esm/import-protection/ast.js.map +1 -0
  9. package/dist/esm/import-protection/constants.d.ts +11 -0
  10. package/dist/esm/{import-protection-plugin → import-protection}/constants.js +7 -2
  11. package/dist/esm/import-protection/constants.js.map +1 -0
  12. package/dist/esm/{import-protection-plugin → import-protection}/defaults.js +1 -1
  13. package/dist/esm/import-protection/defaults.js.map +1 -0
  14. package/dist/esm/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.js +2 -2
  15. package/dist/esm/import-protection/extensionlessAbsoluteIdResolver.js.map +1 -0
  16. package/dist/esm/{import-protection-plugin → import-protection}/matchers.js +1 -1
  17. package/dist/esm/import-protection/matchers.js.map +1 -0
  18. package/dist/esm/{import-protection-plugin/rewriteDeniedImports.d.ts → import-protection/rewrite.d.ts} +0 -4
  19. package/dist/esm/import-protection/rewrite.js +121 -0
  20. package/dist/esm/import-protection/rewrite.js.map +1 -0
  21. package/dist/esm/{import-protection-plugin → import-protection}/sourceLocation.d.ts +32 -3
  22. package/dist/esm/{import-protection-plugin → import-protection}/sourceLocation.js +65 -10
  23. package/dist/esm/import-protection/sourceLocation.js.map +1 -0
  24. package/dist/esm/{import-protection-plugin → import-protection}/trace.d.ts +0 -1
  25. package/dist/esm/{import-protection-plugin → import-protection}/trace.js +1 -1
  26. package/dist/esm/import-protection/trace.js.map +1 -0
  27. package/dist/esm/{import-protection-plugin → import-protection}/utils.d.ts +18 -1
  28. package/dist/esm/{import-protection-plugin → import-protection}/utils.js +13 -20
  29. package/dist/esm/import-protection/utils.js.map +1 -0
  30. package/dist/esm/import-protection/virtualModules.d.ts +25 -0
  31. package/dist/esm/{import-protection-plugin → import-protection}/virtualModules.js +5 -117
  32. package/dist/esm/import-protection/virtualModules.js.map +1 -0
  33. package/dist/esm/index.d.ts +1 -5
  34. package/dist/esm/index.js +2 -4
  35. package/dist/esm/post-build.d.ts +9 -0
  36. package/dist/esm/post-build.js +37 -0
  37. package/dist/esm/post-build.js.map +1 -0
  38. package/dist/esm/prerender.d.ts +11 -0
  39. package/dist/esm/prerender.js +159 -0
  40. package/dist/esm/prerender.js.map +1 -0
  41. package/dist/esm/rsbuild/dev-server.d.ts +21 -0
  42. package/dist/esm/rsbuild/dev-server.js +76 -0
  43. package/dist/esm/rsbuild/dev-server.js.map +1 -0
  44. package/dist/esm/rsbuild/import-protection.d.ts +10 -0
  45. package/dist/esm/rsbuild/import-protection.js +775 -0
  46. package/dist/esm/rsbuild/import-protection.js.map +1 -0
  47. package/dist/esm/rsbuild/index.d.ts +4 -0
  48. package/dist/esm/rsbuild/index.js +3 -0
  49. package/dist/esm/rsbuild/normalized-client-build.d.ts +18 -0
  50. package/dist/esm/rsbuild/normalized-client-build.js +207 -0
  51. package/dist/esm/rsbuild/normalized-client-build.js.map +1 -0
  52. package/dist/esm/rsbuild/planning.d.ts +52 -0
  53. package/dist/esm/rsbuild/planning.js +108 -0
  54. package/dist/esm/rsbuild/planning.js.map +1 -0
  55. package/dist/esm/rsbuild/plugin.d.ts +4 -0
  56. package/dist/esm/rsbuild/plugin.js +344 -0
  57. package/dist/esm/rsbuild/plugin.js.map +1 -0
  58. package/dist/esm/rsbuild/post-build.d.ts +6 -0
  59. package/dist/esm/rsbuild/post-build.js +57 -0
  60. package/dist/esm/rsbuild/post-build.js.map +1 -0
  61. package/dist/esm/rsbuild/schema.d.ts +3372 -0
  62. package/dist/esm/rsbuild/schema.js +12 -0
  63. package/dist/esm/rsbuild/schema.js.map +1 -0
  64. package/dist/esm/rsbuild/start-compiler-host.d.ts +20 -0
  65. package/dist/esm/rsbuild/start-compiler-host.js +150 -0
  66. package/dist/esm/rsbuild/start-compiler-host.js.map +1 -0
  67. package/dist/esm/rsbuild/start-router-plugin.d.ts +18 -0
  68. package/dist/esm/rsbuild/start-router-plugin.js +63 -0
  69. package/dist/esm/rsbuild/start-router-plugin.js.map +1 -0
  70. package/dist/esm/rsbuild/swc-rsc.d.ts +14 -0
  71. package/dist/esm/rsbuild/swc-rsc.js +93 -0
  72. package/dist/esm/rsbuild/swc-rsc.js.map +1 -0
  73. package/dist/esm/rsbuild/types.d.ts +17 -0
  74. package/dist/esm/rsbuild/types.js +0 -0
  75. package/dist/esm/rsbuild/virtual-modules.d.ts +53 -0
  76. package/dist/esm/rsbuild/virtual-modules.js +287 -0
  77. package/dist/esm/rsbuild/virtual-modules.js.map +1 -0
  78. package/dist/esm/schema.d.ts +43 -43
  79. package/dist/esm/start-compiler/compiler.d.ts +1 -1
  80. package/dist/esm/start-compiler/compiler.js +80 -9
  81. package/dist/esm/start-compiler/compiler.js.map +1 -1
  82. package/dist/esm/start-compiler/handleCreateServerFn.js +9 -0
  83. package/dist/esm/start-compiler/handleCreateServerFn.js.map +1 -1
  84. package/dist/esm/start-compiler/host.js +5 -1
  85. package/dist/esm/start-compiler/host.js.map +1 -1
  86. package/dist/esm/start-compiler/types.d.ts +1 -0
  87. package/dist/esm/utils.d.ts +1 -0
  88. package/dist/esm/utils.js +10 -1
  89. package/dist/esm/utils.js.map +1 -1
  90. package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/plugin.js +41 -92
  91. package/dist/esm/vite/import-protection-plugin/plugin.js.map +1 -0
  92. package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/types.d.ts +5 -5
  93. package/dist/esm/vite/import-protection-plugin/virtualModules.d.ts +8 -0
  94. package/dist/esm/vite/import-protection-plugin/virtualModules.js +49 -0
  95. package/dist/esm/vite/import-protection-plugin/virtualModules.js.map +1 -0
  96. package/dist/esm/vite/index.d.ts +5 -0
  97. package/dist/esm/vite/index.js +4 -0
  98. package/dist/esm/vite/plugin.js +1 -1
  99. package/dist/esm/vite/plugin.js.map +1 -1
  100. package/dist/esm/vite/post-server-build.js +14 -32
  101. package/dist/esm/vite/post-server-build.js.map +1 -1
  102. package/dist/esm/vite/prerender.d.ts +2 -2
  103. package/dist/esm/vite/prerender.js +17 -147
  104. package/dist/esm/vite/prerender.js.map +1 -1
  105. package/dist/esm/vite/schema.d.ts +23 -23
  106. package/dist/esm/vite/start-compiler-plugin/hot-update.d.ts +2 -0
  107. package/dist/esm/vite/start-compiler-plugin/hot-update.js +16 -0
  108. package/dist/esm/vite/start-compiler-plugin/hot-update.js.map +1 -0
  109. package/dist/esm/vite/start-compiler-plugin/module-specifier.js +9 -4
  110. package/dist/esm/vite/start-compiler-plugin/module-specifier.js.map +1 -1
  111. package/dist/esm/vite/start-compiler-plugin/plugin.js +86 -13
  112. package/dist/esm/vite/start-compiler-plugin/plugin.js.map +1 -1
  113. package/package.json +32 -4
  114. package/src/import-protection/INTERNALS.md +266 -0
  115. package/src/import-protection/adapterUtils.ts +94 -0
  116. package/src/import-protection/analysis.ts +853 -0
  117. package/src/{import-protection-plugin → import-protection}/constants.ts +7 -0
  118. package/src/import-protection/rewrite.ts +229 -0
  119. package/src/{import-protection-plugin → import-protection}/sourceLocation.ts +125 -9
  120. package/src/{import-protection-plugin → import-protection}/trace.ts +0 -1
  121. package/src/{import-protection-plugin → import-protection}/utils.ts +36 -21
  122. package/src/{import-protection-plugin → import-protection}/virtualModules.ts +30 -177
  123. package/src/index.ts +1 -8
  124. package/src/post-build.ts +64 -0
  125. package/src/prerender.ts +292 -0
  126. package/src/rsbuild/INTERNALS-import-protection.md +169 -0
  127. package/src/rsbuild/dev-server.ts +129 -0
  128. package/src/rsbuild/import-protection.ts +1599 -0
  129. package/src/rsbuild/index.ts +4 -0
  130. package/src/rsbuild/normalized-client-build.ts +346 -0
  131. package/src/rsbuild/planning.ts +234 -0
  132. package/src/rsbuild/plugin.ts +754 -0
  133. package/src/rsbuild/post-build.ts +96 -0
  134. package/src/rsbuild/schema.ts +31 -0
  135. package/src/rsbuild/start-compiler-host.ts +250 -0
  136. package/src/rsbuild/start-router-plugin.ts +86 -0
  137. package/src/rsbuild/swc-rsc.ts +166 -0
  138. package/src/rsbuild/types.ts +20 -0
  139. package/src/rsbuild/virtual-modules.ts +565 -0
  140. package/src/start-compiler/compiler.ts +153 -19
  141. package/src/start-compiler/handleCreateServerFn.ts +18 -0
  142. package/src/start-compiler/types.ts +1 -0
  143. package/src/utils.ts +14 -0
  144. package/src/vite/import-protection-plugin/INTERNALS.md +187 -0
  145. package/src/{import-protection-plugin → vite/import-protection-plugin}/plugin.ts +73 -158
  146. package/src/{import-protection-plugin → vite/import-protection-plugin}/types.ts +5 -5
  147. package/src/vite/import-protection-plugin/virtualModules.ts +122 -0
  148. package/src/vite/index.ts +8 -0
  149. package/src/vite/plugin.ts +1 -1
  150. package/src/vite/post-server-build.ts +14 -57
  151. package/src/vite/prerender.ts +19 -260
  152. package/src/vite/start-compiler-plugin/hot-update.ts +24 -0
  153. package/src/vite/start-compiler-plugin/module-specifier.ts +15 -5
  154. package/src/vite/start-compiler-plugin/plugin.ts +193 -18
  155. package/dist/esm/import-protection-plugin/ast.js.map +0 -1
  156. package/dist/esm/import-protection-plugin/constants.d.ts +0 -6
  157. package/dist/esm/import-protection-plugin/constants.js.map +0 -1
  158. package/dist/esm/import-protection-plugin/defaults.js.map +0 -1
  159. package/dist/esm/import-protection-plugin/extensionlessAbsoluteIdResolver.js.map +0 -1
  160. package/dist/esm/import-protection-plugin/matchers.js.map +0 -1
  161. package/dist/esm/import-protection-plugin/plugin.js.map +0 -1
  162. package/dist/esm/import-protection-plugin/postCompileUsage.d.ts +0 -13
  163. package/dist/esm/import-protection-plugin/postCompileUsage.js +0 -63
  164. package/dist/esm/import-protection-plugin/postCompileUsage.js.map +0 -1
  165. package/dist/esm/import-protection-plugin/rewriteDeniedImports.js +0 -205
  166. package/dist/esm/import-protection-plugin/rewriteDeniedImports.js.map +0 -1
  167. package/dist/esm/import-protection-plugin/sourceLocation.js.map +0 -1
  168. package/dist/esm/import-protection-plugin/trace.js.map +0 -1
  169. package/dist/esm/import-protection-plugin/utils.js.map +0 -1
  170. package/dist/esm/import-protection-plugin/virtualModules.d.ts +0 -78
  171. package/dist/esm/import-protection-plugin/virtualModules.js.map +0 -1
  172. package/dist/esm/start-compiler/load-module.d.ts +0 -14
  173. package/dist/esm/start-compiler/load-module.js +0 -18
  174. package/dist/esm/start-compiler/load-module.js.map +0 -1
  175. package/src/import-protection-plugin/INTERNALS.md +0 -700
  176. package/src/import-protection-plugin/postCompileUsage.ts +0 -100
  177. package/src/import-protection-plugin/rewriteDeniedImports.ts +0 -379
  178. package/src/start-compiler/load-module.ts +0 -31
  179. /package/dist/esm/{import-protection-plugin → import-protection}/ast.d.ts +0 -0
  180. /package/dist/esm/{import-protection-plugin → import-protection}/defaults.d.ts +0 -0
  181. /package/dist/esm/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.d.ts +0 -0
  182. /package/dist/esm/{import-protection-plugin → import-protection}/matchers.d.ts +0 -0
  183. /package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/plugin.d.ts +0 -0
  184. /package/src/{import-protection-plugin → import-protection}/ast.ts +0 -0
  185. /package/src/{import-protection-plugin → import-protection}/defaults.ts +0 -0
  186. /package/src/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.ts +0 -0
  187. /package/src/{import-protection-plugin → import-protection}/matchers.ts +0 -0
@@ -0,0 +1,853 @@
1
+ import * as t from '@babel/types'
2
+
3
+ import { parseImportProtectionAst } from './ast'
4
+ import { buildLineIndex } from './sourceLocation'
5
+ import { getOrCreate } from './utils'
6
+ import type { LineIndex, TransformResult } from './sourceLocation'
7
+ import type { ParsedAst } from './ast'
8
+
9
+ export type UsagePos = { line: number; column0: number }
10
+
11
+ type BoundaryEnv = 'client' | 'server'
12
+
13
+ type ImportBindingInfo = {
14
+ importedLocalNames: Set<string>
15
+ memberBindingToSource: Map<string, string>
16
+ }
17
+
18
+ type UsageCacheKey = `${BoundaryEnv | 'post'}::${string}`
19
+
20
+ export type ImportAnalysis = {
21
+ ast: ParsedAst
22
+ lineIndex: LineIndex
23
+ importSourcesInOrder: Array<string>
24
+ importSpecifierLocationIndex: Map<string, number>
25
+ importBindingsBySource: Map<string, ImportBindingInfo>
26
+ mockExportNamesBySource: Map<string, Array<string>>
27
+ namedExports: Array<string>
28
+ usageByKey: Map<UsageCacheKey, UsagePos | null>
29
+ }
30
+
31
+ function makeTransientResult(code: string): TransformResult {
32
+ return {
33
+ code,
34
+ map: undefined,
35
+ originalCode: undefined,
36
+ }
37
+ }
38
+
39
+ function getModuleExportName(node: t.Identifier | t.StringLiteral): string {
40
+ return t.isIdentifier(node) ? node.name : node.value
41
+ }
42
+
43
+ function getStringLiteralValueStart(node: t.StringLiteral): number {
44
+ if (node.start == null) {
45
+ return -1
46
+ }
47
+
48
+ const raw = node.extra?.raw
49
+ if (typeof raw === 'string' && (raw.startsWith("'") || raw.startsWith('"'))) {
50
+ return node.start + 1
51
+ }
52
+
53
+ return node.start
54
+ }
55
+
56
+ function collectIdentifiersFromPattern(
57
+ pattern: t.LVal,
58
+ add: (name: string) => void,
59
+ ): void {
60
+ if (t.isIdentifier(pattern)) {
61
+ add(pattern.name)
62
+ } else if (t.isObjectPattern(pattern)) {
63
+ for (const prop of pattern.properties) {
64
+ if (t.isRestElement(prop)) {
65
+ collectIdentifiersFromPattern(prop.argument as t.LVal, add)
66
+ } else {
67
+ collectIdentifiersFromPattern(prop.value as t.LVal, add)
68
+ }
69
+ }
70
+ } else if (t.isArrayPattern(pattern)) {
71
+ for (const elem of pattern.elements) {
72
+ if (elem) collectIdentifiersFromPattern(elem as t.LVal, add)
73
+ }
74
+ } else if (t.isAssignmentPattern(pattern)) {
75
+ collectIdentifiersFromPattern(pattern.left, add)
76
+ } else if (t.isRestElement(pattern)) {
77
+ collectIdentifiersFromPattern(pattern.argument as t.LVal, add)
78
+ }
79
+ }
80
+
81
+ export function isValidExportName(name: string): boolean {
82
+ if (name === 'default' || name.length === 0) return false
83
+ const first = name.charCodeAt(0)
84
+ if (
85
+ !(
86
+ (first >= 65 && first <= 90) ||
87
+ (first >= 97 && first <= 122) ||
88
+ first === 95 ||
89
+ first === 36
90
+ )
91
+ )
92
+ return false
93
+ for (let i = 1; i < name.length; i++) {
94
+ const ch = name.charCodeAt(i)
95
+ if (
96
+ !(
97
+ (ch >= 65 && ch <= 90) ||
98
+ (ch >= 97 && ch <= 122) ||
99
+ (ch >= 48 && ch <= 57) ||
100
+ ch === 95 ||
101
+ ch === 36
102
+ )
103
+ )
104
+ return false
105
+ }
106
+ return true
107
+ }
108
+
109
+ function buildImportAnalysis(result: TransformResult): ImportAnalysis {
110
+ const ast = result.parsedAst ?? parseImportProtectionAst(result.code)
111
+ result.parsedAst = ast
112
+
113
+ const importSourcesInOrder: Array<string> = []
114
+ const importSpecifierLocationIndex = new Map<string, number>()
115
+ const importBindingsBySource = new Map<string, ImportBindingInfo>()
116
+ const mockNamesBySource = new Map<string, Set<string>>()
117
+ const namedExports = new Set<string>()
118
+
119
+ const getBindingInfo = (source: string): ImportBindingInfo =>
120
+ getOrCreate(importBindingsBySource, source, () => ({
121
+ importedLocalNames: new Set<string>(),
122
+ memberBindingToSource: new Map<string, string>(),
123
+ }))
124
+
125
+ const addSpecifierLocation = (node: t.StringLiteral) => {
126
+ importSourcesInOrder.push(node.value)
127
+
128
+ const index = getStringLiteralValueStart(node)
129
+ if (index === -1) {
130
+ return
131
+ }
132
+
133
+ const prev = importSpecifierLocationIndex.get(node.value)
134
+ if (prev == null || index < prev) {
135
+ importSpecifierLocationIndex.set(node.value, index)
136
+ }
137
+ }
138
+
139
+ const addMockName = (source: string, name: string) => {
140
+ if (name === 'default' || name.length === 0) return
141
+ getOrCreate(mockNamesBySource, source, () => new Set<string>()).add(name)
142
+ }
143
+
144
+ const addNamedExport = (name: string) => {
145
+ if (name !== 'default' && name.length > 0) {
146
+ namedExports.add(name)
147
+ }
148
+ }
149
+
150
+ const visit = (node: t.Node): void => {
151
+ if (t.isImportDeclaration(node)) {
152
+ addSpecifierLocation(node.source)
153
+ if (node.importKind !== 'type') {
154
+ const source = node.source.value
155
+ const bindingInfo = getBindingInfo(source)
156
+ for (const specifier of node.specifiers) {
157
+ if (t.isImportNamespaceSpecifier(specifier)) {
158
+ bindingInfo.importedLocalNames.add(specifier.local.name)
159
+ bindingInfo.memberBindingToSource.set(specifier.local.name, source)
160
+ continue
161
+ }
162
+
163
+ if (t.isImportDefaultSpecifier(specifier)) {
164
+ bindingInfo.importedLocalNames.add(specifier.local.name)
165
+ bindingInfo.memberBindingToSource.set(specifier.local.name, source)
166
+ continue
167
+ }
168
+
169
+ if (!t.isImportSpecifier(specifier)) continue
170
+ if (specifier.importKind === 'type') continue
171
+
172
+ bindingInfo.importedLocalNames.add(specifier.local.name)
173
+ const importedName = getModuleExportName(specifier.imported)
174
+ if (importedName !== 'default') {
175
+ addMockName(source, importedName)
176
+ }
177
+ }
178
+ }
179
+ } else if (t.isExportNamedDeclaration(node)) {
180
+ if (node.source && t.isStringLiteral(node.source)) {
181
+ addSpecifierLocation(node.source)
182
+ }
183
+
184
+ if (node.exportKind !== 'type' && node.source?.value) {
185
+ const source = node.source.value
186
+ for (const specifier of node.specifiers) {
187
+ if (!t.isExportSpecifier(specifier)) continue
188
+ if (specifier.exportKind === 'type') continue
189
+ addMockName(source, getModuleExportName(specifier.local))
190
+ }
191
+ }
192
+
193
+ if (node.exportKind !== 'type') {
194
+ if (node.declaration) {
195
+ const decl = node.declaration
196
+ if (t.isFunctionDeclaration(decl) || t.isClassDeclaration(decl)) {
197
+ if (decl.id?.name) addNamedExport(decl.id.name)
198
+ } else if (t.isVariableDeclaration(decl)) {
199
+ for (const d of decl.declarations) {
200
+ collectIdentifiersFromPattern(d.id as t.LVal, addNamedExport)
201
+ }
202
+ }
203
+ }
204
+
205
+ for (const specifier of node.specifiers) {
206
+ if (!t.isExportSpecifier(specifier)) continue
207
+ if (specifier.exportKind === 'type') continue
208
+ const exportedName = getModuleExportName(specifier.exported)
209
+ addNamedExport(exportedName)
210
+ }
211
+ }
212
+ } else if (t.isExportAllDeclaration(node)) {
213
+ addSpecifierLocation(node.source)
214
+ } else if (t.isImportExpression(node)) {
215
+ if (t.isStringLiteral(node.source)) {
216
+ addSpecifierLocation(node.source)
217
+ }
218
+ } else if (t.isCallExpression(node) && t.isImport(node.callee)) {
219
+ const sourceNode = node.arguments[0]
220
+ if (t.isStringLiteral(sourceNode)) {
221
+ addSpecifierLocation(sourceNode)
222
+ }
223
+ } else if (
224
+ t.isMemberExpression(node) ||
225
+ t.isOptionalMemberExpression(node)
226
+ ) {
227
+ const object = node.object
228
+ if (t.isIdentifier(object)) {
229
+ for (const [source, bindingInfo] of importBindingsBySource) {
230
+ if (!bindingInfo.memberBindingToSource.has(object.name)) {
231
+ continue
232
+ }
233
+
234
+ const property = node.property
235
+ if (!node.computed && t.isIdentifier(property)) {
236
+ addMockName(source, property.name)
237
+ } else if (node.computed && t.isStringLiteral(property)) {
238
+ addMockName(source, property.value)
239
+ }
240
+ }
241
+ }
242
+ }
243
+
244
+ const keys = t.VISITOR_KEYS[node.type]
245
+ if (!keys) return
246
+ for (const key of keys) {
247
+ const child = (node as unknown as Record<string, unknown>)[key]
248
+ if (Array.isArray(child)) {
249
+ for (const item of child) {
250
+ if (item && typeof item === 'object' && 'type' in item) {
251
+ visit(item as t.Node)
252
+ }
253
+ }
254
+ } else if (child && typeof child === 'object' && 'type' in child) {
255
+ visit(child as t.Node)
256
+ }
257
+ }
258
+ }
259
+
260
+ visit(ast.program)
261
+
262
+ const mockExportNamesBySource = new Map<string, Array<string>>()
263
+ for (const [source, names] of mockNamesBySource) {
264
+ mockExportNamesBySource.set(source, Array.from(names).sort())
265
+ }
266
+
267
+ const lineIndex = result.lineIndex ?? buildLineIndex(result.code)
268
+ result.lineIndex = lineIndex
269
+
270
+ const analysis = {
271
+ ast,
272
+ lineIndex,
273
+ importSourcesInOrder,
274
+ importSpecifierLocationIndex,
275
+ importBindingsBySource,
276
+ mockExportNamesBySource,
277
+ namedExports: Array.from(namedExports).sort(),
278
+ usageByKey: new Map(),
279
+ }
280
+
281
+ return analysis
282
+ }
283
+
284
+ export function getOrCreateImportAnalysis(
285
+ result: TransformResult,
286
+ ): ImportAnalysis {
287
+ if (!result.analysis) {
288
+ result.analysis = buildImportAnalysis(result)
289
+ }
290
+
291
+ return result.analysis
292
+ }
293
+
294
+ export function getImportSourcesFromResult(
295
+ result: TransformResult,
296
+ ): Array<string> {
297
+ return getOrCreateImportAnalysis(result).importSourcesInOrder
298
+ }
299
+
300
+ export function getImportSources(code: string): Array<string> {
301
+ return getImportSourcesFromResult(makeTransientResult(code))
302
+ }
303
+
304
+ export function getImportSpecifierLocationFromResult(
305
+ result: TransformResult,
306
+ source: string,
307
+ ): number {
308
+ return (
309
+ getOrCreateImportAnalysis(result).importSpecifierLocationIndex.get(
310
+ source,
311
+ ) ?? -1
312
+ )
313
+ }
314
+
315
+ export function getMockExportNamesBySourceFromResult(
316
+ result: TransformResult,
317
+ ): Map<string, Array<string>> {
318
+ return getOrCreateImportAnalysis(result).mockExportNamesBySource
319
+ }
320
+
321
+ export function getMockExportNamesBySource(
322
+ code: string,
323
+ ): Map<string, Array<string>> {
324
+ return getMockExportNamesBySourceFromResult(makeTransientResult(code))
325
+ }
326
+
327
+ export function getNamedExportsFromResult(
328
+ result: TransformResult,
329
+ ): Array<string> {
330
+ return getOrCreateImportAnalysis(result).namedExports
331
+ }
332
+
333
+ export function getNamedExports(code: string): Array<string> {
334
+ return getNamedExportsFromResult(makeTransientResult(code))
335
+ }
336
+
337
+ function isCompilerSafeBoundaryCall(
338
+ call: t.CallExpression,
339
+ fnNode: t.Function,
340
+ envType: BoundaryEnv,
341
+ ): boolean {
342
+ const directArgument = call.arguments.some((arg) => arg === fnNode)
343
+ if (!directArgument) {
344
+ return false
345
+ }
346
+
347
+ const callee = call.callee
348
+
349
+ if (t.isIdentifier(callee)) {
350
+ return envType === 'client'
351
+ ? callee.name === 'createServerOnlyFn'
352
+ : callee.name === 'createClientOnlyFn'
353
+ }
354
+
355
+ if (!t.isMemberExpression(callee) || callee.computed) {
356
+ return false
357
+ }
358
+
359
+ if (!t.isIdentifier(callee.property)) {
360
+ return false
361
+ }
362
+
363
+ const prop = callee.property.name
364
+ const rootName = getCalleeRootName(callee.object)
365
+
366
+ if (envType === 'client') {
367
+ if (prop === 'handler') {
368
+ return rootName === 'createServerFn' || /ServerFn$/.test(rootName ?? '')
369
+ }
370
+
371
+ if (prop === 'server') {
372
+ return (
373
+ rootName === 'createMiddleware' ||
374
+ rootName === 'createIsomorphicFn' ||
375
+ /Middleware$/.test(rootName ?? '')
376
+ )
377
+ }
378
+
379
+ return false
380
+ }
381
+
382
+ if (prop === 'client') {
383
+ return rootName === 'createIsomorphicFn'
384
+ }
385
+
386
+ return false
387
+ }
388
+
389
+ function getCalleeRootName(
390
+ node: t.Expression | t.Super | t.V8IntrinsicIdentifier,
391
+ ): string | undefined {
392
+ if (t.isIdentifier(node)) {
393
+ return node.name
394
+ }
395
+
396
+ if (t.isCallExpression(node)) {
397
+ return getCalleeRootName(node.callee)
398
+ }
399
+
400
+ if (t.isMemberExpression(node)) {
401
+ return getCalleeRootName(node.object)
402
+ }
403
+
404
+ return undefined
405
+ }
406
+
407
+ function getBoundNamesFromPattern(pattern: t.LVal, out: Set<string>): void {
408
+ if (t.isIdentifier(pattern)) {
409
+ out.add(pattern.name)
410
+ } else if (t.isObjectPattern(pattern)) {
411
+ for (const prop of pattern.properties) {
412
+ if (t.isRestElement(prop)) {
413
+ getBoundNamesFromPattern(prop.argument as t.LVal, out)
414
+ } else {
415
+ getBoundNamesFromPattern(prop.value as t.LVal, out)
416
+ }
417
+ }
418
+ } else if (t.isArrayPattern(pattern)) {
419
+ for (const elem of pattern.elements) {
420
+ if (elem) getBoundNamesFromPattern(elem as t.LVal, out)
421
+ }
422
+ } else if (t.isAssignmentPattern(pattern)) {
423
+ getBoundNamesFromPattern(pattern.left, out)
424
+ } else if (t.isRestElement(pattern)) {
425
+ getBoundNamesFromPattern(pattern.argument as t.LVal, out)
426
+ }
427
+ }
428
+
429
+ function addPatternBindingsIfTracked(
430
+ pattern: t.LVal,
431
+ tracked: Set<string>,
432
+ out: Set<string>,
433
+ ): void {
434
+ const names = new Set<string>()
435
+ getBoundNamesFromPattern(pattern, names)
436
+ for (const name of names) {
437
+ if (tracked.has(name)) {
438
+ out.add(name)
439
+ }
440
+ }
441
+ }
442
+
443
+ function collectHoistedVarBindings(
444
+ node: t.Node,
445
+ tracked: Set<string>,
446
+ out: Set<string>,
447
+ isRoot = true,
448
+ ): void {
449
+ if (!isRoot && t.isFunction(node)) {
450
+ return
451
+ }
452
+
453
+ if (t.isVariableDeclaration(node) && node.kind === 'var') {
454
+ for (const decl of node.declarations) {
455
+ addPatternBindingsIfTracked(decl.id as t.LVal, tracked, out)
456
+ }
457
+ }
458
+
459
+ const keys = t.VISITOR_KEYS[node.type]
460
+ if (!keys) return
461
+ for (const key of keys) {
462
+ const child = (node as unknown as Record<string, unknown>)[key]
463
+ if (Array.isArray(child)) {
464
+ for (const item of child) {
465
+ if (item && typeof item === 'object' && 'type' in item) {
466
+ collectHoistedVarBindings(item as t.Node, tracked, out, false)
467
+ }
468
+ }
469
+ } else if (child && typeof child === 'object' && 'type' in child) {
470
+ collectHoistedVarBindings(child as t.Node, tracked, out, false)
471
+ }
472
+ }
473
+ }
474
+
475
+ function collectProgramBindings(
476
+ program: t.Program,
477
+ tracked: Set<string>,
478
+ ): Set<string> {
479
+ const bindings = new Set<string>()
480
+
481
+ for (const node of program.body) {
482
+ if (t.isVariableDeclaration(node)) {
483
+ for (const decl of node.declarations) {
484
+ addPatternBindingsIfTracked(decl.id as t.LVal, tracked, bindings)
485
+ }
486
+ continue
487
+ }
488
+
489
+ if (t.isFunctionDeclaration(node) || t.isClassDeclaration(node)) {
490
+ if (node.id && tracked.has(node.id.name)) {
491
+ bindings.add(node.id.name)
492
+ }
493
+ }
494
+ }
495
+
496
+ return bindings
497
+ }
498
+
499
+ function collectBlockBindings(
500
+ block: t.BlockStatement,
501
+ tracked: Set<string>,
502
+ ): Set<string> {
503
+ const bindings = new Set<string>()
504
+
505
+ for (const node of block.body) {
506
+ if (t.isVariableDeclaration(node) && node.kind !== 'var') {
507
+ for (const decl of node.declarations) {
508
+ addPatternBindingsIfTracked(decl.id as t.LVal, tracked, bindings)
509
+ }
510
+ continue
511
+ }
512
+
513
+ if (t.isFunctionDeclaration(node) || t.isClassDeclaration(node)) {
514
+ if (node.id && tracked.has(node.id.name)) {
515
+ bindings.add(node.id.name)
516
+ }
517
+ }
518
+ }
519
+
520
+ return bindings
521
+ }
522
+
523
+ function collectFunctionBindings(
524
+ fn: t.Function,
525
+ tracked: Set<string>,
526
+ ): Set<string> {
527
+ const bindings = new Set<string>()
528
+
529
+ if (
530
+ (t.isFunctionDeclaration(fn) || t.isFunctionExpression(fn)) &&
531
+ fn.id &&
532
+ tracked.has(fn.id.name)
533
+ ) {
534
+ bindings.add(fn.id.name)
535
+ }
536
+
537
+ for (const param of fn.params) {
538
+ addPatternBindingsIfTracked(param as t.LVal, tracked, bindings)
539
+ }
540
+
541
+ if (t.isBlockStatement(fn.body)) {
542
+ collectHoistedVarBindings(fn.body, tracked, bindings)
543
+ }
544
+
545
+ return bindings
546
+ }
547
+
548
+ type UsageWalkContext = {
549
+ parents: Array<t.Node>
550
+ scopeStack: Array<Set<string>>
551
+ }
552
+
553
+ function isShadowedByScope(
554
+ name: string,
555
+ scopeStack: Array<Set<string>>,
556
+ ): boolean {
557
+ for (let i = scopeStack.length - 1; i >= 0; i--) {
558
+ if (scopeStack[i]?.has(name)) {
559
+ return true
560
+ }
561
+ }
562
+ return false
563
+ }
564
+
565
+ function isBindingIdentifierInParent(
566
+ node: t.Identifier,
567
+ parent: t.Node | undefined,
568
+ ): boolean {
569
+ if (!parent) return false
570
+
571
+ if (t.isImportSpecifier(parent) || t.isImportDefaultSpecifier(parent)) {
572
+ return parent.local === node
573
+ }
574
+ if (t.isImportNamespaceSpecifier(parent)) {
575
+ return parent.local === node
576
+ }
577
+ if (t.isFunctionDeclaration(parent) || t.isFunctionExpression(parent)) {
578
+ return (
579
+ parent.id === node || parent.params.includes(node as unknown as t.Pattern)
580
+ )
581
+ }
582
+ if (t.isArrowFunctionExpression(parent)) {
583
+ return parent.params.includes(node as unknown as t.Pattern)
584
+ }
585
+ if (t.isClassDeclaration(parent) || t.isClassExpression(parent)) {
586
+ return parent.id === node
587
+ }
588
+ if (t.isVariableDeclarator(parent)) {
589
+ return parent.id === node
590
+ }
591
+ if (t.isCatchClause(parent)) {
592
+ return parent.param === node
593
+ }
594
+
595
+ return false
596
+ }
597
+
598
+ function isInsideCompilerSafeBoundaryNodes(
599
+ parents: Array<t.Node>,
600
+ envType: BoundaryEnv,
601
+ ): boolean {
602
+ for (let i = parents.length - 1; i >= 0; i--) {
603
+ const node = parents[i]!
604
+ if (!t.isFunction(node)) {
605
+ continue
606
+ }
607
+
608
+ const call = parents[i - 1]
609
+ if (
610
+ call &&
611
+ t.isCallExpression(call) &&
612
+ isCompilerSafeBoundaryCall(call, node, envType)
613
+ ) {
614
+ return true
615
+ }
616
+ }
617
+
618
+ return false
619
+ }
620
+
621
+ function findUsagePosInAnalysis(
622
+ result: TransformResult,
623
+ source: string,
624
+ envType?: BoundaryEnv,
625
+ ): UsagePos | undefined {
626
+ const analysis = getOrCreateImportAnalysis(result)
627
+ const cacheKey: UsageCacheKey = `${envType ?? 'post'}::${source}`
628
+ if (analysis.usageByKey.has(cacheKey)) {
629
+ return analysis.usageByKey.get(cacheKey) ?? undefined
630
+ }
631
+
632
+ const imported =
633
+ analysis.importBindingsBySource.get(source)?.importedLocalNames
634
+ if (!imported || imported.size === 0) {
635
+ analysis.usageByKey.set(cacheKey, null)
636
+ return undefined
637
+ }
638
+
639
+ let preferred: UsagePos | undefined
640
+ let anyUsage: UsagePos | undefined
641
+
642
+ const visit = (node: t.Node, ctx: UsageWalkContext): void => {
643
+ if (preferred && anyUsage) {
644
+ return
645
+ }
646
+
647
+ if (t.isProgram(node)) {
648
+ const nextCtx = {
649
+ parents: [...ctx.parents, node],
650
+ scopeStack: [...ctx.scopeStack, collectProgramBindings(node, imported)],
651
+ }
652
+ for (const child of node.body) {
653
+ visit(child, nextCtx)
654
+ }
655
+ return
656
+ }
657
+
658
+ if (t.isFunction(node)) {
659
+ const functionCtx = {
660
+ parents: [...ctx.parents, node],
661
+ scopeStack: [
662
+ ...ctx.scopeStack,
663
+ collectFunctionBindings(node, imported),
664
+ ],
665
+ }
666
+
667
+ visit(node.body, functionCtx)
668
+ return
669
+ }
670
+
671
+ if (t.isBlockStatement(node)) {
672
+ const nextCtx = {
673
+ parents: [...ctx.parents, node],
674
+ scopeStack: [...ctx.scopeStack, collectBlockBindings(node, imported)],
675
+ }
676
+ for (const child of node.body) {
677
+ visit(child, nextCtx)
678
+ }
679
+ return
680
+ }
681
+
682
+ if (t.isCatchClause(node)) {
683
+ const bindings = new Set<string>()
684
+ if (node.param) {
685
+ addPatternBindingsIfTracked(node.param as t.LVal, imported, bindings)
686
+ }
687
+ const nextCtx = {
688
+ parents: [...ctx.parents, node],
689
+ scopeStack: bindings.size
690
+ ? [...ctx.scopeStack, bindings]
691
+ : ctx.scopeStack,
692
+ }
693
+ visit(node.body, nextCtx)
694
+ return
695
+ }
696
+
697
+ if (
698
+ t.isForStatement(node) &&
699
+ t.isVariableDeclaration(node.init) &&
700
+ node.init.kind !== 'var'
701
+ ) {
702
+ const bindings = new Set<string>()
703
+ for (const decl of node.init.declarations) {
704
+ addPatternBindingsIfTracked(decl.id as t.LVal, imported, bindings)
705
+ }
706
+ const nextCtx = {
707
+ parents: [...ctx.parents, node],
708
+ scopeStack: bindings.size
709
+ ? [...ctx.scopeStack, bindings]
710
+ : ctx.scopeStack,
711
+ }
712
+ visit(node.init, nextCtx)
713
+ if (node.test) visit(node.test, nextCtx)
714
+ if (node.update) visit(node.update, nextCtx)
715
+ visit(node.body, nextCtx)
716
+ return
717
+ }
718
+
719
+ if (
720
+ (t.isForInStatement(node) || t.isForOfStatement(node)) &&
721
+ t.isVariableDeclaration(node.left) &&
722
+ node.left.kind !== 'var'
723
+ ) {
724
+ const bindings = new Set<string>()
725
+ for (const decl of node.left.declarations) {
726
+ addPatternBindingsIfTracked(decl.id as t.LVal, imported, bindings)
727
+ }
728
+ const nextCtx = {
729
+ parents: [...ctx.parents, node],
730
+ scopeStack: bindings.size
731
+ ? [...ctx.scopeStack, bindings]
732
+ : ctx.scopeStack,
733
+ }
734
+ visit(node.left, nextCtx)
735
+ visit(node.right, nextCtx)
736
+ visit(node.body, nextCtx)
737
+ return
738
+ }
739
+
740
+ const nextParents = [...ctx.parents, node]
741
+
742
+ if (t.isIdentifier(node)) {
743
+ const parent = ctx.parents[ctx.parents.length - 1]
744
+ if (imported.has(node.name)) {
745
+ if (!isBindingIdentifierInParent(node, parent)) {
746
+ if (
747
+ !(
748
+ t.isObjectProperty(parent) &&
749
+ parent.key === node &&
750
+ !parent.computed &&
751
+ !parent.shorthand
752
+ ) &&
753
+ !(
754
+ t.isObjectMethod(parent) &&
755
+ parent.key === node &&
756
+ !parent.computed
757
+ ) &&
758
+ !(t.isExportSpecifier(parent) && parent.exported === node) &&
759
+ !isShadowedByScope(node.name, ctx.scopeStack) &&
760
+ !(
761
+ envType && isInsideCompilerSafeBoundaryNodes(ctx.parents, envType)
762
+ )
763
+ ) {
764
+ const loc = node.loc?.start
765
+ if (loc) {
766
+ const pos: UsagePos = { line: loc.line, column0: loc.column }
767
+ const isPreferred =
768
+ (t.isCallExpression(parent) && parent.callee === node) ||
769
+ (t.isNewExpression(parent) && parent.callee === node) ||
770
+ ((t.isMemberExpression(parent) ||
771
+ t.isOptionalMemberExpression(parent)) &&
772
+ parent.object === node)
773
+
774
+ if (isPreferred) {
775
+ preferred ||= pos
776
+ } else {
777
+ anyUsage ||= pos
778
+ }
779
+ }
780
+ }
781
+ }
782
+ }
783
+ }
784
+
785
+ if (t.isImportDeclaration(node)) {
786
+ return
787
+ }
788
+
789
+ const keys = t.VISITOR_KEYS[node.type]
790
+ if (!keys) return
791
+ for (const key of keys) {
792
+ const child = (node as unknown as Record<string, unknown>)[key]
793
+ if (Array.isArray(child)) {
794
+ for (const item of child) {
795
+ if (item && typeof item === 'object' && 'type' in item) {
796
+ visit(item as t.Node, {
797
+ parents: nextParents,
798
+ scopeStack: ctx.scopeStack,
799
+ })
800
+ }
801
+ }
802
+ } else if (child && typeof child === 'object' && 'type' in child) {
803
+ visit(child as t.Node, {
804
+ parents: nextParents,
805
+ scopeStack: ctx.scopeStack,
806
+ })
807
+ }
808
+ }
809
+ }
810
+
811
+ visit(analysis.ast.program, {
812
+ parents: [],
813
+ scopeStack: [],
814
+ })
815
+
816
+ const pos = preferred ?? anyUsage ?? null
817
+ analysis.usageByKey.set(cacheKey, pos)
818
+ return pos ?? undefined
819
+ }
820
+
821
+ export function findPostCompileUsagePosFromResult(
822
+ result: TransformResult,
823
+ source: string,
824
+ ): UsagePos | undefined {
825
+ return findUsagePosInAnalysis(result, source)
826
+ }
827
+
828
+ export function findPostCompileUsagePos(
829
+ code: string,
830
+ source: string,
831
+ ): UsagePos | undefined {
832
+ return findPostCompileUsagePosFromResult(makeTransientResult(code), source)
833
+ }
834
+
835
+ export function findOriginalUnsafeUsagePosFromResult(
836
+ result: TransformResult,
837
+ source: string,
838
+ envType: BoundaryEnv,
839
+ ): UsagePos | undefined {
840
+ return findUsagePosInAnalysis(result, source, envType)
841
+ }
842
+
843
+ export function findOriginalUnsafeUsagePos(
844
+ code: string,
845
+ source: string,
846
+ envType: BoundaryEnv,
847
+ ): UsagePos | undefined {
848
+ return findOriginalUnsafeUsagePosFromResult(
849
+ makeTransientResult(code),
850
+ source,
851
+ envType,
852
+ )
853
+ }