@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,161 +0,0 @@
|
|
|
1
|
-
import type { InspectorFilters, InspectorLogger } from '../types.js'
|
|
2
|
-
import type { PikkuWiringTypes } from '@pikku/core/types'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Match a value against a pattern with wildcard support
|
|
6
|
-
* Supports "*" at the beginning, end, or both (e.g., "send*", "*Payment", "*process*")
|
|
7
|
-
* @param value - The value to check
|
|
8
|
-
* @param pattern - The pattern with optional "*" wildcard(s)
|
|
9
|
-
*/
|
|
10
|
-
export function matchesWildcard(value: string, pattern: string): boolean {
|
|
11
|
-
// If pattern is just '*', match everything
|
|
12
|
-
if (pattern === '*') {
|
|
13
|
-
return true
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const startsWithWildcard = pattern.startsWith('*')
|
|
17
|
-
const endsWithWildcard = pattern.endsWith('*')
|
|
18
|
-
|
|
19
|
-
if (startsWithWildcard && endsWithWildcard) {
|
|
20
|
-
// Pattern like "*middle*" - check if value contains the middle part
|
|
21
|
-
const middle = pattern.slice(1, -1)
|
|
22
|
-
if (middle === '') {
|
|
23
|
-
return true // Pattern is "**", match everything
|
|
24
|
-
}
|
|
25
|
-
return value.includes(middle)
|
|
26
|
-
} else if (startsWithWildcard) {
|
|
27
|
-
// Pattern like "*suffix" - check if value ends with suffix and has content before
|
|
28
|
-
const suffix = pattern.slice(1)
|
|
29
|
-
return value.endsWith(suffix) && value.length > suffix.length
|
|
30
|
-
} else if (endsWithWildcard) {
|
|
31
|
-
// Pattern like "prefix*" - check if value starts with prefix and has content after
|
|
32
|
-
const prefix = pattern.slice(0, -1)
|
|
33
|
-
return value.startsWith(prefix) && value.length > prefix.length
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// No wildcard, exact match
|
|
37
|
-
return value === pattern
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export const matchesFilters = (
|
|
41
|
-
filters: InspectorFilters,
|
|
42
|
-
params: {
|
|
43
|
-
tags?: string[]
|
|
44
|
-
name?: string // Wire/function name for name filter
|
|
45
|
-
},
|
|
46
|
-
meta: {
|
|
47
|
-
type: PikkuWiringTypes
|
|
48
|
-
name: string
|
|
49
|
-
filePath?: string
|
|
50
|
-
httpRoute?: string // For HTTP route filtering
|
|
51
|
-
httpMethod?: string // For HTTP method filtering
|
|
52
|
-
},
|
|
53
|
-
logger: InspectorLogger
|
|
54
|
-
) => {
|
|
55
|
-
// If no filters are provided, allow everything
|
|
56
|
-
if (Object.keys(filters).length === 0) {
|
|
57
|
-
return true
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// If all filter arrays are empty, allow everything
|
|
61
|
-
if (
|
|
62
|
-
(!filters.names || filters.names.length === 0) &&
|
|
63
|
-
(!filters.tags || filters.tags.length === 0) &&
|
|
64
|
-
(!filters.wires || filters.wires.length === 0) &&
|
|
65
|
-
(!filters.excludeWires || filters.excludeWires.length === 0) &&
|
|
66
|
-
(!filters.directories || filters.directories.length === 0) &&
|
|
67
|
-
(!filters.httpRoutes || filters.httpRoutes.length === 0) &&
|
|
68
|
-
(!filters.httpMethods || filters.httpMethods.length === 0)
|
|
69
|
-
) {
|
|
70
|
-
return true
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Check wire include filter
|
|
74
|
-
if (filters.wires && filters.wires.length > 0) {
|
|
75
|
-
if (!filters.wires.includes(meta.type)) {
|
|
76
|
-
logger.debug(`⒡ Filtered by wire include: ${meta.type}:${meta.name}`)
|
|
77
|
-
return false
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Check wire exclude filter
|
|
82
|
-
if (filters.excludeWires && filters.excludeWires.length > 0) {
|
|
83
|
-
if (filters.excludeWires.includes(meta.type)) {
|
|
84
|
-
logger.debug(`⒡ Filtered by wire exclude: ${meta.type}:${meta.name}`)
|
|
85
|
-
return false
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Check directory filter
|
|
90
|
-
if (filters.directories && filters.directories.length > 0) {
|
|
91
|
-
if (!meta.filePath) {
|
|
92
|
-
logger.debug(
|
|
93
|
-
`⒡ Filtered by directory: ${meta.type}:${meta.name} (${meta.filePath})`
|
|
94
|
-
)
|
|
95
|
-
return false
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const matchesDirectory = filters.directories.some((dir) => {
|
|
99
|
-
// Normalize paths for comparison
|
|
100
|
-
const normalizedFilePath = meta.filePath!.replace(/\\/g, '/')
|
|
101
|
-
const normalizedDir = dir.replace(/\\/g, '/')
|
|
102
|
-
return normalizedFilePath.includes(normalizedDir)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
if (!matchesDirectory) {
|
|
106
|
-
logger.debug(
|
|
107
|
-
`⒡ Filtered by directory: ${meta.type}:${meta.name} (${meta.filePath})`
|
|
108
|
-
)
|
|
109
|
-
return false
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Check tag filter
|
|
114
|
-
if (filters.tags && filters.tags.length > 0) {
|
|
115
|
-
if (
|
|
116
|
-
!params.tags ||
|
|
117
|
-
!filters.tags.some((tag) => params.tags!.includes(tag))
|
|
118
|
-
) {
|
|
119
|
-
logger.debug(`⒡ Filtered by tags: ${meta.type}:${meta.name}`)
|
|
120
|
-
return false
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Check name filter (with wildcard support)
|
|
125
|
-
if (filters.names && filters.names.length > 0) {
|
|
126
|
-
const nameToMatch = params.name || meta.name
|
|
127
|
-
const nameMatches = filters.names.some((pattern) =>
|
|
128
|
-
matchesWildcard(nameToMatch, pattern)
|
|
129
|
-
)
|
|
130
|
-
if (!nameMatches) {
|
|
131
|
-
logger.debug(`⒡ Filtered by name: ${meta.type}:${meta.name}`)
|
|
132
|
-
return false
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Check HTTP route filter (with wildcard support)
|
|
137
|
-
if (filters.httpRoutes && filters.httpRoutes.length > 0 && meta.httpRoute) {
|
|
138
|
-
const routeMatches = filters.httpRoutes.some((pattern) =>
|
|
139
|
-
matchesWildcard(meta.httpRoute!, pattern)
|
|
140
|
-
)
|
|
141
|
-
if (!routeMatches) {
|
|
142
|
-
logger.debug(`⒡ Filtered by HTTP route: ${meta.httpRoute}`)
|
|
143
|
-
return false
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Check HTTP method filter
|
|
148
|
-
if (
|
|
149
|
-
filters.httpMethods &&
|
|
150
|
-
filters.httpMethods.length > 0 &&
|
|
151
|
-
meta.httpMethod
|
|
152
|
-
) {
|
|
153
|
-
const normalizedMethod = meta.httpMethod.toUpperCase()
|
|
154
|
-
if (!filters.httpMethods.includes(normalizedMethod)) {
|
|
155
|
-
logger.debug(`⒡ Filtered by HTTP method: ${meta.httpMethod}`)
|
|
156
|
-
return false
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return true
|
|
161
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Finds the common ancestor directory of all the given file paths.
|
|
5
|
-
* This is used to determine the project root directory.
|
|
6
|
-
*
|
|
7
|
-
* @param filePaths - Array of absolute file paths
|
|
8
|
-
* @returns The common ancestor directory path
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* findCommonAncestor([
|
|
12
|
-
* '/Users/yasser/git/pikku/pikku/src/functions/a.ts',
|
|
13
|
-
* '/Users/yasser/git/pikku/pikku/src/routes/b.ts'
|
|
14
|
-
* ])
|
|
15
|
-
* // Returns: '/Users/yasser/git/pikku/pikku'
|
|
16
|
-
*/
|
|
17
|
-
export function findCommonAncestor(filePaths: string[]): string {
|
|
18
|
-
if (filePaths.length === 0) {
|
|
19
|
-
return process.cwd()
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (filePaths.length === 1) {
|
|
23
|
-
return path.dirname(filePaths[0]!)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Normalize all paths and get their directory parts
|
|
27
|
-
const normalizedPaths = filePaths.map((p) =>
|
|
28
|
-
path.dirname(path.normalize(p)).split(path.sep)
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
// Start with the first path's parts
|
|
32
|
-
const firstPath = normalizedPaths[0]!
|
|
33
|
-
let commonParts: string[] = []
|
|
34
|
-
|
|
35
|
-
// Check each part of the first path
|
|
36
|
-
for (let i = 0; i < firstPath.length; i++) {
|
|
37
|
-
const part = firstPath[i]!
|
|
38
|
-
|
|
39
|
-
// Check if this part exists in all other paths at the same position
|
|
40
|
-
const existsInAll = normalizedPaths.every(
|
|
41
|
-
(pathParts) => pathParts[i] === part
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
if (existsInAll) {
|
|
45
|
-
commonParts.push(part)
|
|
46
|
-
} else {
|
|
47
|
-
break
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// If no common parts, return root
|
|
52
|
-
if (commonParts.length === 0) {
|
|
53
|
-
return path.sep
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return commonParts.join(path.sep)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Converts an absolute file path to a relative path from the root directory.
|
|
61
|
-
*
|
|
62
|
-
* @param absolutePath - The absolute file path
|
|
63
|
-
* @param rootDir - The root directory to make the path relative to
|
|
64
|
-
* @returns A relative path from rootDir to the file
|
|
65
|
-
*/
|
|
66
|
-
export function toRelativePath(absolutePath: string, rootDir: string): string {
|
|
67
|
-
return path.relative(rootDir, absolutePath)
|
|
68
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import assert from 'node:assert/strict'
|
|
3
|
-
import * as z from 'zod'
|
|
4
|
-
import { findZodTransform } from './find-zod-transform.js'
|
|
5
|
-
|
|
6
|
-
test('a schema with no transform is reported as clean', () => {
|
|
7
|
-
assert.equal(findZodTransform(z.object({ id: z.string() })), undefined)
|
|
8
|
-
assert.equal(findZodTransform(z.string().min(1).trim()), undefined)
|
|
9
|
-
// a refinement narrows the value, it does not change its shape
|
|
10
|
-
assert.equal(
|
|
11
|
-
findZodTransform(z.object({ id: z.string() }).refine(() => true)),
|
|
12
|
-
undefined
|
|
13
|
-
)
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
test('a transform on the schema itself is found at the root', () => {
|
|
17
|
-
assert.equal(
|
|
18
|
-
findZodTransform(z.object({ id: z.string() }).transform((v) => v)),
|
|
19
|
-
''
|
|
20
|
-
)
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
test('a transform on a field is found by path', () => {
|
|
24
|
-
assert.equal(
|
|
25
|
-
findZodTransform(
|
|
26
|
-
z.object({
|
|
27
|
-
id: z.string(),
|
|
28
|
-
when: z.string().transform((s) => new Date(s)),
|
|
29
|
-
})
|
|
30
|
-
),
|
|
31
|
-
'.when'
|
|
32
|
-
)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('a transform is found through wrappers, arrays and unions', () => {
|
|
36
|
-
assert.equal(
|
|
37
|
-
findZodTransform(
|
|
38
|
-
z.object({ tags: z.array(z.string().transform((s) => s.trim())) })
|
|
39
|
-
),
|
|
40
|
-
'.tags[]'
|
|
41
|
-
)
|
|
42
|
-
assert.equal(
|
|
43
|
-
findZodTransform(z.object({ n: z.string().transform(Number).optional() })),
|
|
44
|
-
'.n'
|
|
45
|
-
)
|
|
46
|
-
assert.equal(
|
|
47
|
-
findZodTransform(
|
|
48
|
-
z.object({ v: z.union([z.string(), z.number().transform(String)]) })
|
|
49
|
-
),
|
|
50
|
-
'.v|1'
|
|
51
|
-
)
|
|
52
|
-
assert.equal(
|
|
53
|
-
findZodTransform(
|
|
54
|
-
z.object({
|
|
55
|
-
m: z.record(
|
|
56
|
-
z.string(),
|
|
57
|
-
z.string().transform((s) => s)
|
|
58
|
-
),
|
|
59
|
-
})
|
|
60
|
-
),
|
|
61
|
-
'.m[]'
|
|
62
|
-
)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
test('a self-referencing schema terminates instead of recursing forever', () => {
|
|
66
|
-
const node: z.ZodType = z.lazy(() =>
|
|
67
|
-
z.object({ name: z.string(), children: z.array(node) })
|
|
68
|
-
)
|
|
69
|
-
assert.equal(findZodTransform(node), undefined)
|
|
70
|
-
})
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Locate a `.transform()` anywhere inside a Zod schema.
|
|
3
|
-
*
|
|
4
|
-
* A transform is why a schema cannot be a function's `input`: the value the
|
|
5
|
-
* caller sends and the value the function receives are different, and a wire
|
|
6
|
-
* contract has to describe one shape. Zod says so twice, in two different
|
|
7
|
-
* places, and neither says it usefully on its own — `toJSONSchema` with
|
|
8
|
-
* `unrepresentable: 'any'` quietly yields `{}`, a schema that accepts
|
|
9
|
-
* everything, and `zodToTs` throws about TypeScript rather than about the
|
|
10
|
-
* wiring. Finding it up front lets the diagnostic name the schema, the path,
|
|
11
|
-
* and the call.
|
|
12
|
-
*
|
|
13
|
-
* Zod 4 models `x.transform(fn)` as a `pipe` whose `out` is a `transform`, so
|
|
14
|
-
* the walk looks for that node rather than for the method.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/** Max nodes visited, so a pathological or cyclic schema cannot hang the walk. */
|
|
18
|
-
const MAX_NODES = 10_000
|
|
19
|
-
|
|
20
|
-
interface ZodNode {
|
|
21
|
-
_zod?: { def?: Record<string, any> }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const isNode = (value: unknown): value is ZodNode =>
|
|
25
|
-
typeof value === 'object' &&
|
|
26
|
-
value !== null &&
|
|
27
|
-
typeof (value as ZodNode)._zod?.def?.type === 'string'
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* The path to the first `.transform()` found — `''` when the transform is the
|
|
31
|
-
* schema itself, `'.user.email'` when it is nested — or `undefined` when there
|
|
32
|
-
* is none.
|
|
33
|
-
*/
|
|
34
|
-
export function findZodTransform(schema: unknown): string | undefined {
|
|
35
|
-
const seen = new Set<unknown>()
|
|
36
|
-
let budget = MAX_NODES
|
|
37
|
-
|
|
38
|
-
const walk = (node: unknown, path: string): string | undefined => {
|
|
39
|
-
if (budget-- <= 0 || !isNode(node) || seen.has(node)) return undefined
|
|
40
|
-
seen.add(node)
|
|
41
|
-
|
|
42
|
-
const def = node._zod!.def!
|
|
43
|
-
if (def.type === 'transform') return path
|
|
44
|
-
|
|
45
|
-
const children: Array<[unknown, string]> = []
|
|
46
|
-
switch (def.type) {
|
|
47
|
-
case 'object':
|
|
48
|
-
case 'interface':
|
|
49
|
-
for (const [key, child] of Object.entries(def.shape ?? {})) {
|
|
50
|
-
children.push([child, `${path}.${key}`])
|
|
51
|
-
}
|
|
52
|
-
break
|
|
53
|
-
case 'array':
|
|
54
|
-
case 'set':
|
|
55
|
-
children.push([def.element, `${path}[]`])
|
|
56
|
-
break
|
|
57
|
-
case 'tuple':
|
|
58
|
-
for (const [i, child] of (def.items ?? []).entries()) {
|
|
59
|
-
children.push([child, `${path}[${i}]`])
|
|
60
|
-
}
|
|
61
|
-
if (def.rest) children.push([def.rest, `${path}[]`])
|
|
62
|
-
break
|
|
63
|
-
case 'union':
|
|
64
|
-
for (const [i, child] of (def.options ?? []).entries()) {
|
|
65
|
-
children.push([child, `${path}|${i}`])
|
|
66
|
-
}
|
|
67
|
-
break
|
|
68
|
-
case 'intersection':
|
|
69
|
-
children.push([def.left, path], [def.right, path])
|
|
70
|
-
break
|
|
71
|
-
case 'record':
|
|
72
|
-
case 'map':
|
|
73
|
-
children.push(
|
|
74
|
-
[def.keyType, `${path}[key]`],
|
|
75
|
-
[def.valueType, `${path}[]`]
|
|
76
|
-
)
|
|
77
|
-
break
|
|
78
|
-
case 'pipe':
|
|
79
|
-
// `.transform()` itself: report the pipe's own path, not `out`'s.
|
|
80
|
-
children.push([def.in, path], [def.out, path])
|
|
81
|
-
break
|
|
82
|
-
default:
|
|
83
|
-
// optional, nullable, default, prefault, nonoptional, readonly, catch,
|
|
84
|
-
// promise, lazy, success — every wrapper Zod spells `innerType`.
|
|
85
|
-
if (def.innerType) children.push([def.innerType, path])
|
|
86
|
-
if (def.getter) {
|
|
87
|
-
try {
|
|
88
|
-
children.push([def.getter(), path])
|
|
89
|
-
} catch {
|
|
90
|
-
// A lazy schema that cannot be forced tells us nothing; skip it.
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
for (const [child, childPath] of children) {
|
|
96
|
-
const found = walk(child, childPath)
|
|
97
|
-
if (found !== undefined) return found
|
|
98
|
-
}
|
|
99
|
-
return undefined
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return walk(schema, '')
|
|
103
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript'
|
|
2
|
-
|
|
3
|
-
const isExportedVariableStatement = (
|
|
4
|
-
statement: ts.Statement
|
|
5
|
-
): statement is ts.VariableStatement =>
|
|
6
|
-
ts.isVariableStatement(statement) &&
|
|
7
|
-
(statement.modifiers?.some(
|
|
8
|
-
(modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword
|
|
9
|
-
) ??
|
|
10
|
-
false)
|
|
11
|
-
|
|
12
|
-
export const getExportedVariableName = (
|
|
13
|
-
node: ts.Node,
|
|
14
|
-
sourceFile: ts.SourceFile | undefined
|
|
15
|
-
): string | null => {
|
|
16
|
-
if (!sourceFile) {
|
|
17
|
-
return null
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
21
|
-
for (const statement of sourceFile.statements) {
|
|
22
|
-
if (!isExportedVariableStatement(statement)) continue
|
|
23
|
-
for (const declaration of statement.declarationList.declarations) {
|
|
24
|
-
if (declaration === node) {
|
|
25
|
-
return node.name.text
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (!ts.isCallExpression(node)) {
|
|
32
|
-
return null
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
for (const statement of sourceFile.statements) {
|
|
36
|
-
if (!isExportedVariableStatement(statement)) continue
|
|
37
|
-
for (const declaration of statement.declarationList.declarations) {
|
|
38
|
-
if (
|
|
39
|
-
ts.isIdentifier(declaration.name) &&
|
|
40
|
-
declaration.initializer === node
|
|
41
|
-
) {
|
|
42
|
-
return declaration.name.text
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return null
|
|
48
|
-
}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
PathToNameAndType,
|
|
3
|
-
InspectorState,
|
|
4
|
-
InspectorOptions,
|
|
5
|
-
} from '../types.js'
|
|
6
|
-
|
|
7
|
-
interface Meta {
|
|
8
|
-
file: string
|
|
9
|
-
variable: string
|
|
10
|
-
type: string
|
|
11
|
-
typePath: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type FilesAndMethods = {
|
|
15
|
-
userSessionType: Meta
|
|
16
|
-
wireServicesType: Meta
|
|
17
|
-
singletonServicesType: Meta
|
|
18
|
-
pikkuConfigType: Meta
|
|
19
|
-
pikkuConfigFactory: Meta
|
|
20
|
-
singletonServicesFactory: Meta
|
|
21
|
-
wireServicesFactory: Meta
|
|
22
|
-
serverLifecycleFactory: Meta
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export type FilesAndMethodsErrors = Map<string, PathToNameAndType>
|
|
26
|
-
|
|
27
|
-
const getMetaTypes = (
|
|
28
|
-
type: string,
|
|
29
|
-
map: PathToNameAndType,
|
|
30
|
-
desiredType?: string,
|
|
31
|
-
errors?: FilesAndMethodsErrors
|
|
32
|
-
): Meta | undefined => {
|
|
33
|
-
if (desiredType) {
|
|
34
|
-
for (const [file, meta] of map.entries()) {
|
|
35
|
-
for (const { type: entryType, variable, typePath } of meta) {
|
|
36
|
-
if (entryType === desiredType) {
|
|
37
|
-
if (entryType === null || typePath === null) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
`Unknown state due to metaType calculation: entryType or typePath is null for ${desiredType} in ${file}`
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
return { file, variable, type: entryType, typePath }
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
if (errors) {
|
|
47
|
-
errors.set(`No ${desiredType} found that extends ${type}`, map)
|
|
48
|
-
}
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const totalValues = Array.from(map.values()).flat()
|
|
53
|
-
|
|
54
|
-
if (totalValues.length === 0) {
|
|
55
|
-
const helpMessage =
|
|
56
|
-
type === 'CoreConfig'
|
|
57
|
-
? `No ${type} found. Make sure you have exported a createConfig function in your codebase:\n\n` +
|
|
58
|
-
`export const createConfig = pikkuConfig(async () => {\n` +
|
|
59
|
-
` return {}\n` +
|
|
60
|
-
`})\n\n` +
|
|
61
|
-
`Possible issues:\n` +
|
|
62
|
-
`- srcDirectories in pikku.config.json doesn't include the file with the createConfig method`
|
|
63
|
-
: `No ${type} found`
|
|
64
|
-
if (errors) {
|
|
65
|
-
errors.set(helpMessage, map)
|
|
66
|
-
}
|
|
67
|
-
} else if (totalValues.length > 1) {
|
|
68
|
-
if (errors) {
|
|
69
|
-
errors.set(`More than one ${type} found`, map)
|
|
70
|
-
}
|
|
71
|
-
} else {
|
|
72
|
-
const entry = Array.from(map.entries())[0]
|
|
73
|
-
if (entry) {
|
|
74
|
-
const [file, [{ type: entryType, variable, typePath }]] = entry
|
|
75
|
-
if (entryType === null || typePath === null) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
`Unknown state due to metaType calculation: entryType or typePath is null for ${type} in ${file}`
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
return { file, type: entryType, variable, typePath }
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export const getFilesAndMethods = (
|
|
88
|
-
{
|
|
89
|
-
singletonServicesTypeImportMap,
|
|
90
|
-
wireServicesTypeImportMap,
|
|
91
|
-
userSessionTypeImportMap,
|
|
92
|
-
configTypeImportMap,
|
|
93
|
-
wireServicesFactories,
|
|
94
|
-
singletonServicesFactories,
|
|
95
|
-
configFactories,
|
|
96
|
-
serverLifecycleFactories,
|
|
97
|
-
}: InspectorState,
|
|
98
|
-
{
|
|
99
|
-
configFileType,
|
|
100
|
-
userSessionType,
|
|
101
|
-
singletonServicesFactoryType,
|
|
102
|
-
wireServicesFactoryType,
|
|
103
|
-
}: InspectorOptions['types'] = {}
|
|
104
|
-
): { result: Partial<FilesAndMethods>; errors: FilesAndMethodsErrors } => {
|
|
105
|
-
const errors: FilesAndMethodsErrors = new Map()
|
|
106
|
-
|
|
107
|
-
const result: Partial<FilesAndMethods> = {
|
|
108
|
-
userSessionType: getMetaTypes(
|
|
109
|
-
'CoreUserSession',
|
|
110
|
-
userSessionTypeImportMap,
|
|
111
|
-
userSessionType,
|
|
112
|
-
errors
|
|
113
|
-
),
|
|
114
|
-
singletonServicesType: getMetaTypes(
|
|
115
|
-
'CoreSingletonServices',
|
|
116
|
-
singletonServicesTypeImportMap,
|
|
117
|
-
undefined,
|
|
118
|
-
errors
|
|
119
|
-
),
|
|
120
|
-
wireServicesType: getMetaTypes(
|
|
121
|
-
'CoreServices',
|
|
122
|
-
wireServicesTypeImportMap,
|
|
123
|
-
undefined,
|
|
124
|
-
errors
|
|
125
|
-
),
|
|
126
|
-
pikkuConfigType: getMetaTypes(
|
|
127
|
-
'CoreConfig',
|
|
128
|
-
configTypeImportMap,
|
|
129
|
-
undefined,
|
|
130
|
-
errors
|
|
131
|
-
),
|
|
132
|
-
pikkuConfigFactory: getMetaTypes(
|
|
133
|
-
'CoreConfig',
|
|
134
|
-
configFactories,
|
|
135
|
-
configFileType,
|
|
136
|
-
errors
|
|
137
|
-
),
|
|
138
|
-
singletonServicesFactory: getMetaTypes(
|
|
139
|
-
'CreateSingletonServices',
|
|
140
|
-
singletonServicesFactories,
|
|
141
|
-
singletonServicesFactoryType,
|
|
142
|
-
errors
|
|
143
|
-
),
|
|
144
|
-
wireServicesFactory: getMetaTypes(
|
|
145
|
-
'CreateWireServices',
|
|
146
|
-
wireServicesFactories,
|
|
147
|
-
wireServicesFactoryType,
|
|
148
|
-
errors
|
|
149
|
-
),
|
|
150
|
-
serverLifecycleFactory: getMetaTypes(
|
|
151
|
-
'ServerLifecycle',
|
|
152
|
-
serverLifecycleFactories
|
|
153
|
-
),
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return { result, errors }
|
|
157
|
-
}
|