@pikku/inspector 0.12.74 → 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 +347 -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 +23 -13
- 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 -2207
- package/src/utils/filter-inspector-state.ts +0 -1302
- 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
package/src/add/add-feature.ts
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript'
|
|
2
|
-
import { extractFunctionName } from '../utils/extract-function-name.js'
|
|
3
|
-
import { ErrorCode } from '../error-codes.js'
|
|
4
|
-
import type {
|
|
5
|
-
AddWiring,
|
|
6
|
-
InspectorFeature,
|
|
7
|
-
InspectorFeatureEntry,
|
|
8
|
-
} from '../types.js'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Reads a fully literal expression into a plain value.
|
|
12
|
-
*
|
|
13
|
-
* Used for a `{ scenario, data }` entry's `data`, which is gherkin's
|
|
14
|
-
* `Examples:` row. Anything not literal yields `undefined` — a computed row
|
|
15
|
-
* belongs to the runtime-resolved portion, not to the extracted meta.
|
|
16
|
-
*/
|
|
17
|
-
const literalValue = (node: ts.Expression): unknown => {
|
|
18
|
-
if (ts.isStringLiteralLike(node)) {
|
|
19
|
-
return node.text
|
|
20
|
-
}
|
|
21
|
-
if (ts.isNumericLiteral(node)) {
|
|
22
|
-
return Number(node.text)
|
|
23
|
-
}
|
|
24
|
-
if (node.kind === ts.SyntaxKind.TrueKeyword) {
|
|
25
|
-
return true
|
|
26
|
-
}
|
|
27
|
-
if (node.kind === ts.SyntaxKind.FalseKeyword) {
|
|
28
|
-
return false
|
|
29
|
-
}
|
|
30
|
-
if (node.kind === ts.SyntaxKind.NullKeyword) {
|
|
31
|
-
return null
|
|
32
|
-
}
|
|
33
|
-
if (
|
|
34
|
-
ts.isPrefixUnaryExpression(node) &&
|
|
35
|
-
node.operator === ts.SyntaxKind.MinusToken &&
|
|
36
|
-
ts.isNumericLiteral(node.operand)
|
|
37
|
-
) {
|
|
38
|
-
return -Number(node.operand.text)
|
|
39
|
-
}
|
|
40
|
-
if (ts.isArrayLiteralExpression(node)) {
|
|
41
|
-
const values: unknown[] = []
|
|
42
|
-
for (const element of node.elements) {
|
|
43
|
-
const value = literalValue(element)
|
|
44
|
-
if (value === undefined) {
|
|
45
|
-
return undefined
|
|
46
|
-
}
|
|
47
|
-
values.push(value)
|
|
48
|
-
}
|
|
49
|
-
return values
|
|
50
|
-
}
|
|
51
|
-
if (ts.isObjectLiteralExpression(node)) {
|
|
52
|
-
const value: Record<string, unknown> = {}
|
|
53
|
-
for (const property of node.properties) {
|
|
54
|
-
if (!ts.isPropertyAssignment(property)) {
|
|
55
|
-
return undefined
|
|
56
|
-
}
|
|
57
|
-
const key =
|
|
58
|
-
ts.isIdentifier(property.name) || ts.isStringLiteralLike(property.name)
|
|
59
|
-
? property.name.text
|
|
60
|
-
: undefined
|
|
61
|
-
if (key === undefined) {
|
|
62
|
-
return undefined
|
|
63
|
-
}
|
|
64
|
-
const propertyValue = literalValue(property.initializer)
|
|
65
|
-
if (propertyValue === undefined) {
|
|
66
|
-
return undefined
|
|
67
|
-
}
|
|
68
|
-
value[key] = propertyValue
|
|
69
|
-
}
|
|
70
|
-
return value
|
|
71
|
-
}
|
|
72
|
-
return undefined
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Resolves a scenario reference to the name it is declared under, following an
|
|
77
|
-
* import alias back to the original export so `{ x as y }` records `x`.
|
|
78
|
-
*/
|
|
79
|
-
const scenarioName = (
|
|
80
|
-
node: ts.Expression,
|
|
81
|
-
checker: ts.TypeChecker
|
|
82
|
-
): string | undefined => {
|
|
83
|
-
if (!ts.isIdentifier(node)) {
|
|
84
|
-
return undefined
|
|
85
|
-
}
|
|
86
|
-
const symbol = checker.getSymbolAtLocation(node)
|
|
87
|
-
if (!symbol) {
|
|
88
|
-
return node.text
|
|
89
|
-
}
|
|
90
|
-
const resolved =
|
|
91
|
-
symbol.flags & ts.SymbolFlags.Alias
|
|
92
|
-
? checker.getAliasedSymbol(symbol)
|
|
93
|
-
: symbol
|
|
94
|
-
return resolved.getName() || node.text
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const getProperty = (
|
|
98
|
-
config: ts.ObjectLiteralExpression,
|
|
99
|
-
name: string
|
|
100
|
-
): ts.Expression | undefined => {
|
|
101
|
-
const property = config.properties.find(
|
|
102
|
-
(p) =>
|
|
103
|
-
ts.isPropertyAssignment(p) &&
|
|
104
|
-
ts.isIdentifier(p.name) &&
|
|
105
|
-
p.name.text === name
|
|
106
|
-
)
|
|
107
|
-
return property && ts.isPropertyAssignment(property)
|
|
108
|
-
? property.initializer
|
|
109
|
-
: undefined
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const hasProperty = (
|
|
113
|
-
config: ts.ObjectLiteralExpression,
|
|
114
|
-
name: string
|
|
115
|
-
): boolean =>
|
|
116
|
-
config.properties.some(
|
|
117
|
-
(p) =>
|
|
118
|
-
(ts.isPropertyAssignment(p) ||
|
|
119
|
-
ts.isMethodDeclaration(p) ||
|
|
120
|
-
ts.isShorthandPropertyAssignment(p)) &&
|
|
121
|
-
ts.isIdentifier(p.name) &&
|
|
122
|
-
p.name.text === name
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
const stringProperty = (
|
|
126
|
-
config: ts.ObjectLiteralExpression,
|
|
127
|
-
name: string
|
|
128
|
-
): string | undefined => {
|
|
129
|
-
const value = getProperty(config, name)
|
|
130
|
-
return value && ts.isStringLiteralLike(value) ? value.text : undefined
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const stringArrayProperty = (
|
|
134
|
-
config: ts.ObjectLiteralExpression,
|
|
135
|
-
name: string
|
|
136
|
-
): string[] | undefined => {
|
|
137
|
-
const value = getProperty(config, name)
|
|
138
|
-
if (!value || !ts.isArrayLiteralExpression(value)) {
|
|
139
|
-
return undefined
|
|
140
|
-
}
|
|
141
|
-
const values = value.elements
|
|
142
|
-
.filter(ts.isStringLiteralLike)
|
|
143
|
-
.map((e) => e.text)
|
|
144
|
-
return values.length === value.elements.length ? values : undefined
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const readEntry = (
|
|
148
|
-
element: ts.Expression,
|
|
149
|
-
checker: ts.TypeChecker
|
|
150
|
-
): InspectorFeatureEntry | undefined => {
|
|
151
|
-
if (ts.isIdentifier(element)) {
|
|
152
|
-
const scenario = scenarioName(element, checker)
|
|
153
|
-
return scenario ? { scenario } : undefined
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (ts.isObjectLiteralExpression(element)) {
|
|
157
|
-
const reference = getProperty(element, 'scenario')
|
|
158
|
-
if (!reference) {
|
|
159
|
-
return undefined
|
|
160
|
-
}
|
|
161
|
-
const scenario = scenarioName(reference, checker)
|
|
162
|
-
if (!scenario) {
|
|
163
|
-
return undefined
|
|
164
|
-
}
|
|
165
|
-
const dataNode = getProperty(element, 'data')
|
|
166
|
-
if (!dataNode) {
|
|
167
|
-
return { scenario }
|
|
168
|
-
}
|
|
169
|
-
const data = literalValue(dataNode)
|
|
170
|
-
return data === undefined ? undefined : { scenario, data }
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return undefined
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Inspector for `pikkuFeature()` calls.
|
|
178
|
-
*
|
|
179
|
-
* A feature is the document structure the console renders — its name,
|
|
180
|
-
* description, tags and the order of its scenarios are what a reader sees — so
|
|
181
|
-
* everything the config states literally is extracted here.
|
|
182
|
-
*
|
|
183
|
-
* What cannot be extracted is a scenarios entry that is not literal:
|
|
184
|
-
* `...['stripe', 'google'].map((name) => ({ scenario, data: { name } }))` is
|
|
185
|
-
* ordinary TypeScript, and no AST walk can enumerate it. Those entries are
|
|
186
|
-
* counted in `unresolvedEntries` rather than dropped, and membership for them
|
|
187
|
-
* is resolved at runtime by object identity (`resolveFeatureScenarios`), where
|
|
188
|
-
* the array has actually been evaluated.
|
|
189
|
-
*
|
|
190
|
-
* The export location is recorded either way, which is what the CLI needs to
|
|
191
|
-
* emit its `addFeature(...)` wiring line.
|
|
192
|
-
*/
|
|
193
|
-
export const addFeature: AddWiring = (logger, node, checker, state) => {
|
|
194
|
-
if (!ts.isCallExpression(node)) {
|
|
195
|
-
return
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const expression = node.expression
|
|
199
|
-
if (!ts.isIdentifier(expression) || expression.text !== 'pikkuFeature') {
|
|
200
|
-
return
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const { exportedName } = extractFunctionName(node, checker, state.rootDir)
|
|
204
|
-
|
|
205
|
-
if (!exportedName) {
|
|
206
|
-
logger.critical(
|
|
207
|
-
ErrorCode.MISSING_NAME,
|
|
208
|
-
`A pikkuFeature() must be assigned to an export — the export identifier is the feature's id.`
|
|
209
|
-
)
|
|
210
|
-
return
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const feature: InspectorFeature = {
|
|
214
|
-
path: node.getSourceFile().fileName,
|
|
215
|
-
exportedName,
|
|
216
|
-
entries: [],
|
|
217
|
-
unresolvedEntries: 0,
|
|
218
|
-
hasBefore: false,
|
|
219
|
-
hasAfter: false,
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const [config] = node.arguments
|
|
223
|
-
if (config && ts.isObjectLiteralExpression(config)) {
|
|
224
|
-
const name = stringProperty(config, 'name')
|
|
225
|
-
const description = stringProperty(config, 'description')
|
|
226
|
-
const tags = stringArrayProperty(config, 'tags')
|
|
227
|
-
if (name !== undefined) {
|
|
228
|
-
feature.name = name
|
|
229
|
-
}
|
|
230
|
-
if (description !== undefined) {
|
|
231
|
-
feature.description = description
|
|
232
|
-
}
|
|
233
|
-
if (tags !== undefined) {
|
|
234
|
-
feature.tags = tags
|
|
235
|
-
}
|
|
236
|
-
feature.hasBefore = hasProperty(config, 'before')
|
|
237
|
-
feature.hasAfter = hasProperty(config, 'after')
|
|
238
|
-
|
|
239
|
-
const scenarios = getProperty(config, 'scenarios')
|
|
240
|
-
if (scenarios && ts.isArrayLiteralExpression(scenarios)) {
|
|
241
|
-
for (const element of scenarios.elements) {
|
|
242
|
-
const entry = readEntry(element, checker)
|
|
243
|
-
if (entry) {
|
|
244
|
-
feature.entries.push(entry)
|
|
245
|
-
} else {
|
|
246
|
-
feature.unresolvedEntries += 1
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
state.workflows.featureFiles.set(exportedName, feature)
|
|
253
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript'
|
|
2
|
-
import type { PathToNameAndType, InspectorState } from '../types.js'
|
|
3
|
-
|
|
4
|
-
export const addFileExtendsCoreType = (
|
|
5
|
-
node: ts.Node,
|
|
6
|
-
checker: ts.TypeChecker,
|
|
7
|
-
methods: PathToNameAndType,
|
|
8
|
-
expectedTypeName: string,
|
|
9
|
-
state?: InspectorState
|
|
10
|
-
) => {
|
|
11
|
-
if (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node)) {
|
|
12
|
-
const fileName = node.getSourceFile().fileName
|
|
13
|
-
const typeName = node.name?.getText()
|
|
14
|
-
|
|
15
|
-
// Check if the class or interface extends the expected type
|
|
16
|
-
if (node.heritageClauses) {
|
|
17
|
-
for (const clause of node.heritageClauses) {
|
|
18
|
-
if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
|
|
19
|
-
for (const type of clause.types) {
|
|
20
|
-
const extendedTypeName = type.expression.getText()
|
|
21
|
-
let extendedTypeDeclarationPath: string | null = null
|
|
22
|
-
|
|
23
|
-
// Check if the extended type matches the expected type name
|
|
24
|
-
if (extendedTypeName === expectedTypeName) {
|
|
25
|
-
// Retrieve the symbol of the extended type
|
|
26
|
-
const typeSymbol = checker.getSymbolAtLocation(type.expression)
|
|
27
|
-
const declaration =
|
|
28
|
-
typeSymbol &&
|
|
29
|
-
typeSymbol.declarations &&
|
|
30
|
-
typeSymbol.declarations[0]
|
|
31
|
-
if (declaration) {
|
|
32
|
-
const sourceFile = declaration.getSourceFile()
|
|
33
|
-
extendedTypeDeclarationPath = sourceFile.fileName // Get the path of the file where the extended type was declared
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const variables = methods.get(fileName) || []
|
|
37
|
-
|
|
38
|
-
if (!typeName) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
`Found anonymous ${ts.isClassDeclaration(node) ? 'class' : 'interface'} extending ${expectedTypeName} in ${fileName}. ` +
|
|
41
|
-
`Classes and interfaces that extend core types must have a name.`
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
variables.push({
|
|
45
|
-
variable: typeName,
|
|
46
|
-
type: typeName,
|
|
47
|
-
typePath: extendedTypeDeclarationPath,
|
|
48
|
-
})
|
|
49
|
-
methods.set(fileName, variables)
|
|
50
|
-
|
|
51
|
-
// Store the type in typesLookup if state is provided
|
|
52
|
-
if (state && node.name) {
|
|
53
|
-
const symbol = checker.getSymbolAtLocation(node.name)
|
|
54
|
-
if (symbol) {
|
|
55
|
-
const declaredType = checker.getDeclaredTypeOfSymbol(symbol)
|
|
56
|
-
// Use the type name as the key in typesLookup
|
|
57
|
-
state.typesLookup.set(typeName, [declaredType])
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript'
|
|
2
|
-
import { doesTypeExtendsCore } from '../utils/does-type-extend-core-type.js'
|
|
3
|
-
import type { PathToNameAndType } from '../types.js'
|
|
4
|
-
|
|
5
|
-
export const addFileWithConfig = (
|
|
6
|
-
node: ts.Node,
|
|
7
|
-
checker: ts.TypeChecker,
|
|
8
|
-
configs: PathToNameAndType
|
|
9
|
-
) => {
|
|
10
|
-
if (ts.isVariableDeclaration(node)) {
|
|
11
|
-
const fileName = node.getSourceFile().fileName
|
|
12
|
-
const variableSymbol = checker.getSymbolAtLocation(node.name)
|
|
13
|
-
|
|
14
|
-
if (variableSymbol) {
|
|
15
|
-
const variableType = checker.getTypeOfSymbolAtLocation(
|
|
16
|
-
variableSymbol,
|
|
17
|
-
node.name
|
|
18
|
-
)
|
|
19
|
-
const variableName = node.name.getText()
|
|
20
|
-
const variableTypeText = node.type?.getText()
|
|
21
|
-
|
|
22
|
-
// Check if the type extends CoreConfig
|
|
23
|
-
if (doesTypeExtendsCore(variableType, checker, new Set(), 'CoreConfig')) {
|
|
24
|
-
// Retrieve the symbol of the type (if it has one)
|
|
25
|
-
const typeSymbol = variableType.symbol
|
|
26
|
-
let typeDeclarationPath: string | null = null
|
|
27
|
-
const declaration =
|
|
28
|
-
typeSymbol && typeSymbol.declarations && typeSymbol.declarations[0]
|
|
29
|
-
|
|
30
|
-
if (declaration) {
|
|
31
|
-
const sourceFile = declaration.getSourceFile()
|
|
32
|
-
typeDeclarationPath = sourceFile.fileName // Get the path of the file where the type was declared
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const variables = configs[fileName] || []
|
|
36
|
-
variables.push({
|
|
37
|
-
variable: variableName,
|
|
38
|
-
type: variableTypeText || null,
|
|
39
|
-
typePath: typeDeclarationPath,
|
|
40
|
-
})
|
|
41
|
-
configs[fileName] = variables
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { strict as assert } from 'assert'
|
|
2
|
-
import { describe, test } from 'node:test'
|
|
3
|
-
import { mkdtemp, rm, writeFile } from 'node:fs/promises'
|
|
4
|
-
import { tmpdir } from 'node:os'
|
|
5
|
-
import { join } from 'node:path'
|
|
6
|
-
import { inspect } from '../inspector.js'
|
|
7
|
-
import type { ErrorCode } from '../error-codes.js'
|
|
8
|
-
import type { InspectorLogger } from '../types.js'
|
|
9
|
-
import {
|
|
10
|
-
serializeInspectorState,
|
|
11
|
-
deserializeInspectorState,
|
|
12
|
-
} from '../utils/serialize-inspector-state.js'
|
|
13
|
-
|
|
14
|
-
const makeLogger = (criticals: Array<{ code: ErrorCode; message: string }>) =>
|
|
15
|
-
({
|
|
16
|
-
debug: () => {},
|
|
17
|
-
info: () => {},
|
|
18
|
-
warn: () => {},
|
|
19
|
-
error: () => {},
|
|
20
|
-
diagnostic: ({ severity, code, message }) => {
|
|
21
|
-
if (severity !== 'warn') {
|
|
22
|
-
criticals.push({ code, message })
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
critical: (code: ErrorCode, message: string) => {
|
|
26
|
-
criticals.push({ code, message })
|
|
27
|
-
},
|
|
28
|
-
hasCriticalErrors: () => criticals.length > 0,
|
|
29
|
-
}) satisfies InspectorLogger
|
|
30
|
-
|
|
31
|
-
const inspectSource = async (prefix: string, source: string) => {
|
|
32
|
-
const rootDir = await mkdtemp(join(tmpdir(), prefix))
|
|
33
|
-
const file = join(rootDir, 'services.ts')
|
|
34
|
-
await writeFile(file, source)
|
|
35
|
-
const criticals: Array<{ code: ErrorCode; message: string }> = []
|
|
36
|
-
try {
|
|
37
|
-
const state = await inspect(makeLogger(criticals), [file], { rootDir })
|
|
38
|
-
return { state, criticals }
|
|
39
|
-
} finally {
|
|
40
|
-
await rm(rootDir, { recursive: true, force: true })
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
describe('pikkuAddonServices — what an addon takes from its parent', () => {
|
|
45
|
-
test('a name destructured in the body, not the parameter list, is still forwarded', async () => {
|
|
46
|
-
const { state } = await inspectSource(
|
|
47
|
-
'pikku-addon-body-destructure-',
|
|
48
|
-
[
|
|
49
|
-
"import { pikkuAddonServices } from '#pikku/addon/setup'",
|
|
50
|
-
'export const createSingletonServices = pikkuAddonServices(',
|
|
51
|
-
' async (_config, existingServices) => {',
|
|
52
|
-
' const { kysely, secrets } = existingServices',
|
|
53
|
-
' return { ...existingServices, stripeApi: makeStripe(secrets) }',
|
|
54
|
-
' }',
|
|
55
|
-
')',
|
|
56
|
-
].join('\n')
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
assert.ok(
|
|
60
|
-
state.addonRequiredParentServices.includes('kysely'),
|
|
61
|
-
'kysely is read off the parent bag and must be declared as required'
|
|
62
|
-
)
|
|
63
|
-
assert.deepEqual(state.addonCreatedServices, ['stripeApi'])
|
|
64
|
-
assert.equal(state.addonServicesFactorySeen, true)
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('an object rest is a binding name, not a service', async () => {
|
|
68
|
-
const { state } = await inspectSource(
|
|
69
|
-
'pikku-addon-object-rest-',
|
|
70
|
-
[
|
|
71
|
-
"import { pikkuAddonServices } from '#pikku/addon/setup'",
|
|
72
|
-
'export const createSingletonServices = pikkuAddonServices(',
|
|
73
|
-
' async (_config, { kysely, ...parentServices }) => ({',
|
|
74
|
-
' ...parentServices,',
|
|
75
|
-
' kysely,',
|
|
76
|
-
' stripeApi: makeStripe(),',
|
|
77
|
-
' })',
|
|
78
|
-
')',
|
|
79
|
-
].join('\n')
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
assert.deepEqual(state.addonRequiredParentServices, ['kysely'])
|
|
83
|
-
assert.ok(
|
|
84
|
-
!state.addonRequiredParentServices.includes('parentServices'),
|
|
85
|
-
'a rest binding names the leftover bag, not a service the parent provides'
|
|
86
|
-
)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
test('a parenthesised return still yields its created services', async () => {
|
|
90
|
-
const { state } = await inspectSource(
|
|
91
|
-
'pikku-addon-parenthesised-return-',
|
|
92
|
-
[
|
|
93
|
-
"import { pikkuAddonServices } from '#pikku/addon/setup'",
|
|
94
|
-
'export const createSingletonServices = pikkuAddonServices(',
|
|
95
|
-
' async (_config, existingServices) => {',
|
|
96
|
-
' return ({ ...existingServices, stripeApi: makeStripe() })',
|
|
97
|
-
' }',
|
|
98
|
-
')',
|
|
99
|
-
].join('\n')
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
assert.deepEqual(state.addonCreatedServices, ['stripeApi'])
|
|
103
|
-
assert.ok(
|
|
104
|
-
!state.addonRequiredParentServices.includes('stripeApi'),
|
|
105
|
-
'a service the factory builds is not one the parent has to supply'
|
|
106
|
-
)
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
test('the addon contract survives a serialize/deserialize round trip', async () => {
|
|
110
|
-
const { state } = await inspectSource(
|
|
111
|
-
'pikku-addon-round-trip-',
|
|
112
|
-
[
|
|
113
|
-
"import { pikkuAddonServices } from '#pikku/addon/setup'",
|
|
114
|
-
'export const createSingletonServices = pikkuAddonServices(',
|
|
115
|
-
' async (_config, existingServices) => {',
|
|
116
|
-
' const { kysely } = existingServices',
|
|
117
|
-
' return { ...existingServices, stripeApi: makeStripe(kysely) }',
|
|
118
|
-
' }',
|
|
119
|
-
')',
|
|
120
|
-
].join('\n')
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
const restored = deserializeInspectorState(
|
|
124
|
-
JSON.parse(JSON.stringify(serializeInspectorState(state)))
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
assert.deepEqual(
|
|
128
|
-
restored.addonRequiredParentServices,
|
|
129
|
-
state.addonRequiredParentServices
|
|
130
|
-
)
|
|
131
|
-
assert.deepEqual(restored.addonCreatedServices, ['stripeApi'])
|
|
132
|
-
assert.equal(restored.addonServicesFactorySeen, true)
|
|
133
|
-
})
|
|
134
|
-
})
|