@pikku/inspector 0.9.5 → 0.9.6-next.0
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 +8 -0
- package/dist/{add-channel.d.ts → add/add-channel.d.ts} +2 -2
- package/dist/{add-channel.js → add/add-channel.js} +12 -5
- package/dist/add/add-cli.d.ts +5 -0
- package/dist/add/add-cli.js +461 -0
- package/dist/{add-file-extends-core-type.d.ts → add/add-file-extends-core-type.d.ts} +2 -2
- package/dist/{add-file-extends-core-type.js → add/add-file-extends-core-type.js} +17 -5
- package/dist/{add-file-with-config.d.ts → add/add-file-with-config.d.ts} +1 -1
- package/dist/{add-file-with-config.js → add/add-file-with-config.js} +1 -1
- package/dist/{add-file-with-factory.d.ts → add/add-file-with-factory.d.ts} +1 -1
- package/dist/{add-file-with-factory.js → add/add-file-with-factory.js} +4 -4
- package/dist/add/add-functions.d.ts +6 -0
- package/dist/{add-functions.js → add/add-functions.js} +25 -5
- package/dist/{add-http-route.d.ts → add/add-http-route.d.ts} +2 -3
- package/dist/{add-http-route.js → add/add-http-route.js} +10 -4
- package/dist/add/add-mcp-prompt.d.ts +2 -0
- package/dist/{add-mcp-prompt.js → add/add-mcp-prompt.js} +10 -4
- package/dist/add/add-mcp-resource.d.ts +2 -0
- package/dist/{add-mcp-resource.js → add/add-mcp-resource.js} +10 -4
- package/dist/add/add-mcp-tool.d.ts +2 -0
- package/dist/{add-mcp-tool.js → add/add-mcp-tool.js} +10 -4
- package/dist/add/add-middleware.d.ts +5 -0
- package/dist/add/add-middleware.js +251 -0
- package/dist/add/add-permission.d.ts +6 -0
- package/dist/{add-permission.js → add/add-permission.js} +4 -3
- package/dist/add/add-queue-worker.d.ts +2 -0
- package/dist/{add-queue-worker.js → add/add-queue-worker.js} +10 -4
- package/dist/{add-rpc-invocations.d.ts → add/add-rpc-invocations.d.ts} +1 -1
- package/dist/add/add-schedule.d.ts +2 -0
- package/dist/{add-schedule.js → add/add-schedule.js} +10 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/inspector.d.ts +2 -3
- package/dist/inspector.js +19 -8
- package/dist/types.d.ts +79 -0
- package/dist/{utils.d.ts → utils/extract-function-name.d.ts} +7 -15
- package/dist/{utils.js → utils/extract-function-name.js} +23 -142
- package/dist/utils/extract-services.d.ts +6 -0
- package/dist/utils/extract-services.js +29 -0
- package/dist/utils/filter-utils.d.ts +9 -0
- package/dist/utils/filter-utils.js +45 -0
- package/dist/utils/get-files-and-methods.d.ts +21 -0
- package/dist/utils/get-files-and-methods.js +60 -0
- package/dist/utils/middleware.d.ts +39 -0
- package/dist/utils/middleware.js +157 -0
- package/dist/utils/type-utils.d.ts +3 -0
- package/dist/utils/type-utils.js +50 -0
- package/dist/visit.d.ts +3 -3
- package/dist/visit.js +33 -30
- package/package.json +3 -4
- package/src/{add-channel.ts → add/add-channel.ts} +19 -19
- package/src/add/add-cli.ts +663 -0
- package/src/{add-file-extends-core-type.ts → add/add-file-extends-core-type.ts} +21 -6
- package/src/{add-file-with-config.ts → add/add-file-with-config.ts} +2 -2
- package/src/{add-file-with-factory.ts → add/add-file-with-factory.ts} +5 -5
- package/src/{add-functions.ts → add/add-functions.ts} +29 -14
- package/src/{add-http-route.ts → add/add-http-route.ts} +23 -14
- package/src/{add-mcp-prompt.ts → add/add-mcp-prompt.ts} +18 -15
- package/src/{add-mcp-resource.ts → add/add-mcp-resource.ts} +18 -15
- package/src/{add-mcp-tool.ts → add/add-mcp-tool.ts} +18 -15
- package/src/add/add-middleware.ts +326 -0
- package/src/{add-permission.ts → add/add-permission.ts} +4 -8
- package/src/{add-queue-worker.ts → add/add-queue-worker.ts} +17 -14
- package/src/{add-rpc-invocations.ts → add/add-rpc-invocations.ts} +1 -1
- package/src/{add-schedule.ts → add/add-schedule.ts} +17 -14
- package/src/index.ts +5 -0
- package/src/inspector.ts +20 -17
- package/src/types.ts +92 -0
- package/src/{utils.ts → utils/extract-function-name.ts} +25 -199
- package/src/utils/extract-services.ts +35 -0
- package/src/{utils.test.ts → utils/filter-utils.test.ts} +2 -2
- package/src/utils/filter-utils.ts +72 -0
- package/src/utils/get-files-and-methods.ts +143 -0
- package/src/utils/middleware.ts +234 -0
- package/src/utils/type-utils.ts +74 -0
- package/src/visit.ts +47 -33
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/add-functions.d.ts +0 -7
- package/dist/add-mcp-prompt.d.ts +0 -3
- package/dist/add-mcp-resource.d.ts +0 -3
- package/dist/add-mcp-tool.d.ts +0 -3
- package/dist/add-middleware.d.ts +0 -7
- package/dist/add-middleware.js +0 -35
- package/dist/add-permission.d.ts +0 -7
- package/dist/add-queue-worker.d.ts +0 -3
- package/dist/add-schedule.d.ts +0 -3
- package/src/add-middleware.ts +0 -51
- /package/dist/{add-rpc-invocations.js → add/add-rpc-invocations.js} +0 -0
- /package/dist/{does-type-extend-core-type.d.ts → utils/does-type-extend-core-type.d.ts} +0 -0
- /package/dist/{does-type-extend-core-type.js → utils/does-type-extend-core-type.js} +0 -0
- /package/dist/{get-property-value.d.ts → utils/get-property-value.d.ts} +0 -0
- /package/dist/{get-property-value.js → utils/get-property-value.js} +0 -0
- /package/src/{does-type-extend-core-type.ts → utils/does-type-extend-core-type.ts} +0 -0
- /package/src/{get-property-value.ts → utils/get-property-value.ts} +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { extractFunctionName
|
|
3
|
-
import {
|
|
2
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
3
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
4
|
+
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
5
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
4
6
|
const isValidVariableName = (name) => {
|
|
5
7
|
const regex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
6
8
|
return regex.test(name);
|
|
@@ -186,7 +188,7 @@ function unwrapPromise(checker, type) {
|
|
|
186
188
|
* Inspect pikkuFunc calls, extract input/output and first-arg destructuring,
|
|
187
189
|
* then push into state.functions.meta.
|
|
188
190
|
*/
|
|
189
|
-
export
|
|
191
|
+
export const addFunctions = (logger, node, checker, state) => {
|
|
190
192
|
if (!ts.isCallExpression(node))
|
|
191
193
|
return;
|
|
192
194
|
const { expression, arguments: args, typeArguments } = node;
|
|
@@ -209,12 +211,14 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
209
211
|
let tags;
|
|
210
212
|
let expose;
|
|
211
213
|
let docs;
|
|
214
|
+
let objectNode;
|
|
212
215
|
// determine the actual handler expression:
|
|
213
216
|
// either the `func` prop or the first argument directly
|
|
214
217
|
let handlerNode = args[0];
|
|
215
218
|
let isDirectFunction = true; // Default to direct function format
|
|
216
219
|
if (ts.isObjectLiteralExpression(handlerNode)) {
|
|
217
220
|
isDirectFunction = false; // This is object format with func property
|
|
221
|
+
objectNode = handlerNode;
|
|
218
222
|
tags = getPropertyValue(handlerNode, 'tags') || undefined;
|
|
219
223
|
expose = getPropertyValue(handlerNode, 'expose');
|
|
220
224
|
docs = getPropertyValue(handlerNode, 'docs');
|
|
@@ -258,7 +262,7 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
258
262
|
.map((tn) => checker.getTypeFromTypeNode(tn))
|
|
259
263
|
.map((t) => unwrapPromise(checker, t));
|
|
260
264
|
// --- Input Extraction ---
|
|
261
|
-
let { names: inputNames } = getNamesAndTypes(checker, state.functions.typesMap, 'Input', name, genericTypes[0]);
|
|
265
|
+
let { names: inputNames, types: inputTypes } = getNamesAndTypes(checker, state.functions.typesMap, 'Input', name, genericTypes[0]);
|
|
262
266
|
// if (inputTypes.length === 0) {
|
|
263
267
|
// logger.debug(
|
|
264
268
|
// `\x1b[31m• Unknown input type for '${name}', assuming void.\x1b[0m`
|
|
@@ -280,6 +284,10 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
280
284
|
if (inputNames.length > 1) {
|
|
281
285
|
logger.warn('More than one input type detected, only the first one will be used as a schema.');
|
|
282
286
|
}
|
|
287
|
+
// --- resolve middleware ---
|
|
288
|
+
const middleware = objectNode
|
|
289
|
+
? resolveMiddleware(state, objectNode, tags, checker)
|
|
290
|
+
: undefined;
|
|
283
291
|
state.functions.meta[pikkuFuncName] = {
|
|
284
292
|
pikkuFuncName,
|
|
285
293
|
name,
|
|
@@ -292,7 +300,19 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
292
300
|
tags: tags || undefined,
|
|
293
301
|
docs: docs || undefined,
|
|
294
302
|
isDirectFunction,
|
|
303
|
+
middleware,
|
|
295
304
|
};
|
|
305
|
+
// Store the input type for later use
|
|
306
|
+
if (inputTypes.length > 0) {
|
|
307
|
+
state.typesLookup.set(pikkuFuncName, inputTypes);
|
|
308
|
+
}
|
|
309
|
+
// Store function file location for wiring generation
|
|
310
|
+
if (exportedName) {
|
|
311
|
+
state.functions.files.set(pikkuFuncName, {
|
|
312
|
+
path: node.getSourceFile().fileName,
|
|
313
|
+
exportedName,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
296
316
|
if (exportedName || explicitName) {
|
|
297
317
|
if (!exportedName) {
|
|
298
318
|
logger.error(`• Function with explicit name '${name}' is not exported, this is not allowed.`);
|
|
@@ -316,4 +336,4 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
316
336
|
});
|
|
317
337
|
}
|
|
318
338
|
}
|
|
319
|
-
}
|
|
339
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { InspectorState, InspectorFilters, InspectorLogger } from './types.js';
|
|
1
|
+
import { AddWiring } from '../types.js';
|
|
3
2
|
/**
|
|
4
3
|
* Populate metaInputTypes for a given route based on method, input type,
|
|
5
4
|
* query and params. Returns undefined (we only mutate metaTypes).
|
|
@@ -13,4 +12,4 @@ export declare const getInputTypes: (metaTypes: Map<string, {
|
|
|
13
12
|
* Simplified wireHTTP: re-uses function metadata from state.functions.meta
|
|
14
13
|
* instead of re-inferring types here.
|
|
15
14
|
*/
|
|
16
|
-
export declare const addHTTPRoute:
|
|
15
|
+
export declare const addHTTPRoute: AddWiring;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue } from '
|
|
2
|
+
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
3
3
|
import { pathToRegexp } from 'path-to-regexp';
|
|
4
4
|
import { PikkuWiringTypes } from '@pikku/core';
|
|
5
|
-
import { extractFunctionName
|
|
5
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
6
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
7
|
+
import { matchesFilters } from '../utils/filter-utils.js';
|
|
8
|
+
import { resolveHTTPMiddlewareFromObject } from '../utils/middleware.js';
|
|
6
9
|
/**
|
|
7
10
|
* Populate metaInputTypes for a given route based on method, input type,
|
|
8
11
|
* query and params. Returns undefined (we only mutate metaTypes).
|
|
@@ -23,7 +26,7 @@ export const getInputTypes = (metaTypes, methodType, inputType, queryValues, par
|
|
|
23
26
|
* Simplified wireHTTP: re-uses function metadata from state.functions.meta
|
|
24
27
|
* instead of re-inferring types here.
|
|
25
28
|
*/
|
|
26
|
-
export const addHTTPRoute = (node, checker, state,
|
|
29
|
+
export const addHTTPRoute = (logger, node, checker, state, options) => {
|
|
27
30
|
// only look at calls
|
|
28
31
|
if (!ts.isCallExpression(node))
|
|
29
32
|
return;
|
|
@@ -46,7 +49,7 @@ export const addHTTPRoute = (node, checker, state, filters, logger) => {
|
|
|
46
49
|
const tags = getPropertyValue(obj, 'tags') || undefined;
|
|
47
50
|
const query = getPropertyValue(obj, 'query') || [];
|
|
48
51
|
const filePath = node.getSourceFile().fileName;
|
|
49
|
-
if (!matchesFilters(filters, { tags }, { type: PikkuWiringTypes.http, name: route, filePath }, logger)) {
|
|
52
|
+
if (!matchesFilters(options.filters || {}, { tags }, { type: PikkuWiringTypes.http, name: route, filePath }, logger)) {
|
|
50
53
|
return;
|
|
51
54
|
}
|
|
52
55
|
// --- find the referenced function ---
|
|
@@ -65,6 +68,8 @@ export const addHTTPRoute = (node, checker, state, filters, logger) => {
|
|
|
65
68
|
const input = fnMeta.inputs?.[0] || null;
|
|
66
69
|
// --- compute inputTypes (body/query/params) ---
|
|
67
70
|
const inputTypes = getInputTypes(state.http.metaInputTypes, method, input, query, params);
|
|
71
|
+
// --- resolve middleware ---
|
|
72
|
+
const middleware = resolveHTTPMiddlewareFromObject(state, route, obj, tags, checker);
|
|
68
73
|
// --- record route ---
|
|
69
74
|
state.http.files.add(node.getSourceFile().fileName);
|
|
70
75
|
state.http.meta[method][route] = {
|
|
@@ -76,5 +81,6 @@ export const addHTTPRoute = (node, checker, state, filters, logger) => {
|
|
|
76
81
|
inputTypes,
|
|
77
82
|
docs,
|
|
78
83
|
tags,
|
|
84
|
+
middleware,
|
|
79
85
|
};
|
|
80
86
|
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue } from '
|
|
2
|
+
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
3
3
|
import { PikkuWiringTypes } from '@pikku/core';
|
|
4
|
-
import { extractFunctionName
|
|
5
|
-
|
|
4
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
5
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
6
|
+
import { matchesFilters } from '../utils/filter-utils.js';
|
|
7
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
8
|
+
export const addMCPPrompt = (logger, node, checker, state, options) => {
|
|
6
9
|
if (!ts.isCallExpression(node)) {
|
|
7
10
|
return;
|
|
8
11
|
}
|
|
@@ -36,7 +39,7 @@ export const addMCPPrompt = (node, checker, state, filters, logger) => {
|
|
|
36
39
|
return;
|
|
37
40
|
}
|
|
38
41
|
const filePath = node.getSourceFile().fileName;
|
|
39
|
-
if (!matchesFilters(filters, { tags }, { type: PikkuWiringTypes.mcp, name: nameValue, filePath }, logger)) {
|
|
42
|
+
if (!matchesFilters(options.filters || {}, { tags }, { type: PikkuWiringTypes.mcp, name: nameValue, filePath }, logger)) {
|
|
40
43
|
return;
|
|
41
44
|
}
|
|
42
45
|
// lookup existing function metadata
|
|
@@ -47,6 +50,8 @@ export const addMCPPrompt = (node, checker, state, filters, logger) => {
|
|
|
47
50
|
}
|
|
48
51
|
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
49
52
|
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
53
|
+
// --- resolve middleware ---
|
|
54
|
+
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
50
55
|
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
51
56
|
state.mcpEndpoints.promptsMeta[nameValue] = {
|
|
52
57
|
pikkuFuncName,
|
|
@@ -56,6 +61,7 @@ export const addMCPPrompt = (node, checker, state, filters, logger) => {
|
|
|
56
61
|
inputSchema,
|
|
57
62
|
outputSchema,
|
|
58
63
|
arguments: [], // Will be populated by CLI during serialization
|
|
64
|
+
middleware,
|
|
59
65
|
};
|
|
60
66
|
}
|
|
61
67
|
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue } from '
|
|
2
|
+
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
3
3
|
import { PikkuWiringTypes } from '@pikku/core';
|
|
4
|
-
import { extractFunctionName
|
|
5
|
-
|
|
4
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
5
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
6
|
+
import { matchesFilters } from '../utils/filter-utils.js';
|
|
7
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
8
|
+
export const addMCPResource = (logger, node, checker, state, options) => {
|
|
6
9
|
if (!ts.isCallExpression(node)) {
|
|
7
10
|
return;
|
|
8
11
|
}
|
|
@@ -42,7 +45,7 @@ export const addMCPResource = (node, checker, state, filters, logger) => {
|
|
|
42
45
|
return;
|
|
43
46
|
}
|
|
44
47
|
const filePath = node.getSourceFile().fileName;
|
|
45
|
-
if (!matchesFilters(filters, { tags }, { type: PikkuWiringTypes.mcp, name: uriValue, filePath }, logger)) {
|
|
48
|
+
if (!matchesFilters(options.filters || {}, { tags }, { type: PikkuWiringTypes.mcp, name: uriValue, filePath }, logger)) {
|
|
46
49
|
return;
|
|
47
50
|
}
|
|
48
51
|
// lookup existing function metadata
|
|
@@ -53,6 +56,8 @@ export const addMCPResource = (node, checker, state, filters, logger) => {
|
|
|
53
56
|
}
|
|
54
57
|
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
55
58
|
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
59
|
+
// --- resolve middleware ---
|
|
60
|
+
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
56
61
|
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
57
62
|
state.mcpEndpoints.resourcesMeta[uriValue] = {
|
|
58
63
|
pikkuFuncName,
|
|
@@ -63,6 +68,7 @@ export const addMCPResource = (node, checker, state, filters, logger) => {
|
|
|
63
68
|
tags,
|
|
64
69
|
inputSchema,
|
|
65
70
|
outputSchema,
|
|
71
|
+
middleware,
|
|
66
72
|
};
|
|
67
73
|
}
|
|
68
74
|
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue } from '
|
|
2
|
+
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
3
3
|
import { PikkuWiringTypes } from '@pikku/core';
|
|
4
|
-
import { extractFunctionName
|
|
5
|
-
|
|
4
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
5
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
6
|
+
import { matchesFilters } from '../utils/filter-utils.js';
|
|
7
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
8
|
+
export const addMCPTool = (logger, node, checker, state, options) => {
|
|
6
9
|
if (!ts.isCallExpression(node)) {
|
|
7
10
|
return;
|
|
8
11
|
}
|
|
@@ -38,7 +41,7 @@ export const addMCPTool = (node, checker, state, filters, logger) => {
|
|
|
38
41
|
return;
|
|
39
42
|
}
|
|
40
43
|
const filePath = node.getSourceFile().fileName;
|
|
41
|
-
if (!matchesFilters(filters, { tags }, { type: PikkuWiringTypes.mcp, name: nameValue, filePath }, logger)) {
|
|
44
|
+
if (!matchesFilters(options.filters || {}, { tags }, { type: PikkuWiringTypes.mcp, name: nameValue, filePath }, logger)) {
|
|
42
45
|
return;
|
|
43
46
|
}
|
|
44
47
|
// lookup existing function metadata
|
|
@@ -49,6 +52,8 @@ export const addMCPTool = (node, checker, state, filters, logger) => {
|
|
|
49
52
|
}
|
|
50
53
|
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
51
54
|
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
55
|
+
// --- resolve middleware ---
|
|
56
|
+
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
52
57
|
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
53
58
|
state.mcpEndpoints.toolsMeta[nameValue] = {
|
|
54
59
|
pikkuFuncName,
|
|
@@ -59,6 +64,7 @@ export const addMCPTool = (node, checker, state, filters, logger) => {
|
|
|
59
64
|
tags,
|
|
60
65
|
inputSchema,
|
|
61
66
|
outputSchema,
|
|
67
|
+
middleware,
|
|
62
68
|
};
|
|
63
69
|
}
|
|
64
70
|
};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { extractFunctionName, isNamedExport, } from '../utils/extract-function-name.js';
|
|
3
|
+
import { extractServicesFromFunction } from '../utils/extract-services.js';
|
|
4
|
+
import { extractMiddlewarePikkuNames } from '../utils/middleware.js';
|
|
5
|
+
/**
|
|
6
|
+
* Inspect pikkuMiddleware calls, addMiddleware calls, and addHTTPMiddleware calls
|
|
7
|
+
*/
|
|
8
|
+
export const addMiddleware = (logger, node, checker, state) => {
|
|
9
|
+
if (!ts.isCallExpression(node))
|
|
10
|
+
return;
|
|
11
|
+
const { expression, arguments: args } = node;
|
|
12
|
+
// only handle specific function calls
|
|
13
|
+
if (!ts.isIdentifier(expression)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
// Handle pikkuMiddleware(...) - individual middleware function definition
|
|
17
|
+
if (expression.text === 'pikkuMiddleware') {
|
|
18
|
+
const handlerNode = args[0];
|
|
19
|
+
if (!handlerNode)
|
|
20
|
+
return;
|
|
21
|
+
if (!ts.isArrowFunction(handlerNode) &&
|
|
22
|
+
!ts.isFunctionExpression(handlerNode)) {
|
|
23
|
+
logger.error(`• Handler for pikkuMiddleware is not a function.`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const services = extractServicesFromFunction(handlerNode);
|
|
27
|
+
const { pikkuFuncName, exportedName } = extractFunctionName(node, checker);
|
|
28
|
+
state.middleware.meta[pikkuFuncName] = {
|
|
29
|
+
services,
|
|
30
|
+
sourceFile: node.getSourceFile().fileName,
|
|
31
|
+
position: node.getStart(),
|
|
32
|
+
exportedName,
|
|
33
|
+
};
|
|
34
|
+
logger.debug(`• Found middleware with services: ${services.services.join(', ')}`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Handle pikkuMiddlewareFactory(...) - middleware factory function
|
|
38
|
+
if (expression.text === 'pikkuMiddlewareFactory') {
|
|
39
|
+
const factoryNode = args[0];
|
|
40
|
+
if (!factoryNode)
|
|
41
|
+
return;
|
|
42
|
+
if (!ts.isArrowFunction(factoryNode) &&
|
|
43
|
+
!ts.isFunctionExpression(factoryNode)) {
|
|
44
|
+
logger.error(`• Handler for pikkuMiddlewareFactory is not a function.`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Extract services by looking inside the factory function body
|
|
48
|
+
// The factory should return pikkuMiddleware(...), so we need to find that call
|
|
49
|
+
let services = { optimized: false, services: [] };
|
|
50
|
+
const findPikkuMiddlewareCall = (node) => {
|
|
51
|
+
if (ts.isCallExpression(node)) {
|
|
52
|
+
const expr = node.expression;
|
|
53
|
+
if (ts.isIdentifier(expr) && expr.text === 'pikkuMiddleware') {
|
|
54
|
+
return node;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return ts.forEachChild(node, findPikkuMiddlewareCall);
|
|
58
|
+
};
|
|
59
|
+
const pikkuMiddlewareCall = findPikkuMiddlewareCall(factoryNode);
|
|
60
|
+
if (pikkuMiddlewareCall && pikkuMiddlewareCall.arguments[0]) {
|
|
61
|
+
const middlewareHandler = pikkuMiddlewareCall.arguments[0];
|
|
62
|
+
if (ts.isArrowFunction(middlewareHandler) ||
|
|
63
|
+
ts.isFunctionExpression(middlewareHandler)) {
|
|
64
|
+
services = extractServicesFromFunction(middlewareHandler);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const { pikkuFuncName, exportedName } = extractFunctionName(node, checker);
|
|
68
|
+
state.middleware.meta[pikkuFuncName] = {
|
|
69
|
+
services,
|
|
70
|
+
sourceFile: node.getSourceFile().fileName,
|
|
71
|
+
position: node.getStart(),
|
|
72
|
+
exportedName,
|
|
73
|
+
factory: true,
|
|
74
|
+
};
|
|
75
|
+
logger.debug(`• Found middleware factory with services: ${services.services.join(', ')}`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Handle addMiddleware('tag', [middleware1, middleware2])
|
|
79
|
+
// Supports two patterns:
|
|
80
|
+
// 1. export const x = () => addMiddleware('tag', [...]) (factory - tree-shakeable)
|
|
81
|
+
// 2. export const x = addMiddleware('tag', [...]) (direct - no tree-shaking)
|
|
82
|
+
if (expression.text === 'addMiddleware') {
|
|
83
|
+
const tagArg = args[0];
|
|
84
|
+
const middlewareArrayArg = args[1];
|
|
85
|
+
if (!tagArg || !middlewareArrayArg)
|
|
86
|
+
return;
|
|
87
|
+
// Extract tag name
|
|
88
|
+
let tag;
|
|
89
|
+
if (ts.isStringLiteral(tagArg)) {
|
|
90
|
+
tag = tagArg.text;
|
|
91
|
+
}
|
|
92
|
+
if (!tag) {
|
|
93
|
+
logger.warn(`• addMiddleware call without valid tag string`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Check if middleware array is a literal array
|
|
97
|
+
if (!ts.isArrayLiteralExpression(middlewareArrayArg)) {
|
|
98
|
+
logger.error(`• addMiddleware('${tag}', ...) must have a literal array as second argument`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// Extract middleware pikkuFuncNames from array
|
|
102
|
+
const middlewareNames = extractMiddlewarePikkuNames(middlewareArrayArg, checker);
|
|
103
|
+
if (middlewareNames.length === 0) {
|
|
104
|
+
logger.warn(`• addMiddleware('${tag}', ...) has empty middleware array`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Collect services from all middleware in the group
|
|
108
|
+
const allServices = new Set();
|
|
109
|
+
for (const middlewareName of middlewareNames) {
|
|
110
|
+
const middlewareMeta = state.middleware.meta[middlewareName];
|
|
111
|
+
if (middlewareMeta && middlewareMeta.services) {
|
|
112
|
+
for (const service of middlewareMeta.services.services) {
|
|
113
|
+
allServices.add(service);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Check if this call is wrapped in a factory function
|
|
118
|
+
// We need to walk up the tree to see if the parent is: const x = () => addMiddleware(...)
|
|
119
|
+
let isFactory = false;
|
|
120
|
+
let exportedName = null;
|
|
121
|
+
let parent = node.parent;
|
|
122
|
+
// Check if parent is arrow function: () => addMiddleware(...)
|
|
123
|
+
if (parent && ts.isArrowFunction(parent)) {
|
|
124
|
+
// Check if arrow function has no parameters
|
|
125
|
+
if (parent.parameters.length === 0) {
|
|
126
|
+
isFactory = true;
|
|
127
|
+
// For factories, we need to check the arrow function's parent for the export name
|
|
128
|
+
// const apiTagMiddleware = () => addMiddleware(...)
|
|
129
|
+
const arrowParent = parent.parent;
|
|
130
|
+
if (arrowParent && ts.isVariableDeclaration(arrowParent)) {
|
|
131
|
+
if (ts.isIdentifier(arrowParent.name)) {
|
|
132
|
+
// Check if it's exported
|
|
133
|
+
if (isNamedExport(arrowParent)) {
|
|
134
|
+
exportedName = arrowParent.name.text;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// If not a factory, get export name from the call expression itself
|
|
141
|
+
if (!isFactory) {
|
|
142
|
+
const extracted = extractFunctionName(node, checker);
|
|
143
|
+
exportedName = extracted.exportedName;
|
|
144
|
+
}
|
|
145
|
+
// Log warning if not using factory pattern
|
|
146
|
+
if (!isFactory && exportedName) {
|
|
147
|
+
logger.warn(`• Middleware group '${exportedName}' for tag '${tag}' is not wrapped in a factory function. ` +
|
|
148
|
+
`For tree-shaking, use: export const ${exportedName} = () => addMiddleware('${tag}', [...])`);
|
|
149
|
+
}
|
|
150
|
+
// Store group metadata
|
|
151
|
+
state.middleware.tagMiddleware.set(tag, {
|
|
152
|
+
exportName: exportedName,
|
|
153
|
+
sourceFile: node.getSourceFile().fileName,
|
|
154
|
+
position: node.getStart(),
|
|
155
|
+
services: {
|
|
156
|
+
optimized: false,
|
|
157
|
+
services: Array.from(allServices),
|
|
158
|
+
},
|
|
159
|
+
middlewareCount: middlewareNames.length,
|
|
160
|
+
isFactory,
|
|
161
|
+
});
|
|
162
|
+
logger.debug(`• Found tag middleware group: ${tag} -> [${middlewareNames.join(', ')}] (${isFactory ? 'factory' : 'direct'})`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
// Handle addHTTPMiddleware(pattern, [middleware1, middleware2])
|
|
166
|
+
// Supports two patterns:
|
|
167
|
+
// 1. export const x = () => addHTTPMiddleware('*', [...]) (factory - tree-shakeable)
|
|
168
|
+
// 2. export const x = addHTTPMiddleware('*', [...]) (direct - no tree-shaking)
|
|
169
|
+
if (expression.text === 'addHTTPMiddleware') {
|
|
170
|
+
const patternArg = args[0];
|
|
171
|
+
const middlewareArrayArg = args[1];
|
|
172
|
+
if (!patternArg || !middlewareArrayArg)
|
|
173
|
+
return;
|
|
174
|
+
// Extract route pattern
|
|
175
|
+
let pattern;
|
|
176
|
+
if (ts.isStringLiteral(patternArg)) {
|
|
177
|
+
pattern = patternArg.text;
|
|
178
|
+
}
|
|
179
|
+
if (!pattern) {
|
|
180
|
+
logger.warn(`• addHTTPMiddleware call without valid pattern string`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// Check if middleware array is a literal array
|
|
184
|
+
if (!ts.isArrayLiteralExpression(middlewareArrayArg)) {
|
|
185
|
+
logger.error(`• addHTTPMiddleware('${pattern}', ...) must have a literal array as second argument`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
// Extract middleware pikkuFuncNames from array
|
|
189
|
+
const middlewareNames = extractMiddlewarePikkuNames(middlewareArrayArg, checker);
|
|
190
|
+
if (middlewareNames.length === 0) {
|
|
191
|
+
logger.warn(`• addHTTPMiddleware('${pattern}', ...) has empty middleware array`);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
// Collect services from all middleware in the group
|
|
195
|
+
const allServices = new Set();
|
|
196
|
+
for (const middlewareName of middlewareNames) {
|
|
197
|
+
const middlewareMeta = state.middleware.meta[middlewareName];
|
|
198
|
+
if (middlewareMeta && middlewareMeta.services) {
|
|
199
|
+
for (const service of middlewareMeta.services.services) {
|
|
200
|
+
allServices.add(service);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Check if this call is wrapped in a factory function
|
|
205
|
+
let isFactory = false;
|
|
206
|
+
let exportedName = null;
|
|
207
|
+
let parent = node.parent;
|
|
208
|
+
// Check if parent is arrow function: () => addHTTPMiddleware(...)
|
|
209
|
+
if (parent && ts.isArrowFunction(parent)) {
|
|
210
|
+
// Check if arrow function has no parameters
|
|
211
|
+
if (parent.parameters.length === 0) {
|
|
212
|
+
isFactory = true;
|
|
213
|
+
// For factories, we need to check the arrow function's parent for the export name
|
|
214
|
+
// const apiRouteMiddleware = () => addHTTPMiddleware(...)
|
|
215
|
+
const arrowParent = parent.parent;
|
|
216
|
+
if (arrowParent && ts.isVariableDeclaration(arrowParent)) {
|
|
217
|
+
if (ts.isIdentifier(arrowParent.name)) {
|
|
218
|
+
// Check if it's exported
|
|
219
|
+
if (isNamedExport(arrowParent)) {
|
|
220
|
+
exportedName = arrowParent.name.text;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// If not a factory, get export name from the call expression itself
|
|
227
|
+
if (!isFactory) {
|
|
228
|
+
const extracted = extractFunctionName(node, checker);
|
|
229
|
+
exportedName = extracted.exportedName;
|
|
230
|
+
}
|
|
231
|
+
// Log warning if not using factory pattern
|
|
232
|
+
if (!isFactory && exportedName) {
|
|
233
|
+
logger.warn(`• HTTP middleware group '${exportedName}' for pattern '${pattern}' is not wrapped in a factory function. ` +
|
|
234
|
+
`For tree-shaking, use: export const ${exportedName} = () => addHTTPMiddleware('${pattern}', [...])`);
|
|
235
|
+
}
|
|
236
|
+
// Store group metadata
|
|
237
|
+
state.http.routeMiddleware.set(pattern, {
|
|
238
|
+
exportName: exportedName,
|
|
239
|
+
sourceFile: node.getSourceFile().fileName,
|
|
240
|
+
position: node.getStart(),
|
|
241
|
+
services: {
|
|
242
|
+
optimized: false,
|
|
243
|
+
services: Array.from(allServices),
|
|
244
|
+
},
|
|
245
|
+
middlewareCount: middlewareNames.length,
|
|
246
|
+
isFactory,
|
|
247
|
+
});
|
|
248
|
+
logger.debug(`• Found HTTP route middleware group: ${pattern} -> [${middlewareNames.join(', ')}] (${isFactory ? 'factory' : 'direct'})`);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { extractFunctionName
|
|
2
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
3
|
+
import { extractServicesFromFunction } from '../utils/extract-services.js';
|
|
3
4
|
/**
|
|
4
5
|
* Inspect pikkuPermission calls and extract first-arg destructuring
|
|
5
6
|
* for tree shaking optimization.
|
|
6
7
|
*/
|
|
7
|
-
export
|
|
8
|
+
export const addPermission = (logger, node, checker, state) => {
|
|
8
9
|
if (!ts.isCallExpression(node))
|
|
9
10
|
return;
|
|
10
11
|
const { expression, arguments: args } = node;
|
|
@@ -32,4 +33,4 @@ export function addPermission(node, checker, state, logger) {
|
|
|
32
33
|
exportedName,
|
|
33
34
|
};
|
|
34
35
|
logger.debug(`• Found permission with services: ${services.services.join(', ')}`);
|
|
35
|
-
}
|
|
36
|
+
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue } from '
|
|
2
|
+
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
3
3
|
import { PikkuWiringTypes } from '@pikku/core';
|
|
4
|
-
import { extractFunctionName
|
|
5
|
-
|
|
4
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
5
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
6
|
+
import { matchesFilters } from '../utils/filter-utils.js';
|
|
7
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
8
|
+
export const addQueueWorker = (logger, node, checker, state, options) => {
|
|
6
9
|
if (!ts.isCallExpression(node)) {
|
|
7
10
|
return;
|
|
8
11
|
}
|
|
@@ -33,16 +36,19 @@ export const addQueueWorker = (node, checker, state, filters, logger) => {
|
|
|
33
36
|
return;
|
|
34
37
|
}
|
|
35
38
|
const filePath = node.getSourceFile().fileName;
|
|
36
|
-
if (!matchesFilters(filters, { tags }, { type: PikkuWiringTypes.queue, name: queueName, filePath }, logger)) {
|
|
39
|
+
if (!matchesFilters(options.filters || {}, { tags }, { type: PikkuWiringTypes.queue, name: queueName, filePath }, logger)) {
|
|
37
40
|
console.info(`• Skipping queue processor '${pikkuFuncName}' for queue '${queueName}' due to filter mismatch.`);
|
|
38
41
|
return;
|
|
39
42
|
}
|
|
43
|
+
// --- resolve middleware ---
|
|
44
|
+
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
40
45
|
state.queueWorkers.files.add(node.getSourceFile().fileName);
|
|
41
46
|
state.queueWorkers.meta[queueName] = {
|
|
42
47
|
pikkuFuncName,
|
|
43
48
|
queueName,
|
|
44
49
|
docs,
|
|
45
50
|
tags,
|
|
51
|
+
middleware,
|
|
46
52
|
};
|
|
47
53
|
}
|
|
48
54
|
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue } from '
|
|
2
|
+
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
3
3
|
import { PikkuWiringTypes } from '@pikku/core';
|
|
4
|
-
import { extractFunctionName
|
|
5
|
-
|
|
4
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
5
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
6
|
+
import { matchesFilters } from '../utils/filter-utils.js';
|
|
7
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
8
|
+
export const addSchedule = (logger, node, checker, state, options) => {
|
|
6
9
|
if (!ts.isCallExpression(node)) {
|
|
7
10
|
return;
|
|
8
11
|
}
|
|
@@ -32,9 +35,11 @@ export const addSchedule = (node, checker, state, filters, logger) => {
|
|
|
32
35
|
return;
|
|
33
36
|
}
|
|
34
37
|
const filePath = node.getSourceFile().fileName;
|
|
35
|
-
if (!matchesFilters(filters, { tags }, { type: PikkuWiringTypes.scheduler, name: nameValue, filePath }, logger)) {
|
|
38
|
+
if (!matchesFilters(options.filters || {}, { tags }, { type: PikkuWiringTypes.scheduler, name: nameValue, filePath }, logger)) {
|
|
36
39
|
return;
|
|
37
40
|
}
|
|
41
|
+
// --- resolve middleware ---
|
|
42
|
+
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
38
43
|
state.scheduledTasks.files.add(node.getSourceFile().fileName);
|
|
39
44
|
state.scheduledTasks.meta[nameValue] = {
|
|
40
45
|
pikkuFuncName,
|
|
@@ -42,6 +47,7 @@ export const addSchedule = (node, checker, state, filters, logger) => {
|
|
|
42
47
|
schedule: scheduleValue,
|
|
43
48
|
docs,
|
|
44
49
|
tags,
|
|
50
|
+
middleware,
|
|
45
51
|
};
|
|
46
52
|
}
|
|
47
53
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { inspect } from './inspector.js';
|
|
2
|
+
export { getFilesAndMethods } from './utils/get-files-and-methods.js';
|
|
2
3
|
export type { TypesMap } from './types-map.js';
|
|
3
4
|
export type * from './types.js';
|
|
4
5
|
export type { InspectorState } from './types.js';
|
|
6
|
+
export type { FilesAndMethods, FilesAndMethodsErrors, } from './utils/get-files-and-methods.js';
|