@pikku/inspector 0.6.2
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 +17 -0
- package/README.md +3 -0
- package/dist/add-channel.d.ts +3 -0
- package/dist/add-channel.js +122 -0
- package/dist/add-file-extends-core-type.d.ts +3 -0
- package/dist/add-file-extends-core-type.js +38 -0
- package/dist/add-file-with-config.d.ts +3 -0
- package/dist/add-file-with-config.js +31 -0
- package/dist/add-file-with-factory.d.ts +3 -0
- package/dist/add-file-with-factory.js +48 -0
- package/dist/add-route.d.ts +4 -0
- package/dist/add-route.js +89 -0
- package/dist/add-schedule.d.ts +3 -0
- package/dist/add-schedule.js +32 -0
- package/dist/does-type-extend-core-type.d.ts +2 -0
- package/dist/does-type-extend-core-type.js +41 -0
- package/dist/get-property-value.d.ts +3 -0
- package/dist/get-property-value.js +60 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -0
- package/dist/inspector.d.ts +3 -0
- package/dist/inspector.js +43 -0
- package/dist/types-map.d.ts +18 -0
- package/dist/types-map.js +103 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +30 -0
- package/dist/utils.js +245 -0
- package/dist/visit.d.ts +3 -0
- package/dist/visit.js +17 -0
- package/package.json +30 -0
- package/run-tests.sh +53 -0
- package/src/add-channel.ts +168 -0
- package/src/add-file-extends-core-type.ts +50 -0
- package/src/add-file-with-config.ts +45 -0
- package/src/add-file-with-factory.ts +65 -0
- package/src/add-route.ts +131 -0
- package/src/add-schedule.ts +47 -0
- package/src/does-type-extend-core-type.ts +53 -0
- package/src/get-property-value.ts +81 -0
- package/src/index.ts +4 -0
- package/src/inspector.ts +53 -0
- package/src/types-map.ts +130 -0
- package/src/types.ts +58 -0
- package/src/utils.ts +349 -0
- package/src/visit.ts +49 -0
- package/tsconfig.json +19 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
export class TypesMap {
|
|
2
|
+
map = new Map();
|
|
3
|
+
customTypes = new Map();
|
|
4
|
+
addCustomType(name, type, references) {
|
|
5
|
+
this.customTypes.set(name, { type, references });
|
|
6
|
+
}
|
|
7
|
+
addType(originalName, path) {
|
|
8
|
+
this.map.set(originalName, { originalName, path });
|
|
9
|
+
}
|
|
10
|
+
addUniqueType(originalName, path) {
|
|
11
|
+
const uniqueName = `${originalName}_${Math.random().toString(36).substring(7)}`;
|
|
12
|
+
this.map.set(uniqueName, { originalName, path });
|
|
13
|
+
return uniqueName;
|
|
14
|
+
}
|
|
15
|
+
getUniqueName(name) {
|
|
16
|
+
const meta = this.getTypeMeta(name);
|
|
17
|
+
return meta.uniqueName;
|
|
18
|
+
}
|
|
19
|
+
getTypeMeta(name) {
|
|
20
|
+
if (['string', 'number', 'boolean', 'null'].includes(name)) {
|
|
21
|
+
return {
|
|
22
|
+
originalName: name,
|
|
23
|
+
uniqueName: name,
|
|
24
|
+
path: null,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (this.customTypes.has(name)) {
|
|
28
|
+
return {
|
|
29
|
+
originalName: name,
|
|
30
|
+
uniqueName: name,
|
|
31
|
+
path: null,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
let meta = this.map.get(name);
|
|
35
|
+
if (!meta) {
|
|
36
|
+
meta = Array.from(this.map.entries()).find(([_, { originalName }]) => originalName === name)?.[1];
|
|
37
|
+
}
|
|
38
|
+
if (!meta) {
|
|
39
|
+
throw new Error(`Type ${name} not found in typesMap`);
|
|
40
|
+
}
|
|
41
|
+
const getName = this.squash();
|
|
42
|
+
return {
|
|
43
|
+
uniqueName: getName(name),
|
|
44
|
+
originalName: meta.originalName,
|
|
45
|
+
path: meta?.path,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
exists(originalName, path) {
|
|
49
|
+
const found = Array.from(this.map.entries()).find(([_, type]) => {
|
|
50
|
+
return type.path === path && type.originalName === originalName;
|
|
51
|
+
});
|
|
52
|
+
return found ? found[0] : undefined;
|
|
53
|
+
}
|
|
54
|
+
squash() {
|
|
55
|
+
const duplicateNames = new Set();
|
|
56
|
+
const pathToNamesMap = new Map();
|
|
57
|
+
const nameOccurrences = new Map();
|
|
58
|
+
// First pass: Track occurrences of each original name across paths
|
|
59
|
+
this.map.forEach(({ path, originalName }) => {
|
|
60
|
+
if (path) {
|
|
61
|
+
if (!nameOccurrences.has(originalName)) {
|
|
62
|
+
nameOccurrences.set(originalName, new Set());
|
|
63
|
+
}
|
|
64
|
+
nameOccurrences.get(originalName).add(path);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
// Second pass: Populate pathToNamesMap
|
|
68
|
+
this.map.forEach(({ path, originalName }, uniqueName) => {
|
|
69
|
+
if (!path)
|
|
70
|
+
return;
|
|
71
|
+
if (!pathToNamesMap.has(path)) {
|
|
72
|
+
pathToNamesMap.set(path, new Map());
|
|
73
|
+
}
|
|
74
|
+
const isDuplicate = nameOccurrences.get(originalName).size > 1;
|
|
75
|
+
if (isDuplicate) {
|
|
76
|
+
duplicateNames.add(uniqueName);
|
|
77
|
+
}
|
|
78
|
+
// Use uniqueName only if the originalName is duplicated across files
|
|
79
|
+
const nameToUse = isDuplicate ? uniqueName : originalName;
|
|
80
|
+
pathToNamesMap.get(path).set(nameToUse, originalName);
|
|
81
|
+
});
|
|
82
|
+
const getName = (uniqueName) => {
|
|
83
|
+
if (duplicateNames.has(uniqueName)) {
|
|
84
|
+
return uniqueName;
|
|
85
|
+
}
|
|
86
|
+
if (uniqueName === 'string' ||
|
|
87
|
+
uniqueName === 'number' ||
|
|
88
|
+
uniqueName === 'boolean' ||
|
|
89
|
+
uniqueName === 'null') {
|
|
90
|
+
return uniqueName;
|
|
91
|
+
}
|
|
92
|
+
if (!this.map.has(uniqueName)) {
|
|
93
|
+
const found = Array.from(this.map.entries()).find(([_, { originalName }]) => originalName === uniqueName)?.[1];
|
|
94
|
+
if (!found) {
|
|
95
|
+
throw new Error(`Type ${uniqueName} not found in typesMap`);
|
|
96
|
+
}
|
|
97
|
+
return found.originalName;
|
|
98
|
+
}
|
|
99
|
+
return this.map.get(uniqueName).originalName;
|
|
100
|
+
};
|
|
101
|
+
return getName;
|
|
102
|
+
}
|
|
103
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ChannelsMeta } from '@pikku/core/channel';
|
|
2
|
+
import { HTTPRoutesMeta } from '@pikku/core/http';
|
|
3
|
+
import { ScheduledTasksMeta } from '@pikku/core/scheduler';
|
|
4
|
+
import { TypesMap } from './types-map.js';
|
|
5
|
+
export type PathToNameAndType = Map<string, {
|
|
6
|
+
variable: string;
|
|
7
|
+
type: string | null;
|
|
8
|
+
typePath: string | null;
|
|
9
|
+
}[]>;
|
|
10
|
+
export type MetaInputTypes = Map<string, {
|
|
11
|
+
query: string[] | undefined;
|
|
12
|
+
params: string[] | undefined;
|
|
13
|
+
body: string[] | undefined;
|
|
14
|
+
}>;
|
|
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
|
+
export interface InspectorHTTPState {
|
|
26
|
+
typesMap: TypesMap;
|
|
27
|
+
metaInputTypes: MetaInputTypes;
|
|
28
|
+
meta: HTTPRoutesMeta;
|
|
29
|
+
files: Set<string>;
|
|
30
|
+
}
|
|
31
|
+
export interface InspectorChannelState {
|
|
32
|
+
typesMap: TypesMap;
|
|
33
|
+
metaInputTypes: MetaInputTypes;
|
|
34
|
+
meta: ChannelsMeta;
|
|
35
|
+
files: Set<string>;
|
|
36
|
+
}
|
|
37
|
+
export interface InspectorState {
|
|
38
|
+
sessionServicesTypeImportMap: PathToNameAndType;
|
|
39
|
+
userSessionTypeImportMap: PathToNameAndType;
|
|
40
|
+
singletonServicesFactories: PathToNameAndType;
|
|
41
|
+
sessionServicesFactories: PathToNameAndType;
|
|
42
|
+
configFactories: PathToNameAndType;
|
|
43
|
+
http: InspectorHTTPState;
|
|
44
|
+
channels: InspectorChannelState;
|
|
45
|
+
scheduledTasks: {
|
|
46
|
+
meta: ScheduledTasksMeta;
|
|
47
|
+
files: Set<string>;
|
|
48
|
+
};
|
|
49
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { TypesMap } from './types-map.js';
|
|
3
|
+
type FunctionTypes = {
|
|
4
|
+
inputTypes: ts.Type[];
|
|
5
|
+
inputs: null | string[];
|
|
6
|
+
outputTypes: ts.Type[];
|
|
7
|
+
outputs: null | string[];
|
|
8
|
+
};
|
|
9
|
+
export declare const extractTypeKeys: (type: ts.Type) => string[];
|
|
10
|
+
export declare const nullifyTypes: (type: string | null) => string | null;
|
|
11
|
+
export declare const getNamesAndTypes: (checker: ts.TypeChecker, typesMap: TypesMap, direction: "Input" | "Output", funcName: string, type: ts.Type) => {
|
|
12
|
+
names: string[];
|
|
13
|
+
types: ts.Type[];
|
|
14
|
+
};
|
|
15
|
+
export declare const isPrimitiveType: (type: ts.Type) => boolean;
|
|
16
|
+
export declare const resolveUnionTypes: (checker: ts.TypeChecker, type: ts.Type) => {
|
|
17
|
+
types: ts.Type[];
|
|
18
|
+
names: string[];
|
|
19
|
+
};
|
|
20
|
+
export declare const resolveTypeImports: (type: ts.Type, resolvedTypes: TypesMap, isCustom: boolean) => string[];
|
|
21
|
+
export declare const getPropertyAssignment: (obj: ts.ObjectLiteralExpression, name: string) => ts.ObjectLiteralElementLike | null;
|
|
22
|
+
export declare const getTypeArgumentsOfType: (checker: ts.TypeChecker, type: ts.Type) => readonly ts.Type[] | null;
|
|
23
|
+
export declare const getFunctionTypes: (checker: ts.TypeChecker, obj: ts.ObjectLiteralExpression, { typesMap, funcName, subFunctionName, inputIndex, outputIndex, }: {
|
|
24
|
+
typesMap: TypesMap;
|
|
25
|
+
subFunctionName?: string;
|
|
26
|
+
funcName: string;
|
|
27
|
+
inputIndex: number;
|
|
28
|
+
outputIndex: number;
|
|
29
|
+
}) => FunctionTypes;
|
|
30
|
+
export {};
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
export const extractTypeKeys = (type) => {
|
|
3
|
+
return type.getProperties().map((symbol) => symbol.getName());
|
|
4
|
+
};
|
|
5
|
+
export const nullifyTypes = (type) => {
|
|
6
|
+
if (type === 'void' ||
|
|
7
|
+
type === 'undefined' ||
|
|
8
|
+
type === 'unknown' ||
|
|
9
|
+
type === 'any') {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
return type;
|
|
13
|
+
};
|
|
14
|
+
const isValidVariableName = (name) => {
|
|
15
|
+
const regex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
16
|
+
return regex.test(name);
|
|
17
|
+
};
|
|
18
|
+
export const getNamesAndTypes = (checker, typesMap, direction, funcName, type) => {
|
|
19
|
+
const result = {
|
|
20
|
+
names: new Set(),
|
|
21
|
+
types: [],
|
|
22
|
+
};
|
|
23
|
+
const { names, types } = resolveUnionTypes(checker, type);
|
|
24
|
+
const firstName = names[0];
|
|
25
|
+
if (names.length > 1 || (firstName && !isValidVariableName(firstName))) {
|
|
26
|
+
const aliasType = names.join(' | ');
|
|
27
|
+
const aliasName = `${funcName.charAt(0).toUpperCase()}${funcName.slice(1)}${direction}`;
|
|
28
|
+
result.names = new Set([aliasName]);
|
|
29
|
+
result.types = types;
|
|
30
|
+
const references = types
|
|
31
|
+
.map((t) => resolveTypeImports(t, typesMap, true))
|
|
32
|
+
.flat();
|
|
33
|
+
typesMap.addCustomType(aliasName, aliasType, references);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const uniqueNames = names
|
|
37
|
+
.map((name, i) => {
|
|
38
|
+
const type = types[i];
|
|
39
|
+
if (!type) {
|
|
40
|
+
throw new Error('TODO: Expected a type here to match name');
|
|
41
|
+
}
|
|
42
|
+
if (isPrimitiveType(type)) {
|
|
43
|
+
return name;
|
|
44
|
+
}
|
|
45
|
+
return resolveTypeImports(type, typesMap, false);
|
|
46
|
+
})
|
|
47
|
+
.flat();
|
|
48
|
+
result.names = new Set(uniqueNames);
|
|
49
|
+
result.types = types;
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
names: Array.from(result.names),
|
|
53
|
+
types: result.types,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
export const isPrimitiveType = (type) => {
|
|
57
|
+
const primitiveFlags = ts.TypeFlags.Number |
|
|
58
|
+
ts.TypeFlags.String |
|
|
59
|
+
ts.TypeFlags.Boolean |
|
|
60
|
+
ts.TypeFlags.BigInt |
|
|
61
|
+
ts.TypeFlags.ESSymbol |
|
|
62
|
+
ts.TypeFlags.Void |
|
|
63
|
+
ts.TypeFlags.Undefined |
|
|
64
|
+
ts.TypeFlags.Null |
|
|
65
|
+
ts.TypeFlags.Any |
|
|
66
|
+
ts.TypeFlags.Unknown;
|
|
67
|
+
return (type.flags & primitiveFlags) !== 0;
|
|
68
|
+
};
|
|
69
|
+
export const resolveUnionTypes = (checker, type) => {
|
|
70
|
+
const types = [];
|
|
71
|
+
const names = [];
|
|
72
|
+
// Check if it's a union type AND not part of an intersection
|
|
73
|
+
if (type.isUnion() && !(type.flags & ts.TypeFlags.Intersection)) {
|
|
74
|
+
for (const t of type.types) {
|
|
75
|
+
const name = nullifyTypes(checker.typeToString(t));
|
|
76
|
+
if (name) {
|
|
77
|
+
types.push(t);
|
|
78
|
+
names.push(name);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const name = nullifyTypes(checker.typeToString(type));
|
|
84
|
+
if (name) {
|
|
85
|
+
types.push(type);
|
|
86
|
+
names.push(name);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return { types, names };
|
|
90
|
+
};
|
|
91
|
+
export const resolveTypeImports = (type, resolvedTypes, isCustom) => {
|
|
92
|
+
const types = [];
|
|
93
|
+
const visitType = (currentType) => {
|
|
94
|
+
const symbol = currentType.aliasSymbol || currentType.getSymbol();
|
|
95
|
+
if (symbol) {
|
|
96
|
+
const declarations = symbol.getDeclarations();
|
|
97
|
+
const declaration = declarations?.[0];
|
|
98
|
+
if (declaration) {
|
|
99
|
+
const sourceFile = declaration.getSourceFile();
|
|
100
|
+
const path = sourceFile.fileName;
|
|
101
|
+
// Skip built-in utility types or TypeScript lib types
|
|
102
|
+
if (!path.includes('node_modules/typescript') &&
|
|
103
|
+
symbol.getName() !== '__type' &&
|
|
104
|
+
!isPrimitiveType(currentType)) {
|
|
105
|
+
const originalName = symbol.getName();
|
|
106
|
+
// Check if the type is already in the map
|
|
107
|
+
let uniqueName = resolvedTypes.exists(originalName, path);
|
|
108
|
+
if (!uniqueName) {
|
|
109
|
+
if (isCustom) {
|
|
110
|
+
uniqueName = resolvedTypes.addUniqueType(originalName, path);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
resolvedTypes.addType(originalName, path);
|
|
114
|
+
uniqueName = originalName;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
types.push(uniqueName);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (isCustom) {
|
|
122
|
+
// Handle nested utility types like Partial, Pick, etc.
|
|
123
|
+
if (currentType.aliasTypeArguments) {
|
|
124
|
+
currentType.aliasTypeArguments.forEach(visitType);
|
|
125
|
+
}
|
|
126
|
+
// Handle intersections and unions
|
|
127
|
+
if (currentType.isUnionOrIntersection()) {
|
|
128
|
+
currentType.types.forEach(visitType);
|
|
129
|
+
}
|
|
130
|
+
// Handle object types with type arguments
|
|
131
|
+
if (currentType.flags & ts.TypeFlags.Object &&
|
|
132
|
+
currentType.objectFlags & ts.ObjectFlags.Reference) {
|
|
133
|
+
const typeRef = currentType;
|
|
134
|
+
typeRef.typeArguments?.forEach(visitType);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
visitType(type);
|
|
139
|
+
return types;
|
|
140
|
+
};
|
|
141
|
+
export const getPropertyAssignment = (obj, name) => {
|
|
142
|
+
const property = obj.properties.find((p) => (ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) &&
|
|
143
|
+
ts.isIdentifier(p.name) &&
|
|
144
|
+
p.name.text === name);
|
|
145
|
+
if (!property) {
|
|
146
|
+
console.error(`Missing property '${name}' in object`);
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
return property;
|
|
150
|
+
};
|
|
151
|
+
export const getTypeArgumentsOfType = (checker, type) => {
|
|
152
|
+
if (type.isUnionOrIntersection()) {
|
|
153
|
+
const types = [];
|
|
154
|
+
for (const subType of type.types) {
|
|
155
|
+
const subTypeArgs = getTypeArgumentsOfType(checker, subType);
|
|
156
|
+
if (subTypeArgs) {
|
|
157
|
+
types.push(...subTypeArgs);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return types.length > 0 ? types : null;
|
|
161
|
+
}
|
|
162
|
+
// If the type is a TypeReference with typeArguments, return them
|
|
163
|
+
if (type.flags & ts.TypeFlags.Object &&
|
|
164
|
+
type.objectFlags & ts.ObjectFlags.Reference) {
|
|
165
|
+
const typeRef = type;
|
|
166
|
+
if (typeRef.typeArguments && typeRef.typeArguments.length > 0) {
|
|
167
|
+
return typeRef.typeArguments;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// If the type is an alias with aliasTypeArguments, return them
|
|
171
|
+
if (type.aliasTypeArguments && type.aliasTypeArguments.length > 0) {
|
|
172
|
+
return type.aliasTypeArguments;
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
};
|
|
176
|
+
export const getFunctionTypes = (checker, obj, { typesMap, funcName, subFunctionName = funcName, inputIndex, outputIndex, }) => {
|
|
177
|
+
const result = {
|
|
178
|
+
inputTypes: [],
|
|
179
|
+
inputs: null,
|
|
180
|
+
outputTypes: [],
|
|
181
|
+
outputs: null,
|
|
182
|
+
};
|
|
183
|
+
const property = getPropertyAssignment(obj, subFunctionName);
|
|
184
|
+
if (!property) {
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
let type;
|
|
188
|
+
// Handle shorthand property assignment
|
|
189
|
+
if (ts.isShorthandPropertyAssignment(property)) {
|
|
190
|
+
const symbol = checker.getShorthandAssignmentValueSymbol(property);
|
|
191
|
+
if (symbol) {
|
|
192
|
+
type = checker.getTypeOfSymbolAtLocation(symbol, property);
|
|
193
|
+
if (funcName === 'func') {
|
|
194
|
+
funcName = symbol.name;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Handle regular property assignment
|
|
199
|
+
else if (ts.isPropertyAssignment(property)) {
|
|
200
|
+
if (ts.isObjectLiteralExpression(property.initializer)) {
|
|
201
|
+
return getFunctionTypes(checker, property.initializer, {
|
|
202
|
+
typesMap,
|
|
203
|
+
funcName,
|
|
204
|
+
subFunctionName: 'func',
|
|
205
|
+
inputIndex,
|
|
206
|
+
outputIndex,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (property.initializer) {
|
|
210
|
+
type = checker.getTypeAtLocation(property.initializer);
|
|
211
|
+
if (funcName === 'func') {
|
|
212
|
+
funcName = property.initializer.getText();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!type) {
|
|
217
|
+
console.error(`Unable to resolve type for property '${funcName}'`);
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
// Access type arguments from TypeReference
|
|
221
|
+
const typeArguments = getTypeArgumentsOfType(checker, type);
|
|
222
|
+
if (!typeArguments || typeArguments.length === 0) {
|
|
223
|
+
// This is the case for inline functions. In this case we would want to
|
|
224
|
+
// get the types from the second argument of the function...
|
|
225
|
+
console.error(`\x1b[31m• No generic type arguments found for ${funcName}. Support for inline functions is not yet implemented.\x1b[0m`);
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
if (inputIndex !== undefined && inputIndex < typeArguments.length) {
|
|
229
|
+
const { names, types } = getNamesAndTypes(checker, typesMap, 'Input', funcName, typeArguments[inputIndex]);
|
|
230
|
+
result.inputs = names;
|
|
231
|
+
result.inputTypes = types;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
console.log(`No input defined for ${funcName}`);
|
|
235
|
+
}
|
|
236
|
+
if (outputIndex !== undefined && outputIndex < typeArguments.length) {
|
|
237
|
+
const { names, types } = getNamesAndTypes(checker, typesMap, 'Output', funcName, typeArguments[outputIndex]);
|
|
238
|
+
result.outputs = names;
|
|
239
|
+
result.outputTypes = types;
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
console.info(`No output defined for ${funcName}`);
|
|
243
|
+
}
|
|
244
|
+
return result;
|
|
245
|
+
};
|
package/dist/visit.d.ts
ADDED
package/dist/visit.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
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 { addRoute } from './add-route.js';
|
|
5
|
+
import { addSchedule } from './add-schedule.js';
|
|
6
|
+
import { addChannel } from './add-channel.js';
|
|
7
|
+
export const visit = (checker, node, state) => {
|
|
8
|
+
addFileExtendsCoreType(node, checker, state.sessionServicesTypeImportMap, 'CoreServices');
|
|
9
|
+
addFileExtendsCoreType(node, checker, state.userSessionTypeImportMap, 'CoreUserSession');
|
|
10
|
+
addFileWithFactory(node, checker, state.singletonServicesFactories, 'CreateSingletonServices');
|
|
11
|
+
addFileWithFactory(node, checker, state.sessionServicesFactories, 'CreateSessionServices');
|
|
12
|
+
addFileWithFactory(node, checker, state.configFactories, 'CreateConfig');
|
|
13
|
+
addRoute(node, checker, state);
|
|
14
|
+
addSchedule(node, checker, state);
|
|
15
|
+
addChannel(node, checker, state);
|
|
16
|
+
ts.forEachChild(node, (child) => visit(checker, child, state));
|
|
17
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pikku/inspector",
|
|
3
|
+
"version": "0.6.2",
|
|
4
|
+
"author": "yasser.fadl@gmail.com",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"tsc": "tsc",
|
|
11
|
+
"build:esm": "tsc -b",
|
|
12
|
+
"build": "yarn build:esm",
|
|
13
|
+
"ncu": "ncu -x '/.*glob.*/'",
|
|
14
|
+
"release": "yarn build && npm test",
|
|
15
|
+
"test": "bash run-tests.sh",
|
|
16
|
+
"test:watch": "bash run-tests.sh --watch",
|
|
17
|
+
"test:coverage": "bash run-tests.sh --coverage"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@pikku/core": "^0.6.5",
|
|
21
|
+
"path-to-regexp": "^8.2.0",
|
|
22
|
+
"typescript": "^5.6"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^22.7.8"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/run-tests.sh
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Enable nullglob to handle cases where no files match the pattern
|
|
4
|
+
shopt -s nullglob
|
|
5
|
+
|
|
6
|
+
# Initialize variables for options
|
|
7
|
+
watch_mode=false
|
|
8
|
+
coverage_mode=false
|
|
9
|
+
|
|
10
|
+
# Parse command-line options
|
|
11
|
+
while [[ $# -gt 0 ]]; do
|
|
12
|
+
case $1 in
|
|
13
|
+
--watch)
|
|
14
|
+
watch_mode=true
|
|
15
|
+
shift
|
|
16
|
+
;;
|
|
17
|
+
--coverage)
|
|
18
|
+
coverage_mode=true
|
|
19
|
+
shift
|
|
20
|
+
;;
|
|
21
|
+
*)
|
|
22
|
+
echo "Unknown option: $1"
|
|
23
|
+
exit 1
|
|
24
|
+
;;
|
|
25
|
+
esac
|
|
26
|
+
done
|
|
27
|
+
|
|
28
|
+
# Define the pattern to match your test files
|
|
29
|
+
pattern="src/*.test.ts"
|
|
30
|
+
|
|
31
|
+
# Expand the pattern into an array of files
|
|
32
|
+
files=($(find src -type f -name "*.test.ts"))
|
|
33
|
+
|
|
34
|
+
# Check if any files matched the pattern
|
|
35
|
+
if [ ${#files[@]} -eq 0 ]; then
|
|
36
|
+
echo "No test files found matching pattern: $pattern"
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Construct the node command
|
|
41
|
+
node_cmd="node --import tsx --test"
|
|
42
|
+
|
|
43
|
+
# Append options based on flags
|
|
44
|
+
if [ "$watch_mode" = true ]; then
|
|
45
|
+
node_cmd="$node_cmd --watch"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
if [ "$coverage_mode" = true ]; then
|
|
49
|
+
node_cmd="$node_cmd --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Execute the node command with the expanded list of files
|
|
53
|
+
$node_cmd "${files[@]}"
|