@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/dist/add/add-workflow.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
|
|
3
2
|
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
4
|
-
import {
|
|
5
|
-
import { resolveMiddleware } from '../utils/middleware.js';
|
|
6
|
-
import { extractWireNames } from '../utils/post-process.js';
|
|
3
|
+
import { extractFunctionNode } from '../utils/extract-function-node.js';
|
|
7
4
|
import { ErrorCode } from '../error-codes.js';
|
|
8
|
-
import { extractStringLiteral,
|
|
5
|
+
import { extractStringLiteral, isStringLike, isFunctionLike, extractDescription, extractDuration, } from '../utils/extract-node-value.js';
|
|
6
|
+
import { extractSimpleWorkflow } from '../workflow/extract-simple-workflow.js';
|
|
7
|
+
import { getCommonWireMetaData } from '../utils/get-property-value.js';
|
|
9
8
|
/**
|
|
10
|
-
* Scan for workflow.do() and workflow.
|
|
9
|
+
* Scan for workflow.do(), workflow.sleep(), and workflow.cancel() calls to extract workflow steps
|
|
11
10
|
*/
|
|
12
11
|
function getWorkflowInvocations(node, checker, state, workflowName, steps) {
|
|
13
12
|
// Look for property access expressions: workflow.do or workflow.sleep
|
|
14
13
|
if (ts.isPropertyAccessExpression(node)) {
|
|
15
14
|
const { name } = node;
|
|
16
15
|
// Check if this is accessing 'do' or 'sleep' property
|
|
17
|
-
if (name.text === 'do' || name.text === 'sleep') {
|
|
16
|
+
if (name.text === 'do' || name.text === 'sleep' || name.text === 'cancel') {
|
|
18
17
|
// Check if the parent is a call expression
|
|
19
18
|
const parent = node.parent;
|
|
20
19
|
if (ts.isCallExpression(parent) && parent.expression === node) {
|
|
@@ -34,7 +33,6 @@ function getWorkflowInvocations(node, checker, state, workflowName, steps) {
|
|
|
34
33
|
type: 'rpc',
|
|
35
34
|
stepName,
|
|
36
35
|
rpcName,
|
|
37
|
-
description,
|
|
38
36
|
});
|
|
39
37
|
state.rpc.invokedFunctions.add(rpcName);
|
|
40
38
|
}
|
|
@@ -59,6 +57,12 @@ function getWorkflowInvocations(node, checker, state, workflowName, steps) {
|
|
|
59
57
|
duration: duration || '<dynamic>',
|
|
60
58
|
});
|
|
61
59
|
}
|
|
60
|
+
else if (name.text === 'cancel') {
|
|
61
|
+
// workflow.cancel(reason?)
|
|
62
|
+
steps.push({
|
|
63
|
+
type: 'cancel',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
}
|
|
@@ -73,80 +77,102 @@ function getWorkflowInvocations(node, checker, state, workflowName, steps) {
|
|
|
73
77
|
});
|
|
74
78
|
}
|
|
75
79
|
/**
|
|
76
|
-
*
|
|
77
|
-
*/
|
|
78
|
-
function extractDescription(optionsNode, checker) {
|
|
79
|
-
if (!optionsNode || !ts.isObjectLiteralExpression(optionsNode)) {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
return extractPropertyString(optionsNode, 'description', checker);
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Extract duration value (number or string)
|
|
86
|
-
*/
|
|
87
|
-
function extractDuration(node, checker) {
|
|
88
|
-
const numValue = extractNumberLiteral(node);
|
|
89
|
-
if (numValue !== null) {
|
|
90
|
-
return numValue;
|
|
91
|
-
}
|
|
92
|
-
return extractStringLiteral(node, checker);
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Inspector for wireWorkflow() calls
|
|
80
|
+
* Inspector for pikkuWorkflow() and pikkuSimpleWorkflow() calls
|
|
96
81
|
* Detects workflow registration and extracts metadata
|
|
97
82
|
*/
|
|
98
|
-
export const addWorkflow = (logger, node, checker, state
|
|
83
|
+
export const addWorkflow = (logger, node, checker, state) => {
|
|
99
84
|
if (!ts.isCallExpression(node)) {
|
|
100
85
|
return;
|
|
101
86
|
}
|
|
102
87
|
const args = node.arguments;
|
|
103
88
|
const firstArg = args[0];
|
|
104
89
|
const expression = node.expression;
|
|
105
|
-
|
|
106
|
-
|
|
90
|
+
if (!ts.isIdentifier(expression)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
let wrapperType = null;
|
|
94
|
+
if (expression.text === 'pikkuWorkflowFunc') {
|
|
95
|
+
wrapperType = 'regular';
|
|
96
|
+
}
|
|
97
|
+
else if (expression.text === 'pikkuSimpleWorkflowFunc') {
|
|
98
|
+
wrapperType = 'simple';
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
107
101
|
return;
|
|
108
102
|
}
|
|
109
103
|
if (!firstArg) {
|
|
110
104
|
return;
|
|
111
105
|
}
|
|
106
|
+
// Extract workflow name and metadata using same logic as add-functions
|
|
107
|
+
const { pikkuFuncName, name, exportedName } = extractFunctionName(node, checker, state.rootDir);
|
|
108
|
+
const workflowName = exportedName || name;
|
|
109
|
+
if (!workflowName) {
|
|
110
|
+
logger.critical(ErrorCode.MISSING_NAME, `Could not determine workflow name from export.`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
// Extract the function node (either direct function or from config.func)
|
|
114
|
+
const { funcNode, resolvedFunc } = extractFunctionNode(firstArg, checker);
|
|
115
|
+
// Extract metadata if using object form
|
|
116
|
+
let tags;
|
|
117
|
+
let summary;
|
|
118
|
+
let description;
|
|
119
|
+
let errors;
|
|
112
120
|
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
121
|
+
const metadata = getCommonWireMetaData(firstArg, 'Workflow', workflowName, logger);
|
|
122
|
+
tags = metadata.tags;
|
|
123
|
+
summary = metadata.summary;
|
|
124
|
+
description = metadata.description;
|
|
125
|
+
errors = metadata.errors;
|
|
126
|
+
}
|
|
127
|
+
// Validate that we got a valid function
|
|
128
|
+
if (ts.isObjectLiteralExpression(firstArg) &&
|
|
129
|
+
(!funcNode || funcNode === firstArg)) {
|
|
130
|
+
logger.critical(ErrorCode.MISSING_FUNC, `No valid 'func' property for workflow '${workflowName}'.`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (!resolvedFunc) {
|
|
134
|
+
logger.critical(ErrorCode.MISSING_FUNC, `Could not resolve workflow function for '${workflowName}'.`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// Track workflow file for wiring generation
|
|
138
|
+
if (exportedName) {
|
|
139
|
+
state.workflows.files.set(pikkuFuncName, {
|
|
140
|
+
path: node.getSourceFile().fileName,
|
|
141
|
+
exportedName,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
let steps = [];
|
|
145
|
+
let simple = undefined;
|
|
146
|
+
// Try simple workflow extraction first
|
|
147
|
+
// Pass the whole CallExpression node so findWorkflowFunction can find the arrow function
|
|
148
|
+
const result = extractSimpleWorkflow(node, checker);
|
|
149
|
+
if (result.status === 'ok' && result.steps) {
|
|
150
|
+
// Simple extraction succeeded
|
|
151
|
+
steps = result.steps;
|
|
152
|
+
simple = true;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Simple extraction failed
|
|
156
|
+
if (wrapperType === 'simple') {
|
|
157
|
+
// For pikkuSimpleWorkflowFunc, this is a critical error
|
|
158
|
+
logger.critical(ErrorCode.INVALID_SIMPLE_WORKFLOW, `Workflow '${workflowName}' uses pikkuSimpleWorkflowFunc but does not conform to simple workflow DSL:\n${result.reason || 'Unknown error'}`);
|
|
126
159
|
return;
|
|
127
160
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
state.serviceAggregation.usedFunctions.add(pikkuFuncName);
|
|
133
|
-
extractWireNames(middleware).forEach((name) => state.serviceAggregation.usedMiddleware.add(name));
|
|
134
|
-
state.workflows.files.add(node.getSourceFile().fileName);
|
|
135
|
-
// Extract workflow steps from function body
|
|
136
|
-
// Resolve the identifier to the actual function declaration
|
|
137
|
-
const resolvedFunc = resolveFunctionDeclaration(funcInitializer, checker);
|
|
138
|
-
const steps = [];
|
|
139
|
-
if (resolvedFunc) {
|
|
140
|
-
getWorkflowInvocations(resolvedFunc, checker, state, workflowName, steps);
|
|
161
|
+
else {
|
|
162
|
+
// For pikkuWorkflowFunc, fall back to basic extraction
|
|
163
|
+
logger.debug(`Workflow '${workflowName}' could not be extracted as simple workflow: ${result.reason || 'Unknown error'}. Falling back to basic extraction.`);
|
|
164
|
+
simple = false;
|
|
141
165
|
}
|
|
142
|
-
state.workflows.meta[workflowName] = {
|
|
143
|
-
pikkuFuncName,
|
|
144
|
-
workflowName,
|
|
145
|
-
description,
|
|
146
|
-
docs,
|
|
147
|
-
tags,
|
|
148
|
-
middleware,
|
|
149
|
-
steps,
|
|
150
|
-
};
|
|
151
166
|
}
|
|
167
|
+
getWorkflowInvocations(resolvedFunc, checker, state, workflowName, steps);
|
|
168
|
+
state.workflows.meta[workflowName] = {
|
|
169
|
+
pikkuFuncName,
|
|
170
|
+
workflowName,
|
|
171
|
+
steps,
|
|
172
|
+
simple,
|
|
173
|
+
summary,
|
|
174
|
+
description,
|
|
175
|
+
errors,
|
|
176
|
+
tags,
|
|
177
|
+
};
|
|
152
178
|
};
|
package/dist/error-codes.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export declare enum ErrorCode {
|
|
|
19
19
|
CLI_CLIENTSIDE_RENDERER_HAS_SERVICES = "PKU672",
|
|
20
20
|
DYNAMIC_STEP_NAME = "PKU529",
|
|
21
21
|
WORKFLOW_ORCHESTRATOR_NOT_CONFIGURED = "PKU600",
|
|
22
|
+
INVALID_SIMPLE_WORKFLOW = "PKU641",
|
|
22
23
|
CONFIG_TYPE_NOT_FOUND = "PKU426",
|
|
23
24
|
CONFIG_TYPE_UNDEFINED = "PKU427",
|
|
24
25
|
SCHEMA_NO_ROOT = "PKU431",
|
package/dist/error-codes.js
CHANGED
|
@@ -21,6 +21,7 @@ export var ErrorCode;
|
|
|
21
21
|
ErrorCode["CLI_CLIENTSIDE_RENDERER_HAS_SERVICES"] = "PKU672";
|
|
22
22
|
ErrorCode["DYNAMIC_STEP_NAME"] = "PKU529";
|
|
23
23
|
ErrorCode["WORKFLOW_ORCHESTRATOR_NOT_CONFIGURED"] = "PKU600";
|
|
24
|
+
ErrorCode["INVALID_SIMPLE_WORKFLOW"] = "PKU641";
|
|
24
25
|
// Configuration errors
|
|
25
26
|
ErrorCode["CONFIG_TYPE_NOT_FOUND"] = "PKU426";
|
|
26
27
|
ErrorCode["CONFIG_TYPE_UNDEFINED"] = "PKU427";
|
package/dist/index.d.ts
CHANGED
|
@@ -8,3 +8,5 @@ export { ErrorCode } from './error-codes.js';
|
|
|
8
8
|
export { serializeInspectorState, deserializeInspectorState, } from './utils/serialize-inspector-state.js';
|
|
9
9
|
export type { SerializableInspectorState } from './utils/serialize-inspector-state.js';
|
|
10
10
|
export { filterInspectorState } from './utils/filter-inspector-state.js';
|
|
11
|
+
export { writeAllServiceMetadata } from './utils/write-service-metadata.js';
|
|
12
|
+
export type { ServiceMetadata } from './utils/extract-service-metadata.js';
|
package/dist/index.js
CHANGED
|
@@ -3,3 +3,4 @@ export { getFilesAndMethods } from './utils/get-files-and-methods.js';
|
|
|
3
3
|
export { ErrorCode } from './error-codes.js';
|
|
4
4
|
export { serializeInspectorState, deserializeInspectorState, } from './utils/serialize-inspector-state.js';
|
|
5
5
|
export { filterInspectorState } from './utils/filter-inspector-state.js';
|
|
6
|
+
export { writeAllServiceMetadata } from './utils/write-service-metadata.js';
|
package/dist/inspector.js
CHANGED
|
@@ -4,7 +4,7 @@ import { visitSetup, visitRoutes } from './visit.js';
|
|
|
4
4
|
import { TypesMap } from './types-map.js';
|
|
5
5
|
import { getFilesAndMethods } from './utils/get-files-and-methods.js';
|
|
6
6
|
import { findCommonAncestor } from './utils/find-root-dir.js';
|
|
7
|
-
import { aggregateRequiredServices } from './utils/post-process.js';
|
|
7
|
+
import { aggregateRequiredServices, extractServiceInterfaceMetadata, } from './utils/post-process.js';
|
|
8
8
|
/**
|
|
9
9
|
* Creates an initial/empty inspector state with all required properties initialized
|
|
10
10
|
* @param rootDir - The root directory for the project
|
|
@@ -14,12 +14,12 @@ export function getInitialInspectorState(rootDir) {
|
|
|
14
14
|
return {
|
|
15
15
|
rootDir,
|
|
16
16
|
singletonServicesTypeImportMap: new Map(),
|
|
17
|
-
|
|
17
|
+
wireServicesTypeImportMap: new Map(),
|
|
18
18
|
userSessionTypeImportMap: new Map(),
|
|
19
19
|
configTypeImportMap: new Map(),
|
|
20
20
|
singletonServicesFactories: new Map(),
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
wireServicesFactories: new Map(),
|
|
22
|
+
wireServicesMeta: new Map(),
|
|
23
23
|
configFactories: new Map(),
|
|
24
24
|
filesAndMethods: {},
|
|
25
25
|
filesAndMethodsErrors: new Map(),
|
|
@@ -58,7 +58,7 @@ export function getInitialInspectorState(rootDir) {
|
|
|
58
58
|
},
|
|
59
59
|
workflows: {
|
|
60
60
|
meta: {},
|
|
61
|
-
files: new
|
|
61
|
+
files: new Map(),
|
|
62
62
|
},
|
|
63
63
|
rpc: {
|
|
64
64
|
internalMeta: {},
|
|
@@ -94,8 +94,9 @@ export function getInitialInspectorState(rootDir) {
|
|
|
94
94
|
usedMiddleware: new Set(),
|
|
95
95
|
usedPermissions: new Set(),
|
|
96
96
|
allSingletonServices: [],
|
|
97
|
-
|
|
97
|
+
allWireServices: [],
|
|
98
98
|
},
|
|
99
|
+
serviceMetadata: [],
|
|
99
100
|
};
|
|
100
101
|
}
|
|
101
102
|
export const inspect = (logger, routeFiles, options = {}) => {
|
|
@@ -144,6 +145,9 @@ export const inspect = (logger, routeFiles, options = {}) => {
|
|
|
144
145
|
const startAggregate = performance.now();
|
|
145
146
|
aggregateRequiredServices(state);
|
|
146
147
|
logger.debug(`Aggregate required services completed in ${(performance.now() - startAggregate).toFixed(2)}ms`);
|
|
148
|
+
const startServiceMeta = performance.now();
|
|
149
|
+
extractServiceInterfaceMetadata(state, checker);
|
|
150
|
+
logger.debug(`Extract service metadata completed in ${(performance.now() - startServiceMeta).toFixed(2)}ms`);
|
|
147
151
|
}
|
|
148
152
|
return state;
|
|
149
153
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -92,7 +92,7 @@ export type InspectorOptions = Partial<{
|
|
|
92
92
|
configFileType: string;
|
|
93
93
|
userSessionType: string;
|
|
94
94
|
singletonServicesFactoryType: string;
|
|
95
|
-
|
|
95
|
+
wireServicesFactoryType: string;
|
|
96
96
|
}>;
|
|
97
97
|
}>;
|
|
98
98
|
export interface InspectorLogger {
|
|
@@ -111,7 +111,7 @@ export interface InspectorFilesAndMethods {
|
|
|
111
111
|
type: string;
|
|
112
112
|
typePath: string;
|
|
113
113
|
};
|
|
114
|
-
|
|
114
|
+
wireServicesType?: {
|
|
115
115
|
file: string;
|
|
116
116
|
variable: string;
|
|
117
117
|
type: string;
|
|
@@ -141,7 +141,7 @@ export interface InspectorFilesAndMethods {
|
|
|
141
141
|
type: string;
|
|
142
142
|
typePath: string;
|
|
143
143
|
};
|
|
144
|
-
|
|
144
|
+
wireServicesFactory?: {
|
|
145
145
|
file: string;
|
|
146
146
|
variable: string;
|
|
147
147
|
type: string;
|
|
@@ -151,12 +151,12 @@ export interface InspectorFilesAndMethods {
|
|
|
151
151
|
export interface InspectorState {
|
|
152
152
|
rootDir: string;
|
|
153
153
|
singletonServicesTypeImportMap: PathToNameAndType;
|
|
154
|
-
|
|
154
|
+
wireServicesTypeImportMap: PathToNameAndType;
|
|
155
155
|
userSessionTypeImportMap: PathToNameAndType;
|
|
156
156
|
configTypeImportMap: PathToNameAndType;
|
|
157
157
|
singletonServicesFactories: PathToNameAndType;
|
|
158
|
-
|
|
159
|
-
|
|
158
|
+
wireServicesFactories: PathToNameAndType;
|
|
159
|
+
wireServicesMeta: Map<string, string[]>;
|
|
160
160
|
configFactories: PathToNameAndType;
|
|
161
161
|
filesAndMethods: InspectorFilesAndMethods;
|
|
162
162
|
filesAndMethodsErrors: Map<string, PathToNameAndType>;
|
|
@@ -174,7 +174,10 @@ export interface InspectorState {
|
|
|
174
174
|
};
|
|
175
175
|
workflows: {
|
|
176
176
|
meta: WorkflowsMeta;
|
|
177
|
-
files:
|
|
177
|
+
files: Map<string, {
|
|
178
|
+
path: string;
|
|
179
|
+
exportedName: string;
|
|
180
|
+
}>;
|
|
178
181
|
};
|
|
179
182
|
rpc: {
|
|
180
183
|
internalMeta: Record<string, string>;
|
|
@@ -207,6 +210,16 @@ export interface InspectorState {
|
|
|
207
210
|
usedMiddleware: Set<string>;
|
|
208
211
|
usedPermissions: Set<string>;
|
|
209
212
|
allSingletonServices: string[];
|
|
210
|
-
|
|
213
|
+
allWireServices: string[];
|
|
211
214
|
};
|
|
215
|
+
serviceMetadata: Array<{
|
|
216
|
+
name: string;
|
|
217
|
+
summary: string;
|
|
218
|
+
description: string;
|
|
219
|
+
package: string;
|
|
220
|
+
path: string;
|
|
221
|
+
version: string;
|
|
222
|
+
interface: string;
|
|
223
|
+
expandedProperties: Record<string, string>;
|
|
224
|
+
}>;
|
|
212
225
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts the actual function node from a pikkuFunc/pikkuWorkflowFunc call
|
|
4
|
+
* Handles both direct function form and config object form { func: ... }
|
|
5
|
+
*/
|
|
6
|
+
export declare function extractFunctionNode(firstArg: ts.Expression, checker: ts.TypeChecker): {
|
|
7
|
+
funcNode: ts.Node;
|
|
8
|
+
resolvedFunc: ts.Node | null;
|
|
9
|
+
isDirectFunction: boolean;
|
|
10
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyAssignmentInitializer, resolveFunctionDeclaration, } from './type-utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extracts the actual function node from a pikkuFunc/pikkuWorkflowFunc call
|
|
5
|
+
* Handles both direct function form and config object form { func: ... }
|
|
6
|
+
*/
|
|
7
|
+
export function extractFunctionNode(firstArg, checker) {
|
|
8
|
+
let funcNode = firstArg;
|
|
9
|
+
let isDirectFunction = true;
|
|
10
|
+
// Check if first argument is a config object with 'func' property
|
|
11
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
12
|
+
isDirectFunction = false;
|
|
13
|
+
const funcInitializer = getPropertyAssignmentInitializer(firstArg, 'func', true, checker);
|
|
14
|
+
if (funcInitializer) {
|
|
15
|
+
funcNode = funcInitializer;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
// Return the original node if no func property found
|
|
19
|
+
// Caller should handle validation
|
|
20
|
+
funcNode = firstArg;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// Resolve identifier to get the actual function node
|
|
24
|
+
if (ts.isIdentifier(funcNode)) {
|
|
25
|
+
const symbol = checker.getSymbolAtLocation(funcNode);
|
|
26
|
+
const decl = symbol?.valueDeclaration || symbol?.declarations?.[0];
|
|
27
|
+
if (decl && ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
28
|
+
funcNode = decl.initializer;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Resolve function declaration for deeper analysis
|
|
32
|
+
const resolvedFunc = resolveFunctionDeclaration(funcNode, checker);
|
|
33
|
+
return {
|
|
34
|
+
funcNode,
|
|
35
|
+
resolvedFunc,
|
|
36
|
+
isDirectFunction,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -22,3 +22,11 @@ export declare function extractNumberLiteral(node: ts.Node): number | null;
|
|
|
22
22
|
* Returns the extracted value or null if not found/cannot extract
|
|
23
23
|
*/
|
|
24
24
|
export declare function extractPropertyString(objNode: ts.ObjectLiteralExpression, propertyName: string, checker: ts.TypeChecker): string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Extract description from options object
|
|
27
|
+
*/
|
|
28
|
+
export declare function extractDescription(optionsNode: ts.Node | undefined, checker: ts.TypeChecker): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Extract duration value (number or string)
|
|
31
|
+
*/
|
|
32
|
+
export declare function extractDuration(node: ts.Node, checker: ts.TypeChecker): string | number | null;
|
|
@@ -77,3 +77,27 @@ export function extractPropertyString(objNode, propertyName, checker) {
|
|
|
77
77
|
}
|
|
78
78
|
return null;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Extract description from options object
|
|
82
|
+
*/
|
|
83
|
+
export function extractDescription(optionsNode, checker) {
|
|
84
|
+
if (!optionsNode || !ts.isObjectLiteralExpression(optionsNode)) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return extractPropertyString(optionsNode, 'description', checker);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Extract duration value (number or string)
|
|
91
|
+
*/
|
|
92
|
+
export function extractDuration(node, checker) {
|
|
93
|
+
const numValue = extractNumberLiteral(node);
|
|
94
|
+
if (numValue !== null) {
|
|
95
|
+
return numValue;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
return extractStringLiteral(node, checker);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
export interface ServiceMetadata {
|
|
3
|
+
name: string;
|
|
4
|
+
summary: string;
|
|
5
|
+
description: string;
|
|
6
|
+
package: string;
|
|
7
|
+
path: string;
|
|
8
|
+
version: string;
|
|
9
|
+
interface: string;
|
|
10
|
+
expandedProperties: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Extract metadata for a service from its TypeScript declaration
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractServiceMetadata(serviceName: string, type: ts.Type, checker: ts.TypeChecker, rootDir: string): ServiceMetadata | null;
|
|
16
|
+
/**
|
|
17
|
+
* Extract metadata for all services in a type
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractAllServiceMetadata(servicesType: ts.Type, checker: ts.TypeChecker, rootDir: string): ServiceMetadata[];
|