@pikku/inspector 0.12.75 → 0.12.81

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 (219) hide show
  1. package/CHANGELOG.md +330 -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-wire-addon.js +1 -0
  8. package/dist/add/add-wire-remote-addon.js +1 -0
  9. package/dist/index.d.ts +3 -1
  10. package/dist/index.js +3 -1
  11. package/dist/inspector.js +4 -0
  12. package/dist/surface/collect-surface.d.ts +58 -0
  13. package/dist/surface/collect-surface.js +613 -0
  14. package/dist/types.d.ts +20 -11
  15. package/dist/utils/filter-inspector-state.js +14 -0
  16. package/dist/utils/post-process.js +15 -0
  17. package/dist/utils/read-module-specifiers.d.ts +8 -0
  18. package/dist/utils/read-module-specifiers.js +23 -0
  19. package/dist/utils/read-tsconfig-out-dir.d.ts +5 -0
  20. package/dist/utils/read-tsconfig-out-dir.js +12 -0
  21. package/dist/utils/resolve-deploy-target.d.ts +7 -0
  22. package/dist/utils/resolve-deploy-target.js +15 -7
  23. package/dist/utils/serialize-inspector-state.d.ts +5 -0
  24. package/dist/utils/serialize-inspector-state.js +8 -0
  25. package/dist/visit.js +4 -0
  26. package/package.json +16 -6
  27. package/run-tests.sh +21 -6
  28. package/src/add/add-addon-bans.ts +0 -85
  29. package/src/add/add-agent-scorer.test.ts +0 -197
  30. package/src/add/add-agent-scorer.ts +0 -83
  31. package/src/add/add-agent.test.ts +0 -87
  32. package/src/add/add-agent.ts +0 -638
  33. package/src/add/add-approval-description.ts +0 -76
  34. package/src/add/add-auth.test.ts +0 -791
  35. package/src/add/add-auth.ts +0 -424
  36. package/src/add/add-channel.ts +0 -778
  37. package/src/add/add-cli-renderers.test.ts +0 -74
  38. package/src/add/add-cli.ts +0 -1006
  39. package/src/add/add-credential.ts +0 -186
  40. package/src/add/add-feature.test.ts +0 -306
  41. package/src/add/add-feature.ts +0 -253
  42. package/src/add/add-file-extends-core-type.ts +0 -66
  43. package/src/add/add-file-with-config.ts +0 -45
  44. package/src/add/add-file-with-factory.test.ts +0 -134
  45. package/src/add/add-file-with-factory.ts +0 -288
  46. package/src/add/add-functions.test.ts +0 -743
  47. package/src/add/add-functions.ts +0 -1548
  48. package/src/add/add-gateway.ts +0 -143
  49. package/src/add/add-http-route-ref.test.ts +0 -149
  50. package/src/add/add-http-route.ts +0 -530
  51. package/src/add/add-http-routes.ts +0 -471
  52. package/src/add/add-keyed-wiring.ts +0 -180
  53. package/src/add/add-mcp-prompt.ts +0 -157
  54. package/src/add/add-mcp-resource.ts +0 -175
  55. package/src/add/add-middleware.test.ts +0 -196
  56. package/src/add/add-middleware.ts +0 -879
  57. package/src/add/add-permission-auth.test.ts +0 -59
  58. package/src/add/add-permission.ts +0 -311
  59. package/src/add/add-personas.test.ts +0 -406
  60. package/src/add/add-personas.ts +0 -287
  61. package/src/add/add-queue-worker.ts +0 -117
  62. package/src/add/add-rpc-invocations.test.ts +0 -287
  63. package/src/add/add-rpc-invocations.ts +0 -221
  64. package/src/add/add-scenario-step.test.ts +0 -509
  65. package/src/add/add-schedule.ts +0 -120
  66. package/src/add/add-scope.test.ts +0 -419
  67. package/src/add/add-scope.ts +0 -221
  68. package/src/add/add-secret.ts +0 -10
  69. package/src/add/add-subject-scenario-steps.test.ts +0 -161
  70. package/src/add/add-system-role.test.ts +0 -297
  71. package/src/add/add-system-role.ts +0 -162
  72. package/src/add/add-trigger.ts +0 -165
  73. package/src/add/add-variable.ts +0 -10
  74. package/src/add/add-wire-addon.test.ts +0 -185
  75. package/src/add/add-wire-addon.ts +0 -146
  76. package/src/add/add-wire-remote-addon.ts +0 -80
  77. package/src/add/add-workflow-edge-cases.test.ts +0 -201
  78. package/src/add/add-workflow-fanout.test.ts +0 -166
  79. package/src/add/add-workflow-graph-foreach.test.ts +0 -174
  80. package/src/add/add-workflow-graph-input.test.ts +0 -94
  81. package/src/add/add-workflow-graph-notes.test.ts +0 -74
  82. package/src/add/add-workflow-graph.ts +0 -644
  83. package/src/add/add-workflow-on-error.test.ts +0 -118
  84. package/src/add/add-workflow-return-switch.test.ts +0 -121
  85. package/src/add/add-workflow-silent-drops.test.ts +0 -261
  86. package/src/add/add-workflow-sleep-expression.test.ts +0 -96
  87. package/src/add/add-workflow.test.ts +0 -155
  88. package/src/add/add-workflow.ts +0 -482
  89. package/src/add/addon-bans.test.ts +0 -121
  90. package/src/add/addon-contracts.test.ts +0 -221
  91. package/src/add/allow-escape-hatches.test.ts +0 -144
  92. package/src/add/audit-meta.test.ts +0 -75
  93. package/src/add/classified-sink-check.test.ts +0 -347
  94. package/src/add/config-value-metadata.test.ts +0 -263
  95. package/src/add/dynamic-import-check.test.ts +0 -119
  96. package/src/add/expect-eventually-scenario-only.test.ts +0 -108
  97. package/src/add/function-body-span.test.ts +0 -96
  98. package/src/add/inline-wiring-function.test.ts +0 -104
  99. package/src/add/pii-check.test.ts +0 -258
  100. package/src/add/rpc-type-cast.test.ts +0 -123
  101. package/src/add/scenario-instrumentation.test.ts +0 -89
  102. package/src/add/scenario-instrumentation.ts +0 -42
  103. package/src/add/scenario-marker.test.ts +0 -89
  104. package/src/add/scenario-not-extractable.test.ts +0 -159
  105. package/src/add/scenario-services.test.ts +0 -103
  106. package/src/add/scenario-skip.test.ts +0 -83
  107. package/src/add/validate-workflow-graph-addons.test.ts +0 -102
  108. package/src/add/wire-name-literal.test.ts +0 -117
  109. package/src/error-codes-emitted.test.ts +0 -76
  110. package/src/error-codes.ts +0 -145
  111. package/src/index.ts +0 -66
  112. package/src/inspector.ts +0 -575
  113. package/src/schema-generator.ts +0 -1
  114. package/src/source-file-cache.ts +0 -73
  115. package/src/tsconfig-paths.test.ts +0 -90
  116. package/src/types-map.ts +0 -141
  117. package/src/types.ts +0 -775
  118. package/src/utils/annotate-http-route-auth.test.ts +0 -161
  119. package/src/utils/annotate-http-route-auth.ts +0 -53
  120. package/src/utils/check-classified-sinks.ts +0 -215
  121. package/src/utils/check-pii-output.ts +0 -120
  122. package/src/utils/compute-diagnostics.test.ts +0 -106
  123. package/src/utils/compute-required-schemas.ts +0 -48
  124. package/src/utils/contract-hashes.test.ts +0 -553
  125. package/src/utils/contract-hashes.ts +0 -387
  126. package/src/utils/custom-types-generator.test.ts +0 -124
  127. package/src/utils/custom-types-generator.ts +0 -150
  128. package/src/utils/detect-schema-vendor.test.ts +0 -123
  129. package/src/utils/detect-schema-vendor.ts +0 -120
  130. package/src/utils/does-type-extend-core-type.ts +0 -53
  131. package/src/utils/ensure-function-metadata.ts +0 -385
  132. package/src/utils/extract-function-name.ts +0 -612
  133. package/src/utils/extract-function-node.ts +0 -70
  134. package/src/utils/extract-node-value.test.ts +0 -117
  135. package/src/utils/extract-node-value.ts +0 -172
  136. package/src/utils/extract-secret-usage.test.ts +0 -81
  137. package/src/utils/extract-secret-usage.ts +0 -73
  138. package/src/utils/extract-services.ts +0 -70
  139. package/src/utils/extract-surface-usage.test.ts +0 -147
  140. package/src/utils/extract-surface-usage.ts +0 -121
  141. package/src/utils/filter-inspector-state.test.ts +0 -2232
  142. package/src/utils/filter-inspector-state.ts +0 -1298
  143. package/src/utils/filter-utils.test.ts +0 -843
  144. package/src/utils/filter-utils.ts +0 -161
  145. package/src/utils/find-root-dir.ts +0 -68
  146. package/src/utils/find-zod-transform.test.ts +0 -70
  147. package/src/utils/find-zod-transform.ts +0 -103
  148. package/src/utils/get-exported-variable-name.ts +0 -48
  149. package/src/utils/get-files-and-methods.ts +0 -157
  150. package/src/utils/get-property-value.test.ts +0 -141
  151. package/src/utils/get-property-value.ts +0 -331
  152. package/src/utils/hash.ts +0 -26
  153. package/src/utils/literal-properties.ts +0 -97
  154. package/src/utils/load-addon-functions-meta.test.ts +0 -157
  155. package/src/utils/load-addon-functions-meta.ts +0 -508
  156. package/src/utils/load-addon-scopes.test.ts +0 -138
  157. package/src/utils/middleware.test.ts +0 -204
  158. package/src/utils/middleware.ts +0 -303
  159. package/src/utils/nested-project-filter.test.ts +0 -53
  160. package/src/utils/nested-project-filter.ts +0 -28
  161. package/src/utils/permissions-shorthand.test.ts +0 -79
  162. package/src/utils/permissions.test.ts +0 -125
  163. package/src/utils/permissions.ts +0 -129
  164. package/src/utils/post-process.test.ts +0 -1094
  165. package/src/utils/post-process.ts +0 -1604
  166. package/src/utils/resolve-addon-package.ts +0 -106
  167. package/src/utils/resolve-core-type.test.ts +0 -142
  168. package/src/utils/resolve-core-type.ts +0 -35
  169. package/src/utils/resolve-deploy-target.test.ts +0 -135
  170. package/src/utils/resolve-deploy-target.ts +0 -65
  171. package/src/utils/resolve-function-meta.ts +0 -25
  172. package/src/utils/resolve-function-types.ts +0 -42
  173. package/src/utils/resolve-identifier.ts +0 -46
  174. package/src/utils/resolve-ref-contract.ts +0 -71
  175. package/src/utils/resolve-versions.test.ts +0 -499
  176. package/src/utils/resolve-versions.ts +0 -228
  177. package/src/utils/schema-cache.test.ts +0 -124
  178. package/src/utils/schema-generator.test.ts +0 -272
  179. package/src/utils/schema-generator.ts +0 -780
  180. package/src/utils/secret-alias-services.test.ts +0 -146
  181. package/src/utils/secret-alias-services.ts +0 -58
  182. package/src/utils/serialize-inspector-state.ts +0 -742
  183. package/src/utils/serialize-mcp-json.ts +0 -150
  184. package/src/utils/serialize-middleware-groups-meta.ts +0 -36
  185. package/src/utils/serialize-openapi-json.ts +0 -277
  186. package/src/utils/serialize-permissions-groups-meta.ts +0 -7
  187. package/src/utils/single-declaration.ts +0 -57
  188. package/src/utils/type-utils.ts +0 -145
  189. package/src/utils/validate-auth-sessionless.ts +0 -30
  190. package/src/utils/validate-exposed-functions-gated.test.ts +0 -230
  191. package/src/utils/validate-exposed-functions-gated.ts +0 -103
  192. package/src/utils/validate-tags-resolve-to-middleware.test.ts +0 -108
  193. package/src/utils/validate-tags-resolve-to-middleware.ts +0 -48
  194. package/src/utils/workflow/derive-workflow-plan.test.ts +0 -178
  195. package/src/utils/workflow/derive-workflow-plan.ts +0 -117
  196. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +0 -1465
  197. package/src/utils/workflow/dsl/deserialize-fanout-body.test.ts +0 -71
  198. package/src/utils/workflow/dsl/deserialize-fanout-fidelity.test.ts +0 -99
  199. package/src/utils/workflow/dsl/deserialize-graph-next.test.ts +0 -161
  200. package/src/utils/workflow/dsl/deserialize-roundtrip-bindings.test.ts +0 -121
  201. package/src/utils/workflow/dsl/deserialize-roundtrip-values.test.ts +0 -116
  202. package/src/utils/workflow/dsl/deserialize-roundtrip.test.ts +0 -145
  203. package/src/utils/workflow/dsl/extract-approval-policy.test.ts +0 -71
  204. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +0 -2254
  205. package/src/utils/workflow/dsl/index.ts +0 -11
  206. package/src/utils/workflow/dsl/patterns.ts +0 -440
  207. package/src/utils/workflow/dsl/validation.ts +0 -203
  208. package/src/utils/workflow/graph/convert-dsl-to-graph-skip.test.ts +0 -35
  209. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +0 -543
  210. package/src/utils/workflow/graph/fanout-node-identity.test.ts +0 -105
  211. package/src/utils/workflow/graph/finalize-workflow-wires.ts +0 -310
  212. package/src/utils/workflow/graph/finalize-workflows.test.ts +0 -50
  213. package/src/utils/workflow/graph/finalize-workflows.ts +0 -130
  214. package/src/utils/workflow/graph/index.ts +0 -28
  215. package/src/utils/workflow/graph/serialize-workflow-graph.ts +0 -240
  216. package/src/utils/workflow/graph/workflow-graph.types.ts +0 -281
  217. package/src/visit.ts +0 -181
  218. package/tsconfig.json +0 -19
  219. 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
- }