@pikku/inspector 0.6.4 → 0.7.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 +10 -0
- package/dist/add-channel.d.ts +12 -2
- package/dist/add-channel.js +336 -109
- package/dist/add-functions.d.ts +7 -0
- package/dist/add-functions.js +260 -0
- package/dist/add-http-route.d.ts +15 -3
- package/dist/add-http-route.js +69 -80
- package/dist/add-schedule.d.ts +1 -1
- package/dist/add-schedule.js +14 -4
- package/dist/events/add-channel.d.ts +1 -0
- package/dist/events/add-channel.js +170 -0
- package/dist/events/add-http-route.d.ts +16 -0
- package/dist/events/add-http-route.js +83 -0
- package/dist/events/add-schedule.d.ts +3 -0
- package/dist/events/add-schedule.js +38 -0
- package/dist/inspector.js +14 -4
- package/dist/types.d.ts +7 -10
- package/dist/utils.d.ts +21 -27
- package/dist/utils.js +631 -211
- package/dist/visit.d.ts +2 -1
- package/dist/visit.js +9 -4
- package/package.json +2 -2
- package/src/add-channel.ts +0 -180
- package/src/add-file-extends-core-type.ts +0 -50
- package/src/add-file-with-config.ts +0 -45
- package/src/add-file-with-factory.ts +0 -65
- package/src/add-http-route.ts +0 -138
- package/src/add-schedule.ts +0 -56
- package/src/does-type-extend-core-type.ts +0 -53
- package/src/get-property-value.ts +0 -84
- package/src/index.ts +0 -4
- package/src/inspector.ts +0 -63
- package/src/types-map.ts +0 -130
- package/src/types.ts +0 -62
- package/src/utils.ts +0 -371
- package/src/visit.ts +0 -57
- package/tsconfig.json +0 -19
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue } from '../get-property-value.js';
|
|
3
|
+
import { pathToRegexp } from 'path-to-regexp';
|
|
4
|
+
import { matchesFilters } from '../utils.js';
|
|
5
|
+
/**
|
|
6
|
+
* Populate metaInputTypes for a given route based on method, input type,
|
|
7
|
+
* query and params. Returns undefined (we only mutate metaTypes).
|
|
8
|
+
*/
|
|
9
|
+
export const getInputTypes = (metaTypes, methodType, inputType, queryValues, paramsValues) => {
|
|
10
|
+
if (!inputType)
|
|
11
|
+
return;
|
|
12
|
+
metaTypes.set(inputType, {
|
|
13
|
+
query: queryValues,
|
|
14
|
+
params: paramsValues,
|
|
15
|
+
body: ['post', 'put', 'patch'].includes(methodType)
|
|
16
|
+
? [...new Set([...queryValues, ...paramsValues])]
|
|
17
|
+
: [],
|
|
18
|
+
});
|
|
19
|
+
return;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Simplified addRoute: re-uses function metadata from state.functions.meta
|
|
23
|
+
* instead of re-inferring types here.
|
|
24
|
+
*/
|
|
25
|
+
export const addRoute = (node, checker, state, filters) => {
|
|
26
|
+
// only look at calls
|
|
27
|
+
if (!ts.isCallExpression(node))
|
|
28
|
+
return;
|
|
29
|
+
const { expression, arguments: args } = node;
|
|
30
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addRoute')
|
|
31
|
+
return;
|
|
32
|
+
// must pass an object literal
|
|
33
|
+
const firstArg = args[0];
|
|
34
|
+
if (!firstArg || !ts.isObjectLiteralExpression(firstArg))
|
|
35
|
+
return;
|
|
36
|
+
const obj = firstArg;
|
|
37
|
+
// --- extract HTTP metadata ---
|
|
38
|
+
const route = getPropertyValue(obj, 'route');
|
|
39
|
+
if (!route)
|
|
40
|
+
return;
|
|
41
|
+
const keys = pathToRegexp(route).keys;
|
|
42
|
+
const params = keys
|
|
43
|
+
.filter(k => k.type === 'param')
|
|
44
|
+
.map(k => k.name);
|
|
45
|
+
const method = getPropertyValue(obj, 'method')?.toLowerCase() || 'get';
|
|
46
|
+
const docs = getPropertyValue(obj, 'docs') || undefined;
|
|
47
|
+
const tags = getPropertyValue(obj, 'tags') || undefined;
|
|
48
|
+
const query = getPropertyValue(obj, 'query') || [];
|
|
49
|
+
if (!matchesFilters(filters, { tags }, { type: 'http', name: route })) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// --- find the referenced function ---
|
|
53
|
+
const funcProp = obj.properties.find(p => ts.isPropertyAssignment(p) &&
|
|
54
|
+
ts.isIdentifier(p.name) &&
|
|
55
|
+
p.name.text === 'func');
|
|
56
|
+
if (!funcProp || !ts.isIdentifier(funcProp.initializer)) {
|
|
57
|
+
console.error(`• No valid 'func' property for route '${route}'.`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const funcName = funcProp.initializer.text;
|
|
61
|
+
console.log(state.functions);
|
|
62
|
+
// lookup existing function metadata
|
|
63
|
+
const fnMeta = state.functions.meta.find(m => m.name === funcName);
|
|
64
|
+
if (!fnMeta) {
|
|
65
|
+
console.error(`• No function metadata found for '${funcName}'.`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// --- compute inputTypes (body/query/params) ---
|
|
69
|
+
const inputTypes = getInputTypes(state.http.metaInputTypes, method, fnMeta.input, query, params);
|
|
70
|
+
// --- record route ---
|
|
71
|
+
state.http.files.add(node.getSourceFile().fileName);
|
|
72
|
+
state.http.meta.push({
|
|
73
|
+
route,
|
|
74
|
+
method: method,
|
|
75
|
+
input: fnMeta.input,
|
|
76
|
+
output: fnMeta.output,
|
|
77
|
+
params: params.length > 0 ? params : undefined,
|
|
78
|
+
query: query.length > 0 ? query : undefined,
|
|
79
|
+
inputTypes,
|
|
80
|
+
docs,
|
|
81
|
+
tags,
|
|
82
|
+
});
|
|
83
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue } from '../get-property-value.js';
|
|
3
|
+
import { matchesFilters } from '../utils.js';
|
|
4
|
+
export const addSchedule = (node, _checker, state, filters) => {
|
|
5
|
+
if (!ts.isCallExpression(node)) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const args = node.arguments;
|
|
9
|
+
const firstArg = args[0];
|
|
10
|
+
const expression = node.expression;
|
|
11
|
+
// Check if the call is to addScheduledTask
|
|
12
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'addScheduledTask') {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (!firstArg) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
19
|
+
const obj = firstArg;
|
|
20
|
+
const nameValue = getPropertyValue(obj, 'name');
|
|
21
|
+
const scheduleValue = getPropertyValue(obj, 'schedule');
|
|
22
|
+
const docs = getPropertyValue(obj, 'docs') || undefined;
|
|
23
|
+
const tags = getPropertyValue(obj, 'tags') || undefined;
|
|
24
|
+
if (!nameValue || !scheduleValue) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!matchesFilters(filters, { tags }, { type: 'schedule', name: nameValue })) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
state.scheduledTasks.files.add(node.getSourceFile().fileName);
|
|
31
|
+
state.scheduledTasks.meta.push({
|
|
32
|
+
name: nameValue,
|
|
33
|
+
schedule: scheduleValue,
|
|
34
|
+
docs,
|
|
35
|
+
tags,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
};
|
package/dist/inspector.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import {
|
|
2
|
+
import { visitSetup, visitRoutes } from './visit.js';
|
|
3
3
|
import { TypesMap } from './types-map.js';
|
|
4
4
|
export const normalizeHTTPTypes = (httpState) => {
|
|
5
5
|
return httpState;
|
|
@@ -18,6 +18,11 @@ export const inspect = (routeFiles, filters) => {
|
|
|
18
18
|
singletonServicesFactories: new Map(),
|
|
19
19
|
sessionServicesFactories: new Map(),
|
|
20
20
|
configFactories: new Map(),
|
|
21
|
+
functions: {
|
|
22
|
+
typesMap: new TypesMap(),
|
|
23
|
+
meta: {},
|
|
24
|
+
files: new Set(),
|
|
25
|
+
},
|
|
21
26
|
http: {
|
|
22
27
|
typesMap: new TypesMap(),
|
|
23
28
|
metaInputTypes: new Map(),
|
|
@@ -28,15 +33,20 @@ export const inspect = (routeFiles, filters) => {
|
|
|
28
33
|
typesMap: new TypesMap(),
|
|
29
34
|
metaInputTypes: new Map(),
|
|
30
35
|
files: new Set(),
|
|
31
|
-
meta:
|
|
36
|
+
meta: {},
|
|
32
37
|
},
|
|
33
38
|
scheduledTasks: {
|
|
34
|
-
meta:
|
|
39
|
+
meta: {},
|
|
35
40
|
files: new Set(),
|
|
36
41
|
},
|
|
37
42
|
};
|
|
43
|
+
// First sweep: add all functions
|
|
44
|
+
for (const sourceFile of sourceFiles) {
|
|
45
|
+
ts.forEachChild(sourceFile, (child) => visitSetup(checker, child, state, filters));
|
|
46
|
+
}
|
|
47
|
+
// Second sweep: add all transports
|
|
38
48
|
for (const sourceFile of sourceFiles) {
|
|
39
|
-
ts.forEachChild(sourceFile, (child) =>
|
|
49
|
+
ts.forEachChild(sourceFile, (child) => visitRoutes(checker, child, state, filters));
|
|
40
50
|
}
|
|
41
51
|
// Normalise the typesMap
|
|
42
52
|
state.http = normalizeHTTPTypes(state.http);
|
package/dist/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { ChannelsMeta } from '@pikku/core/channel';
|
|
|
2
2
|
import { HTTPRoutesMeta } from '@pikku/core/http';
|
|
3
3
|
import { ScheduledTasksMeta } from '@pikku/core/scheduler';
|
|
4
4
|
import { TypesMap } from './types-map.js';
|
|
5
|
+
import { FunctionsMeta } from '@pikku/core';
|
|
5
6
|
export type PathToNameAndType = Map<string, {
|
|
6
7
|
variable: string;
|
|
7
8
|
type: string | null;
|
|
@@ -12,22 +13,17 @@ export type MetaInputTypes = Map<string, {
|
|
|
12
13
|
params: string[] | undefined;
|
|
13
14
|
body: string[] | undefined;
|
|
14
15
|
}>;
|
|
15
|
-
export type APIFunctionMeta = Array<{
|
|
16
|
-
name: string;
|
|
17
|
-
input: string;
|
|
18
|
-
output: string;
|
|
19
|
-
file: string;
|
|
20
|
-
}>;
|
|
21
|
-
export type InspectorAPIFunction = {
|
|
22
|
-
typesMap: TypesMap;
|
|
23
|
-
meta: APIFunctionMeta;
|
|
24
|
-
};
|
|
25
16
|
export interface InspectorHTTPState {
|
|
26
17
|
typesMap: TypesMap;
|
|
27
18
|
metaInputTypes: MetaInputTypes;
|
|
28
19
|
meta: HTTPRoutesMeta;
|
|
29
20
|
files: Set<string>;
|
|
30
21
|
}
|
|
22
|
+
export interface InspectorFunctionState {
|
|
23
|
+
typesMap: TypesMap;
|
|
24
|
+
meta: FunctionsMeta;
|
|
25
|
+
files: Set<string>;
|
|
26
|
+
}
|
|
31
27
|
export interface InspectorChannelState {
|
|
32
28
|
typesMap: TypesMap;
|
|
33
29
|
metaInputTypes: MetaInputTypes;
|
|
@@ -45,6 +41,7 @@ export interface InspectorState {
|
|
|
45
41
|
sessionServicesFactories: PathToNameAndType;
|
|
46
42
|
configFactories: PathToNameAndType;
|
|
47
43
|
http: InspectorHTTPState;
|
|
44
|
+
functions: InspectorFunctionState;
|
|
48
45
|
channels: InspectorChannelState;
|
|
49
46
|
scheduledTasks: {
|
|
50
47
|
meta: ScheduledTasksMeta;
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,34 +1,28 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { TypesMap } from './types-map.js';
|
|
3
2
|
import { InspectorFilters } from './types.js';
|
|
4
|
-
type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
type ExtractedFunctionName = {
|
|
4
|
+
pikkuFuncName: string;
|
|
5
|
+
name: string;
|
|
6
|
+
exportedName: string | null;
|
|
7
|
+
functionName: string | null;
|
|
8
|
+
propertyName: string | null;
|
|
10
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* Generate a deterministic "anonymous" name for any expression node,
|
|
12
|
+
* but if it's an Identifier pointing to a function, resolve it back
|
|
13
|
+
* to the function's declaration (so you get the true source location).
|
|
14
|
+
*/
|
|
15
|
+
export declare function makeDeterministicAnonName(start: ts.Node, checker: ts.TypeChecker): string;
|
|
16
|
+
/**
|
|
17
|
+
* Updated function to extract and prioritize function names correctly
|
|
18
|
+
* This function follows the priority:
|
|
19
|
+
* 1. Object with a name property
|
|
20
|
+
* 2. Exported name
|
|
21
|
+
* 3. Fallback to deterministic name
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractFunctionName(callExpr: ts.Node, checker: ts.TypeChecker): ExtractedFunctionName;
|
|
11
24
|
export declare const extractTypeKeys: (type: ts.Type) => string[];
|
|
12
|
-
export declare
|
|
13
|
-
export declare const getNamesAndTypes: (checker: ts.TypeChecker, typesMap: TypesMap, direction: "Input" | "Output", funcName: string, type: ts.Type) => {
|
|
14
|
-
names: string[];
|
|
15
|
-
types: ts.Type[];
|
|
16
|
-
};
|
|
17
|
-
export declare const isPrimitiveType: (type: ts.Type) => boolean;
|
|
18
|
-
export declare const resolveUnionTypes: (checker: ts.TypeChecker, type: ts.Type) => {
|
|
19
|
-
types: ts.Type[];
|
|
20
|
-
names: string[];
|
|
21
|
-
};
|
|
22
|
-
export declare const resolveTypeImports: (type: ts.Type, resolvedTypes: TypesMap, isCustom: boolean) => string[];
|
|
23
|
-
export declare const getPropertyAssignment: (obj: ts.ObjectLiteralExpression, name: string) => ts.ObjectLiteralElementLike | null;
|
|
24
|
-
export declare const getTypeArgumentsOfType: (checker: ts.TypeChecker, type: ts.Type) => readonly ts.Type[] | null;
|
|
25
|
-
export declare const getFunctionTypes: (checker: ts.TypeChecker, obj: ts.ObjectLiteralExpression, { typesMap, funcName, subFunctionName, inputIndex, outputIndex, }: {
|
|
26
|
-
typesMap: TypesMap;
|
|
27
|
-
subFunctionName?: string;
|
|
28
|
-
funcName: string;
|
|
29
|
-
inputIndex: number;
|
|
30
|
-
outputIndex: number;
|
|
31
|
-
}) => FunctionTypes;
|
|
25
|
+
export declare function getPropertyAssignmentInitializer(obj: ts.ObjectLiteralExpression, propName: string, followShorthand?: boolean, checker?: ts.TypeChecker): ts.Expression | undefined;
|
|
32
26
|
export declare const matchesFilters: (filters: InspectorFilters, params: {
|
|
33
27
|
tags?: string[];
|
|
34
28
|
}, meta: {
|