@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.
- package/CHANGELOG.md +330 -0
- package/dist/add/add-analytics.d.ts +9 -0
- package/dist/add/add-analytics.js +178 -0
- package/dist/add/add-auth.js +0 -54
- package/dist/add/add-feature-flag.d.ts +2 -0
- package/dist/add/add-feature-flag.js +162 -0
- package/dist/add/add-wire-addon.js +1 -0
- package/dist/add/add-wire-remote-addon.js +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/inspector.js +4 -0
- package/dist/surface/collect-surface.d.ts +58 -0
- package/dist/surface/collect-surface.js +613 -0
- package/dist/types.d.ts +20 -11
- package/dist/utils/filter-inspector-state.js +14 -0
- package/dist/utils/post-process.js +15 -0
- package/dist/utils/read-module-specifiers.d.ts +8 -0
- package/dist/utils/read-module-specifiers.js +23 -0
- package/dist/utils/read-tsconfig-out-dir.d.ts +5 -0
- package/dist/utils/read-tsconfig-out-dir.js +12 -0
- package/dist/utils/resolve-deploy-target.d.ts +7 -0
- package/dist/utils/resolve-deploy-target.js +15 -7
- package/dist/utils/serialize-inspector-state.d.ts +5 -0
- package/dist/utils/serialize-inspector-state.js +8 -0
- package/dist/visit.js +4 -0
- package/package.json +16 -6
- package/run-tests.sh +21 -6
- package/src/add/add-addon-bans.ts +0 -85
- package/src/add/add-agent-scorer.test.ts +0 -197
- package/src/add/add-agent-scorer.ts +0 -83
- package/src/add/add-agent.test.ts +0 -87
- package/src/add/add-agent.ts +0 -638
- package/src/add/add-approval-description.ts +0 -76
- package/src/add/add-auth.test.ts +0 -791
- package/src/add/add-auth.ts +0 -424
- package/src/add/add-channel.ts +0 -778
- package/src/add/add-cli-renderers.test.ts +0 -74
- package/src/add/add-cli.ts +0 -1006
- package/src/add/add-credential.ts +0 -186
- package/src/add/add-feature.test.ts +0 -306
- package/src/add/add-feature.ts +0 -253
- package/src/add/add-file-extends-core-type.ts +0 -66
- package/src/add/add-file-with-config.ts +0 -45
- package/src/add/add-file-with-factory.test.ts +0 -134
- package/src/add/add-file-with-factory.ts +0 -288
- package/src/add/add-functions.test.ts +0 -743
- package/src/add/add-functions.ts +0 -1548
- package/src/add/add-gateway.ts +0 -143
- package/src/add/add-http-route-ref.test.ts +0 -149
- package/src/add/add-http-route.ts +0 -530
- package/src/add/add-http-routes.ts +0 -471
- package/src/add/add-keyed-wiring.ts +0 -180
- package/src/add/add-mcp-prompt.ts +0 -157
- package/src/add/add-mcp-resource.ts +0 -175
- package/src/add/add-middleware.test.ts +0 -196
- package/src/add/add-middleware.ts +0 -879
- package/src/add/add-permission-auth.test.ts +0 -59
- package/src/add/add-permission.ts +0 -311
- package/src/add/add-personas.test.ts +0 -406
- package/src/add/add-personas.ts +0 -287
- package/src/add/add-queue-worker.ts +0 -117
- package/src/add/add-rpc-invocations.test.ts +0 -287
- package/src/add/add-rpc-invocations.ts +0 -221
- package/src/add/add-scenario-step.test.ts +0 -509
- package/src/add/add-schedule.ts +0 -120
- package/src/add/add-scope.test.ts +0 -419
- package/src/add/add-scope.ts +0 -221
- package/src/add/add-secret.ts +0 -10
- package/src/add/add-subject-scenario-steps.test.ts +0 -161
- package/src/add/add-system-role.test.ts +0 -297
- package/src/add/add-system-role.ts +0 -162
- package/src/add/add-trigger.ts +0 -165
- package/src/add/add-variable.ts +0 -10
- package/src/add/add-wire-addon.test.ts +0 -185
- package/src/add/add-wire-addon.ts +0 -146
- package/src/add/add-wire-remote-addon.ts +0 -80
- package/src/add/add-workflow-edge-cases.test.ts +0 -201
- package/src/add/add-workflow-fanout.test.ts +0 -166
- package/src/add/add-workflow-graph-foreach.test.ts +0 -174
- package/src/add/add-workflow-graph-input.test.ts +0 -94
- package/src/add/add-workflow-graph-notes.test.ts +0 -74
- package/src/add/add-workflow-graph.ts +0 -644
- package/src/add/add-workflow-on-error.test.ts +0 -118
- package/src/add/add-workflow-return-switch.test.ts +0 -121
- package/src/add/add-workflow-silent-drops.test.ts +0 -261
- package/src/add/add-workflow-sleep-expression.test.ts +0 -96
- package/src/add/add-workflow.test.ts +0 -155
- package/src/add/add-workflow.ts +0 -482
- package/src/add/addon-bans.test.ts +0 -121
- package/src/add/addon-contracts.test.ts +0 -221
- package/src/add/allow-escape-hatches.test.ts +0 -144
- package/src/add/audit-meta.test.ts +0 -75
- package/src/add/classified-sink-check.test.ts +0 -347
- package/src/add/config-value-metadata.test.ts +0 -263
- package/src/add/dynamic-import-check.test.ts +0 -119
- package/src/add/expect-eventually-scenario-only.test.ts +0 -108
- package/src/add/function-body-span.test.ts +0 -96
- package/src/add/inline-wiring-function.test.ts +0 -104
- package/src/add/pii-check.test.ts +0 -258
- package/src/add/rpc-type-cast.test.ts +0 -123
- package/src/add/scenario-instrumentation.test.ts +0 -89
- package/src/add/scenario-instrumentation.ts +0 -42
- package/src/add/scenario-marker.test.ts +0 -89
- package/src/add/scenario-not-extractable.test.ts +0 -159
- package/src/add/scenario-services.test.ts +0 -103
- package/src/add/scenario-skip.test.ts +0 -83
- package/src/add/validate-workflow-graph-addons.test.ts +0 -102
- package/src/add/wire-name-literal.test.ts +0 -117
- package/src/error-codes-emitted.test.ts +0 -76
- package/src/error-codes.ts +0 -145
- package/src/index.ts +0 -66
- package/src/inspector.ts +0 -575
- package/src/schema-generator.ts +0 -1
- package/src/source-file-cache.ts +0 -73
- package/src/tsconfig-paths.test.ts +0 -90
- package/src/types-map.ts +0 -141
- package/src/types.ts +0 -775
- package/src/utils/annotate-http-route-auth.test.ts +0 -161
- package/src/utils/annotate-http-route-auth.ts +0 -53
- package/src/utils/check-classified-sinks.ts +0 -215
- package/src/utils/check-pii-output.ts +0 -120
- package/src/utils/compute-diagnostics.test.ts +0 -106
- package/src/utils/compute-required-schemas.ts +0 -48
- package/src/utils/contract-hashes.test.ts +0 -553
- package/src/utils/contract-hashes.ts +0 -387
- package/src/utils/custom-types-generator.test.ts +0 -124
- package/src/utils/custom-types-generator.ts +0 -150
- package/src/utils/detect-schema-vendor.test.ts +0 -123
- package/src/utils/detect-schema-vendor.ts +0 -120
- package/src/utils/does-type-extend-core-type.ts +0 -53
- package/src/utils/ensure-function-metadata.ts +0 -385
- package/src/utils/extract-function-name.ts +0 -612
- package/src/utils/extract-function-node.ts +0 -70
- package/src/utils/extract-node-value.test.ts +0 -117
- package/src/utils/extract-node-value.ts +0 -172
- package/src/utils/extract-secret-usage.test.ts +0 -81
- package/src/utils/extract-secret-usage.ts +0 -73
- package/src/utils/extract-services.ts +0 -70
- package/src/utils/extract-surface-usage.test.ts +0 -147
- package/src/utils/extract-surface-usage.ts +0 -121
- package/src/utils/filter-inspector-state.test.ts +0 -2232
- package/src/utils/filter-inspector-state.ts +0 -1298
- package/src/utils/filter-utils.test.ts +0 -843
- package/src/utils/filter-utils.ts +0 -161
- package/src/utils/find-root-dir.ts +0 -68
- package/src/utils/find-zod-transform.test.ts +0 -70
- package/src/utils/find-zod-transform.ts +0 -103
- package/src/utils/get-exported-variable-name.ts +0 -48
- package/src/utils/get-files-and-methods.ts +0 -157
- package/src/utils/get-property-value.test.ts +0 -141
- package/src/utils/get-property-value.ts +0 -331
- package/src/utils/hash.ts +0 -26
- package/src/utils/literal-properties.ts +0 -97
- package/src/utils/load-addon-functions-meta.test.ts +0 -157
- package/src/utils/load-addon-functions-meta.ts +0 -508
- package/src/utils/load-addon-scopes.test.ts +0 -138
- package/src/utils/middleware.test.ts +0 -204
- package/src/utils/middleware.ts +0 -303
- package/src/utils/nested-project-filter.test.ts +0 -53
- package/src/utils/nested-project-filter.ts +0 -28
- package/src/utils/permissions-shorthand.test.ts +0 -79
- package/src/utils/permissions.test.ts +0 -125
- package/src/utils/permissions.ts +0 -129
- package/src/utils/post-process.test.ts +0 -1094
- package/src/utils/post-process.ts +0 -1604
- package/src/utils/resolve-addon-package.ts +0 -106
- package/src/utils/resolve-core-type.test.ts +0 -142
- package/src/utils/resolve-core-type.ts +0 -35
- package/src/utils/resolve-deploy-target.test.ts +0 -135
- package/src/utils/resolve-deploy-target.ts +0 -65
- package/src/utils/resolve-function-meta.ts +0 -25
- package/src/utils/resolve-function-types.ts +0 -42
- package/src/utils/resolve-identifier.ts +0 -46
- package/src/utils/resolve-ref-contract.ts +0 -71
- package/src/utils/resolve-versions.test.ts +0 -499
- package/src/utils/resolve-versions.ts +0 -228
- package/src/utils/schema-cache.test.ts +0 -124
- package/src/utils/schema-generator.test.ts +0 -272
- package/src/utils/schema-generator.ts +0 -780
- package/src/utils/secret-alias-services.test.ts +0 -146
- package/src/utils/secret-alias-services.ts +0 -58
- package/src/utils/serialize-inspector-state.ts +0 -742
- package/src/utils/serialize-mcp-json.ts +0 -150
- package/src/utils/serialize-middleware-groups-meta.ts +0 -36
- package/src/utils/serialize-openapi-json.ts +0 -277
- package/src/utils/serialize-permissions-groups-meta.ts +0 -7
- package/src/utils/single-declaration.ts +0 -57
- package/src/utils/type-utils.ts +0 -145
- package/src/utils/validate-auth-sessionless.ts +0 -30
- package/src/utils/validate-exposed-functions-gated.test.ts +0 -230
- package/src/utils/validate-exposed-functions-gated.ts +0 -103
- package/src/utils/validate-tags-resolve-to-middleware.test.ts +0 -108
- package/src/utils/validate-tags-resolve-to-middleware.ts +0 -48
- package/src/utils/workflow/derive-workflow-plan.test.ts +0 -178
- package/src/utils/workflow/derive-workflow-plan.ts +0 -117
- package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +0 -1465
- package/src/utils/workflow/dsl/deserialize-fanout-body.test.ts +0 -71
- package/src/utils/workflow/dsl/deserialize-fanout-fidelity.test.ts +0 -99
- package/src/utils/workflow/dsl/deserialize-graph-next.test.ts +0 -161
- package/src/utils/workflow/dsl/deserialize-roundtrip-bindings.test.ts +0 -121
- package/src/utils/workflow/dsl/deserialize-roundtrip-values.test.ts +0 -116
- package/src/utils/workflow/dsl/deserialize-roundtrip.test.ts +0 -145
- package/src/utils/workflow/dsl/extract-approval-policy.test.ts +0 -71
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +0 -2254
- package/src/utils/workflow/dsl/index.ts +0 -11
- package/src/utils/workflow/dsl/patterns.ts +0 -440
- package/src/utils/workflow/dsl/validation.ts +0 -203
- package/src/utils/workflow/graph/convert-dsl-to-graph-skip.test.ts +0 -35
- package/src/utils/workflow/graph/convert-dsl-to-graph.ts +0 -543
- package/src/utils/workflow/graph/fanout-node-identity.test.ts +0 -105
- package/src/utils/workflow/graph/finalize-workflow-wires.ts +0 -310
- package/src/utils/workflow/graph/finalize-workflows.test.ts +0 -50
- package/src/utils/workflow/graph/finalize-workflows.ts +0 -130
- package/src/utils/workflow/graph/index.ts +0 -28
- package/src/utils/workflow/graph/serialize-workflow-graph.ts +0 -240
- package/src/utils/workflow/graph/workflow-graph.types.ts +0 -281
- package/src/visit.ts +0 -181
- package/tsconfig.json +0 -19
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -1,879 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript'
|
|
2
|
-
import type {
|
|
3
|
-
AddWiring,
|
|
4
|
-
InspectorState,
|
|
5
|
-
MiddlewareGroupMeta,
|
|
6
|
-
} from '../types.js'
|
|
7
|
-
import {
|
|
8
|
-
extractFunctionName,
|
|
9
|
-
isNamedExport,
|
|
10
|
-
makeContextBasedId,
|
|
11
|
-
} from '../utils/extract-function-name.js'
|
|
12
|
-
import {
|
|
13
|
-
extractServicesFromFunction,
|
|
14
|
-
extractUsedWires,
|
|
15
|
-
} from '../utils/extract-services.js'
|
|
16
|
-
import { extractMiddlewareRefs } from '../utils/middleware.js'
|
|
17
|
-
import { getPropertyValue } from '../utils/get-property-value.js'
|
|
18
|
-
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Record a middleware group, keeping any registration already stored under the
|
|
22
|
-
* same pattern or tag.
|
|
23
|
-
*
|
|
24
|
-
* Several files may add middleware for one pattern — an app's own `'*'` group
|
|
25
|
-
* alongside the generated better-auth session bridge, say — and the runtime
|
|
26
|
-
* composes them. A plain `set` kept only the last, and codegen emits imports
|
|
27
|
-
* from what is stored, so the other file was never imported and its middleware
|
|
28
|
-
* silently stopped running. Merging is the only shape that cannot lose a gate;
|
|
29
|
-
* the first registration stays primary so single-registration groups serialize
|
|
30
|
-
* exactly as before.
|
|
31
|
-
*/
|
|
32
|
-
function recordMiddlewareGroup(
|
|
33
|
-
groups: Map<string, MiddlewareGroupMeta>,
|
|
34
|
-
key: string,
|
|
35
|
-
group: MiddlewareGroupMeta
|
|
36
|
-
): void {
|
|
37
|
-
const existing = groups.get(key)
|
|
38
|
-
if (!existing) {
|
|
39
|
-
groups.set(key, group)
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// The same call seen twice — the inspector may revisit a file — is not a
|
|
44
|
-
// second registration, and appending it would emit a duplicate import.
|
|
45
|
-
const alreadyRecorded = [
|
|
46
|
-
existing,
|
|
47
|
-
...(existing.additionalRegistrations ?? []),
|
|
48
|
-
]
|
|
49
|
-
if (
|
|
50
|
-
alreadyRecorded.some(
|
|
51
|
-
(r) => r.sourceFile === group.sourceFile && r.position === group.position
|
|
52
|
-
)
|
|
53
|
-
) {
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
existing.additionalRegistrations = [
|
|
58
|
-
...(existing.additionalRegistrations ?? []),
|
|
59
|
-
{
|
|
60
|
-
exportName: group.exportName,
|
|
61
|
-
sourceFile: group.sourceFile,
|
|
62
|
-
position: group.position,
|
|
63
|
-
isFactory: group.isFactory,
|
|
64
|
-
},
|
|
65
|
-
]
|
|
66
|
-
existing.count += group.count
|
|
67
|
-
existing.instanceIds = [...existing.instanceIds, ...group.instanceIds]
|
|
68
|
-
existing.services = {
|
|
69
|
-
optimized: false,
|
|
70
|
-
services: Array.from(
|
|
71
|
-
new Set([...existing.services.services, ...group.services.services])
|
|
72
|
-
),
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function renameTempDefinitions(
|
|
77
|
-
state: InspectorState,
|
|
78
|
-
definitionIds: string[],
|
|
79
|
-
groupType: string,
|
|
80
|
-
groupKey: string,
|
|
81
|
-
storeKey: 'middleware' | 'channelMiddleware' = 'middleware'
|
|
82
|
-
): void {
|
|
83
|
-
const tempIndices = definitionIds
|
|
84
|
-
.map((name, i) => (name.startsWith('__temp_') ? i : -1))
|
|
85
|
-
.filter((i) => i >= 0)
|
|
86
|
-
|
|
87
|
-
for (const idx of tempIndices) {
|
|
88
|
-
const oldId = definitionIds[idx]
|
|
89
|
-
const newId =
|
|
90
|
-
tempIndices.length === 1
|
|
91
|
-
? makeContextBasedId(groupType, groupKey)
|
|
92
|
-
: makeContextBasedId(groupType, groupKey, String(idx))
|
|
93
|
-
const existing = state[storeKey].definitions[oldId]
|
|
94
|
-
if (existing) {
|
|
95
|
-
delete state[storeKey].definitions[oldId]
|
|
96
|
-
state[storeKey].definitions[newId] = existing
|
|
97
|
-
}
|
|
98
|
-
definitionIds[idx] = newId
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export const addMiddleware: AddWiring = (logger, node, checker, state) => {
|
|
103
|
-
if (!ts.isCallExpression(node)) return
|
|
104
|
-
|
|
105
|
-
const { expression, arguments: args } = node
|
|
106
|
-
|
|
107
|
-
if (!ts.isIdentifier(expression)) {
|
|
108
|
-
return
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (expression.text === 'pikkuMiddleware') {
|
|
112
|
-
const arg = args[0]
|
|
113
|
-
if (!arg) return
|
|
114
|
-
|
|
115
|
-
let actualHandler: ts.ArrowFunction | ts.FunctionExpression
|
|
116
|
-
let name: string | undefined
|
|
117
|
-
let description: string | undefined
|
|
118
|
-
|
|
119
|
-
if (ts.isObjectLiteralExpression(arg)) {
|
|
120
|
-
const nameValue = getPropertyValue(arg, 'name')
|
|
121
|
-
const descValue = getPropertyValue(arg, 'description')
|
|
122
|
-
name = typeof nameValue === 'string' ? nameValue : undefined
|
|
123
|
-
description = typeof descValue === 'string' ? descValue : undefined
|
|
124
|
-
|
|
125
|
-
const fnProp = getPropertyAssignmentInitializer(
|
|
126
|
-
arg,
|
|
127
|
-
'func',
|
|
128
|
-
true,
|
|
129
|
-
checker
|
|
130
|
-
)
|
|
131
|
-
if (
|
|
132
|
-
!fnProp ||
|
|
133
|
-
(!ts.isArrowFunction(fnProp) && !ts.isFunctionExpression(fnProp))
|
|
134
|
-
) {
|
|
135
|
-
logger.error(
|
|
136
|
-
`• pikkuMiddleware object missing required 'func' property.`
|
|
137
|
-
)
|
|
138
|
-
return
|
|
139
|
-
}
|
|
140
|
-
actualHandler = fnProp
|
|
141
|
-
} else if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
|
|
142
|
-
actualHandler = arg
|
|
143
|
-
} else {
|
|
144
|
-
logger.error(`• Handler for pikkuMiddleware is not a function.`)
|
|
145
|
-
return
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const services = extractServicesFromFunction(actualHandler)
|
|
149
|
-
const wires = extractUsedWires(actualHandler, 1)
|
|
150
|
-
let { pikkuFuncId, exportedName } = extractFunctionName(
|
|
151
|
-
node,
|
|
152
|
-
checker,
|
|
153
|
-
state.rootDir
|
|
154
|
-
)
|
|
155
|
-
if (pikkuFuncId.startsWith('__temp_')) {
|
|
156
|
-
if (
|
|
157
|
-
ts.isVariableDeclaration(node.parent) &&
|
|
158
|
-
ts.isIdentifier(node.parent.name)
|
|
159
|
-
) {
|
|
160
|
-
pikkuFuncId = node.parent.name.text
|
|
161
|
-
} else if (
|
|
162
|
-
ts.isPropertyAssignment(node.parent) &&
|
|
163
|
-
ts.isIdentifier(node.parent.name)
|
|
164
|
-
) {
|
|
165
|
-
pikkuFuncId = node.parent.name.text
|
|
166
|
-
} else {
|
|
167
|
-
logger.error(
|
|
168
|
-
`• pikkuMiddleware() must be assigned to a variable or object property. ` +
|
|
169
|
-
`Extract it to a const: const myMiddleware = pikkuMiddleware(...)`
|
|
170
|
-
)
|
|
171
|
-
return
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
state.middleware.definitions[pikkuFuncId] = {
|
|
175
|
-
services,
|
|
176
|
-
wires: wires.wires.length > 0 || !wires.optimized ? wires : undefined,
|
|
177
|
-
sourceFile: node.getSourceFile().fileName,
|
|
178
|
-
position: node.getStart(),
|
|
179
|
-
exportedName,
|
|
180
|
-
name,
|
|
181
|
-
description,
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
logger.debug(
|
|
185
|
-
`• Found middleware with services: ${services.services.join(', ')}${name ? ` (name: ${name})` : ''}${description ? ` (description: ${description})` : ''}`
|
|
186
|
-
)
|
|
187
|
-
return
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (expression.text === 'pikkuMiddlewareFactory') {
|
|
191
|
-
const factoryNode = args[0]
|
|
192
|
-
if (!factoryNode) return
|
|
193
|
-
|
|
194
|
-
if (
|
|
195
|
-
!ts.isArrowFunction(factoryNode) &&
|
|
196
|
-
!ts.isFunctionExpression(factoryNode)
|
|
197
|
-
) {
|
|
198
|
-
logger.error(`• Handler for pikkuMiddlewareFactory is not a function.`)
|
|
199
|
-
return
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
let services = { optimized: false, services: [] as string[] }
|
|
203
|
-
let wires: ReturnType<typeof extractUsedWires> = {
|
|
204
|
-
optimized: true,
|
|
205
|
-
wires: [],
|
|
206
|
-
}
|
|
207
|
-
let name: string | undefined
|
|
208
|
-
let description: string | undefined
|
|
209
|
-
|
|
210
|
-
const findPikkuMiddlewareCall = (
|
|
211
|
-
node: ts.Node
|
|
212
|
-
): ts.CallExpression | undefined => {
|
|
213
|
-
if (ts.isCallExpression(node)) {
|
|
214
|
-
const expr = node.expression
|
|
215
|
-
if (ts.isIdentifier(expr) && expr.text === 'pikkuMiddleware') {
|
|
216
|
-
return node
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return ts.forEachChild(node, findPikkuMiddlewareCall)
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const pikkuMiddlewareCall = findPikkuMiddlewareCall(factoryNode)
|
|
223
|
-
if (pikkuMiddlewareCall && pikkuMiddlewareCall.arguments[0]) {
|
|
224
|
-
const middlewareArg = pikkuMiddlewareCall.arguments[0]
|
|
225
|
-
if (ts.isObjectLiteralExpression(middlewareArg)) {
|
|
226
|
-
const nameValue = getPropertyValue(middlewareArg, 'name')
|
|
227
|
-
const descValue = getPropertyValue(middlewareArg, 'description')
|
|
228
|
-
name = typeof nameValue === 'string' ? nameValue : undefined
|
|
229
|
-
description = typeof descValue === 'string' ? descValue : undefined
|
|
230
|
-
|
|
231
|
-
const fnProp = getPropertyAssignmentInitializer(
|
|
232
|
-
middlewareArg,
|
|
233
|
-
'func',
|
|
234
|
-
true,
|
|
235
|
-
checker
|
|
236
|
-
)
|
|
237
|
-
if (
|
|
238
|
-
fnProp &&
|
|
239
|
-
(ts.isArrowFunction(fnProp) || ts.isFunctionExpression(fnProp))
|
|
240
|
-
) {
|
|
241
|
-
services = extractServicesFromFunction(fnProp)
|
|
242
|
-
wires = extractUsedWires(fnProp, 1)
|
|
243
|
-
}
|
|
244
|
-
} else if (
|
|
245
|
-
ts.isArrowFunction(middlewareArg) ||
|
|
246
|
-
ts.isFunctionExpression(middlewareArg)
|
|
247
|
-
) {
|
|
248
|
-
services = extractServicesFromFunction(middlewareArg)
|
|
249
|
-
wires = extractUsedWires(middlewareArg, 1)
|
|
250
|
-
}
|
|
251
|
-
} else {
|
|
252
|
-
if (
|
|
253
|
-
ts.isArrowFunction(factoryNode) ||
|
|
254
|
-
ts.isFunctionExpression(factoryNode)
|
|
255
|
-
) {
|
|
256
|
-
const factoryBody = factoryNode.body
|
|
257
|
-
if (
|
|
258
|
-
ts.isArrowFunction(factoryBody) ||
|
|
259
|
-
ts.isFunctionExpression(factoryBody)
|
|
260
|
-
) {
|
|
261
|
-
services = extractServicesFromFunction(factoryBody)
|
|
262
|
-
wires = extractUsedWires(factoryBody, 1)
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
let { pikkuFuncId, exportedName } = extractFunctionName(
|
|
268
|
-
node,
|
|
269
|
-
checker,
|
|
270
|
-
state.rootDir
|
|
271
|
-
)
|
|
272
|
-
if (pikkuFuncId.startsWith('__temp_')) {
|
|
273
|
-
if (
|
|
274
|
-
ts.isVariableDeclaration(node.parent) &&
|
|
275
|
-
ts.isIdentifier(node.parent.name)
|
|
276
|
-
) {
|
|
277
|
-
pikkuFuncId = node.parent.name.text
|
|
278
|
-
} else if (
|
|
279
|
-
ts.isPropertyAssignment(node.parent) &&
|
|
280
|
-
ts.isIdentifier(node.parent.name)
|
|
281
|
-
) {
|
|
282
|
-
pikkuFuncId = node.parent.name.text
|
|
283
|
-
} else {
|
|
284
|
-
logger.error(
|
|
285
|
-
`• pikkuMiddlewareFactory() must be assigned to a variable or object property. ` +
|
|
286
|
-
`Extract it to a const: const myMiddleware = pikkuMiddlewareFactory(...)`
|
|
287
|
-
)
|
|
288
|
-
return
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
state.middleware.definitions[pikkuFuncId] = {
|
|
292
|
-
services,
|
|
293
|
-
wires: wires.wires.length > 0 || !wires.optimized ? wires : undefined,
|
|
294
|
-
sourceFile: node.getSourceFile().fileName,
|
|
295
|
-
position: node.getStart(),
|
|
296
|
-
exportedName,
|
|
297
|
-
factory: true,
|
|
298
|
-
name,
|
|
299
|
-
description,
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
logger.debug(
|
|
303
|
-
`• Found middleware factory with services: ${services.services.join(', ')}${name ? ` (name: ${name})` : ''}${description ? ` (description: ${description})` : ''}`
|
|
304
|
-
)
|
|
305
|
-
return
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (expression.text === 'addTagMiddleware') {
|
|
309
|
-
const tagArg = args[0]
|
|
310
|
-
const middlewareArrayArg = args[1]
|
|
311
|
-
|
|
312
|
-
if (!tagArg || !middlewareArrayArg) return
|
|
313
|
-
|
|
314
|
-
let tag: string | undefined
|
|
315
|
-
if (ts.isStringLiteral(tagArg)) {
|
|
316
|
-
tag = tagArg.text
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
if (!tag) {
|
|
320
|
-
logger.warn(`• addTagMiddleware call without valid tag string`)
|
|
321
|
-
return
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (!ts.isArrayLiteralExpression(middlewareArrayArg)) {
|
|
325
|
-
logger.error(
|
|
326
|
-
`• addTagMiddleware('${tag}', ...) must have a literal array as second argument`
|
|
327
|
-
)
|
|
328
|
-
return
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const refs = extractMiddlewareRefs(
|
|
332
|
-
middlewareArrayArg,
|
|
333
|
-
checker,
|
|
334
|
-
state.rootDir
|
|
335
|
-
)
|
|
336
|
-
|
|
337
|
-
const definitionIds = refs.map((r) => r.definitionId)
|
|
338
|
-
if (definitionIds.length > 0) {
|
|
339
|
-
renameTempDefinitions(state, definitionIds, 'tag', tag)
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const sourceFile = node.getSourceFile().fileName
|
|
343
|
-
const instanceIds: string[] = []
|
|
344
|
-
for (let i = 0; i < refs.length; i++) {
|
|
345
|
-
const instanceId = makeContextBasedId('tag', tag, String(i))
|
|
346
|
-
state.middleware.instances[instanceId] = {
|
|
347
|
-
definitionId: definitionIds[i],
|
|
348
|
-
sourceFile,
|
|
349
|
-
position: node.getStart(),
|
|
350
|
-
isFactoryCall: refs[i].isFactoryCall,
|
|
351
|
-
}
|
|
352
|
-
instanceIds.push(instanceId)
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
const allServices = new Set<string>()
|
|
356
|
-
for (const defId of definitionIds) {
|
|
357
|
-
const def = state.middleware.definitions[defId]
|
|
358
|
-
if (def?.services) {
|
|
359
|
-
for (const service of def.services.services) {
|
|
360
|
-
allServices.add(service)
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
let isFactory = false
|
|
366
|
-
let exportedName: string | null = null
|
|
367
|
-
let parent = node.parent
|
|
368
|
-
|
|
369
|
-
if (parent && ts.isArrowFunction(parent)) {
|
|
370
|
-
if (parent.parameters.length === 0) {
|
|
371
|
-
isFactory = true
|
|
372
|
-
|
|
373
|
-
const arrowParent = parent.parent
|
|
374
|
-
if (arrowParent && ts.isVariableDeclaration(arrowParent)) {
|
|
375
|
-
if (ts.isIdentifier(arrowParent.name)) {
|
|
376
|
-
if (isNamedExport(arrowParent)) {
|
|
377
|
-
exportedName = arrowParent.name.text
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (!isFactory) {
|
|
385
|
-
const extracted = extractFunctionName(node, checker, state.rootDir)
|
|
386
|
-
exportedName = extracted.exportedName
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
if (!isFactory && exportedName) {
|
|
390
|
-
logger.warn(
|
|
391
|
-
`• Middleware group '${exportedName}' for tag '${tag}' is not wrapped in a factory function. ` +
|
|
392
|
-
`For tree-shaking, use: export const ${exportedName} = () => addTagMiddleware('${tag}', [...])`
|
|
393
|
-
)
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
recordMiddlewareGroup(state.middleware.tagMiddleware, tag, {
|
|
397
|
-
exportName: exportedName,
|
|
398
|
-
sourceFile,
|
|
399
|
-
position: node.getStart(),
|
|
400
|
-
services: {
|
|
401
|
-
optimized: false,
|
|
402
|
-
services: Array.from(allServices),
|
|
403
|
-
},
|
|
404
|
-
count: refs.length,
|
|
405
|
-
instanceIds,
|
|
406
|
-
isFactory,
|
|
407
|
-
})
|
|
408
|
-
|
|
409
|
-
logger.debug(
|
|
410
|
-
`• Found tag middleware group: ${tag} -> [${instanceIds.join(', ')}] (${isFactory ? 'factory' : 'direct'})`
|
|
411
|
-
)
|
|
412
|
-
return
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
if (expression.text === 'addGlobalMiddleware') {
|
|
416
|
-
const middlewareArrayArg = args[0]
|
|
417
|
-
if (
|
|
418
|
-
!middlewareArrayArg ||
|
|
419
|
-
!ts.isArrayLiteralExpression(middlewareArrayArg)
|
|
420
|
-
) {
|
|
421
|
-
logger.error(
|
|
422
|
-
`• addGlobalMiddleware(...) must have a literal array as its only argument`
|
|
423
|
-
)
|
|
424
|
-
return
|
|
425
|
-
}
|
|
426
|
-
const refs = extractMiddlewareRefs(
|
|
427
|
-
middlewareArrayArg,
|
|
428
|
-
checker,
|
|
429
|
-
state.rootDir
|
|
430
|
-
)
|
|
431
|
-
const definitionIds = refs.map((r) => r.definitionId)
|
|
432
|
-
if (definitionIds.length > 0) {
|
|
433
|
-
renameTempDefinitions(state, definitionIds, 'global', 'middleware')
|
|
434
|
-
}
|
|
435
|
-
const sourceFile = node.getSourceFile().fileName
|
|
436
|
-
for (let i = 0; i < refs.length; i++) {
|
|
437
|
-
const instanceId = makeContextBasedId('global', 'middleware', String(i))
|
|
438
|
-
state.middleware.instances[instanceId] = {
|
|
439
|
-
definitionId: definitionIds[i],
|
|
440
|
-
sourceFile,
|
|
441
|
-
position: node.getStart(),
|
|
442
|
-
isFactoryCall: refs[i].isFactoryCall,
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
// Without this, bootstrap codegen's "import every file with a wire-call"
|
|
446
|
-
// pass skips middleware-only files and the registration never runs.
|
|
447
|
-
state.http.files.add(sourceFile)
|
|
448
|
-
logger.debug(`• Found global middleware group with ${refs.length} entries`)
|
|
449
|
-
return
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
if (expression.text === 'addHTTPMiddleware') {
|
|
453
|
-
const patternArg = args[0]
|
|
454
|
-
const middlewareArrayArg = args[1]
|
|
455
|
-
|
|
456
|
-
if (!patternArg || !middlewareArrayArg) return
|
|
457
|
-
|
|
458
|
-
let pattern: string | undefined
|
|
459
|
-
if (ts.isStringLiteral(patternArg)) {
|
|
460
|
-
pattern = patternArg.text
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (!pattern) {
|
|
464
|
-
logger.warn(`• addHTTPMiddleware call without valid pattern string`)
|
|
465
|
-
return
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
if (!ts.isArrayLiteralExpression(middlewareArrayArg)) {
|
|
469
|
-
logger.error(
|
|
470
|
-
`• addHTTPMiddleware('${pattern}', ...) must have a literal array as second argument`
|
|
471
|
-
)
|
|
472
|
-
return
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
const refs = extractMiddlewareRefs(
|
|
476
|
-
middlewareArrayArg,
|
|
477
|
-
checker,
|
|
478
|
-
state.rootDir
|
|
479
|
-
)
|
|
480
|
-
|
|
481
|
-
const definitionIds = refs.map((r) => r.definitionId)
|
|
482
|
-
if (definitionIds.length > 0) {
|
|
483
|
-
renameTempDefinitions(state, definitionIds, 'http', pattern)
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
const sourceFile = node.getSourceFile().fileName
|
|
487
|
-
const instanceIds: string[] = []
|
|
488
|
-
for (let i = 0; i < refs.length; i++) {
|
|
489
|
-
const instanceId = makeContextBasedId('http', pattern, String(i))
|
|
490
|
-
state.middleware.instances[instanceId] = {
|
|
491
|
-
definitionId: definitionIds[i],
|
|
492
|
-
sourceFile,
|
|
493
|
-
position: node.getStart(),
|
|
494
|
-
isFactoryCall: refs[i].isFactoryCall,
|
|
495
|
-
}
|
|
496
|
-
instanceIds.push(instanceId)
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
const allServices = new Set<string>()
|
|
500
|
-
for (const defId of definitionIds) {
|
|
501
|
-
const def = state.middleware.definitions[defId]
|
|
502
|
-
if (def?.services) {
|
|
503
|
-
for (const service of def.services.services) {
|
|
504
|
-
allServices.add(service)
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
let isFactory = false
|
|
510
|
-
let exportedName: string | null = null
|
|
511
|
-
let parent = node.parent
|
|
512
|
-
|
|
513
|
-
if (parent && ts.isArrowFunction(parent)) {
|
|
514
|
-
if (parent.parameters.length === 0) {
|
|
515
|
-
isFactory = true
|
|
516
|
-
|
|
517
|
-
const arrowParent = parent.parent
|
|
518
|
-
if (arrowParent && ts.isVariableDeclaration(arrowParent)) {
|
|
519
|
-
if (ts.isIdentifier(arrowParent.name)) {
|
|
520
|
-
if (isNamedExport(arrowParent)) {
|
|
521
|
-
exportedName = arrowParent.name.text
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
if (!isFactory) {
|
|
529
|
-
const extracted = extractFunctionName(node, checker, state.rootDir)
|
|
530
|
-
exportedName = extracted.exportedName
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
if (!isFactory && exportedName) {
|
|
534
|
-
logger.warn(
|
|
535
|
-
`• HTTP middleware group '${exportedName}' for pattern '${pattern}' is not wrapped in a factory function. ` +
|
|
536
|
-
`For tree-shaking, use: export const ${exportedName} = () => addHTTPMiddleware('${pattern}', [...])`
|
|
537
|
-
)
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
recordMiddlewareGroup(state.http.routeMiddleware, pattern, {
|
|
541
|
-
exportName: exportedName,
|
|
542
|
-
sourceFile,
|
|
543
|
-
position: node.getStart(),
|
|
544
|
-
services: {
|
|
545
|
-
optimized: false,
|
|
546
|
-
services: Array.from(allServices),
|
|
547
|
-
},
|
|
548
|
-
count: refs.length,
|
|
549
|
-
instanceIds,
|
|
550
|
-
isFactory,
|
|
551
|
-
})
|
|
552
|
-
state.http.files.add(sourceFile)
|
|
553
|
-
|
|
554
|
-
logger.debug(
|
|
555
|
-
`• Found HTTP route middleware group: ${pattern} -> [${instanceIds.join(', ')}] (${isFactory ? 'factory' : 'direct'})`
|
|
556
|
-
)
|
|
557
|
-
return
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
if (expression.text === 'pikkuChannelMiddleware') {
|
|
561
|
-
const arg = args[0]
|
|
562
|
-
if (!arg) return
|
|
563
|
-
|
|
564
|
-
let actualHandler: ts.ArrowFunction | ts.FunctionExpression
|
|
565
|
-
|
|
566
|
-
if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
|
|
567
|
-
actualHandler = arg
|
|
568
|
-
} else {
|
|
569
|
-
logger.error(`• Handler for pikkuChannelMiddleware is not a function.`)
|
|
570
|
-
return
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
const services = extractServicesFromFunction(actualHandler)
|
|
574
|
-
let { pikkuFuncId, exportedName } = extractFunctionName(
|
|
575
|
-
node,
|
|
576
|
-
checker,
|
|
577
|
-
state.rootDir
|
|
578
|
-
)
|
|
579
|
-
if (pikkuFuncId.startsWith('__temp_')) {
|
|
580
|
-
if (
|
|
581
|
-
ts.isVariableDeclaration(node.parent) &&
|
|
582
|
-
ts.isIdentifier(node.parent.name)
|
|
583
|
-
) {
|
|
584
|
-
pikkuFuncId = node.parent.name.text
|
|
585
|
-
} else if (
|
|
586
|
-
ts.isPropertyAssignment(node.parent) &&
|
|
587
|
-
ts.isIdentifier(node.parent.name)
|
|
588
|
-
) {
|
|
589
|
-
pikkuFuncId = node.parent.name.text
|
|
590
|
-
} else {
|
|
591
|
-
logger.error(
|
|
592
|
-
`• pikkuChannelMiddleware() must be assigned to a variable or object property. ` +
|
|
593
|
-
`Extract it to a const: const myMiddleware = pikkuChannelMiddleware(...)`
|
|
594
|
-
)
|
|
595
|
-
return
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
state.channelMiddleware.definitions[pikkuFuncId] = {
|
|
599
|
-
services,
|
|
600
|
-
sourceFile: node.getSourceFile().fileName,
|
|
601
|
-
position: node.getStart(),
|
|
602
|
-
exportedName,
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
logger.debug(
|
|
606
|
-
`• Found channel middleware with services: ${services.services.join(', ')}`
|
|
607
|
-
)
|
|
608
|
-
return
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
if (expression.text === 'pikkuChannelMiddlewareFactory') {
|
|
612
|
-
const factoryNode = args[0]
|
|
613
|
-
if (!factoryNode) return
|
|
614
|
-
|
|
615
|
-
if (
|
|
616
|
-
!ts.isArrowFunction(factoryNode) &&
|
|
617
|
-
!ts.isFunctionExpression(factoryNode)
|
|
618
|
-
) {
|
|
619
|
-
logger.error(
|
|
620
|
-
`• Handler for pikkuChannelMiddlewareFactory is not a function.`
|
|
621
|
-
)
|
|
622
|
-
return
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
let services = { optimized: false, services: [] as string[] }
|
|
626
|
-
|
|
627
|
-
const findPikkuChannelMiddlewareCall = (
|
|
628
|
-
n: ts.Node
|
|
629
|
-
): ts.CallExpression | undefined => {
|
|
630
|
-
if (ts.isCallExpression(n)) {
|
|
631
|
-
const expr = n.expression
|
|
632
|
-
if (ts.isIdentifier(expr) && expr.text === 'pikkuChannelMiddleware') {
|
|
633
|
-
return n
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
return ts.forEachChild(n, findPikkuChannelMiddlewareCall)
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
const channelMiddlewareCall = findPikkuChannelMiddlewareCall(factoryNode)
|
|
640
|
-
if (channelMiddlewareCall && channelMiddlewareCall.arguments[0]) {
|
|
641
|
-
const middlewareHandler = channelMiddlewareCall.arguments[0]
|
|
642
|
-
if (
|
|
643
|
-
ts.isArrowFunction(middlewareHandler) ||
|
|
644
|
-
ts.isFunctionExpression(middlewareHandler)
|
|
645
|
-
) {
|
|
646
|
-
services = extractServicesFromFunction(middlewareHandler)
|
|
647
|
-
}
|
|
648
|
-
} else {
|
|
649
|
-
if (
|
|
650
|
-
ts.isArrowFunction(factoryNode) ||
|
|
651
|
-
ts.isFunctionExpression(factoryNode)
|
|
652
|
-
) {
|
|
653
|
-
const factoryBody = factoryNode.body
|
|
654
|
-
if (
|
|
655
|
-
ts.isArrowFunction(factoryBody) ||
|
|
656
|
-
ts.isFunctionExpression(factoryBody)
|
|
657
|
-
) {
|
|
658
|
-
services = extractServicesFromFunction(factoryBody)
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
let { pikkuFuncId, exportedName } = extractFunctionName(
|
|
664
|
-
node,
|
|
665
|
-
checker,
|
|
666
|
-
state.rootDir
|
|
667
|
-
)
|
|
668
|
-
if (pikkuFuncId.startsWith('__temp_')) {
|
|
669
|
-
if (
|
|
670
|
-
ts.isVariableDeclaration(node.parent) &&
|
|
671
|
-
ts.isIdentifier(node.parent.name)
|
|
672
|
-
) {
|
|
673
|
-
pikkuFuncId = node.parent.name.text
|
|
674
|
-
} else if (
|
|
675
|
-
ts.isPropertyAssignment(node.parent) &&
|
|
676
|
-
ts.isIdentifier(node.parent.name)
|
|
677
|
-
) {
|
|
678
|
-
pikkuFuncId = node.parent.name.text
|
|
679
|
-
} else {
|
|
680
|
-
logger.error(
|
|
681
|
-
`• pikkuChannelMiddlewareFactory() must be assigned to a variable or object property. ` +
|
|
682
|
-
`Extract it to a const: const myMiddleware = pikkuChannelMiddlewareFactory(...)`
|
|
683
|
-
)
|
|
684
|
-
return
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
state.channelMiddleware.definitions[pikkuFuncId] = {
|
|
688
|
-
services,
|
|
689
|
-
sourceFile: node.getSourceFile().fileName,
|
|
690
|
-
position: node.getStart(),
|
|
691
|
-
exportedName,
|
|
692
|
-
factory: true,
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
logger.debug(
|
|
696
|
-
`• Found channel middleware factory with services: ${services.services.join(', ')}`
|
|
697
|
-
)
|
|
698
|
-
return
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
if (expression.text === 'pikkuAgentMiddleware') {
|
|
702
|
-
const arg = args[0]
|
|
703
|
-
if (!arg) return
|
|
704
|
-
|
|
705
|
-
if (!ts.isObjectLiteralExpression(arg)) {
|
|
706
|
-
logger.error(
|
|
707
|
-
`• pikkuAgentMiddleware() requires an object literal argument.`
|
|
708
|
-
)
|
|
709
|
-
return
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
const allServices = new Set<string>()
|
|
713
|
-
for (const prop of arg.properties) {
|
|
714
|
-
if (
|
|
715
|
-
ts.isPropertyAssignment(prop) &&
|
|
716
|
-
(ts.isArrowFunction(prop.initializer) ||
|
|
717
|
-
ts.isFunctionExpression(prop.initializer))
|
|
718
|
-
) {
|
|
719
|
-
const hookServices = extractServicesFromFunction(prop.initializer)
|
|
720
|
-
for (const s of hookServices.services) {
|
|
721
|
-
allServices.add(s)
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
const services = {
|
|
727
|
-
optimized: allServices.size > 0,
|
|
728
|
-
services: Array.from(allServices),
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
let { pikkuFuncId, exportedName } = extractFunctionName(
|
|
732
|
-
node,
|
|
733
|
-
checker,
|
|
734
|
-
state.rootDir
|
|
735
|
-
)
|
|
736
|
-
if (pikkuFuncId.startsWith('__temp_')) {
|
|
737
|
-
if (
|
|
738
|
-
ts.isVariableDeclaration(node.parent) &&
|
|
739
|
-
ts.isIdentifier(node.parent.name)
|
|
740
|
-
) {
|
|
741
|
-
pikkuFuncId = node.parent.name.text
|
|
742
|
-
} else if (
|
|
743
|
-
ts.isPropertyAssignment(node.parent) &&
|
|
744
|
-
ts.isIdentifier(node.parent.name)
|
|
745
|
-
) {
|
|
746
|
-
pikkuFuncId = node.parent.name.text
|
|
747
|
-
} else {
|
|
748
|
-
logger.error(
|
|
749
|
-
`• pikkuAgentMiddleware() must be assigned to a variable or object property. ` +
|
|
750
|
-
`Extract it to a const: const myMiddleware = pikkuAgentMiddleware(...)`
|
|
751
|
-
)
|
|
752
|
-
return
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
state.agentMiddleware.definitions[pikkuFuncId] = {
|
|
756
|
-
services,
|
|
757
|
-
sourceFile: node.getSourceFile().fileName,
|
|
758
|
-
position: node.getStart(),
|
|
759
|
-
exportedName,
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
logger.debug(
|
|
763
|
-
`• Found AI middleware with services: ${services.services.join(', ')}`
|
|
764
|
-
)
|
|
765
|
-
return
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
if (expression.text === 'addChannelMiddleware') {
|
|
769
|
-
const tagArg = args[0]
|
|
770
|
-
const middlewareArrayArg = args[1]
|
|
771
|
-
|
|
772
|
-
if (!tagArg || !middlewareArrayArg) return
|
|
773
|
-
|
|
774
|
-
let tag: string | undefined
|
|
775
|
-
if (ts.isStringLiteral(tagArg)) {
|
|
776
|
-
tag = tagArg.text
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
if (!tag) {
|
|
780
|
-
logger.warn(`• addChannelMiddleware call without valid tag string`)
|
|
781
|
-
return
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
if (!ts.isArrayLiteralExpression(middlewareArrayArg)) {
|
|
785
|
-
logger.error(
|
|
786
|
-
`• addChannelMiddleware('${tag}', ...) must have a literal array as second argument`
|
|
787
|
-
)
|
|
788
|
-
return
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
const refs = extractMiddlewareRefs(
|
|
792
|
-
middlewareArrayArg,
|
|
793
|
-
checker,
|
|
794
|
-
state.rootDir
|
|
795
|
-
)
|
|
796
|
-
|
|
797
|
-
if (refs.length === 0) {
|
|
798
|
-
logger.warn(
|
|
799
|
-
`• addChannelMiddleware('${tag}', ...) has empty middleware array`
|
|
800
|
-
)
|
|
801
|
-
return
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
const definitionIds = refs.map((r) => r.definitionId)
|
|
805
|
-
renameTempDefinitions(state, definitionIds, 'tag', tag, 'channelMiddleware')
|
|
806
|
-
|
|
807
|
-
const sourceFile = node.getSourceFile().fileName
|
|
808
|
-
const instanceIds: string[] = []
|
|
809
|
-
for (let i = 0; i < refs.length; i++) {
|
|
810
|
-
const instanceId = makeContextBasedId('tag', tag, String(i))
|
|
811
|
-
state.channelMiddleware.instances[instanceId] = {
|
|
812
|
-
definitionId: definitionIds[i],
|
|
813
|
-
sourceFile,
|
|
814
|
-
position: node.getStart(),
|
|
815
|
-
isFactoryCall: refs[i].isFactoryCall,
|
|
816
|
-
}
|
|
817
|
-
instanceIds.push(instanceId)
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
const allServices = new Set<string>()
|
|
821
|
-
for (const defId of definitionIds) {
|
|
822
|
-
const def = state.channelMiddleware.definitions[defId]
|
|
823
|
-
if (def?.services) {
|
|
824
|
-
for (const service of def.services.services) {
|
|
825
|
-
allServices.add(service)
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
let isFactory = false
|
|
831
|
-
let exportedName: string | null = null
|
|
832
|
-
let parent = node.parent
|
|
833
|
-
|
|
834
|
-
if (parent && ts.isArrowFunction(parent)) {
|
|
835
|
-
if (parent.parameters.length === 0) {
|
|
836
|
-
isFactory = true
|
|
837
|
-
|
|
838
|
-
const arrowParent = parent.parent
|
|
839
|
-
if (arrowParent && ts.isVariableDeclaration(arrowParent)) {
|
|
840
|
-
if (ts.isIdentifier(arrowParent.name)) {
|
|
841
|
-
if (isNamedExport(arrowParent)) {
|
|
842
|
-
exportedName = arrowParent.name.text
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
if (!isFactory) {
|
|
850
|
-
const extracted = extractFunctionName(node, checker, state.rootDir)
|
|
851
|
-
exportedName = extracted.exportedName
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
if (!isFactory && exportedName) {
|
|
855
|
-
logger.warn(
|
|
856
|
-
`• Channel middleware group '${exportedName}' for tag '${tag}' is not wrapped in a factory function. ` +
|
|
857
|
-
`For tree-shaking, use: export const ${exportedName} = () => addChannelMiddleware('${tag}', [...])`
|
|
858
|
-
)
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
recordMiddlewareGroup(state.channelMiddleware.tagMiddleware, tag, {
|
|
862
|
-
exportName: exportedName,
|
|
863
|
-
sourceFile,
|
|
864
|
-
position: node.getStart(),
|
|
865
|
-
services: {
|
|
866
|
-
optimized: false,
|
|
867
|
-
services: Array.from(allServices),
|
|
868
|
-
},
|
|
869
|
-
count: refs.length,
|
|
870
|
-
instanceIds,
|
|
871
|
-
isFactory,
|
|
872
|
-
})
|
|
873
|
-
|
|
874
|
-
logger.debug(
|
|
875
|
-
`• Found tag channel middleware group: ${tag} -> [${instanceIds.join(', ')}] (${isFactory ? 'factory' : 'direct'})`
|
|
876
|
-
)
|
|
877
|
-
return
|
|
878
|
-
}
|
|
879
|
-
}
|