@pikku/inspector 0.9.4 → 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 +14 -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} +26 -6
- 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/run-tests.sh +1 -1
- 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} +30 -15
- 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
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const getMetaTypes = (type, map, desiredType, errors) => {
|
|
2
|
+
if (desiredType) {
|
|
3
|
+
for (const [file, meta] of map.entries()) {
|
|
4
|
+
for (const { type: entryType, variable, typePath } of meta) {
|
|
5
|
+
if (entryType === desiredType) {
|
|
6
|
+
if (entryType === null || typePath === null) {
|
|
7
|
+
throw new Error(`Unknown state due to metaType calculation: entryType or typePath is null for ${desiredType} in ${file}`);
|
|
8
|
+
}
|
|
9
|
+
return { file, variable, type: entryType, typePath };
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (errors) {
|
|
14
|
+
errors.set(`No ${desiredType} found that extends ${type}`, map);
|
|
15
|
+
}
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const totalValues = Array.from(map.values()).flat();
|
|
19
|
+
if (totalValues.length === 0) {
|
|
20
|
+
const helpMessage = type === 'CoreConfig'
|
|
21
|
+
? `No ${type} found. Make sure you have exported a createConfig function in your codebase:\n\n` +
|
|
22
|
+
`export const createConfig: CreateConfig<Config> = async () => {\n` +
|
|
23
|
+
` return {}\n` +
|
|
24
|
+
`}\n\n` +
|
|
25
|
+
`Possible issues:\n` +
|
|
26
|
+
`- srcDirectories in pikku.config.json doesn't include the file with the createConfig method`
|
|
27
|
+
: `No ${type} found`;
|
|
28
|
+
if (errors) {
|
|
29
|
+
errors.set(helpMessage, map);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (totalValues.length > 1) {
|
|
33
|
+
if (errors) {
|
|
34
|
+
errors.set(`More than one ${type} found`, map);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const entry = Array.from(map.entries())[0];
|
|
39
|
+
if (entry) {
|
|
40
|
+
const [file, [{ type: entryType, variable, typePath }]] = entry;
|
|
41
|
+
if (entryType === null || typePath === null) {
|
|
42
|
+
throw new Error(`Unknown state due to metaType calculation: entryType or typePath is null for ${type} in ${file}`);
|
|
43
|
+
}
|
|
44
|
+
return { file, type: entryType, variable, typePath };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
};
|
|
49
|
+
export const getFilesAndMethods = ({ singletonServicesTypeImportMap, sessionServicesTypeImportMap, userSessionTypeImportMap, sessionServicesFactories, singletonServicesFactories, configFactories, }, { configFileType, userSessionType, singletonServicesFactoryType, sessionServicesFactoryType, } = {}) => {
|
|
50
|
+
const errors = new Map();
|
|
51
|
+
const result = {
|
|
52
|
+
userSessionType: getMetaTypes('CoreUserSession', userSessionTypeImportMap, userSessionType, errors),
|
|
53
|
+
singletonServicesType: getMetaTypes('CoreSingletonServices', singletonServicesTypeImportMap, undefined, errors),
|
|
54
|
+
sessionServicesType: getMetaTypes('CoreServices', sessionServicesTypeImportMap, undefined, errors),
|
|
55
|
+
pikkuConfigFactory: getMetaTypes('CoreConfig', configFactories, configFileType, errors),
|
|
56
|
+
singletonServicesFactory: getMetaTypes('CreateSingletonServices', singletonServicesFactories, singletonServicesFactoryType, errors),
|
|
57
|
+
sessionServicesFactory: getMetaTypes('CreateSessionServices', sessionServicesFactories, sessionServicesFactoryType, errors),
|
|
58
|
+
};
|
|
59
|
+
return { result, errors };
|
|
60
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { MiddlewareMetadata } from '@pikku/core';
|
|
3
|
+
import { InspectorState } from '../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Extract middleware pikkuFuncNames from an array literal expression
|
|
6
|
+
* Resolves each identifier to its pikkuFuncName using extractFunctionName
|
|
7
|
+
* Also handles call expressions (like logCommandInfoAndTime({...}))
|
|
8
|
+
*/
|
|
9
|
+
export declare function extractMiddlewarePikkuNames(arrayNode: ts.Expression, checker: ts.TypeChecker): string[];
|
|
10
|
+
/**
|
|
11
|
+
* Get middleware array from an object literal expression property
|
|
12
|
+
* Returns the initializer node for the 'middleware' property if it exists
|
|
13
|
+
*/
|
|
14
|
+
export declare function getMiddlewareNode(obj: ts.ObjectLiteralExpression): ts.Expression | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a route matches a pattern with wildcards
|
|
17
|
+
* Pattern can be exact match or use * as wildcard
|
|
18
|
+
* e.g., '/api/*' matches '/api/users', '/api/posts/123', etc.
|
|
19
|
+
*/
|
|
20
|
+
export declare function routeMatchesPattern(route: string, pattern: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve middleware for an HTTP wiring based on:
|
|
23
|
+
* 1. Global HTTP middleware (addd([...]))
|
|
24
|
+
* 2. Route-specific HTTP middleware (addHTTPMiddleware('/pattern', [...]))
|
|
25
|
+
* 3. Tag-based middleware (addMiddleware('tag', [...]))
|
|
26
|
+
* 4. Explicit wiring middleware (wireHTTP({ middleware: [...] }))
|
|
27
|
+
* Returns undefined if no middleware is found, otherwise returns array with at least one item
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveHTTPMiddleware(state: InspectorState, route: string, tags: string[] | undefined, explicitMiddlewareNode: ts.Expression | undefined, checker: ts.TypeChecker): MiddlewareMetadata[] | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Convenience wrapper: Extract middleware node from object and resolve
|
|
32
|
+
* Use this in add-* files for cleaner code
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveMiddleware(state: InspectorState, obj: ts.ObjectLiteralExpression, tags: string[] | undefined, checker: ts.TypeChecker): MiddlewareMetadata[] | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Convenience wrapper for HTTP: Extract middleware and resolve with HTTP-specific logic
|
|
37
|
+
* Use this in add-http-route.ts for cleaner code
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveHTTPMiddlewareFromObject(state: InspectorState, route: string, obj: ts.ObjectLiteralExpression, tags: string[] | undefined, checker: ts.TypeChecker): MiddlewareMetadata[] | undefined;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { extractFunctionName } from './extract-function-name.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract middleware pikkuFuncNames from an array literal expression
|
|
5
|
+
* Resolves each identifier to its pikkuFuncName using extractFunctionName
|
|
6
|
+
* Also handles call expressions (like logCommandInfoAndTime({...}))
|
|
7
|
+
*/
|
|
8
|
+
export function extractMiddlewarePikkuNames(arrayNode, checker) {
|
|
9
|
+
if (!ts.isArrayLiteralExpression(arrayNode)) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
const names = [];
|
|
13
|
+
for (const element of arrayNode.elements) {
|
|
14
|
+
if (ts.isIdentifier(element)) {
|
|
15
|
+
// Resolve the identifier to its pikkuFuncName
|
|
16
|
+
const { pikkuFuncName } = extractFunctionName(element, checker);
|
|
17
|
+
names.push(pikkuFuncName);
|
|
18
|
+
}
|
|
19
|
+
else if (ts.isCallExpression(element)) {
|
|
20
|
+
// Handle call expressions like logCommandInfoAndTime({...})
|
|
21
|
+
// These create inline middleware, so we use the call expression itself as the name
|
|
22
|
+
const { pikkuFuncName } = extractFunctionName(element, checker);
|
|
23
|
+
names.push(pikkuFuncName);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return names;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get middleware array from an object literal expression property
|
|
30
|
+
* Returns the initializer node for the 'middleware' property if it exists
|
|
31
|
+
*/
|
|
32
|
+
export function getMiddlewareNode(obj) {
|
|
33
|
+
const middlewareProp = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
|
|
34
|
+
ts.isIdentifier(p.name) &&
|
|
35
|
+
p.name.text === 'middleware');
|
|
36
|
+
return middlewareProp?.initializer;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if a route matches a pattern with wildcards
|
|
40
|
+
* Pattern can be exact match or use * as wildcard
|
|
41
|
+
* e.g., '/api/*' matches '/api/users', '/api/posts/123', etc.
|
|
42
|
+
*/
|
|
43
|
+
export function routeMatchesPattern(route, pattern) {
|
|
44
|
+
if (route === pattern)
|
|
45
|
+
return true;
|
|
46
|
+
// Convert pattern to regex: replace * with .*
|
|
47
|
+
const regexPattern = pattern
|
|
48
|
+
.replace(/[.+?^${}()|[\]\\]/g, '\\$&') // Escape regex special chars except *
|
|
49
|
+
.replace(/\*/g, '.*'); // Replace * with .*
|
|
50
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
51
|
+
return regex.test(route);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve middleware for an HTTP wiring based on:
|
|
55
|
+
* 1. Global HTTP middleware (addd([...]))
|
|
56
|
+
* 2. Route-specific HTTP middleware (addHTTPMiddleware('/pattern', [...]))
|
|
57
|
+
* 3. Tag-based middleware (addMiddleware('tag', [...]))
|
|
58
|
+
* 4. Explicit wiring middleware (wireHTTP({ middleware: [...] }))
|
|
59
|
+
* Returns undefined if no middleware is found, otherwise returns array with at least one item
|
|
60
|
+
*/
|
|
61
|
+
export function resolveHTTPMiddleware(state, route, tags, explicitMiddlewareNode, checker) {
|
|
62
|
+
const resolved = [];
|
|
63
|
+
// 1. HTTP route middleware groups (includes '*' for global)
|
|
64
|
+
for (const [pattern, _groupMeta] of state.http.routeMiddleware.entries()) {
|
|
65
|
+
if (routeMatchesPattern(route, pattern)) {
|
|
66
|
+
// Just reference the group by route pattern
|
|
67
|
+
resolved.push({
|
|
68
|
+
type: 'http',
|
|
69
|
+
route: pattern,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// 2. Tag-based middleware groups
|
|
74
|
+
if (tags && tags.length > 0) {
|
|
75
|
+
for (const tag of tags) {
|
|
76
|
+
if (state.middleware.tagMiddleware.has(tag)) {
|
|
77
|
+
// Just reference the group by tag
|
|
78
|
+
resolved.push({
|
|
79
|
+
type: 'tag',
|
|
80
|
+
tag,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// 3. Explicit wire middleware (inline is OK here)
|
|
86
|
+
if (explicitMiddlewareNode) {
|
|
87
|
+
const middlewareNames = extractMiddlewarePikkuNames(explicitMiddlewareNode, checker);
|
|
88
|
+
for (const name of middlewareNames) {
|
|
89
|
+
const meta = state.middleware.meta[name];
|
|
90
|
+
resolved.push({
|
|
91
|
+
type: 'wire',
|
|
92
|
+
name,
|
|
93
|
+
inline: meta?.exportedName === null,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return resolved.length > 0 ? resolved : undefined;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Resolve tag-based and explicit middleware (common logic for wires and functions)
|
|
101
|
+
* 1. Tag-based middleware (addMiddleware('tag', [...]))
|
|
102
|
+
* 2. Explicit middleware (wireHTTP/pikkuFunc({ middleware: [...] }))
|
|
103
|
+
*/
|
|
104
|
+
function resolveTagAndExplicitMiddleware(state, tags, explicitMiddlewareNode, checker) {
|
|
105
|
+
const resolved = [];
|
|
106
|
+
// 1. Tag-based middleware groups
|
|
107
|
+
if (tags && tags.length > 0) {
|
|
108
|
+
for (const tag of tags) {
|
|
109
|
+
if (state.middleware.tagMiddleware.has(tag)) {
|
|
110
|
+
// Just reference the group by tag
|
|
111
|
+
resolved.push({
|
|
112
|
+
type: 'tag',
|
|
113
|
+
tag,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// 2. Explicit middleware (inline is OK here - used directly in wire/function)
|
|
119
|
+
if (explicitMiddlewareNode) {
|
|
120
|
+
const middlewareNames = extractMiddlewarePikkuNames(explicitMiddlewareNode, checker);
|
|
121
|
+
for (const name of middlewareNames) {
|
|
122
|
+
const meta = state.middleware.meta[name];
|
|
123
|
+
resolved.push({
|
|
124
|
+
type: 'wire',
|
|
125
|
+
name,
|
|
126
|
+
inline: meta?.exportedName === null,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return resolved;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Resolve middleware for a function based on:
|
|
134
|
+
* 1. Tag-based middleware (addMiddleware('tag', [...]))
|
|
135
|
+
* 2. Explicit function middleware (pikkuFunc({ middleware: [...] }))
|
|
136
|
+
* Returns undefined if no middleware is found, otherwise returns array with at least one item
|
|
137
|
+
*/
|
|
138
|
+
function resolveFunctionMiddlewareInternal(state, tags, explicitMiddlewareNode, checker) {
|
|
139
|
+
const resolved = resolveTagAndExplicitMiddleware(state, tags, explicitMiddlewareNode, checker);
|
|
140
|
+
return resolved.length > 0 ? resolved : undefined;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Convenience wrapper: Extract middleware node from object and resolve
|
|
144
|
+
* Use this in add-* files for cleaner code
|
|
145
|
+
*/
|
|
146
|
+
export function resolveMiddleware(state, obj, tags, checker) {
|
|
147
|
+
const explicitMiddlewareNode = getMiddlewareNode(obj);
|
|
148
|
+
return resolveFunctionMiddlewareInternal(state, tags, explicitMiddlewareNode, checker);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Convenience wrapper for HTTP: Extract middleware and resolve with HTTP-specific logic
|
|
152
|
+
* Use this in add-http-route.ts for cleaner code
|
|
153
|
+
*/
|
|
154
|
+
export function resolveHTTPMiddlewareFromObject(state, route, obj, tags, checker) {
|
|
155
|
+
const explicitMiddlewareNode = getMiddlewareNode(obj);
|
|
156
|
+
return resolveHTTPMiddleware(state, route, tags, explicitMiddlewareNode, checker);
|
|
157
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
export declare const extractTypeKeys: (type: ts.Type) => string[];
|
|
3
|
+
export declare function getPropertyAssignmentInitializer(obj: ts.ObjectLiteralExpression, propName: string, followShorthand?: boolean, checker?: ts.TypeChecker): ts.Expression | undefined;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
export const extractTypeKeys = (type) => {
|
|
3
|
+
return type.getProperties().map((symbol) => symbol.getName());
|
|
4
|
+
};
|
|
5
|
+
export function getPropertyAssignmentInitializer(obj, propName, followShorthand = false, checker) {
|
|
6
|
+
for (const prop of obj.properties) {
|
|
7
|
+
// ① foo: () => {}
|
|
8
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
9
|
+
ts.isIdentifier(prop.name) &&
|
|
10
|
+
prop.name.text === propName) {
|
|
11
|
+
return prop.initializer;
|
|
12
|
+
}
|
|
13
|
+
// ② foo() { … }
|
|
14
|
+
if (ts.isMethodDeclaration(prop) &&
|
|
15
|
+
ts.isIdentifier(prop.name) &&
|
|
16
|
+
prop.name.text === propName) {
|
|
17
|
+
return prop.name; // the method node *is* the function
|
|
18
|
+
}
|
|
19
|
+
// ③ { foo } (shorthand)
|
|
20
|
+
if (followShorthand &&
|
|
21
|
+
ts.isShorthandPropertyAssignment(prop) &&
|
|
22
|
+
prop.name.text === propName) {
|
|
23
|
+
if (!checker)
|
|
24
|
+
return prop.name; // best effort without a checker
|
|
25
|
+
let sym = checker.getSymbolAtLocation(prop.name);
|
|
26
|
+
if (sym && sym.flags & ts.SymbolFlags.Alias) {
|
|
27
|
+
sym = checker.getAliasedSymbol(sym);
|
|
28
|
+
}
|
|
29
|
+
const decl = sym?.declarations?.[0];
|
|
30
|
+
// const foo = () => {}
|
|
31
|
+
if (decl &&
|
|
32
|
+
ts.isVariableDeclaration(decl) &&
|
|
33
|
+
decl.initializer &&
|
|
34
|
+
(ts.isArrowFunction(decl.initializer) ||
|
|
35
|
+
ts.isFunctionExpression(decl.initializer))) {
|
|
36
|
+
return decl.initializer;
|
|
37
|
+
}
|
|
38
|
+
// function foo() {}
|
|
39
|
+
if (decl &&
|
|
40
|
+
(ts.isFunctionDeclaration(decl) ||
|
|
41
|
+
ts.isArrowFunction(decl) ||
|
|
42
|
+
ts.isFunctionExpression(decl))) {
|
|
43
|
+
return decl;
|
|
44
|
+
}
|
|
45
|
+
// fallback – just give back the identifier
|
|
46
|
+
return prop.name;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
package/dist/visit.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import {
|
|
3
|
-
export declare const visitSetup: (checker: ts.TypeChecker, node: ts.Node, state: InspectorState,
|
|
4
|
-
export declare const visitRoutes: (checker: ts.TypeChecker, node: ts.Node, state: InspectorState,
|
|
2
|
+
import { InspectorState, InspectorLogger, InspectorOptions } from './types.js';
|
|
3
|
+
export declare const visitSetup: (logger: InspectorLogger, checker: ts.TypeChecker, node: ts.Node, state: InspectorState, options: InspectorOptions) => void;
|
|
4
|
+
export declare const visitRoutes: (logger: InspectorLogger, checker: ts.TypeChecker, node: ts.Node, state: InspectorState, options: InspectorOptions) => void;
|
package/dist/visit.js
CHANGED
|
@@ -1,37 +1,40 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { addFileWithFactory } from './add-file-with-factory.js';
|
|
3
|
-
import { addFileExtendsCoreType } from './add-file-extends-core-type.js';
|
|
4
|
-
import { addHTTPRoute } from './add-http-route.js';
|
|
5
|
-
import { addSchedule } from './add-schedule.js';
|
|
6
|
-
import { addQueueWorker } from './add-queue-worker.js';
|
|
7
|
-
import { addMCPResource } from './add-mcp-resource.js';
|
|
8
|
-
import { addMCPTool } from './add-mcp-tool.js';
|
|
9
|
-
import { addMCPPrompt } from './add-mcp-prompt.js';
|
|
10
|
-
import { addFunctions } from './add-functions.js';
|
|
11
|
-
import { addChannel } from './add-channel.js';
|
|
12
|
-
import { addRPCInvocations } from './add-rpc-invocations.js';
|
|
13
|
-
import { addMiddleware } from './add-middleware.js';
|
|
14
|
-
import { addPermission } from './add-permission.js';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
addFileExtendsCoreType(node, checker, state.
|
|
18
|
-
addFileExtendsCoreType(node, checker, state.
|
|
2
|
+
import { addFileWithFactory } from './add/add-file-with-factory.js';
|
|
3
|
+
import { addFileExtendsCoreType } from './add/add-file-extends-core-type.js';
|
|
4
|
+
import { addHTTPRoute } from './add/add-http-route.js';
|
|
5
|
+
import { addSchedule } from './add/add-schedule.js';
|
|
6
|
+
import { addQueueWorker } from './add/add-queue-worker.js';
|
|
7
|
+
import { addMCPResource } from './add/add-mcp-resource.js';
|
|
8
|
+
import { addMCPTool } from './add/add-mcp-tool.js';
|
|
9
|
+
import { addMCPPrompt } from './add/add-mcp-prompt.js';
|
|
10
|
+
import { addFunctions } from './add/add-functions.js';
|
|
11
|
+
import { addChannel } from './add/add-channel.js';
|
|
12
|
+
import { addRPCInvocations } from './add/add-rpc-invocations.js';
|
|
13
|
+
import { addMiddleware } from './add/add-middleware.js';
|
|
14
|
+
import { addPermission } from './add/add-permission.js';
|
|
15
|
+
import { addCLI } from './add/add-cli.js';
|
|
16
|
+
export const visitSetup = (logger, checker, node, state, options) => {
|
|
17
|
+
addFileExtendsCoreType(node, checker, state.singletonServicesTypeImportMap, 'CoreSingletonServices', state);
|
|
18
|
+
addFileExtendsCoreType(node, checker, state.sessionServicesTypeImportMap, 'CoreServices', state);
|
|
19
|
+
addFileExtendsCoreType(node, checker, state.userSessionTypeImportMap, 'CoreUserSession', state);
|
|
20
|
+
addFileExtendsCoreType(node, checker, state.configTypeImportMap, 'CoreConfig', state);
|
|
19
21
|
addFileWithFactory(node, checker, state.singletonServicesFactories, 'CreateSingletonServices');
|
|
20
22
|
addFileWithFactory(node, checker, state.sessionServicesFactories, 'CreateSessionServices');
|
|
21
23
|
addFileWithFactory(node, checker, state.configFactories, 'CreateConfig');
|
|
22
24
|
addRPCInvocations(node, state, logger);
|
|
23
|
-
|
|
25
|
+
addMiddleware(logger, node, checker, state, options);
|
|
26
|
+
addPermission(logger, node, checker, state, options);
|
|
27
|
+
ts.forEachChild(node, (child) => visitSetup(logger, checker, child, state, options));
|
|
24
28
|
};
|
|
25
|
-
export const visitRoutes = (checker, node, state,
|
|
26
|
-
addFunctions(node, checker, state,
|
|
27
|
-
addHTTPRoute(node, checker, state,
|
|
28
|
-
addSchedule(node, checker, state,
|
|
29
|
-
addQueueWorker(node, checker, state,
|
|
30
|
-
addChannel(node, checker, state,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
ts.forEachChild(node, (child) => visitRoutes(checker, child, state, filters, logger));
|
|
29
|
+
export const visitRoutes = (logger, checker, node, state, options) => {
|
|
30
|
+
addFunctions(logger, node, checker, state, options);
|
|
31
|
+
addHTTPRoute(logger, node, checker, state, options);
|
|
32
|
+
addSchedule(logger, node, checker, state, options);
|
|
33
|
+
addQueueWorker(logger, node, checker, state, options);
|
|
34
|
+
addChannel(logger, node, checker, state, options);
|
|
35
|
+
addCLI(logger, node, checker, state, options);
|
|
36
|
+
addMCPResource(logger, node, checker, state, options);
|
|
37
|
+
addMCPTool(logger, node, checker, state, options);
|
|
38
|
+
addMCPPrompt(logger, node, checker, state, options);
|
|
39
|
+
ts.forEachChild(node, (child) => visitRoutes(logger, checker, child, state, options));
|
|
37
40
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/inspector",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6-next.0",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"scripts": {
|
|
10
10
|
"tsc": "tsc",
|
|
11
|
-
"build
|
|
12
|
-
"build": "yarn build:esm",
|
|
11
|
+
"build": "tsc -b",
|
|
13
12
|
"ncu": "npx npm-check-updates -x '/.*glob.*/'",
|
|
14
13
|
"release": "yarn build && npm test",
|
|
15
14
|
"test": "bash run-tests.sh",
|
|
@@ -17,7 +16,7 @@
|
|
|
17
16
|
"test:coverage": "bash run-tests.sh --coverage"
|
|
18
17
|
},
|
|
19
18
|
"dependencies": {
|
|
20
|
-
"@pikku/core": "^0.9.
|
|
19
|
+
"@pikku/core": "^0.9.12-next.0",
|
|
21
20
|
"path-to-regexp": "^8.2.0",
|
|
22
21
|
"typescript": "^5.9"
|
|
23
22
|
},
|
package/run-tests.sh
CHANGED
|
@@ -46,7 +46,7 @@ if [ "$watch_mode" = true ]; then
|
|
|
46
46
|
fi
|
|
47
47
|
|
|
48
48
|
if [ "$coverage_mode" = true ]; then
|
|
49
|
-
node_cmd="$node_cmd --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info"
|
|
49
|
+
node_cmd="$node_cmd --test-coverage-include=\"src/**/*.{ts,js}\" --test-coverage-exclude=\"**/dist/**\" --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info"
|
|
50
50
|
fi
|
|
51
51
|
|
|
52
52
|
# Execute the node command with the expanded list of files
|
|
@@ -1,21 +1,16 @@
|
|
|
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 { PikkuDocs, PikkuWiringTypes } from '@pikku/core'
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
matchesFilters,
|
|
9
|
-
} from './utils.js'
|
|
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'
|
|
10
8
|
import type { ChannelMessageMeta, ChannelMeta } from '@pikku/core/channel'
|
|
11
|
-
import type {
|
|
12
|
-
|
|
13
|
-
InspectorState,
|
|
14
|
-
InspectorLogger,
|
|
15
|
-
} from './types.js'
|
|
9
|
+
import type { InspectorState, AddWiring } from '../types.js'
|
|
10
|
+
import { resolveMiddleware } from '../utils/middleware.js'
|
|
16
11
|
|
|
17
12
|
/**
|
|
18
|
-
* Safely get the
|
|
13
|
+
* Safely get the "initializer" expression of a property-like AST node:
|
|
19
14
|
* - for `foo: expr`, returns `expr`
|
|
20
15
|
* - for `{ foo }` shorthand, returns the identifier `foo`
|
|
21
16
|
* - otherwise, returns undefined
|
|
@@ -363,13 +358,14 @@ export function addMessagesRoutes(
|
|
|
363
358
|
* Inspect addChannel calls, look up all handlers in state.functions.meta,
|
|
364
359
|
* and emit one entry into state.channels.meta.
|
|
365
360
|
*/
|
|
366
|
-
export
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
) {
|
|
361
|
+
export const addChannel: AddWiring = (
|
|
362
|
+
logger,
|
|
363
|
+
node,
|
|
364
|
+
checker,
|
|
365
|
+
state,
|
|
366
|
+
options
|
|
367
|
+
) => {
|
|
368
|
+
const filters = options.filters || {}
|
|
373
369
|
if (!ts.isCallExpression(node)) return
|
|
374
370
|
const { expression, arguments: args } = node
|
|
375
371
|
if (!ts.isIdentifier(expression) || expression.text !== 'wireChannel') return
|
|
@@ -450,6 +446,9 @@ export function addChannel(
|
|
|
450
446
|
// nested message-routes
|
|
451
447
|
const messageWirings = addMessagesRoutes(obj, state, checker)
|
|
452
448
|
|
|
449
|
+
// --- resolve middleware ---
|
|
450
|
+
const middleware = resolveMiddleware(state, obj, tags, checker)
|
|
451
|
+
|
|
453
452
|
// record into state
|
|
454
453
|
state.channels.files.add(node.getSourceFile().fileName)
|
|
455
454
|
state.channels.meta[name] = {
|
|
@@ -478,5 +477,6 @@ export function addChannel(
|
|
|
478
477
|
messageWirings,
|
|
479
478
|
docs: docs ?? undefined,
|
|
480
479
|
tags: tags ?? undefined,
|
|
480
|
+
middleware,
|
|
481
481
|
}
|
|
482
482
|
}
|