@pikku/inspector 0.12.75 → 0.12.82

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 (223) hide show
  1. package/CHANGELOG.md +357 -0
  2. package/dist/add/add-analytics.d.ts +9 -0
  3. package/dist/add/add-analytics.js +178 -0
  4. package/dist/add/add-auth.js +0 -54
  5. package/dist/add/add-feature-flag.d.ts +2 -0
  6. package/dist/add/add-feature-flag.js +162 -0
  7. package/dist/add/add-middleware.js +66 -42
  8. package/dist/add/add-wire-addon.js +7 -4
  9. package/dist/add/add-wire-remote-addon.js +1 -0
  10. package/dist/error-codes.d.ts +1 -0
  11. package/dist/error-codes.js +1 -0
  12. package/dist/index.d.ts +3 -1
  13. package/dist/index.js +3 -1
  14. package/dist/inspector.js +5 -0
  15. package/dist/surface/collect-surface.d.ts +58 -0
  16. package/dist/surface/collect-surface.js +613 -0
  17. package/dist/types.d.ts +36 -12
  18. package/dist/utils/filter-inspector-state.js +14 -0
  19. package/dist/utils/load-addon-functions-meta.js +24 -11
  20. package/dist/utils/post-process.js +15 -0
  21. package/dist/utils/read-module-specifiers.d.ts +8 -0
  22. package/dist/utils/read-module-specifiers.js +23 -0
  23. package/dist/utils/read-tsconfig-out-dir.d.ts +5 -0
  24. package/dist/utils/read-tsconfig-out-dir.js +12 -0
  25. package/dist/utils/resolve-deploy-target.d.ts +7 -0
  26. package/dist/utils/resolve-deploy-target.js +15 -7
  27. package/dist/utils/serialize-inspector-state.d.ts +6 -0
  28. package/dist/utils/serialize-inspector-state.js +10 -0
  29. package/dist/visit.js +4 -0
  30. package/package.json +16 -6
  31. package/run-tests.sh +21 -6
  32. package/src/add/add-addon-bans.ts +0 -85
  33. package/src/add/add-agent-scorer.test.ts +0 -197
  34. package/src/add/add-agent-scorer.ts +0 -83
  35. package/src/add/add-agent.test.ts +0 -87
  36. package/src/add/add-agent.ts +0 -638
  37. package/src/add/add-approval-description.ts +0 -76
  38. package/src/add/add-auth.test.ts +0 -791
  39. package/src/add/add-auth.ts +0 -424
  40. package/src/add/add-channel.ts +0 -778
  41. package/src/add/add-cli-renderers.test.ts +0 -74
  42. package/src/add/add-cli.ts +0 -1006
  43. package/src/add/add-credential.ts +0 -186
  44. package/src/add/add-feature.test.ts +0 -306
  45. package/src/add/add-feature.ts +0 -253
  46. package/src/add/add-file-extends-core-type.ts +0 -66
  47. package/src/add/add-file-with-config.ts +0 -45
  48. package/src/add/add-file-with-factory.test.ts +0 -134
  49. package/src/add/add-file-with-factory.ts +0 -288
  50. package/src/add/add-functions.test.ts +0 -743
  51. package/src/add/add-functions.ts +0 -1548
  52. package/src/add/add-gateway.ts +0 -143
  53. package/src/add/add-http-route-ref.test.ts +0 -149
  54. package/src/add/add-http-route.ts +0 -530
  55. package/src/add/add-http-routes.ts +0 -471
  56. package/src/add/add-keyed-wiring.ts +0 -180
  57. package/src/add/add-mcp-prompt.ts +0 -157
  58. package/src/add/add-mcp-resource.ts +0 -175
  59. package/src/add/add-middleware.test.ts +0 -196
  60. package/src/add/add-middleware.ts +0 -879
  61. package/src/add/add-permission-auth.test.ts +0 -59
  62. package/src/add/add-permission.ts +0 -311
  63. package/src/add/add-personas.test.ts +0 -406
  64. package/src/add/add-personas.ts +0 -287
  65. package/src/add/add-queue-worker.ts +0 -117
  66. package/src/add/add-rpc-invocations.test.ts +0 -287
  67. package/src/add/add-rpc-invocations.ts +0 -221
  68. package/src/add/add-scenario-step.test.ts +0 -509
  69. package/src/add/add-schedule.ts +0 -120
  70. package/src/add/add-scope.test.ts +0 -419
  71. package/src/add/add-scope.ts +0 -221
  72. package/src/add/add-secret.ts +0 -10
  73. package/src/add/add-subject-scenario-steps.test.ts +0 -161
  74. package/src/add/add-system-role.test.ts +0 -297
  75. package/src/add/add-system-role.ts +0 -162
  76. package/src/add/add-trigger.ts +0 -165
  77. package/src/add/add-variable.ts +0 -10
  78. package/src/add/add-wire-addon.test.ts +0 -185
  79. package/src/add/add-wire-addon.ts +0 -146
  80. package/src/add/add-wire-remote-addon.ts +0 -80
  81. package/src/add/add-workflow-edge-cases.test.ts +0 -201
  82. package/src/add/add-workflow-fanout.test.ts +0 -166
  83. package/src/add/add-workflow-graph-foreach.test.ts +0 -174
  84. package/src/add/add-workflow-graph-input.test.ts +0 -94
  85. package/src/add/add-workflow-graph-notes.test.ts +0 -74
  86. package/src/add/add-workflow-graph.ts +0 -644
  87. package/src/add/add-workflow-on-error.test.ts +0 -118
  88. package/src/add/add-workflow-return-switch.test.ts +0 -121
  89. package/src/add/add-workflow-silent-drops.test.ts +0 -261
  90. package/src/add/add-workflow-sleep-expression.test.ts +0 -96
  91. package/src/add/add-workflow.test.ts +0 -155
  92. package/src/add/add-workflow.ts +0 -482
  93. package/src/add/addon-bans.test.ts +0 -121
  94. package/src/add/addon-contracts.test.ts +0 -221
  95. package/src/add/allow-escape-hatches.test.ts +0 -144
  96. package/src/add/audit-meta.test.ts +0 -75
  97. package/src/add/classified-sink-check.test.ts +0 -347
  98. package/src/add/config-value-metadata.test.ts +0 -263
  99. package/src/add/dynamic-import-check.test.ts +0 -119
  100. package/src/add/expect-eventually-scenario-only.test.ts +0 -108
  101. package/src/add/function-body-span.test.ts +0 -96
  102. package/src/add/inline-wiring-function.test.ts +0 -104
  103. package/src/add/pii-check.test.ts +0 -258
  104. package/src/add/rpc-type-cast.test.ts +0 -123
  105. package/src/add/scenario-instrumentation.test.ts +0 -89
  106. package/src/add/scenario-instrumentation.ts +0 -42
  107. package/src/add/scenario-marker.test.ts +0 -89
  108. package/src/add/scenario-not-extractable.test.ts +0 -159
  109. package/src/add/scenario-services.test.ts +0 -103
  110. package/src/add/scenario-skip.test.ts +0 -83
  111. package/src/add/validate-workflow-graph-addons.test.ts +0 -102
  112. package/src/add/wire-name-literal.test.ts +0 -117
  113. package/src/error-codes-emitted.test.ts +0 -76
  114. package/src/error-codes.ts +0 -145
  115. package/src/index.ts +0 -66
  116. package/src/inspector.ts +0 -575
  117. package/src/schema-generator.ts +0 -1
  118. package/src/source-file-cache.ts +0 -73
  119. package/src/tsconfig-paths.test.ts +0 -90
  120. package/src/types-map.ts +0 -141
  121. package/src/types.ts +0 -775
  122. package/src/utils/annotate-http-route-auth.test.ts +0 -161
  123. package/src/utils/annotate-http-route-auth.ts +0 -53
  124. package/src/utils/check-classified-sinks.ts +0 -215
  125. package/src/utils/check-pii-output.ts +0 -120
  126. package/src/utils/compute-diagnostics.test.ts +0 -106
  127. package/src/utils/compute-required-schemas.ts +0 -48
  128. package/src/utils/contract-hashes.test.ts +0 -553
  129. package/src/utils/contract-hashes.ts +0 -387
  130. package/src/utils/custom-types-generator.test.ts +0 -124
  131. package/src/utils/custom-types-generator.ts +0 -150
  132. package/src/utils/detect-schema-vendor.test.ts +0 -123
  133. package/src/utils/detect-schema-vendor.ts +0 -120
  134. package/src/utils/does-type-extend-core-type.ts +0 -53
  135. package/src/utils/ensure-function-metadata.ts +0 -385
  136. package/src/utils/extract-function-name.ts +0 -612
  137. package/src/utils/extract-function-node.ts +0 -70
  138. package/src/utils/extract-node-value.test.ts +0 -117
  139. package/src/utils/extract-node-value.ts +0 -172
  140. package/src/utils/extract-secret-usage.test.ts +0 -81
  141. package/src/utils/extract-secret-usage.ts +0 -73
  142. package/src/utils/extract-services.ts +0 -70
  143. package/src/utils/extract-surface-usage.test.ts +0 -147
  144. package/src/utils/extract-surface-usage.ts +0 -121
  145. package/src/utils/filter-inspector-state.test.ts +0 -2232
  146. package/src/utils/filter-inspector-state.ts +0 -1298
  147. package/src/utils/filter-utils.test.ts +0 -843
  148. package/src/utils/filter-utils.ts +0 -161
  149. package/src/utils/find-root-dir.ts +0 -68
  150. package/src/utils/find-zod-transform.test.ts +0 -70
  151. package/src/utils/find-zod-transform.ts +0 -103
  152. package/src/utils/get-exported-variable-name.ts +0 -48
  153. package/src/utils/get-files-and-methods.ts +0 -157
  154. package/src/utils/get-property-value.test.ts +0 -141
  155. package/src/utils/get-property-value.ts +0 -331
  156. package/src/utils/hash.ts +0 -26
  157. package/src/utils/literal-properties.ts +0 -97
  158. package/src/utils/load-addon-functions-meta.test.ts +0 -157
  159. package/src/utils/load-addon-functions-meta.ts +0 -508
  160. package/src/utils/load-addon-scopes.test.ts +0 -138
  161. package/src/utils/middleware.test.ts +0 -204
  162. package/src/utils/middleware.ts +0 -303
  163. package/src/utils/nested-project-filter.test.ts +0 -53
  164. package/src/utils/nested-project-filter.ts +0 -28
  165. package/src/utils/permissions-shorthand.test.ts +0 -79
  166. package/src/utils/permissions.test.ts +0 -125
  167. package/src/utils/permissions.ts +0 -129
  168. package/src/utils/post-process.test.ts +0 -1094
  169. package/src/utils/post-process.ts +0 -1604
  170. package/src/utils/resolve-addon-package.ts +0 -106
  171. package/src/utils/resolve-core-type.test.ts +0 -142
  172. package/src/utils/resolve-core-type.ts +0 -35
  173. package/src/utils/resolve-deploy-target.test.ts +0 -135
  174. package/src/utils/resolve-deploy-target.ts +0 -65
  175. package/src/utils/resolve-function-meta.ts +0 -25
  176. package/src/utils/resolve-function-types.ts +0 -42
  177. package/src/utils/resolve-identifier.ts +0 -46
  178. package/src/utils/resolve-ref-contract.ts +0 -71
  179. package/src/utils/resolve-versions.test.ts +0 -499
  180. package/src/utils/resolve-versions.ts +0 -228
  181. package/src/utils/schema-cache.test.ts +0 -124
  182. package/src/utils/schema-generator.test.ts +0 -272
  183. package/src/utils/schema-generator.ts +0 -780
  184. package/src/utils/secret-alias-services.test.ts +0 -146
  185. package/src/utils/secret-alias-services.ts +0 -58
  186. package/src/utils/serialize-inspector-state.ts +0 -742
  187. package/src/utils/serialize-mcp-json.ts +0 -150
  188. package/src/utils/serialize-middleware-groups-meta.ts +0 -36
  189. package/src/utils/serialize-openapi-json.ts +0 -277
  190. package/src/utils/serialize-permissions-groups-meta.ts +0 -7
  191. package/src/utils/single-declaration.ts +0 -57
  192. package/src/utils/type-utils.ts +0 -145
  193. package/src/utils/validate-auth-sessionless.ts +0 -30
  194. package/src/utils/validate-exposed-functions-gated.test.ts +0 -230
  195. package/src/utils/validate-exposed-functions-gated.ts +0 -103
  196. package/src/utils/validate-tags-resolve-to-middleware.test.ts +0 -108
  197. package/src/utils/validate-tags-resolve-to-middleware.ts +0 -48
  198. package/src/utils/workflow/derive-workflow-plan.test.ts +0 -178
  199. package/src/utils/workflow/derive-workflow-plan.ts +0 -117
  200. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +0 -1465
  201. package/src/utils/workflow/dsl/deserialize-fanout-body.test.ts +0 -71
  202. package/src/utils/workflow/dsl/deserialize-fanout-fidelity.test.ts +0 -99
  203. package/src/utils/workflow/dsl/deserialize-graph-next.test.ts +0 -161
  204. package/src/utils/workflow/dsl/deserialize-roundtrip-bindings.test.ts +0 -121
  205. package/src/utils/workflow/dsl/deserialize-roundtrip-values.test.ts +0 -116
  206. package/src/utils/workflow/dsl/deserialize-roundtrip.test.ts +0 -145
  207. package/src/utils/workflow/dsl/extract-approval-policy.test.ts +0 -71
  208. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +0 -2254
  209. package/src/utils/workflow/dsl/index.ts +0 -11
  210. package/src/utils/workflow/dsl/patterns.ts +0 -440
  211. package/src/utils/workflow/dsl/validation.ts +0 -203
  212. package/src/utils/workflow/graph/convert-dsl-to-graph-skip.test.ts +0 -35
  213. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +0 -543
  214. package/src/utils/workflow/graph/fanout-node-identity.test.ts +0 -105
  215. package/src/utils/workflow/graph/finalize-workflow-wires.ts +0 -310
  216. package/src/utils/workflow/graph/finalize-workflows.test.ts +0 -50
  217. package/src/utils/workflow/graph/finalize-workflows.ts +0 -130
  218. package/src/utils/workflow/graph/index.ts +0 -28
  219. package/src/utils/workflow/graph/serialize-workflow-graph.ts +0 -240
  220. package/src/utils/workflow/graph/workflow-graph.types.ts +0 -281
  221. package/src/visit.ts +0 -181
  222. package/tsconfig.json +0 -19
  223. package/tsconfig.tsbuildinfo +0 -1
