@pikku/inspector 0.12.7 → 0.12.9
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 +29 -0
- package/dist/add/add-ai-agent.js +24 -7
- package/dist/add/add-channel.js +2 -2
- package/dist/add/add-cli.js +13 -10
- package/dist/add/add-file-with-factory.js +22 -5
- package/dist/add/add-functions.js +4 -3
- package/dist/add/add-http-route.js +1 -0
- package/dist/add/add-mcp-prompt.js +4 -0
- package/dist/add/add-mcp-resource.js +4 -0
- package/dist/add/add-rpc-invocations.js +2 -2
- package/dist/add/add-workflow.d.ts +5 -0
- package/dist/add/add-workflow.js +20 -2
- package/dist/inspector.js +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/utils/extract-function-name.d.ts +1 -0
- package/dist/utils/extract-function-name.js +27 -32
- package/dist/utils/extract-node-value.js +6 -1
- package/dist/utils/filter-inspector-state.js +211 -8
- package/dist/utils/load-addon-functions-meta.js +47 -0
- package/dist/utils/post-process.js +63 -0
- package/dist/utils/resolve-versions.js +30 -0
- package/dist/utils/schema-generator.js +124 -33
- package/dist/utils/serialize-inspector-state.d.ts +1 -0
- package/dist/utils/serialize-inspector-state.js +2 -0
- package/dist/visit.js +1 -1
- package/package.json +2 -2
- package/src/add/add-ai-agent.ts +25 -10
- package/src/add/add-channel.ts +2 -2
- package/src/add/add-cli.ts +17 -16
- package/src/add/add-file-with-factory.ts +26 -7
- package/src/add/add-functions.ts +4 -4
- package/src/add/add-http-route.ts +6 -1
- package/src/add/add-mcp-prompt.ts +5 -0
- package/src/add/add-mcp-resource.ts +5 -0
- package/src/add/add-queue-worker.ts +5 -1
- package/src/add/add-rpc-invocations.ts +2 -2
- package/src/add/add-workflow.ts +22 -2
- package/src/inspector.ts +1 -0
- package/src/types.ts +1 -0
- package/src/utils/extract-function-name.ts +36 -37
- package/src/utils/extract-node-value.test.ts +67 -0
- package/src/utils/extract-node-value.ts +5 -1
- package/src/utils/filter-inspector-state.ts +246 -11
- package/src/utils/load-addon-functions-meta.ts +59 -0
- package/src/utils/post-process.ts +74 -0
- package/src/utils/resolve-versions.test.ts +141 -0
- package/src/utils/resolve-versions.ts +37 -0
- package/src/utils/schema-generator.ts +191 -41
- package/src/utils/serialize-inspector-state.ts +3 -0
- package/src/visit.ts +2 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
## 0.12.0
|
|
2
2
|
|
|
3
|
+
## 0.12.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2ac6468: Fix workflow inspector crash when workflow.do() data object has a 'description' property
|
|
8
|
+
- fbcf5b9: Add version awareness to RPC handler: versioned functions now appear in the exposed RPC type map (e.g. `getData@v1`, `getData@v2`), enabling type-safe `rpc.invoke('getData@v1', data)` calls. Tree-shaking respects specific version filters without pulling in all versions. HTTP wirings correctly resolve versioned function IDs.
|
|
9
|
+
- Updated dependencies [fbcf5b9]
|
|
10
|
+
- @pikku/core@0.12.16
|
|
11
|
+
|
|
12
|
+
## 0.12.8
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 624097e: Add deploy pipeline with provider-agnostic architecture
|
|
17
|
+
|
|
18
|
+
- Add MetaService with explicit typed API, absorb WiringService reads
|
|
19
|
+
- Add deployment service, traceId propagation, scoped logger
|
|
20
|
+
- Rewrite analyzer: one function = one worker, gateways dispatch via RPC
|
|
21
|
+
- Add Cloudflare deploy provider with plan/apply commands
|
|
22
|
+
- Add per-unit filtered codegen for deploy pipeline
|
|
23
|
+
- Skip missing metadata in wiring registration for deploy units
|
|
24
|
+
- Fix schema coercion crash when schema has no properties
|
|
25
|
+
- Fix E2E codegen: double-pass resolves cross-package Zod type imports
|
|
26
|
+
|
|
27
|
+
- Updated dependencies [9e8605f]
|
|
28
|
+
- Updated dependencies [624097e]
|
|
29
|
+
- Updated dependencies [7ab3243]
|
|
30
|
+
- @pikku/core@0.12.15
|
|
31
|
+
|
|
3
32
|
## 0.12.7
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
package/dist/add/add-ai-agent.js
CHANGED
|
@@ -33,7 +33,7 @@ function resolveToolReferences(obj, checker, agentName, logger) {
|
|
|
33
33
|
continue;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
if (calleeName === '
|
|
36
|
+
if (calleeName === 'ref') {
|
|
37
37
|
const [firstArg] = element.arguments;
|
|
38
38
|
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
39
39
|
resolved.push(firstArg.text);
|
|
@@ -163,11 +163,12 @@ export const addAIAgent = (logger, node, checker, state, options) => {
|
|
|
163
163
|
if (disabled)
|
|
164
164
|
return;
|
|
165
165
|
const modelValue = getPropertyValue(obj, 'model');
|
|
166
|
-
const
|
|
166
|
+
const roleValue = getPropertyValue(obj, 'role');
|
|
167
|
+
const personalityValue = getPropertyValue(obj, 'personality');
|
|
168
|
+
const goalValue = getPropertyValue(obj, 'goal');
|
|
167
169
|
const maxStepsValue = getPropertyValue(obj, 'maxSteps');
|
|
168
170
|
const temperatureValue = getPropertyValue(obj, 'temperature');
|
|
169
171
|
const toolChoiceValue = getPropertyValue(obj, 'toolChoice');
|
|
170
|
-
const dynamicWorkflowsValue = getPropertyValue(obj, 'dynamicWorkflows');
|
|
171
172
|
const toolsValue = resolveToolReferences(obj, checker, nameValue || '', logger);
|
|
172
173
|
if (toolsValue) {
|
|
173
174
|
for (const toolName of toolsValue) {
|
|
@@ -291,10 +292,14 @@ export const addAIAgent = (logger, node, checker, state, options) => {
|
|
|
291
292
|
state.agents.agentsMeta[agentKey] = {
|
|
292
293
|
name: nameValue,
|
|
293
294
|
description,
|
|
294
|
-
|
|
295
|
+
role: roleValue || undefined,
|
|
296
|
+
personality: personalityValue || undefined,
|
|
297
|
+
goal: goalValue || '',
|
|
295
298
|
model: modelValue || '',
|
|
296
299
|
summary,
|
|
297
300
|
errors,
|
|
301
|
+
sourceFile: node.getSourceFile().fileName,
|
|
302
|
+
exportedName: exportedName || undefined,
|
|
298
303
|
...(maxStepsValue !== null && { maxSteps: maxStepsValue }),
|
|
299
304
|
...(temperatureValue !== null && { temperature: temperatureValue }),
|
|
300
305
|
...(toolChoiceValue !== null && {
|
|
@@ -302,9 +307,6 @@ export const addAIAgent = (logger, node, checker, state, options) => {
|
|
|
302
307
|
}),
|
|
303
308
|
...(toolsValue !== null && { tools: toolsValue }),
|
|
304
309
|
...(agentsValue !== null && { agents: agentsValue }),
|
|
305
|
-
...(dynamicWorkflowsValue !== null && {
|
|
306
|
-
dynamicWorkflows: dynamicWorkflowsValue,
|
|
307
|
-
}),
|
|
308
310
|
tags,
|
|
309
311
|
inputSchema,
|
|
310
312
|
outputSchema,
|
|
@@ -314,5 +316,20 @@ export const addAIAgent = (logger, node, checker, state, options) => {
|
|
|
314
316
|
aiMiddleware,
|
|
315
317
|
permissions,
|
|
316
318
|
};
|
|
319
|
+
// AI agent functions require platform services that aren't visible
|
|
320
|
+
// through parameter destructuring
|
|
321
|
+
const funcMeta = state.functions.meta[agentKey];
|
|
322
|
+
if (funcMeta?.services) {
|
|
323
|
+
for (const svc of [
|
|
324
|
+
'aiStorage',
|
|
325
|
+
'aiRunState',
|
|
326
|
+
'agentRunService',
|
|
327
|
+
'aiAgentRunner',
|
|
328
|
+
]) {
|
|
329
|
+
if (!funcMeta.services.services.includes(svc)) {
|
|
330
|
+
funcMeta.services.services.push(svc);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
317
334
|
}
|
|
318
335
|
};
|
package/dist/add/add-channel.js
CHANGED
|
@@ -65,8 +65,8 @@ function getHandlerNameFromExpression(expr, checker, rootDir) {
|
|
|
65
65
|
}
|
|
66
66
|
// Handle call expressions
|
|
67
67
|
if (ts.isCallExpression(expr)) {
|
|
68
|
-
// Handle
|
|
69
|
-
if (ts.isIdentifier(expr.expression) && expr.expression.text === '
|
|
68
|
+
// Handle ref('name') calls
|
|
69
|
+
if (ts.isIdentifier(expr.expression) && expr.expression.text === 'ref') {
|
|
70
70
|
const [firstArg] = expr.arguments;
|
|
71
71
|
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
72
72
|
return firstArg.text;
|
package/dist/add/add-cli.js
CHANGED
|
@@ -206,22 +206,25 @@ function processCommand(logger, inspectorState, options, name, node, sourceFile,
|
|
|
206
206
|
if (propName === 'func') {
|
|
207
207
|
if (ts.isCallExpression(prop.initializer) &&
|
|
208
208
|
ts.isIdentifier(prop.initializer.expression) &&
|
|
209
|
-
prop.initializer.expression.text === '
|
|
209
|
+
prop.initializer.expression.text === 'ref') {
|
|
210
210
|
const [firstArg] = prop.initializer.arguments;
|
|
211
211
|
if (!firstArg || !ts.isStringLiteral(firstArg)) {
|
|
212
|
-
throw new Error(`
|
|
212
|
+
throw new Error(`ref() call requires a string literal argument`);
|
|
213
213
|
}
|
|
214
214
|
pikkuFuncId = firstArg.text;
|
|
215
|
-
const addonNamespace = pikkuFuncId.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
215
|
+
const addonNamespace = pikkuFuncId.includes(':')
|
|
216
|
+
? pikkuFuncId.split(':')[0]
|
|
217
|
+
: null;
|
|
218
|
+
if (addonNamespace) {
|
|
219
|
+
if (!inspectorState.rpc.wireAddonDeclarations.has(addonNamespace)) {
|
|
220
|
+
throw new Error(`Unknown addon namespace "${addonNamespace}" in "${pikkuFuncId}": no matching wireAddonDeclarations entry found`);
|
|
221
|
+
}
|
|
221
222
|
}
|
|
222
223
|
meta.pikkuFuncId = pikkuFuncId;
|
|
223
|
-
|
|
224
|
-
|
|
224
|
+
if (addonNamespace) {
|
|
225
|
+
meta.packageName =
|
|
226
|
+
inspectorState.rpc.wireAddonDeclarations.get(addonNamespace).package;
|
|
227
|
+
}
|
|
225
228
|
}
|
|
226
229
|
else {
|
|
227
230
|
pikkuFuncId = extractFunctionName(prop.initializer, typeChecker, inspectorState.rootDir).pikkuFuncId;
|
|
@@ -40,10 +40,7 @@ export const addFileWithFactory = (node, checker, methods = new Map(), expectedT
|
|
|
40
40
|
typePath: typeDeclarationPath,
|
|
41
41
|
});
|
|
42
42
|
methods.set(fileName, variables);
|
|
43
|
-
|
|
44
|
-
if (expectedTypeName === 'CreateWireServices' &&
|
|
45
|
-
state &&
|
|
46
|
-
callExpression.arguments.length > 0) {
|
|
43
|
+
if (state && callExpression.arguments.length > 0) {
|
|
47
44
|
const firstArg = callExpression.arguments[0];
|
|
48
45
|
let functionNode;
|
|
49
46
|
if (ts.isArrowFunction(firstArg)) {
|
|
@@ -52,10 +49,30 @@ export const addFileWithFactory = (node, checker, methods = new Map(), expectedT
|
|
|
52
49
|
else if (ts.isFunctionExpression(firstArg)) {
|
|
53
50
|
functionNode = firstArg;
|
|
54
51
|
}
|
|
55
|
-
|
|
52
|
+
// Extract singleton services for CreateWireServices factories
|
|
53
|
+
if (expectedTypeName === 'CreateWireServices' && functionNode) {
|
|
56
54
|
const servicesMeta = extractServicesFromFunction(functionNode);
|
|
57
55
|
state.wireServicesMeta.set(variableName, servicesMeta.services);
|
|
58
56
|
}
|
|
57
|
+
// Extract existing services an addon needs from the parent
|
|
58
|
+
// (second parameter of pikkuAddonServices callback)
|
|
59
|
+
if (wrapperFunctionName === 'pikkuAddonServices' &&
|
|
60
|
+
functionNode &&
|
|
61
|
+
functionNode.parameters.length >= 2) {
|
|
62
|
+
const secondParam = functionNode.parameters[1];
|
|
63
|
+
if (secondParam && ts.isObjectBindingPattern(secondParam.name)) {
|
|
64
|
+
for (const elem of secondParam.name.elements) {
|
|
65
|
+
const name = elem.propertyName && ts.isIdentifier(elem.propertyName)
|
|
66
|
+
? elem.propertyName.text
|
|
67
|
+
: ts.isIdentifier(elem.name)
|
|
68
|
+
? elem.name.text
|
|
69
|
+
: undefined;
|
|
70
|
+
if (name) {
|
|
71
|
+
state.addonRequiredParentServices.push(name);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
59
76
|
}
|
|
60
77
|
return; // Early return since we found a match
|
|
61
78
|
}
|
|
@@ -594,6 +594,8 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
594
594
|
middleware,
|
|
595
595
|
permissions,
|
|
596
596
|
isDirectFunction,
|
|
597
|
+
sourceFile: node.getSourceFile().fileName,
|
|
598
|
+
exportedName: exportedName || undefined,
|
|
597
599
|
};
|
|
598
600
|
// Populate node metadata if node config is present
|
|
599
601
|
if (nodeDisplayName && nodeCategory && nodeType) {
|
|
@@ -613,15 +615,14 @@ export const addFunctions = (logger, node, checker, state, options) => {
|
|
|
613
615
|
}
|
|
614
616
|
if (mcpEnabled) {
|
|
615
617
|
if (!description) {
|
|
616
|
-
logger.
|
|
617
|
-
return;
|
|
618
|
+
logger.warn(`MCP tool '${name}' is missing a description.`);
|
|
618
619
|
}
|
|
619
620
|
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
620
621
|
state.mcpEndpoints.toolsMeta[name] = {
|
|
621
622
|
pikkuFuncId,
|
|
622
623
|
name,
|
|
623
624
|
title: title || undefined,
|
|
624
|
-
description,
|
|
625
|
+
description: description || undefined,
|
|
625
626
|
summary,
|
|
626
627
|
errors,
|
|
627
628
|
tags,
|
|
@@ -174,6 +174,7 @@ export function registerHTTPRoute({ obj, state, checker, logger, sourceFile, bas
|
|
|
174
174
|
pikkuFuncId: funcName,
|
|
175
175
|
...(packageName && { packageName }),
|
|
176
176
|
route: fullRoute,
|
|
177
|
+
sourceFile: sourceFile.fileName,
|
|
177
178
|
method: method,
|
|
178
179
|
params: params.length > 0 ? params : undefined,
|
|
179
180
|
query: query.length > 0 ? query : undefined,
|
|
@@ -58,6 +58,10 @@ export const addMCPPrompt = (logger, node, checker, state, options) => {
|
|
|
58
58
|
}
|
|
59
59
|
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
60
60
|
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
61
|
+
if (!fnMeta.outputSchemaName) {
|
|
62
|
+
fnMeta.outputSchemaName = 'MCPPromptResponse';
|
|
63
|
+
fnMeta.outputs = ['MCPPromptResponse'];
|
|
64
|
+
}
|
|
61
65
|
// --- resolve middleware ---
|
|
62
66
|
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
63
67
|
// --- resolve permissions ---
|
|
@@ -67,6 +67,10 @@ export const addMCPResource = (logger, node, checker, state, options) => {
|
|
|
67
67
|
}
|
|
68
68
|
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
69
69
|
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
70
|
+
if (!fnMeta.outputSchemaName) {
|
|
71
|
+
fnMeta.outputSchemaName = 'MCPResourceResponse';
|
|
72
|
+
fnMeta.outputs = ['MCPResourceResponse'];
|
|
73
|
+
}
|
|
70
74
|
// --- resolve middleware ---
|
|
71
75
|
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
72
76
|
// --- resolve permissions ---
|
|
@@ -19,8 +19,8 @@ export function addRPCInvocations(node, state, logger) {
|
|
|
19
19
|
// Look for call expressions: addon('ext:hello') or rpc.invoke('...')
|
|
20
20
|
if (ts.isCallExpression(node)) {
|
|
21
21
|
const { expression, arguments: args } = node;
|
|
22
|
-
// Check for
|
|
23
|
-
if (ts.isIdentifier(expression) && expression.text === '
|
|
22
|
+
// Check for ref('name') calls
|
|
23
|
+
if (ts.isIdentifier(expression) && expression.text === 'ref') {
|
|
24
24
|
const [firstArg] = args;
|
|
25
25
|
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
26
26
|
const functionRef = firstArg.text;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { AddWiring } from '../types.js';
|
|
2
|
+
import type { WorkflowStepMeta } from '@pikku/core/workflow';
|
|
3
|
+
/**
|
|
4
|
+
* Recursively collect all RPC names from workflow steps
|
|
5
|
+
*/
|
|
6
|
+
export declare function collectInvokedRPCs(steps: WorkflowStepMeta[], rpcs: Set<string>): void;
|
|
2
7
|
/**
|
|
3
8
|
* Inspector for pikkuWorkflow() and pikkuSimpleWorkflow() calls
|
|
4
9
|
* Detects workflow registration and extracts metadata
|
package/dist/add/add-workflow.js
CHANGED
|
@@ -43,7 +43,7 @@ function hasInlineSteps(steps) {
|
|
|
43
43
|
/**
|
|
44
44
|
* Recursively collect all RPC names from workflow steps
|
|
45
45
|
*/
|
|
46
|
-
function collectInvokedRPCs(steps, rpcs) {
|
|
46
|
+
export function collectInvokedRPCs(steps, rpcs) {
|
|
47
47
|
for (const step of steps) {
|
|
48
48
|
if (step.type === 'rpc' && step.rpcName) {
|
|
49
49
|
rpcs.add(step.rpcName);
|
|
@@ -88,7 +88,7 @@ function getWorkflowInvocations(node, checker, state, workflowName, steps) {
|
|
|
88
88
|
// workflow.do(stepName, rpcName|fn, data?, options?)
|
|
89
89
|
const stepNameArg = args[0];
|
|
90
90
|
const secondArg = args[1];
|
|
91
|
-
const optionsArg = args.length >=
|
|
91
|
+
const optionsArg = args.length >= 4 ? args[args.length - 1] : undefined;
|
|
92
92
|
const stepName = extractStringLiteral(stepNameArg, checker);
|
|
93
93
|
const description = extractDescription(optionsArg, checker) ?? undefined;
|
|
94
94
|
// Determine form by checking 2nd argument type
|
|
@@ -183,6 +183,7 @@ export const addWorkflow = (logger, node, checker, state) => {
|
|
|
183
183
|
let description;
|
|
184
184
|
let errors;
|
|
185
185
|
let inline;
|
|
186
|
+
let expose;
|
|
186
187
|
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
187
188
|
const metadata = getCommonWireMetaData(firstArg, 'Workflow', workflowName, logger);
|
|
188
189
|
if (metadata.disabled)
|
|
@@ -195,6 +196,7 @@ export const addWorkflow = (logger, node, checker, state) => {
|
|
|
195
196
|
if (inlineProp === true) {
|
|
196
197
|
inline = true;
|
|
197
198
|
}
|
|
199
|
+
expose = getPropertyValue(firstArg, 'expose');
|
|
198
200
|
}
|
|
199
201
|
// Validate that we got a valid function
|
|
200
202
|
if (ts.isObjectLiteralExpression(firstArg) &&
|
|
@@ -278,5 +280,21 @@ export const addWorkflow = (logger, node, checker, state) => {
|
|
|
278
280
|
errors,
|
|
279
281
|
tags,
|
|
280
282
|
inline,
|
|
283
|
+
expose,
|
|
281
284
|
};
|
|
285
|
+
// Workflow functions require platform services that aren't visible
|
|
286
|
+
// through parameter destructuring (they're accessed via workflow.do/sleep)
|
|
287
|
+
const funcMeta = state.functions.meta[pikkuFuncId];
|
|
288
|
+
if (funcMeta?.services) {
|
|
289
|
+
for (const svc of [
|
|
290
|
+
'workflowService',
|
|
291
|
+
'workflowRunService',
|
|
292
|
+
'schedulerService',
|
|
293
|
+
'queueService',
|
|
294
|
+
]) {
|
|
295
|
+
if (!funcMeta.services.services.includes(svc)) {
|
|
296
|
+
funcMeta.services.services.push(svc);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
282
300
|
};
|
package/dist/inspector.js
CHANGED
|
@@ -28,6 +28,7 @@ export function getInitialInspectorState(rootDir) {
|
|
|
28
28
|
singletonServicesFactories: new Map(),
|
|
29
29
|
wireServicesFactories: new Map(),
|
|
30
30
|
wireServicesMeta: new Map(),
|
|
31
|
+
addonRequiredParentServices: [],
|
|
31
32
|
configFactories: new Map(),
|
|
32
33
|
filesAndMethods: {},
|
|
33
34
|
filesAndMethodsErrors: new Map(),
|
package/dist/types.d.ts
CHANGED
|
@@ -264,6 +264,7 @@ export interface InspectorState {
|
|
|
264
264
|
singletonServicesFactories: PathToNameAndType;
|
|
265
265
|
wireServicesFactories: PathToNameAndType;
|
|
266
266
|
wireServicesMeta: Map<string, string[]>;
|
|
267
|
+
addonRequiredParentServices: string[];
|
|
267
268
|
configFactories: PathToNameAndType;
|
|
268
269
|
filesAndMethods: InspectorFilesAndMethods;
|
|
269
270
|
filesAndMethodsErrors: Map<string, PathToNameAndType>;
|
|
@@ -6,6 +6,7 @@ export type ExtractedFunctionName = {
|
|
|
6
6
|
exportedName: string | null;
|
|
7
7
|
propertyName: string | null;
|
|
8
8
|
isHelper: boolean;
|
|
9
|
+
version: number | null;
|
|
9
10
|
};
|
|
10
11
|
export declare function makeContextBasedId(wiringType: string, ...segments: string[]): string;
|
|
11
12
|
export declare function funcIdToTypeName(id: string): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
|
+
import { formatVersionedId } from '@pikku/core';
|
|
3
4
|
export function makeContextBasedId(wiringType, ...segments) {
|
|
4
5
|
return [wiringType, ...segments].join(':');
|
|
5
6
|
}
|
|
@@ -20,6 +21,7 @@ export function extractFunctionName(callExpr, checker, rootDir) {
|
|
|
20
21
|
propertyName: null,
|
|
21
22
|
explicitName: null,
|
|
22
23
|
isHelper: false,
|
|
24
|
+
version: null,
|
|
23
25
|
};
|
|
24
26
|
const workflowHelpers = new Set([
|
|
25
27
|
'workflow',
|
|
@@ -103,16 +105,7 @@ export function extractFunctionName(callExpr, checker, rootDir) {
|
|
|
103
105
|
// Check for object with 'name' property in first argument
|
|
104
106
|
const firstArg = args[0];
|
|
105
107
|
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
106
|
-
|
|
107
|
-
if (ts.isPropertyAssignment(prop) &&
|
|
108
|
-
ts.isIdentifier(prop.name) &&
|
|
109
|
-
prop.name.text === 'override' &&
|
|
110
|
-
ts.isStringLiteral(prop.initializer)) {
|
|
111
|
-
// Priority 1: Object with override property
|
|
112
|
-
result.explicitName = prop.initializer.text;
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
108
|
+
extractOverrideAndVersion(firstArg, result);
|
|
116
109
|
}
|
|
117
110
|
// Special handling for pikkuSessionlessFunc pattern - use the arrow function directly
|
|
118
111
|
if (expression.text.startsWith('pikku')) {
|
|
@@ -274,19 +267,9 @@ export function extractFunctionName(callExpr, checker, rootDir) {
|
|
|
274
267
|
if (ts.isCallExpression(decl.initializer) &&
|
|
275
268
|
ts.isIdentifier(decl.initializer.expression) &&
|
|
276
269
|
decl.initializer.expression.text.startsWith('pikku')) {
|
|
277
|
-
// Check for object with 'override' property in first argument
|
|
278
270
|
const firstArg = decl.initializer.arguments[0];
|
|
279
271
|
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
280
|
-
|
|
281
|
-
if (ts.isPropertyAssignment(prop) &&
|
|
282
|
-
ts.isIdentifier(prop.name) &&
|
|
283
|
-
prop.name.text === 'override' &&
|
|
284
|
-
ts.isStringLiteral(prop.initializer)) {
|
|
285
|
-
// Priority 1: Object with override property
|
|
286
|
-
result.explicitName = prop.initializer.text;
|
|
287
|
-
break;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
272
|
+
extractOverrideAndVersion(firstArg, result);
|
|
290
273
|
}
|
|
291
274
|
if (decl.initializer.expression.text.startsWith('pikku')) {
|
|
292
275
|
if (firstArg &&
|
|
@@ -340,17 +323,7 @@ export function extractFunctionName(callExpr, checker, rootDir) {
|
|
|
340
323
|
else if (ts.isCallExpression(callExpr)) {
|
|
341
324
|
const firstArg = callExpr.arguments[0];
|
|
342
325
|
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
343
|
-
|
|
344
|
-
if (ts.isPropertyAssignment(prop) &&
|
|
345
|
-
ts.isIdentifier(prop.name) &&
|
|
346
|
-
prop.name.text === 'override' &&
|
|
347
|
-
ts.isStringLiteral(prop.initializer) &&
|
|
348
|
-
!result.explicitName // Only set if not already set
|
|
349
|
-
) {
|
|
350
|
-
result.explicitName = prop.initializer.text;
|
|
351
|
-
break;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
326
|
+
extractOverrideAndVersion(firstArg, result);
|
|
354
327
|
}
|
|
355
328
|
}
|
|
356
329
|
// Apply name priority logic
|
|
@@ -364,6 +337,9 @@ export function extractFunctionName(callExpr, checker, rootDir) {
|
|
|
364
337
|
else {
|
|
365
338
|
result.pikkuFuncId = `__temp_${randomUUID()}`;
|
|
366
339
|
}
|
|
340
|
+
if (result.version !== null) {
|
|
341
|
+
result.pikkuFuncId = formatVersionedId(result.pikkuFuncId, result.version);
|
|
342
|
+
}
|
|
367
343
|
return result;
|
|
368
344
|
}
|
|
369
345
|
/**
|
|
@@ -420,3 +396,22 @@ export function isNamedExport(declaration, checker) {
|
|
|
420
396
|
}
|
|
421
397
|
return false;
|
|
422
398
|
}
|
|
399
|
+
function extractOverrideAndVersion(objLiteral, result) {
|
|
400
|
+
for (const prop of objLiteral.properties) {
|
|
401
|
+
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
402
|
+
if (prop.name.text === 'override' &&
|
|
403
|
+
ts.isStringLiteral(prop.initializer) &&
|
|
404
|
+
!result.explicitName) {
|
|
405
|
+
result.explicitName = prop.initializer.text;
|
|
406
|
+
}
|
|
407
|
+
else if (prop.name.text === 'version' &&
|
|
408
|
+
ts.isNumericLiteral(prop.initializer) &&
|
|
409
|
+
result.version === null) {
|
|
410
|
+
const parsed = Number(prop.initializer.text);
|
|
411
|
+
if (Number.isInteger(parsed) && parsed >= 1) {
|
|
412
|
+
result.version = parsed;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
@@ -84,7 +84,12 @@ export function extractDescription(optionsNode, checker) {
|
|
|
84
84
|
if (!optionsNode || !ts.isObjectLiteralExpression(optionsNode)) {
|
|
85
85
|
return null;
|
|
86
86
|
}
|
|
87
|
-
|
|
87
|
+
try {
|
|
88
|
+
return extractPropertyString(optionsNode, 'description', checker);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
88
93
|
}
|
|
89
94
|
/**
|
|
90
95
|
* Extract duration value (number or string)
|