@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,141 +0,0 @@
|
|
|
1
|
-
import { describe, test } from 'node:test'
|
|
2
|
-
import assert from 'node:assert'
|
|
3
|
-
import * as ts from 'typescript'
|
|
4
|
-
import {
|
|
5
|
-
getArrayPropertyValue,
|
|
6
|
-
getRecordPropertyValue,
|
|
7
|
-
} from './get-property-value.js'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Parses `const x = { ... }` and hands back the object literal.
|
|
11
|
-
*/
|
|
12
|
-
const objectLiteral = (source: string): ts.ObjectLiteralExpression => {
|
|
13
|
-
const file = ts.createSourceFile(
|
|
14
|
-
'test.ts',
|
|
15
|
-
`const x = ${source}`,
|
|
16
|
-
ts.ScriptTarget.Latest,
|
|
17
|
-
true
|
|
18
|
-
)
|
|
19
|
-
const statement = file.statements[0] as ts.VariableStatement
|
|
20
|
-
const initializer = statement.declarationList.declarations[0]!.initializer
|
|
21
|
-
if (!initializer || !ts.isObjectLiteralExpression(initializer)) {
|
|
22
|
-
throw new Error('expected an object literal')
|
|
23
|
-
}
|
|
24
|
-
return initializer
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const firstObjectLiteral = (src: string): ts.ObjectLiteralExpression => {
|
|
28
|
-
const sourceFile = ts.createSourceFile(
|
|
29
|
-
'test.ts',
|
|
30
|
-
src,
|
|
31
|
-
ts.ScriptTarget.Latest,
|
|
32
|
-
true
|
|
33
|
-
)
|
|
34
|
-
let found: ts.ObjectLiteralExpression | undefined
|
|
35
|
-
const walk = (node: ts.Node) => {
|
|
36
|
-
if (!found && ts.isObjectLiteralExpression(node)) {
|
|
37
|
-
found = node
|
|
38
|
-
}
|
|
39
|
-
ts.forEachChild(node, walk)
|
|
40
|
-
}
|
|
41
|
-
walk(sourceFile)
|
|
42
|
-
if (!found) {
|
|
43
|
-
throw new Error('no object literal in source')
|
|
44
|
-
}
|
|
45
|
-
return found
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
describe('getArrayPropertyValue', () => {
|
|
49
|
-
test('reads a plain array literal', () => {
|
|
50
|
-
const obj = objectLiteral(`{ tags: ['a', 'b'] }`)
|
|
51
|
-
assert.deepEqual(getArrayPropertyValue(obj, 'tags'), ['a', 'b'])
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
test('returns null when the property is absent', () => {
|
|
55
|
-
const obj = objectLiteral(`{ other: ['a'] }`)
|
|
56
|
-
assert.equal(getArrayPropertyValue(obj, 'tags'), null)
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
test('reads an array widened with `as const`', () => {
|
|
60
|
-
const obj = objectLiteral(`{ tags: ['a', 'b'] as const }`)
|
|
61
|
-
assert.deepEqual(
|
|
62
|
-
getArrayPropertyValue(obj, 'tags'),
|
|
63
|
-
['a', 'b'],
|
|
64
|
-
'`as const` on an array is idiomatic and must not drop the value'
|
|
65
|
-
)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
test('reads an array cast with `as any`', () => {
|
|
69
|
-
const obj = objectLiteral(`{ tags: ['a'] as any }`)
|
|
70
|
-
assert.deepEqual(
|
|
71
|
-
getArrayPropertyValue(obj, 'tags'),
|
|
72
|
-
['a'],
|
|
73
|
-
'a cast must not let a value escape static validation'
|
|
74
|
-
)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
test('reads an array through `satisfies`', () => {
|
|
78
|
-
const obj = objectLiteral(`{ tags: ['a'] satisfies string[] }`)
|
|
79
|
-
assert.deepEqual(getArrayPropertyValue(obj, 'tags'), ['a'])
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test('reads an array through nested casts', () => {
|
|
83
|
-
const obj = objectLiteral(`{ tags: ['a'] as const as any }`)
|
|
84
|
-
assert.deepEqual(getArrayPropertyValue(obj, 'tags'), ['a'])
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
test('ignores non-string elements', () => {
|
|
88
|
-
const obj = objectLiteral(`{ tags: ['a', 1, foo] }`)
|
|
89
|
-
assert.deepEqual(getArrayPropertyValue(obj, 'tags'), ['a'])
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
test('returns null for a non-array initializer', () => {
|
|
93
|
-
const obj = objectLiteral(`{ tags: 'a' }`)
|
|
94
|
-
assert.equal(getArrayPropertyValue(obj, 'tags'), null)
|
|
95
|
-
})
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
describe('getRecordPropertyValue', () => {
|
|
99
|
-
test('extracts a string record', () => {
|
|
100
|
-
const obj = firstObjectLiteral(
|
|
101
|
-
`const x = { additionalParams: { access_type: 'offline', prompt: 'consent' } }`
|
|
102
|
-
)
|
|
103
|
-
assert.deepStrictEqual(getRecordPropertyValue(obj, 'additionalParams'), {
|
|
104
|
-
access_type: 'offline',
|
|
105
|
-
prompt: 'consent',
|
|
106
|
-
})
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
test('handles quoted keys', () => {
|
|
110
|
-
const obj = firstObjectLiteral(
|
|
111
|
-
`const x = { additionalParams: { 'token_access_type': 'offline' } }`
|
|
112
|
-
)
|
|
113
|
-
assert.deepStrictEqual(getRecordPropertyValue(obj, 'additionalParams'), {
|
|
114
|
-
token_access_type: 'offline',
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
test('returns null when the property is absent', () => {
|
|
119
|
-
const obj = firstObjectLiteral(`const x = { scopes: ['a'] }`)
|
|
120
|
-
assert.strictEqual(getRecordPropertyValue(obj, 'additionalParams'), null)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
test('returns null for a non-literal initializer', () => {
|
|
124
|
-
const obj = firstObjectLiteral(`const x = { additionalParams: SOME_CONST }`)
|
|
125
|
-
assert.strictEqual(getRecordPropertyValue(obj, 'additionalParams'), null)
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
test('skips non-string values rather than coercing them', () => {
|
|
129
|
-
const obj = firstObjectLiteral(
|
|
130
|
-
`const x = { additionalParams: { a: 'keep', b: 42, c: true } }`
|
|
131
|
-
)
|
|
132
|
-
assert.deepStrictEqual(getRecordPropertyValue(obj, 'additionalParams'), {
|
|
133
|
-
a: 'keep',
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
test('returns null for an empty record', () => {
|
|
138
|
-
const obj = firstObjectLiteral(`const x = { additionalParams: {} }`)
|
|
139
|
-
assert.strictEqual(getRecordPropertyValue(obj, 'additionalParams'), null)
|
|
140
|
-
})
|
|
141
|
-
})
|
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript'
|
|
2
|
-
import { ErrorCode } from '../error-codes.js'
|
|
3
|
-
import { extractStringLiteral } from './extract-node-value.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Extracts an array of strings from an object property.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Unwraps `x as const` / `x as any` / `x satisfies T` down to the underlying
|
|
10
|
-
* expression. Without this a cast makes the value invisible to the inspector,
|
|
11
|
-
* so it is silently dropped from meta rather than validated — and `as const` on
|
|
12
|
-
* an array is idiomatic enough that this is easy to hit by accident.
|
|
13
|
-
*/
|
|
14
|
-
const unwrapAs = (node: ts.Expression): ts.Expression =>
|
|
15
|
-
ts.isAsExpression(node) || ts.isSatisfiesExpression(node)
|
|
16
|
-
? unwrapAs(node.expression)
|
|
17
|
-
: node
|
|
18
|
-
|
|
19
|
-
export const getArrayPropertyValue = (
|
|
20
|
-
obj: ts.ObjectLiteralExpression,
|
|
21
|
-
propertyName: string
|
|
22
|
-
): string[] | null => {
|
|
23
|
-
const property = obj.properties.find(
|
|
24
|
-
(p) =>
|
|
25
|
-
ts.isPropertyAssignment(p) &&
|
|
26
|
-
ts.isIdentifier(p.name) &&
|
|
27
|
-
p.name.text === propertyName
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
if (property && ts.isPropertyAssignment(property)) {
|
|
31
|
-
const initializer = unwrapAs(property.initializer)
|
|
32
|
-
if (ts.isArrayLiteralExpression(initializer)) {
|
|
33
|
-
return initializer.elements
|
|
34
|
-
.filter(ts.isStringLiteral)
|
|
35
|
-
.map((element) => element.text)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return null
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Extracts a string->string record from an object property.
|
|
44
|
-
*
|
|
45
|
-
* `getPropertyValue` falls through to `getText()` for an object literal, which
|
|
46
|
-
* returns the raw source text rather than the record — so callers that need the
|
|
47
|
-
* entries (e.g. oauth2 `additionalParams`) must use this instead.
|
|
48
|
-
*/
|
|
49
|
-
export const getRecordPropertyValue = (
|
|
50
|
-
obj: ts.ObjectLiteralExpression,
|
|
51
|
-
propertyName: string
|
|
52
|
-
): Record<string, string> | null => {
|
|
53
|
-
const property = obj.properties.find(
|
|
54
|
-
(p) =>
|
|
55
|
-
ts.isPropertyAssignment(p) &&
|
|
56
|
-
ts.isIdentifier(p.name) &&
|
|
57
|
-
p.name.text === propertyName
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
if (!property || !ts.isPropertyAssignment(property)) {
|
|
61
|
-
return null
|
|
62
|
-
}
|
|
63
|
-
const initializer = property.initializer
|
|
64
|
-
if (!ts.isObjectLiteralExpression(initializer)) {
|
|
65
|
-
return null
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const record: Record<string, string> = {}
|
|
69
|
-
for (const prop of initializer.properties) {
|
|
70
|
-
if (!ts.isPropertyAssignment(prop)) {
|
|
71
|
-
continue
|
|
72
|
-
}
|
|
73
|
-
const key = ts.isIdentifier(prop.name)
|
|
74
|
-
? prop.name.text
|
|
75
|
-
: ts.isStringLiteral(prop.name)
|
|
76
|
-
? prop.name.text
|
|
77
|
-
: null
|
|
78
|
-
if (key === null) {
|
|
79
|
-
continue
|
|
80
|
-
}
|
|
81
|
-
if (
|
|
82
|
-
ts.isStringLiteral(prop.initializer) ||
|
|
83
|
-
ts.isNoSubstitutionTemplateLiteral(prop.initializer)
|
|
84
|
-
) {
|
|
85
|
-
record[key] = prop.initializer.text
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return Object.keys(record).length > 0 ? record : null
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Wiring identity fields (`name`, `secretId`, `variableId`, …) are read
|
|
94
|
-
* STATICALLY from source — a const or variable reference is keyed by its
|
|
95
|
-
* identifier text, not its runtime value, so the wiring is silently skipped at
|
|
96
|
-
* runtime (`metadata not found`). If the named property exists but is not an
|
|
97
|
-
* inline literal, raise a fatal diagnostic so the build fails instead.
|
|
98
|
-
*/
|
|
99
|
-
export const assertStringLiteralProperty = (
|
|
100
|
-
obj: ts.ObjectLiteralExpression,
|
|
101
|
-
propertyName: string,
|
|
102
|
-
wiringType: string,
|
|
103
|
-
logger?: { critical: (code: ErrorCode, message: string) => void }
|
|
104
|
-
): void => {
|
|
105
|
-
const property = obj.properties.find(
|
|
106
|
-
(p) =>
|
|
107
|
-
ts.isPropertyAssignment(p) &&
|
|
108
|
-
ts.isIdentifier(p.name) &&
|
|
109
|
-
p.name.text === propertyName
|
|
110
|
-
)
|
|
111
|
-
if (!property || !ts.isPropertyAssignment(property)) {
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
const init = property.initializer
|
|
115
|
-
const isStaticLiteral =
|
|
116
|
-
ts.isStringLiteral(init) ||
|
|
117
|
-
ts.isNoSubstitutionTemplateLiteral(init) ||
|
|
118
|
-
ts.isNumericLiteral(init)
|
|
119
|
-
if (isStaticLiteral) {
|
|
120
|
-
return
|
|
121
|
-
}
|
|
122
|
-
const errorMsg = `${wiringType} has a non-literal '${propertyName}': \`${init.getText()}\`. Wiring identity fields must be inline string literals — the inspector reads them statically from source, so a const or variable reference is keyed by its identifier text and the wiring is silently skipped at runtime. Inline the literal instead, e.g. ${propertyName}: 'my-wiring-name'.`
|
|
123
|
-
if (logger) {
|
|
124
|
-
logger.critical(ErrorCode.NON_LITERAL_WIRE_NAME, errorMsg)
|
|
125
|
-
} else {
|
|
126
|
-
console.error(errorMsg)
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Fold a node that is a compile-time constant string down to its value.
|
|
132
|
-
*
|
|
133
|
-
* The fallback below this is `getText()`, which returns the node's *source*.
|
|
134
|
-
* For a lone `'…'` that is indistinguishable from the value, so nobody noticed
|
|
135
|
-
* that anything written as an expression comes through raw: a `description`
|
|
136
|
-
* split across lines as `'Fetch the thing ' + 'from upstream'` reaches
|
|
137
|
-
* `infra.json` with the quotes and the `+` still in it, and is rendered that
|
|
138
|
-
* way in the fabric console.
|
|
139
|
-
*
|
|
140
|
-
* Deliberately checker-free, unlike `extractStringLiteral`. Every value this
|
|
141
|
-
* resolves is a literal in the same expression, so no symbol resolution is
|
|
142
|
-
* needed, and `getPropertyValue` is called from a dozen places that have no
|
|
143
|
-
* checker to hand. Anything it cannot fold — an identifier, a template with a
|
|
144
|
-
* substitution — returns `undefined` and takes the old path, so this only ever
|
|
145
|
-
* turns a wrong answer into a right one.
|
|
146
|
-
*/
|
|
147
|
-
const foldStaticString = (node: ts.Node): string | undefined => {
|
|
148
|
-
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
149
|
-
return node.text
|
|
150
|
-
}
|
|
151
|
-
if (ts.isParenthesizedExpression(node)) {
|
|
152
|
-
return foldStaticString(node.expression)
|
|
153
|
-
}
|
|
154
|
-
if (ts.isAsExpression(node) || ts.isTypeAssertionExpression(node)) {
|
|
155
|
-
return foldStaticString(node.expression)
|
|
156
|
-
}
|
|
157
|
-
if (
|
|
158
|
-
ts.isBinaryExpression(node) &&
|
|
159
|
-
node.operatorToken.kind === ts.SyntaxKind.PlusToken
|
|
160
|
-
) {
|
|
161
|
-
const left = foldStaticString(node.left)
|
|
162
|
-
if (left === undefined) return undefined
|
|
163
|
-
const right = foldStaticString(node.right)
|
|
164
|
-
if (right === undefined) return undefined
|
|
165
|
-
return left + right
|
|
166
|
-
}
|
|
167
|
-
return undefined
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export const getPropertyValue = (
|
|
171
|
-
obj: ts.ObjectLiteralExpression,
|
|
172
|
-
propertyName: string
|
|
173
|
-
): string | string[] | number | null | boolean => {
|
|
174
|
-
const property = obj.properties.find(
|
|
175
|
-
(p) =>
|
|
176
|
-
ts.isPropertyAssignment(p) &&
|
|
177
|
-
ts.isIdentifier(p.name) &&
|
|
178
|
-
p.name.text === propertyName
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
if (property && ts.isPropertyAssignment(property)) {
|
|
182
|
-
const initializer = property.initializer
|
|
183
|
-
|
|
184
|
-
// Special handling for 'query' -> expect an array of strings
|
|
185
|
-
if (
|
|
186
|
-
['query', 'tags'].includes(propertyName) &&
|
|
187
|
-
ts.isArrayLiteralExpression(initializer)
|
|
188
|
-
) {
|
|
189
|
-
const stringArray = initializer.elements
|
|
190
|
-
.map((element) => {
|
|
191
|
-
if (ts.isStringLiteral(element)) {
|
|
192
|
-
return element.text
|
|
193
|
-
}
|
|
194
|
-
return null
|
|
195
|
-
})
|
|
196
|
-
.filter((item) => item !== null) as string[] // Filter non-null and assert type
|
|
197
|
-
|
|
198
|
-
return stringArray.length > 0 ? stringArray : null
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// booleans -> true/false
|
|
202
|
-
if (initializer.kind === ts.SyntaxKind.TrueKeyword) {
|
|
203
|
-
return true
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (initializer.kind === ts.SyntaxKind.FalseKeyword) {
|
|
207
|
-
return false
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (ts.isNumericLiteral(initializer)) {
|
|
211
|
-
if (propertyName === 'name' || propertyName === 'schedule') {
|
|
212
|
-
return initializer.text
|
|
213
|
-
}
|
|
214
|
-
return Number(initializer.text)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const staticString = foldStaticString(initializer)
|
|
218
|
-
if (staticString !== undefined) {
|
|
219
|
-
return staticString
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return initializer.getText()
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return null
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Extracts common wire metadata (title, tags, summary, description, errors) directly from an object
|
|
230
|
-
* @param obj - The TypeScript object literal expression to extract metadata from
|
|
231
|
-
* @param wiringType - The type of wiring (e.g., 'HTTP route', 'Channel', 'Queue worker')
|
|
232
|
-
* @param wiringName - The name/identifier of the wiring (e.g., route path, channel name)
|
|
233
|
-
* @param logger - Optional logger instance; if not provided, uses console.error
|
|
234
|
-
* @returns Object containing the common wire metadata fields
|
|
235
|
-
*/
|
|
236
|
-
export const getCommonWireMetaData = (
|
|
237
|
-
obj: ts.ObjectLiteralExpression,
|
|
238
|
-
wiringType: string,
|
|
239
|
-
wiringName: string | null,
|
|
240
|
-
logger?: { critical: (code: ErrorCode, message: string) => void },
|
|
241
|
-
checker?: ts.TypeChecker
|
|
242
|
-
): {
|
|
243
|
-
disabled?: true
|
|
244
|
-
title?: string
|
|
245
|
-
tags?: string[]
|
|
246
|
-
summary?: string
|
|
247
|
-
description?: string
|
|
248
|
-
errors?: string[]
|
|
249
|
-
} => {
|
|
250
|
-
const metadata: {
|
|
251
|
-
disabled?: true
|
|
252
|
-
title?: string
|
|
253
|
-
tags?: string[]
|
|
254
|
-
summary?: string
|
|
255
|
-
description?: string
|
|
256
|
-
errors?: string[]
|
|
257
|
-
} = {}
|
|
258
|
-
|
|
259
|
-
assertStringLiteralProperty(obj, 'name', wiringType, logger)
|
|
260
|
-
|
|
261
|
-
obj.properties.forEach((prop) => {
|
|
262
|
-
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
263
|
-
const propName = prop.name.text
|
|
264
|
-
|
|
265
|
-
if (
|
|
266
|
-
propName === 'disabled' &&
|
|
267
|
-
prop.initializer.kind === ts.SyntaxKind.TrueKeyword
|
|
268
|
-
) {
|
|
269
|
-
metadata.disabled = true
|
|
270
|
-
} else if (propName === 'title') {
|
|
271
|
-
try {
|
|
272
|
-
metadata.title = checker
|
|
273
|
-
? extractStringLiteral(prop.initializer, checker)
|
|
274
|
-
: ts.isStringLiteral(prop.initializer)
|
|
275
|
-
? prop.initializer.text
|
|
276
|
-
: undefined
|
|
277
|
-
} catch {
|
|
278
|
-
// non-static title — skip
|
|
279
|
-
}
|
|
280
|
-
} else if (propName === 'summary') {
|
|
281
|
-
try {
|
|
282
|
-
metadata.summary = checker
|
|
283
|
-
? extractStringLiteral(prop.initializer, checker)
|
|
284
|
-
: ts.isStringLiteral(prop.initializer)
|
|
285
|
-
? prop.initializer.text
|
|
286
|
-
: undefined
|
|
287
|
-
} catch {
|
|
288
|
-
// non-static summary — skip
|
|
289
|
-
}
|
|
290
|
-
} else if (propName === 'description') {
|
|
291
|
-
try {
|
|
292
|
-
metadata.description = checker
|
|
293
|
-
? extractStringLiteral(prop.initializer, checker)
|
|
294
|
-
: ts.isStringLiteral(prop.initializer)
|
|
295
|
-
? prop.initializer.text
|
|
296
|
-
: undefined
|
|
297
|
-
} catch {
|
|
298
|
-
// non-static description — skip
|
|
299
|
-
}
|
|
300
|
-
} else if (propName === 'tags') {
|
|
301
|
-
if (ts.isArrayLiteralExpression(prop.initializer)) {
|
|
302
|
-
metadata.tags = prop.initializer.elements
|
|
303
|
-
.filter(ts.isStringLiteral)
|
|
304
|
-
.map((element) => element.text)
|
|
305
|
-
} else {
|
|
306
|
-
const errorMsg = `${wiringType} '${wiringName}' has invalid 'tags' property - must be an array of strings.`
|
|
307
|
-
if (logger) {
|
|
308
|
-
logger.critical(ErrorCode.INVALID_TAGS_TYPE, errorMsg)
|
|
309
|
-
} else {
|
|
310
|
-
console.error(errorMsg)
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
} else if (propName === 'errors') {
|
|
314
|
-
if (ts.isArrayLiteralExpression(prop.initializer)) {
|
|
315
|
-
metadata.errors = prop.initializer.elements
|
|
316
|
-
.filter(ts.isIdentifier)
|
|
317
|
-
.map((element) => element.text as unknown as string)
|
|
318
|
-
} else {
|
|
319
|
-
const errorMsg = `${wiringType} '${wiringName}' has invalid 'errors' property - must be an array of error identifiers.`
|
|
320
|
-
if (logger) {
|
|
321
|
-
logger.critical(ErrorCode.INVALID_TAGS_TYPE, errorMsg)
|
|
322
|
-
} else {
|
|
323
|
-
console.error(errorMsg)
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
return metadata
|
|
331
|
-
}
|
package/src/utils/hash.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'crypto'
|
|
2
|
-
|
|
3
|
-
export function canonicalJSON(obj: unknown): string {
|
|
4
|
-
return JSON.stringify(sortDeep(obj))
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
function sortDeep(value: unknown): unknown {
|
|
8
|
-
if (value === null || value === undefined) {
|
|
9
|
-
return value
|
|
10
|
-
}
|
|
11
|
-
if (Array.isArray(value)) {
|
|
12
|
-
return value.map(sortDeep)
|
|
13
|
-
}
|
|
14
|
-
if (typeof value === 'object') {
|
|
15
|
-
const sorted: Record<string, unknown> = {}
|
|
16
|
-
for (const key of Object.keys(value as Record<string, unknown>).sort()) {
|
|
17
|
-
sorted[key] = sortDeep((value as Record<string, unknown>)[key])
|
|
18
|
-
}
|
|
19
|
-
return sorted
|
|
20
|
-
}
|
|
21
|
-
return value
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function hashString(input: string, length: number = 16): string {
|
|
25
|
-
return createHash('sha256').update(input).digest('hex').slice(0, length)
|
|
26
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Readers for object-literal properties that must be statically knowable.
|
|
5
|
-
*
|
|
6
|
-
* Declarations extracted this way are never evaluated — the CLI reads them from
|
|
7
|
-
* source and writes them to JSON that a deployed stage carries without the app.
|
|
8
|
-
* So a computed value is not "unsupported", it is unreadable, and every reader
|
|
9
|
-
* here returns `undefined` for one rather than guessing.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
export const getProperty = (
|
|
13
|
-
config: ts.ObjectLiteralExpression,
|
|
14
|
-
name: string
|
|
15
|
-
): ts.Expression | undefined => {
|
|
16
|
-
const property = config.properties.find(
|
|
17
|
-
(p) =>
|
|
18
|
-
ts.isPropertyAssignment(p) &&
|
|
19
|
-
(ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) &&
|
|
20
|
-
p.name.text === name
|
|
21
|
-
)
|
|
22
|
-
return property && ts.isPropertyAssignment(property)
|
|
23
|
-
? property.initializer
|
|
24
|
-
: undefined
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const stringProperty = (
|
|
28
|
-
config: ts.ObjectLiteralExpression,
|
|
29
|
-
name: string
|
|
30
|
-
): string | undefined => {
|
|
31
|
-
const value = getProperty(config, name)
|
|
32
|
-
return value && ts.isStringLiteralLike(value) ? value.text : undefined
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const numberProperty = (
|
|
36
|
-
config: ts.ObjectLiteralExpression,
|
|
37
|
-
name: string
|
|
38
|
-
): number | undefined => {
|
|
39
|
-
const value = getProperty(config, name)
|
|
40
|
-
if (!value) {
|
|
41
|
-
return undefined
|
|
42
|
-
}
|
|
43
|
-
// `-1` parses as a unary minus over a literal, not as a literal. Reading it
|
|
44
|
-
// rather than ignoring it is what lets a negative be *rejected* by the caller
|
|
45
|
-
// instead of silently dropped and defaulted.
|
|
46
|
-
if (
|
|
47
|
-
ts.isPrefixUnaryExpression(value) &&
|
|
48
|
-
value.operator === ts.SyntaxKind.MinusToken &&
|
|
49
|
-
ts.isNumericLiteral(value.operand)
|
|
50
|
-
) {
|
|
51
|
-
return -Number(value.operand.text)
|
|
52
|
-
}
|
|
53
|
-
return ts.isNumericLiteral(value) ? Number(value.text) : undefined
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export const booleanProperty = (
|
|
57
|
-
config: ts.ObjectLiteralExpression,
|
|
58
|
-
name: string
|
|
59
|
-
): boolean | undefined => {
|
|
60
|
-
const value = getProperty(config, name)
|
|
61
|
-
if (!value) {
|
|
62
|
-
return undefined
|
|
63
|
-
}
|
|
64
|
-
if (value.kind === ts.SyntaxKind.TrueKeyword) {
|
|
65
|
-
return true
|
|
66
|
-
}
|
|
67
|
-
if (value.kind === ts.SyntaxKind.FalseKeyword) {
|
|
68
|
-
return false
|
|
69
|
-
}
|
|
70
|
-
return undefined
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* All-or-nothing: an array with one computed entry reads as unreadable rather
|
|
75
|
-
* than as the entries that happened to be literals. A half-read `roles` or
|
|
76
|
-
* `scopes` array is worse than none — it typechecks, runs, and grants less
|
|
77
|
-
* than the source says.
|
|
78
|
-
*/
|
|
79
|
-
export const stringArrayProperty = (
|
|
80
|
-
config: ts.ObjectLiteralExpression,
|
|
81
|
-
name: string
|
|
82
|
-
): string[] | undefined => {
|
|
83
|
-
const value = getProperty(config, name)
|
|
84
|
-
if (!value || !ts.isArrayLiteralExpression(value)) {
|
|
85
|
-
return undefined
|
|
86
|
-
}
|
|
87
|
-
const values = value.elements
|
|
88
|
-
.filter(ts.isStringLiteralLike)
|
|
89
|
-
.map((e) => e.text)
|
|
90
|
-
return values.length === value.elements.length ? values : undefined
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** Unwraps `x as const` / `x satisfies T` so a cast is still extracted. */
|
|
94
|
-
export const unwrapAs = (node: ts.Expression): ts.Expression =>
|
|
95
|
-
ts.isAsExpression(node) || ts.isSatisfiesExpression(node)
|
|
96
|
-
? unwrapAs(node.expression)
|
|
97
|
-
: node
|