@@ -1,612 +0,0 @@
1
- import * as ts from 'typescript'
2
- import { createHash } from 'crypto'
3
- import { relative } from 'path'
4
- import { formatVersionedId } from '@pikku/core/utils'
5
-
6
- /**
7
- * Deterministic placeholder id for an anonymous/unnamed pikku function or
8
- * permission. Derived from the call expression's source location (relative path
9
- * + start position) so `pikku all` produces byte-identical output across runs —
10
- * a `randomUUID()` here made generated meta non-reproducible. Still `__temp_`
11
- * prefixed so downstream resolution (which keys off that prefix) is unchanged.
12
- */
13
- function tempFuncId(callExpr: ts.Node, rootDir: string): string {
14
- const sourceFile = callExpr.getSourceFile()
15
- const relPath = relative(rootDir, sourceFile.fileName)
16
- const hash = createHash('sha1')
17
- .update(`${relPath}:${callExpr.getStart()}`)
18
- .digest('hex')
19
- .slice(0, 16)
20
- return `__temp_${hash}`
21
- }
22
-
23
- export type ExtractedFunctionName = {
24
- pikkuFuncId: string
25
- name: string
26
- explicitName: string | null
27
- exportedName: string | null
28
- propertyName: string | null
29
- isHelper: boolean
30
- version: number | null
31
- }
32
-
33
- export function makeContextBasedId(
34
- wiringType: string,
35
- ...segments: string[]
36
- ): string {
37
- return [wiringType, ...segments].join(':')
38
- }
39
-
40
- export function funcIdToTypeName(id: string): string {
41
- return id
42
- .split(/[^a-zA-Z0-9]/)
43
- .filter(Boolean)
44
- .map((s) => s.charAt(0).toUpperCase() + s.slice(1))
45
- .join('')
46
- }
47
-
48
- /**
49
- * The step wrappers, whichever kind of subject acts in them. A scenario calls a
50
- * platform or addon step by name exactly as it calls a persona one.
51
- */
52
- const SCENARIO_STEP_WRAPPERS = new Set([
53
- 'pikkuScenarioStep',
54
- 'pikkuPlatformScenarioStep',
55
- 'pikkuAddonScenarioStep',
56
- ])
57
-
58
- /**
59
- * A scenario step is the one wrapper whose `name` is its identity: scenarios
60
- * reference a step by that string, so it must become the pikkuFuncId (and hence
61
- * the generated step map's key), not just a cosmetic label the way
62
- * `pikkuMiddleware`/`pikkuAgent` use it.
63
- */
64
- function extractScenarioStepName(
65
- callExpr: ts.Node,
66
- result: ExtractedFunctionName
67
- ): void {
68
- if (
69
- !ts.isCallExpression(callExpr) ||
70
- !ts.isIdentifier(callExpr.expression) ||
71
- !SCENARIO_STEP_WRAPPERS.has(callExpr.expression.text)
72
- ) {
73
- return
74
- }
75
- const firstArg = callExpr.arguments[0]
76
- if (!firstArg || !ts.isObjectLiteralExpression(firstArg)) {
77
- return
78
- }
79
- for (const prop of firstArg.properties) {
80
- if (
81
- ts.isPropertyAssignment(prop) &&
82
- ts.isIdentifier(prop.name) &&
83
- prop.name.text === 'name' &&
84
- ts.isStringLiteral(prop.initializer)
85
- ) {
86
- result.explicitName = prop.initializer.text
87
- return
88
- }
89
- }
90
- }
91
-
92
- export function extractFunctionName(
93
- callExpr: ts.Node,
94
- checker: ts.TypeChecker,
95
- rootDir: string
96
- ): ExtractedFunctionName {
97
- const parent: any = callExpr.parent
98
-
99
- // Initialize the result
100
- const result: ExtractedFunctionName = {
101
- pikkuFuncId: '',
102
- name: '',
103
- exportedName: null,
104
- propertyName: null,
105
- explicitName: null,
106
- isHelper: false,
107
- version: null,
108
- }
109
-
110
- extractScenarioStepName(callExpr, result)
111
-
112
- const workflowHelpers = new Set([
113
- 'workflow',
114
- 'workflowStart',
115
- 'workflowStatus',
116
- 'graphStart',
117
- ])
118
-
119
- if (
120
- ts.isCallExpression(callExpr) &&
121
- ts.isIdentifier(callExpr.expression) &&
122
- workflowHelpers.has(callExpr.expression.text)
123
- ) {
124
- const helperName = callExpr.expression.text
125
- const [firstArg, secondArg] = callExpr.arguments
126
- if (firstArg && ts.isStringLiteral(firstArg)) {
127
- const workflowName = firstArg.text
128
- let funcName: string
129
- if (
130
- helperName === 'graphStart' &&
131
- secondArg &&
132
- ts.isStringLiteral(secondArg)
133
- ) {
134
- funcName = `${helperName}:${workflowName}:${secondArg.text}`
135
- } else {
136
- funcName = `${helperName}:${workflowName}`
137
- }
138
- result.pikkuFuncId = funcName
139
- result.name = funcName
140
- result.explicitName = funcName
141
- result.isHelper = true
142
- return result
143
- }
144
- }
145
-
146
- // Special case for wireHTTP: if this is an identifier within an object literal,
147
- // it might be coming from the HTTP route handling flow
148
- if (
149
- ts.isIdentifier(callExpr) &&
150
- callExpr.parent &&
151
- ts.isPropertyAssignment(callExpr.parent)
152
- ) {
153
- // Try to handle the special case for HTTP route functions
154
- const sym = checker.getSymbolAtLocation(callExpr)
155
- if (sym) {
156
- let resolvedSym = sym
157
- if (resolvedSym.flags & ts.SymbolFlags.Alias) {
158
- resolvedSym = checker.getAliasedSymbol(resolvedSym) ?? resolvedSym
159
- }
160
-
161
- const decls = resolvedSym.declarations ?? []
162
- if (decls.length > 0) {
163
- const decl = decls[0]!
164
- // Check if the declaration is a variable that uses a pikkuFun
165
- if (ts.isVariableDeclaration(decl) && decl.initializer) {
166
- if (
167
- ts.isCallExpression(decl.initializer) &&
168
- ts.isIdentifier(decl.initializer.expression) &&
169
- decl.initializer.expression.text.startsWith('pikku')
170
- ) {
171
- const args = decl.initializer.arguments
172
- const firstArg = args[0]
173
- if (
174
- firstArg &&
175
- (ts.isArrowFunction(firstArg) ||
176
- ts.isFunctionExpression(firstArg))
177
- ) {
178
- // Continue with name extraction
179
- if (ts.isIdentifier(parent.name)) {
180
- result.propertyName = parent.name.text
181
- }
182
-
183
- if (
184
- ts.isVariableDeclaration(decl) &&
185
- isNamedExport(decl, checker) &&
186
- ts.isIdentifier(decl.name)
187
- ) {
188
- result.exportedName = decl.name.text
189
- result.pikkuFuncId = decl.name.text
190
- }
191
-
192
- if (!result.pikkuFuncId) {
193
- result.pikkuFuncId = tempFuncId(callExpr, rootDir)
194
- }
195
-
196
- populateNameByPriority(result)
197
- return result
198
- }
199
- }
200
- }
201
- }
202
- }
203
- }
204
-
205
- if (ts.isCallExpression(callExpr)) {
206
- const { expression, arguments: args } = callExpr
207
-
208
- // Check if this is a pikku function call (pikkuFunc, pikkuSessionlessFunc, etc)
209
- if (ts.isIdentifier(expression) && expression.text.startsWith('pikku')) {
210
- // Check for object with 'name' property in first argument
211
- const firstArg = args[0]
212
- if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
213
- extractOverrideAndVersion(firstArg, result)
214
- }
215
-
216
- // Special handling for pikkuSessionlessFunc pattern - use the arrow function directly
217
- if (expression.text.startsWith('pikku')) {
218
- if (args.length > 0) {
219
- const firstArg = args[0]!
220
- if (
221
- ts.isArrowFunction(firstArg) ||
222
- ts.isFunctionExpression(firstArg)
223
- ) {
224
- // mainFunc = firstArg // Use the arrow function directly instead of the call expression
225
- }
226
- }
227
- }
228
- }
229
-
230
- // Handle object initializer with a func property (for both patterns)
231
- if (args.length > 0) {
232
- const firstArg = args[0]
233
- if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
234
- // Look for func property in the object
235
- for (const prop of firstArg.properties) {
236
- if (
237
- ts.isPropertyAssignment(prop) &&
238
- ts.isIdentifier(prop.name) &&
239
- prop.name.text === 'func'
240
- ) {
241
- if (ts.isIdentifier(prop.initializer)) {
242
- // func: someFunction - resolve the function
243
- const funcSym = checker.getSymbolAtLocation(prop.initializer)
244
- if (funcSym) {
245
- let resolvedFuncSym = funcSym
246
- if (resolvedFuncSym.flags & ts.SymbolFlags.Alias) {
247
- resolvedFuncSym =
248
- checker.getAliasedSymbol(resolvedFuncSym) ?? resolvedFuncSym
249
- }
250
-
251
- const funcDecls = resolvedFuncSym.declarations ?? []
252
- if (funcDecls.length > 0) {
253
- const funcDecl = funcDecls[0]!
254
- // Check if it's a pikkuSessionlessFunc
255
- if (
256
- ts.isVariableDeclaration(funcDecl) &&
257
- funcDecl.initializer
258
- ) {
259
- if (
260
- ts.isCallExpression(funcDecl.initializer) &&
261
- ts.isIdentifier(funcDecl.initializer.expression) &&
262
- funcDecl.initializer.expression.text.startsWith('pikku')
263
- ) {
264
- const funcArgs = funcDecl.initializer.arguments
265
- const firstArg = funcArgs[0]
266
- if (
267
- firstArg &&
268
- (ts.isArrowFunction(firstArg) ||
269
- ts.isFunctionExpression(firstArg))
270
- ) {
271
- // mainFunc = firstArg
272
-
273
- // Check if the variable is exported
274
- if (
275
- isNamedExport(funcDecl, checker) &&
276
- ts.isIdentifier(funcDecl.name)
277
- ) {
278
- result.exportedName = funcDecl.name.text
279
- }
280
-
281
- break
282
- }
283
- } else if (
284
- ts.isFunctionExpression(funcDecl.initializer) ||
285
- ts.isArrowFunction(funcDecl.initializer)
286
- ) {
287
- if (
288
- isNamedExport(funcDecl, checker) &&
289
- ts.isIdentifier(funcDecl.name)
290
- ) {
291
- result.exportedName = funcDecl.name.text
292
- }
293
-
294
- break
295
- }
296
- } else if (ts.isFunctionDeclaration(funcDecl)) {
297
- // mainFunc = funcDecl
298
-
299
- // Check if the function is exported
300
- if (
301
- funcDecl.modifiers?.some(
302
- (m) => m.kind === ts.SyntaxKind.ExportKeyword
303
- ) &&
304
- funcDecl.name &&
305
- ts.isIdentifier(funcDecl.name)
306
- ) {
307
- result.exportedName = funcDecl.name.text
308
- }
309
-
310
- break
311
- }
312
- }
313
- } else {
314
- // If we can't resolve the symbol, use the identifier itself
315
- // mainFunc = prop.initializer
316
- }
317
- break
318
- } else if (
319
- ts.isFunctionExpression(prop.initializer) ||
320
- ts.isArrowFunction(prop.initializer)
321
- ) {
322
- // func: () => {} or func: function() {} - use directly
323
- // mainFunc = prop.initializer
324
- break
325
- }
326
- } else if (
327
- ts.isShorthandPropertyAssignment(prop) &&
328
- ts.isIdentifier(prop.name) &&
329
- prop.name.text === 'func'
330
- ) {
331
- // Handle func shorthand property
332
- const shorthandSym = checker.getShorthandAssignmentValueSymbol(prop)
333
- if (
334
- shorthandSym &&
335
- shorthandSym.declarations &&
336
- shorthandSym.declarations.length > 0
337
- ) {
338
- const shorthandDecl = shorthandSym.declarations[0]
339
- if (!shorthandDecl) {
340
- throw new Error('No shorthand declaration found')
341
- }
342
- if (
343
- ts.isVariableDeclaration(shorthandDecl) &&
344
- shorthandDecl.initializer
345
- ) {
346
- if (
347
- ts.isCallExpression(shorthandDecl.initializer) &&
348
- ts.isIdentifier(shorthandDecl.initializer.expression) &&
349
- shorthandDecl.initializer.expression.text.startsWith('pikku')
350
- ) {
351
- const args = shorthandDecl.initializer.arguments
352
- const firstArg = args[0]
353
- if (
354
- firstArg &&
355
- (ts.isArrowFunction(firstArg) ||
356
- ts.isFunctionExpression(firstArg))
357
- ) {
358
- // mainFunc = firstArg
359
-
360
- // Check if the variable is exported
361
- if (
362
- isNamedExport(shorthandDecl, checker) &&
363
- ts.isIdentifier(shorthandDecl.name)
364
- ) {
365
- result.exportedName = shorthandDecl.name.text
366
- }
367
-
368
- break
369
- }
370
- } else if (
371
- ts.isFunctionExpression(shorthandDecl.initializer) ||
372
- ts.isArrowFunction(shorthandDecl.initializer)
373
- ) {
374
- if (
375
- isNamedExport(shorthandDecl, checker) &&
376
- ts.isIdentifier(shorthandDecl.name)
377
- ) {
378
- result.exportedName = shorthandDecl.name.text
379
- }
380
-
381
- break
382
- }
383
- } else if (ts.isFunctionDeclaration(shorthandDecl)) {
384
- // mainFunc = shorthandDecl
385
-
386
- // Check if the function is exported
387
- if (
388
- shorthandDecl.modifiers?.some(
389
- (m) => m.kind === ts.SyntaxKind.ExportKeyword
390
- ) &&
391
- shorthandDecl.name &&
392
- ts.isIdentifier(shorthandDecl.name)
393
- ) {
394
- result.exportedName = shorthandDecl.name.text
395
- }
396
-
397
- break
398
- }
399
- }
400
- }
401
- }
402
- }
403
- }
404
- }
405
- // Handle direct identifier case
406
- else if (ts.isIdentifier(callExpr)) {
407
- const sym = checker.getSymbolAtLocation(callExpr)
408
- if (sym) {
409
- let resolvedSym = sym
410
- if (resolvedSym.flags & ts.SymbolFlags.Alias) {
411
- resolvedSym = checker.getAliasedSymbol(resolvedSym) ?? resolvedSym
412
- }
413
-
414
- const decls = resolvedSym.declarations ?? []
415
- if (decls.length > 0) {
416
- const decl = decls[0]
417
- if (!decl) {
418
- throw new Error('No declaration found')
419
- }
420
- if (ts.isVariableDeclaration(decl) && decl.initializer) {
421
- if (
422
- ts.isCallExpression(decl.initializer) &&
423
- ts.isIdentifier(decl.initializer.expression) &&
424
- decl.initializer.expression.text.startsWith('pikku')
425
- ) {
426
- const firstArg = decl.initializer.arguments[0]
427
- if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
428
- extractOverrideAndVersion(firstArg, result)
429
- }
430
-
431
- if (decl.initializer.expression.text.startsWith('pikku')) {
432
- if (
433
- firstArg &&
434
- (ts.isArrowFunction(firstArg) ||
435
- ts.isFunctionExpression(firstArg))
436
- ) {
437
- // mainFunc = firstArg
438
- }
439
- }
440
-
441
- // Check if the variable is exported
442
- if (isNamedExport(decl, checker) && ts.isIdentifier(decl.name)) {
443
- result.exportedName = decl.name.text
444
- }
445
- } else if (
446
- ts.isFunctionExpression(decl.initializer) ||
447
- ts.isArrowFunction(decl.initializer)
448
- ) {
449
- // mainFunc = decl.initializer
450
-
451
- // Check if the variable is exported
452
- if (isNamedExport(decl, checker) && ts.isIdentifier(decl.name)) {
453
- result.exportedName = decl.name.text
454
- }
455
- }
456
- } else if (ts.isFunctionDeclaration(decl)) {
457
- // mainFunc = decl
458
-
459
- // Check if the function is exported
460
- if (
461
- decl.modifiers?.some(
462
- (m) => m.kind === ts.SyntaxKind.ExportKeyword
463
- ) &&
464
- decl.name &&
465
- ts.isIdentifier(decl.name)
466
- ) {
467
- result.exportedName = decl.name.text
468
- }
469
- }
470
- }
471
- }
472
- }
473
-
474
- // 1) const foo = pikkuFunc(...)
475
- if (ts.isVariableDeclaration(parent) && ts.isIdentifier(parent.name)) {
476
- if (isNamedExport(parent, checker)) {
477
- result.exportedName = parent.name.text
478
- }
479
- }
480
- // 2) { foo: pikkuFunc(...) }
481
- else if (ts.isPropertyAssignment(parent) && ts.isIdentifier(parent.name)) {
482
- result.propertyName = parent.name.text
483
- }
484
- // 2b) Handle shorthand property { foo } - which is equivalent to { foo: foo }
485
- else if (
486
- ts.isShorthandPropertyAssignment(parent) &&
487
- ts.isIdentifier(parent.name)
488
- ) {
489
- result.propertyName = parent.name.text
490
- }
491
- // 3) Handle any remaining cases for pikkuFunc({ override: '…', func: … })
492
- else if (ts.isCallExpression(callExpr)) {
493
- const firstArg = callExpr.arguments[0]
494
- if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
495
- extractOverrideAndVersion(firstArg, result)
496
- }
497
- }
498
-
499
- // Apply name priority logic
500
- populateNameByPriority(result)
501
-
502
- if (result.explicitName) {
503
- result.pikkuFuncId = result.explicitName
504
- } else if (result.exportedName) {
505
- result.pikkuFuncId = result.exportedName
506
- } else {
507
- result.pikkuFuncId = tempFuncId(callExpr, rootDir)
508
- }
509
-
510
- if (result.version !== null) {
511
- // Strip trailing VN suffix if it matches the version (e.g. createCardV1 + version:1 → createCard@v1)
512
- const vSuffix = `V${result.version}`
513
- if (
514
- result.pikkuFuncId.endsWith(vSuffix) &&
515
- result.pikkuFuncId.length > vSuffix.length
516
- ) {
517
- result.pikkuFuncId = result.pikkuFuncId.slice(0, -vSuffix.length)
518
- }
519
- result.pikkuFuncId = formatVersionedId(result.pikkuFuncId, result.version)
520
- }
521
-
522
- return result
523
- }
524
-
525
- /**
526
- * Helper function to populate the 'name' field based on priority
527
- */
528
- export function populateNameByPriority(result: ExtractedFunctionName): void {
529
- // Priority 1: If we have an explict name, use that
530
- if (result.explicitName) {
531
- result.name = result.explicitName
532
- }
533
- // Priority 2: If we have an exported name, use that
534
- else if (result.exportedName) {
535
- result.name = result.exportedName
536
- }
537
- // Fallback: Use the deterministic name, but we could shorten it in the future
538
- else {
539
- // For now, just use the full pikkuFuncId
540
- result.name = result.pikkuFuncId
541
- }
542
- }
543
-
544
- /**
545
- * Helper function to check if a variable declaration is a named export
546
- */
547
- export function isNamedExport(
548
- declaration: ts.VariableDeclaration,
549
- checker?: ts.TypeChecker
550
- ): boolean {
551
- let parent: any = declaration.parent
552
- if (!parent) return false
553
-
554
- if (ts.isVariableDeclarationList(parent)) {
555
- parent = parent.parent
556
- if (!parent) return false
557
-
558
- if (ts.isVariableStatement(parent)) {
559
- if (
560
- parent.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)
561
- ) {
562
- return true
563
- }
564
- }
565
- }
566
-
567
- if (checker && ts.isIdentifier(declaration.name)) {
568
- const sourceFile = declaration.getSourceFile()
569
- const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile)
570
- if (sourceFileSymbol) {
571
- const exports = checker.getExportsOfModule(sourceFileSymbol)
572
- const declSymbol = checker.getSymbolAtLocation(declaration.name)
573
- if (declSymbol) {
574
- return exports.some((exp) => {
575
- let resolved = exp
576
- if (resolved.flags & ts.SymbolFlags.Alias) {
577
- resolved = checker.getAliasedSymbol(resolved) ?? resolved
578
- }
579
- return resolved === declSymbol
580
- })
581
- }
582
- }
583
- }
584
-
585
- return false
586
- }
587
-
588
- function extractOverrideAndVersion(
589
- objLiteral: ts.ObjectLiteralExpression,
590
- result: ExtractedFunctionName
591
- ): void {
592
- for (const prop of objLiteral.properties) {
593
- if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
594
- if (
595
- prop.name.text === 'override' &&
596
- ts.isStringLiteral(prop.initializer) &&
597
- !result.explicitName
598
- ) {
599
- result.explicitName = prop.initializer.text
600
- } else if (
601
- prop.name.text === 'version' &&
602
- ts.isNumericLiteral(prop.initializer) &&
603
- result.version === null
604
- ) {
605
- const parsed = Number(prop.initializer.text)
606
- if (Number.isInteger(parsed) && parsed >= 1) {
607
- result.version = parsed
608
- }
609
- }
610
- }
611
- }
612
- }
@@ -1,70 +0,0 @@
1
- import * as ts from 'typescript'
2
- import {
3
- getPropertyAssignmentInitializer,
4
- resolveFunctionDeclaration,
5
- } from './type-utils.js'
6
-
7
- /**
8
- * Where a config object's implementation can live, in the order it is looked for.
9
- *
10
- * `func` is the ordinary case. A `pikkuScenarioStep` instead declares one
11
- * implementation per surface, and every binding shares the step's input and
12
- * output — that is what makes them interchangeable — so any one of them types
13
- * the step. `default` is preferred because it is the binding every step is
14
- * expected to have.
15
- */
16
- const IMPLEMENTATION_KEYS = ['func', 'default', 'browser', 'cli'] as const
17
-
18
- /**
19
- * Extracts the actual function node from a pikkuFunc/pikkuWorkflowFunc call
20
- * Handles both direct function form and config object form { func: ... }
21
- */
22
- export function extractFunctionNode(
23
- firstArg: ts.Expression,
24
- checker: ts.TypeChecker
25
- ): {
26
- funcNode: ts.Node
27
- resolvedFunc: ts.Node | null
28
- isDirectFunction: boolean
29
- } {
30
- let funcNode: ts.Node = firstArg
31
- let isDirectFunction = true
32
-
33
- // Check if first argument is a config object with 'func' property
34
- if (ts.isObjectLiteralExpression(firstArg)) {
35
- isDirectFunction = false
36
- let funcInitializer: ts.Expression | undefined
37
- for (const key of IMPLEMENTATION_KEYS) {
38
- funcInitializer =
39
- getPropertyAssignmentInitializer(firstArg, key, true, checker) ??
40
- undefined
41
- if (funcInitializer) break
42
- }
43
-
44
- if (funcInitializer) {
45
- funcNode = funcInitializer
46
- } else {
47
- // Return the original node if no func property found
48
- // Caller should handle validation
49
- funcNode = firstArg
50
- }
51
- }
52
-
53
- // Resolve identifier to get the actual function node
54
- if (ts.isIdentifier(funcNode)) {
55
- const symbol = checker.getSymbolAtLocation(funcNode)
56
- const decl = symbol?.valueDeclaration || symbol?.declarations?.[0]
57
- if (decl && ts.isVariableDeclaration(decl) && decl.initializer) {
58
- funcNode = decl.initializer
59
- }
60
- }
61
-
62
- // Resolve function declaration for deeper analysis
63
- const resolvedFunc = resolveFunctionDeclaration(funcNode, checker)
64
-
65
- return {
66
- funcNode,
67
- resolvedFunc,
68
- isDirectFunction,
69
- }
70
- }