@pikku/inspector 0.11.0 → 0.11.1
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 +16 -1
- package/dist/add/add-channel.js +11 -10
- package/dist/add/add-file-with-factory.js +10 -10
- package/dist/add/add-functions.js +57 -43
- package/dist/add/add-http-route.js +5 -4
- package/dist/add/add-mcp-prompt.js +6 -5
- package/dist/add/add-mcp-resource.js +6 -5
- package/dist/add/add-mcp-tool.js +6 -5
- package/dist/add/add-middleware.js +1 -1
- package/dist/add/add-permission.js +1 -1
- package/dist/add/add-queue-worker.js +6 -5
- package/dist/add/add-schedule.js +5 -4
- package/dist/add/add-workflow.d.ts +1 -1
- package/dist/add/add-workflow.js +92 -66
- package/dist/error-codes.d.ts +1 -0
- package/dist/error-codes.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/inspector.js +10 -6
- package/dist/types.d.ts +21 -8
- package/dist/utils/extract-function-node.d.ts +10 -0
- package/dist/utils/extract-function-node.js +38 -0
- package/dist/utils/extract-node-value.d.ts +8 -0
- package/dist/utils/extract-node-value.js +24 -0
- package/dist/utils/extract-service-metadata.d.ts +19 -0
- package/dist/utils/extract-service-metadata.js +244 -0
- package/dist/utils/get-files-and-methods.d.ts +3 -3
- package/dist/utils/get-files-and-methods.js +3 -3
- package/dist/utils/get-property-value.d.ts +13 -6
- package/dist/utils/get-property-value.js +51 -43
- package/dist/utils/post-process.d.ts +9 -0
- package/dist/utils/post-process.js +30 -3
- package/dist/utils/serialize-inspector-state.d.ts +18 -5
- package/dist/utils/serialize-inspector-state.js +12 -10
- package/dist/utils/write-service-metadata.d.ts +13 -0
- package/dist/utils/write-service-metadata.js +37 -0
- package/dist/visit.js +2 -2
- package/dist/workflow/extract-simple-workflow.d.ts +15 -0
- package/dist/workflow/extract-simple-workflow.js +803 -0
- package/dist/workflow/patterns.d.ts +39 -0
- package/dist/workflow/patterns.js +138 -0
- package/dist/workflow/validation.d.ts +28 -0
- package/dist/workflow/validation.js +124 -0
- package/package.json +4 -4
- package/src/add/add-channel.ts +37 -17
- package/src/add/add-file-with-factory.ts +10 -10
- package/src/add/add-functions.ts +72 -56
- package/src/add/add-http-route.ts +10 -5
- package/src/add/add-mcp-prompt.ts +11 -7
- package/src/add/add-mcp-resource.ts +11 -7
- package/src/add/add-mcp-tool.ts +11 -7
- package/src/add/add-middleware.ts +1 -1
- package/src/add/add-permission.ts +1 -1
- package/src/add/add-queue-worker.ts +11 -12
- package/src/add/add-schedule.ts +10 -5
- package/src/add/add-workflow.ts +120 -110
- package/src/error-codes.ts +1 -0
- package/src/index.ts +2 -0
- package/src/inspector.ts +16 -6
- package/src/types.ts +18 -8
- package/src/utils/extract-function-node.ts +58 -0
- package/src/utils/extract-node-value.ts +31 -0
- package/src/utils/extract-service-metadata.ts +353 -0
- package/src/utils/filter-inspector-state.test.ts +3 -3
- package/src/utils/filter-utils.test.ts +45 -51
- package/src/utils/get-files-and-methods.ts +11 -11
- package/src/utils/get-property-value.ts +60 -53
- package/src/utils/permissions.test.ts +3 -3
- package/src/utils/post-process.ts +56 -3
- package/src/utils/serialize-inspector-state.ts +28 -18
- package/src/utils/test-data/inspector-state.json +9 -9
- package/src/utils/write-service-metadata.ts +51 -0
- package/src/visit.ts +3 -3
- package/src/workflow/extract-simple-workflow.ts +1035 -0
- package/src/workflow/patterns.ts +182 -0
- package/src/workflow/validation.ts +153 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/add/add-workflow.ts
CHANGED
|
@@ -1,29 +1,21 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
|
-
import {
|
|
3
|
-
getPropertyValue,
|
|
4
|
-
getPropertyTags,
|
|
5
|
-
} from '../utils/get-property-value.js'
|
|
6
|
-
import { PikkuDocs } from '@pikku/core'
|
|
7
2
|
import { AddWiring, InspectorState } from '../types.js'
|
|
8
3
|
import { extractFunctionName } from '../utils/extract-function-name.js'
|
|
9
|
-
import {
|
|
10
|
-
getPropertyAssignmentInitializer,
|
|
11
|
-
resolveFunctionDeclaration,
|
|
12
|
-
} from '../utils/type-utils.js'
|
|
13
|
-
import { resolveMiddleware } from '../utils/middleware.js'
|
|
14
|
-
import { extractWireNames } from '../utils/post-process.js'
|
|
4
|
+
import { extractFunctionNode } from '../utils/extract-function-node.js'
|
|
15
5
|
import { ErrorCode } from '../error-codes.js'
|
|
16
6
|
import { WorkflowStepMeta } from '@pikku/core/workflow'
|
|
17
7
|
import {
|
|
18
8
|
extractStringLiteral,
|
|
19
|
-
extractNumberLiteral,
|
|
20
|
-
extractPropertyString,
|
|
21
9
|
isStringLike,
|
|
22
10
|
isFunctionLike,
|
|
11
|
+
extractDescription,
|
|
12
|
+
extractDuration,
|
|
23
13
|
} from '../utils/extract-node-value.js'
|
|
14
|
+
import { extractSimpleWorkflow } from '../workflow/extract-simple-workflow.js'
|
|
15
|
+
import { getCommonWireMetaData } from '../utils/get-property-value.js'
|
|
24
16
|
|
|
25
17
|
/**
|
|
26
|
-
* Scan for workflow.do() and workflow.
|
|
18
|
+
* Scan for workflow.do(), workflow.sleep(), and workflow.cancel() calls to extract workflow steps
|
|
27
19
|
*/
|
|
28
20
|
function getWorkflowInvocations(
|
|
29
21
|
node: ts.Node,
|
|
@@ -37,7 +29,7 @@ function getWorkflowInvocations(
|
|
|
37
29
|
const { name } = node
|
|
38
30
|
|
|
39
31
|
// Check if this is accessing 'do' or 'sleep' property
|
|
40
|
-
if (name.text === 'do' || name.text === 'sleep') {
|
|
32
|
+
if (name.text === 'do' || name.text === 'sleep' || name.text === 'cancel') {
|
|
41
33
|
// Check if the parent is a call expression
|
|
42
34
|
const parent = node.parent
|
|
43
35
|
if (ts.isCallExpression(parent) && parent.expression === node) {
|
|
@@ -62,7 +54,6 @@ function getWorkflowInvocations(
|
|
|
62
54
|
type: 'rpc',
|
|
63
55
|
stepName,
|
|
64
56
|
rpcName,
|
|
65
|
-
description,
|
|
66
57
|
})
|
|
67
58
|
state.rpc.invokedFunctions.add(rpcName)
|
|
68
59
|
} else if (isFunctionLike(secondArg)) {
|
|
@@ -86,6 +77,11 @@ function getWorkflowInvocations(
|
|
|
86
77
|
stepName: stepName || '<dynamic>',
|
|
87
78
|
duration: duration || '<dynamic>',
|
|
88
79
|
})
|
|
80
|
+
} else if (name.text === 'cancel') {
|
|
81
|
+
// workflow.cancel(reason?)
|
|
82
|
+
steps.push({
|
|
83
|
+
type: 'cancel',
|
|
84
|
+
})
|
|
89
85
|
}
|
|
90
86
|
}
|
|
91
87
|
}
|
|
@@ -105,43 +101,10 @@ function getWorkflowInvocations(
|
|
|
105
101
|
}
|
|
106
102
|
|
|
107
103
|
/**
|
|
108
|
-
*
|
|
109
|
-
*/
|
|
110
|
-
function extractDescription(
|
|
111
|
-
optionsNode: ts.Node | undefined,
|
|
112
|
-
checker: ts.TypeChecker
|
|
113
|
-
): string | null {
|
|
114
|
-
if (!optionsNode || !ts.isObjectLiteralExpression(optionsNode)) {
|
|
115
|
-
return null
|
|
116
|
-
}
|
|
117
|
-
return extractPropertyString(optionsNode, 'description', checker)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Extract duration value (number or string)
|
|
122
|
-
*/
|
|
123
|
-
function extractDuration(
|
|
124
|
-
node: ts.Node,
|
|
125
|
-
checker: ts.TypeChecker
|
|
126
|
-
): string | number | null {
|
|
127
|
-
const numValue = extractNumberLiteral(node)
|
|
128
|
-
if (numValue !== null) {
|
|
129
|
-
return numValue
|
|
130
|
-
}
|
|
131
|
-
return extractStringLiteral(node, checker)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Inspector for wireWorkflow() calls
|
|
104
|
+
* Inspector for pikkuWorkflow() and pikkuSimpleWorkflow() calls
|
|
136
105
|
* Detects workflow registration and extracts metadata
|
|
137
106
|
*/
|
|
138
|
-
export const addWorkflow: AddWiring = (
|
|
139
|
-
logger,
|
|
140
|
-
node,
|
|
141
|
-
checker,
|
|
142
|
-
state,
|
|
143
|
-
options
|
|
144
|
-
) => {
|
|
107
|
+
export const addWorkflow: AddWiring = (logger, node, checker, state) => {
|
|
145
108
|
if (!ts.isCallExpression(node)) {
|
|
146
109
|
return
|
|
147
110
|
}
|
|
@@ -150,8 +113,16 @@ export const addWorkflow: AddWiring = (
|
|
|
150
113
|
const firstArg = args[0]
|
|
151
114
|
const expression = node.expression
|
|
152
115
|
|
|
153
|
-
|
|
154
|
-
|
|
116
|
+
if (!ts.isIdentifier(expression)) {
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let wrapperType: 'simple' | 'regular' | null = null
|
|
121
|
+
if (expression.text === 'pikkuWorkflowFunc') {
|
|
122
|
+
wrapperType = 'regular'
|
|
123
|
+
} else if (expression.text === 'pikkuSimpleWorkflowFunc') {
|
|
124
|
+
wrapperType = 'simple'
|
|
125
|
+
} else {
|
|
155
126
|
return
|
|
156
127
|
}
|
|
157
128
|
|
|
@@ -159,73 +130,112 @@ export const addWorkflow: AddWiring = (
|
|
|
159
130
|
return
|
|
160
131
|
}
|
|
161
132
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
'func',
|
|
176
|
-
true,
|
|
177
|
-
checker
|
|
133
|
+
// Extract workflow name and metadata using same logic as add-functions
|
|
134
|
+
const { pikkuFuncName, name, exportedName } = extractFunctionName(
|
|
135
|
+
node,
|
|
136
|
+
checker,
|
|
137
|
+
state.rootDir
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
const workflowName = exportedName || name
|
|
141
|
+
|
|
142
|
+
if (!workflowName) {
|
|
143
|
+
logger.critical(
|
|
144
|
+
ErrorCode.MISSING_NAME,
|
|
145
|
+
`Could not determine workflow name from export.`
|
|
178
146
|
)
|
|
147
|
+
return
|
|
148
|
+
}
|
|
179
149
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
ErrorCode.MISSING_NAME,
|
|
183
|
-
`Wasn't able to determine 'name' property for workflow wiring.`
|
|
184
|
-
)
|
|
185
|
-
return
|
|
186
|
-
}
|
|
150
|
+
// Extract the function node (either direct function or from config.func)
|
|
151
|
+
const { funcNode, resolvedFunc } = extractFunctionNode(firstArg, checker)
|
|
187
152
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return
|
|
194
|
-
}
|
|
153
|
+
// Extract metadata if using object form
|
|
154
|
+
let tags: string[] | undefined
|
|
155
|
+
let summary: string | undefined
|
|
156
|
+
let description: string | undefined
|
|
157
|
+
let errors: string[] | undefined
|
|
195
158
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
159
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
160
|
+
const metadata = getCommonWireMetaData(
|
|
161
|
+
firstArg,
|
|
162
|
+
'Workflow',
|
|
163
|
+
workflowName,
|
|
164
|
+
logger
|
|
165
|
+
)
|
|
166
|
+
tags = metadata.tags
|
|
167
|
+
summary = metadata.summary
|
|
168
|
+
description = metadata.description
|
|
169
|
+
errors = metadata.errors
|
|
170
|
+
}
|
|
201
171
|
|
|
202
|
-
|
|
203
|
-
|
|
172
|
+
// Validate that we got a valid function
|
|
173
|
+
if (
|
|
174
|
+
ts.isObjectLiteralExpression(firstArg) &&
|
|
175
|
+
(!funcNode || funcNode === firstArg)
|
|
176
|
+
) {
|
|
177
|
+
logger.critical(
|
|
178
|
+
ErrorCode.MISSING_FUNC,
|
|
179
|
+
`No valid 'func' property for workflow '${workflowName}'.`
|
|
180
|
+
)
|
|
181
|
+
return
|
|
182
|
+
}
|
|
204
183
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
184
|
+
if (!resolvedFunc) {
|
|
185
|
+
logger.critical(
|
|
186
|
+
ErrorCode.MISSING_FUNC,
|
|
187
|
+
`Could not resolve workflow function for '${workflowName}'.`
|
|
209
188
|
)
|
|
189
|
+
return
|
|
190
|
+
}
|
|
210
191
|
|
|
211
|
-
|
|
192
|
+
// Track workflow file for wiring generation
|
|
193
|
+
if (exportedName) {
|
|
194
|
+
state.workflows.files.set(pikkuFuncName, {
|
|
195
|
+
path: node.getSourceFile().fileName,
|
|
196
|
+
exportedName,
|
|
197
|
+
})
|
|
198
|
+
}
|
|
212
199
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
200
|
+
let steps: WorkflowStepMeta[] = []
|
|
201
|
+
let simple: boolean | undefined = undefined
|
|
202
|
+
|
|
203
|
+
// Try simple workflow extraction first
|
|
204
|
+
// Pass the whole CallExpression node so findWorkflowFunction can find the arrow function
|
|
205
|
+
const result = extractSimpleWorkflow(node, checker)
|
|
206
|
+
|
|
207
|
+
if (result.status === 'ok' && result.steps) {
|
|
208
|
+
// Simple extraction succeeded
|
|
209
|
+
steps = result.steps
|
|
210
|
+
simple = true
|
|
211
|
+
} else {
|
|
212
|
+
// Simple extraction failed
|
|
213
|
+
if (wrapperType === 'simple') {
|
|
214
|
+
// For pikkuSimpleWorkflowFunc, this is a critical error
|
|
215
|
+
logger.critical(
|
|
216
|
+
ErrorCode.INVALID_SIMPLE_WORKFLOW,
|
|
217
|
+
`Workflow '${workflowName}' uses pikkuSimpleWorkflowFunc but does not conform to simple workflow DSL:\n${result.reason || 'Unknown error'}`
|
|
218
|
+
)
|
|
219
|
+
return
|
|
220
|
+
} else {
|
|
221
|
+
// For pikkuWorkflowFunc, fall back to basic extraction
|
|
222
|
+
logger.debug(
|
|
223
|
+
`Workflow '${workflowName}' could not be extracted as simple workflow: ${result.reason || 'Unknown error'}. Falling back to basic extraction.`
|
|
224
|
+
)
|
|
225
|
+
simple = false
|
|
219
226
|
}
|
|
227
|
+
}
|
|
220
228
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
229
|
+
getWorkflowInvocations(resolvedFunc, checker, state, workflowName, steps)
|
|
230
|
+
|
|
231
|
+
state.workflows.meta[workflowName] = {
|
|
232
|
+
pikkuFuncName,
|
|
233
|
+
workflowName,
|
|
234
|
+
steps,
|
|
235
|
+
simple,
|
|
236
|
+
summary,
|
|
237
|
+
description,
|
|
238
|
+
errors,
|
|
239
|
+
tags,
|
|
230
240
|
}
|
|
231
241
|
}
|
package/src/error-codes.ts
CHANGED
|
@@ -21,6 +21,7 @@ export enum ErrorCode {
|
|
|
21
21
|
CLI_CLIENTSIDE_RENDERER_HAS_SERVICES = 'PKU672',
|
|
22
22
|
DYNAMIC_STEP_NAME = 'PKU529',
|
|
23
23
|
WORKFLOW_ORCHESTRATOR_NOT_CONFIGURED = 'PKU600',
|
|
24
|
+
INVALID_SIMPLE_WORKFLOW = 'PKU641',
|
|
24
25
|
|
|
25
26
|
// Configuration errors
|
|
26
27
|
CONFIG_TYPE_NOT_FOUND = 'PKU426',
|
package/src/index.ts
CHANGED
|
@@ -14,3 +14,5 @@ export {
|
|
|
14
14
|
} from './utils/serialize-inspector-state.js'
|
|
15
15
|
export type { SerializableInspectorState } from './utils/serialize-inspector-state.js'
|
|
16
16
|
export { filterInspectorState } from './utils/filter-inspector-state.js'
|
|
17
|
+
export { writeAllServiceMetadata } from './utils/write-service-metadata.js'
|
|
18
|
+
export type { ServiceMetadata } from './utils/extract-service-metadata.js'
|
package/src/inspector.ts
CHANGED
|
@@ -5,7 +5,10 @@ import { TypesMap } from './types-map.js'
|
|
|
5
5
|
import { InspectorState, InspectorLogger, InspectorOptions } from './types.js'
|
|
6
6
|
import { getFilesAndMethods } from './utils/get-files-and-methods.js'
|
|
7
7
|
import { findCommonAncestor } from './utils/find-root-dir.js'
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
aggregateRequiredServices,
|
|
10
|
+
extractServiceInterfaceMetadata,
|
|
11
|
+
} from './utils/post-process.js'
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Creates an initial/empty inspector state with all required properties initialized
|
|
@@ -16,12 +19,12 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
|
|
|
16
19
|
return {
|
|
17
20
|
rootDir,
|
|
18
21
|
singletonServicesTypeImportMap: new Map(),
|
|
19
|
-
|
|
22
|
+
wireServicesTypeImportMap: new Map(),
|
|
20
23
|
userSessionTypeImportMap: new Map(),
|
|
21
24
|
configTypeImportMap: new Map(),
|
|
22
25
|
singletonServicesFactories: new Map(),
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
wireServicesFactories: new Map(),
|
|
27
|
+
wireServicesMeta: new Map(),
|
|
25
28
|
configFactories: new Map(),
|
|
26
29
|
filesAndMethods: {},
|
|
27
30
|
filesAndMethodsErrors: new Map(),
|
|
@@ -60,7 +63,7 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
|
|
|
60
63
|
},
|
|
61
64
|
workflows: {
|
|
62
65
|
meta: {},
|
|
63
|
-
files: new
|
|
66
|
+
files: new Map(),
|
|
64
67
|
},
|
|
65
68
|
rpc: {
|
|
66
69
|
internalMeta: {},
|
|
@@ -96,8 +99,9 @@ export function getInitialInspectorState(rootDir: string): InspectorState {
|
|
|
96
99
|
usedMiddleware: new Set(),
|
|
97
100
|
usedPermissions: new Set(),
|
|
98
101
|
allSingletonServices: [],
|
|
99
|
-
|
|
102
|
+
allWireServices: [],
|
|
100
103
|
},
|
|
104
|
+
serviceMetadata: [],
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
|
|
@@ -177,6 +181,12 @@ export const inspect = (
|
|
|
177
181
|
logger.debug(
|
|
178
182
|
`Aggregate required services completed in ${(performance.now() - startAggregate).toFixed(2)}ms`
|
|
179
183
|
)
|
|
184
|
+
|
|
185
|
+
const startServiceMeta = performance.now()
|
|
186
|
+
extractServiceInterfaceMetadata(state, checker)
|
|
187
|
+
logger.debug(
|
|
188
|
+
`Extract service metadata completed in ${(performance.now() - startServiceMeta).toFixed(2)}ms`
|
|
189
|
+
)
|
|
180
190
|
}
|
|
181
191
|
|
|
182
192
|
return state
|
package/src/types.ts
CHANGED
|
@@ -120,7 +120,7 @@ export type InspectorOptions = Partial<{
|
|
|
120
120
|
configFileType: string
|
|
121
121
|
userSessionType: string
|
|
122
122
|
singletonServicesFactoryType: string
|
|
123
|
-
|
|
123
|
+
wireServicesFactoryType: string
|
|
124
124
|
}>
|
|
125
125
|
}>
|
|
126
126
|
|
|
@@ -147,7 +147,7 @@ export interface InspectorFilesAndMethods {
|
|
|
147
147
|
type: string
|
|
148
148
|
typePath: string
|
|
149
149
|
}
|
|
150
|
-
|
|
150
|
+
wireServicesType?: {
|
|
151
151
|
file: string
|
|
152
152
|
variable: string
|
|
153
153
|
type: string
|
|
@@ -177,7 +177,7 @@ export interface InspectorFilesAndMethods {
|
|
|
177
177
|
type: string
|
|
178
178
|
typePath: string
|
|
179
179
|
}
|
|
180
|
-
|
|
180
|
+
wireServicesFactory?: {
|
|
181
181
|
file: string
|
|
182
182
|
variable: string
|
|
183
183
|
type: string
|
|
@@ -188,12 +188,12 @@ export interface InspectorFilesAndMethods {
|
|
|
188
188
|
export interface InspectorState {
|
|
189
189
|
rootDir: string // Root directory inferred from source files
|
|
190
190
|
singletonServicesTypeImportMap: PathToNameAndType
|
|
191
|
-
|
|
191
|
+
wireServicesTypeImportMap: PathToNameAndType
|
|
192
192
|
userSessionTypeImportMap: PathToNameAndType
|
|
193
193
|
configTypeImportMap: PathToNameAndType
|
|
194
194
|
singletonServicesFactories: PathToNameAndType
|
|
195
|
-
|
|
196
|
-
|
|
195
|
+
wireServicesFactories: PathToNameAndType
|
|
196
|
+
wireServicesMeta: Map<string, string[]> // variable name -> singleton services consumed
|
|
197
197
|
configFactories: PathToNameAndType
|
|
198
198
|
filesAndMethods: InspectorFilesAndMethods
|
|
199
199
|
filesAndMethodsErrors: Map<string, PathToNameAndType>
|
|
@@ -211,7 +211,7 @@ export interface InspectorState {
|
|
|
211
211
|
}
|
|
212
212
|
workflows: {
|
|
213
213
|
meta: WorkflowsMeta
|
|
214
|
-
files:
|
|
214
|
+
files: Map<string, { path: string; exportedName: string }>
|
|
215
215
|
}
|
|
216
216
|
rpc: {
|
|
217
217
|
internalMeta: Record<string, string>
|
|
@@ -238,6 +238,16 @@ export interface InspectorState {
|
|
|
238
238
|
usedMiddleware: Set<string> // Middleware names used by wired functions
|
|
239
239
|
usedPermissions: Set<string> // Permission names used by wired functions
|
|
240
240
|
allSingletonServices: string[] // All services available in SingletonServices type
|
|
241
|
-
|
|
241
|
+
allWireServices: string[] // All services available in Services type (excluding SingletonServices)
|
|
242
242
|
}
|
|
243
|
+
serviceMetadata: Array<{
|
|
244
|
+
name: string
|
|
245
|
+
summary: string
|
|
246
|
+
description: string
|
|
247
|
+
package: string
|
|
248
|
+
path: string
|
|
249
|
+
version: string
|
|
250
|
+
interface: string
|
|
251
|
+
expandedProperties: Record<string, string>
|
|
252
|
+
}>
|
|
243
253
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import {
|
|
3
|
+
getPropertyAssignmentInitializer,
|
|
4
|
+
resolveFunctionDeclaration,
|
|
5
|
+
} from './type-utils.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Extracts the actual function node from a pikkuFunc/pikkuWorkflowFunc call
|
|
9
|
+
* Handles both direct function form and config object form { func: ... }
|
|
10
|
+
*/
|
|
11
|
+
export function extractFunctionNode(
|
|
12
|
+
firstArg: ts.Expression,
|
|
13
|
+
checker: ts.TypeChecker
|
|
14
|
+
): {
|
|
15
|
+
funcNode: ts.Node
|
|
16
|
+
resolvedFunc: ts.Node | null
|
|
17
|
+
isDirectFunction: boolean
|
|
18
|
+
} {
|
|
19
|
+
let funcNode: ts.Node = firstArg
|
|
20
|
+
let isDirectFunction = true
|
|
21
|
+
|
|
22
|
+
// Check if first argument is a config object with 'func' property
|
|
23
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
24
|
+
isDirectFunction = false
|
|
25
|
+
const funcInitializer = getPropertyAssignmentInitializer(
|
|
26
|
+
firstArg,
|
|
27
|
+
'func',
|
|
28
|
+
true,
|
|
29
|
+
checker
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if (funcInitializer) {
|
|
33
|
+
funcNode = funcInitializer
|
|
34
|
+
} else {
|
|
35
|
+
// Return the original node if no func property found
|
|
36
|
+
// Caller should handle validation
|
|
37
|
+
funcNode = firstArg
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Resolve identifier to get the actual function node
|
|
42
|
+
if (ts.isIdentifier(funcNode)) {
|
|
43
|
+
const symbol = checker.getSymbolAtLocation(funcNode)
|
|
44
|
+
const decl = symbol?.valueDeclaration || symbol?.declarations?.[0]
|
|
45
|
+
if (decl && ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
46
|
+
funcNode = decl.initializer
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Resolve function declaration for deeper analysis
|
|
51
|
+
const resolvedFunc = resolveFunctionDeclaration(funcNode, checker)
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
funcNode,
|
|
55
|
+
resolvedFunc,
|
|
56
|
+
isDirectFunction,
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -99,3 +99,34 @@ export function extractPropertyString(
|
|
|
99
99
|
}
|
|
100
100
|
return null
|
|
101
101
|
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Extract description from options object
|
|
105
|
+
*/
|
|
106
|
+
export function extractDescription(
|
|
107
|
+
optionsNode: ts.Node | undefined,
|
|
108
|
+
checker: ts.TypeChecker
|
|
109
|
+
): string | null {
|
|
110
|
+
if (!optionsNode || !ts.isObjectLiteralExpression(optionsNode)) {
|
|
111
|
+
return null
|
|
112
|
+
}
|
|
113
|
+
return extractPropertyString(optionsNode, 'description', checker)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Extract duration value (number or string)
|
|
118
|
+
*/
|
|
119
|
+
export function extractDuration(
|
|
120
|
+
node: ts.Node,
|
|
121
|
+
checker: ts.TypeChecker
|
|
122
|
+
): string | number | null {
|
|
123
|
+
const numValue = extractNumberLiteral(node)
|
|
124
|
+
if (numValue !== null) {
|
|
125
|
+
return numValue
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
return extractStringLiteral(node, checker)
|
|
129
|
+
} catch {
|
|
130
|
+
return null
|
|
131
|
+
}
|
|
132
|
+
}
|