@pikku/inspector 0.7.0 → 0.7.1
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 +6 -0
- package/dist/add-functions.js +10 -1
- package/package.json +1 -1
- package/src/add-channel.ts +482 -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-functions.ts +376 -0
- package/src/add-http-route.ts +123 -0
- package/src/add-schedule.ts +76 -0
- package/src/does-type-extend-core-type.ts +53 -0
- package/src/get-property-value.ts +84 -0
- package/src/index.ts +4 -0
- package/src/inspector.ts +75 -0
- package/src/types-map.ts +130 -0
- package/src/types.ts +58 -0
- package/src/utils.ts +863 -0
- package/src/visit.ts +67 -0
- package/tsconfig.json +19 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/events/add-channel.d.ts +0 -1
- package/dist/events/add-channel.js +0 -170
- package/dist/events/add-http-route.d.ts +0 -16
- package/dist/events/add-http-route.js +0 -83
- package/dist/events/add-schedule.d.ts +0 -3
- package/dist/events/add-schedule.js +0 -38
package/src/index.ts
ADDED
package/src/inspector.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import { visitSetup, visitRoutes } from './visit.js'
|
|
3
|
+
import { TypesMap } from './types-map.js'
|
|
4
|
+
import {
|
|
5
|
+
InspectorState,
|
|
6
|
+
InspectorHTTPState,
|
|
7
|
+
InspectorFilters,
|
|
8
|
+
} from './types.js'
|
|
9
|
+
|
|
10
|
+
export const normalizeHTTPTypes = (
|
|
11
|
+
httpState: InspectorHTTPState
|
|
12
|
+
): InspectorHTTPState => {
|
|
13
|
+
return httpState
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const inspect = (
|
|
17
|
+
routeFiles: string[],
|
|
18
|
+
filters: InspectorFilters
|
|
19
|
+
): InspectorState => {
|
|
20
|
+
const program = ts.createProgram(routeFiles, {
|
|
21
|
+
target: ts.ScriptTarget.ESNext,
|
|
22
|
+
module: ts.ModuleKind.CommonJS,
|
|
23
|
+
})
|
|
24
|
+
const checker = program.getTypeChecker()
|
|
25
|
+
const sourceFiles = program.getSourceFiles()
|
|
26
|
+
|
|
27
|
+
const state: InspectorState = {
|
|
28
|
+
singletonServicesTypeImportMap: new Map(),
|
|
29
|
+
sessionServicesTypeImportMap: new Map(),
|
|
30
|
+
userSessionTypeImportMap: new Map(),
|
|
31
|
+
singletonServicesFactories: new Map(),
|
|
32
|
+
sessionServicesFactories: new Map(),
|
|
33
|
+
configFactories: new Map(),
|
|
34
|
+
functions: {
|
|
35
|
+
typesMap: new TypesMap(),
|
|
36
|
+
meta: {},
|
|
37
|
+
files: new Set(),
|
|
38
|
+
},
|
|
39
|
+
http: {
|
|
40
|
+
typesMap: new TypesMap(),
|
|
41
|
+
metaInputTypes: new Map(),
|
|
42
|
+
meta: [],
|
|
43
|
+
files: new Set(),
|
|
44
|
+
},
|
|
45
|
+
channels: {
|
|
46
|
+
typesMap: new TypesMap(),
|
|
47
|
+
metaInputTypes: new Map(),
|
|
48
|
+
files: new Set(),
|
|
49
|
+
meta: {},
|
|
50
|
+
},
|
|
51
|
+
scheduledTasks: {
|
|
52
|
+
meta: {},
|
|
53
|
+
files: new Set(),
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// First sweep: add all functions
|
|
58
|
+
for (const sourceFile of sourceFiles) {
|
|
59
|
+
ts.forEachChild(sourceFile, (child) =>
|
|
60
|
+
visitSetup(checker, child, state, filters)
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Second sweep: add all transports
|
|
65
|
+
for (const sourceFile of sourceFiles) {
|
|
66
|
+
ts.forEachChild(sourceFile, (child) =>
|
|
67
|
+
visitRoutes(checker, child, state, filters)
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Normalise the typesMap
|
|
72
|
+
state.http = normalizeHTTPTypes(state.http)
|
|
73
|
+
|
|
74
|
+
return state
|
|
75
|
+
}
|
package/src/types-map.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export class TypesMap {
|
|
2
|
+
private map: Map<string, { originalName: string; path: string | null }> =
|
|
3
|
+
new Map()
|
|
4
|
+
public customTypes: Map<string, { type: string; references: string[] }> =
|
|
5
|
+
new Map()
|
|
6
|
+
|
|
7
|
+
public addCustomType(name: string, type: string, references: string[]) {
|
|
8
|
+
this.customTypes.set(name, { type, references })
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public addType(originalName: string, path: string) {
|
|
12
|
+
this.map.set(originalName, { originalName, path })
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public addUniqueType(originalName: string, path: string): string {
|
|
16
|
+
const uniqueName = `${originalName}_${Math.random().toString(36).substring(7)}`
|
|
17
|
+
this.map.set(uniqueName, { originalName, path })
|
|
18
|
+
return uniqueName
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public getUniqueName(name: string): string {
|
|
22
|
+
const meta = this.getTypeMeta(name)
|
|
23
|
+
return meta.uniqueName
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public getTypeMeta(name: string): {
|
|
27
|
+
originalName: string
|
|
28
|
+
uniqueName: string
|
|
29
|
+
path: string | null
|
|
30
|
+
} {
|
|
31
|
+
if (['string', 'number', 'boolean', 'null'].includes(name)) {
|
|
32
|
+
return {
|
|
33
|
+
originalName: name,
|
|
34
|
+
uniqueName: name,
|
|
35
|
+
path: null,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (this.customTypes.has(name)) {
|
|
40
|
+
return {
|
|
41
|
+
originalName: name,
|
|
42
|
+
uniqueName: name,
|
|
43
|
+
path: null,
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let meta = this.map.get(name)
|
|
48
|
+
if (!meta) {
|
|
49
|
+
meta = Array.from(this.map.entries()).find(
|
|
50
|
+
([_, { originalName }]) => originalName === name
|
|
51
|
+
)?.[1]
|
|
52
|
+
}
|
|
53
|
+
if (!meta) {
|
|
54
|
+
throw new Error(`Type ${name} not found in typesMap`)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const getName = this.squash()
|
|
58
|
+
return {
|
|
59
|
+
uniqueName: getName(name),
|
|
60
|
+
originalName: meta.originalName,
|
|
61
|
+
path: meta?.path,
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public exists(originalName: string, path: string): string | undefined {
|
|
66
|
+
const found = Array.from(this.map.entries()).find(([_, type]) => {
|
|
67
|
+
return type.path === path && type.originalName === originalName
|
|
68
|
+
})
|
|
69
|
+
return found ? found[0] : undefined
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private squash() {
|
|
73
|
+
const duplicateNames = new Set<string>()
|
|
74
|
+
const pathToNamesMap = new Map<string, Map<string, string>>()
|
|
75
|
+
const nameOccurrences = new Map<string, Set<string>>()
|
|
76
|
+
|
|
77
|
+
// First pass: Track occurrences of each original name across paths
|
|
78
|
+
this.map.forEach(({ path, originalName }) => {
|
|
79
|
+
if (path) {
|
|
80
|
+
if (!nameOccurrences.has(originalName)) {
|
|
81
|
+
nameOccurrences.set(originalName, new Set())
|
|
82
|
+
}
|
|
83
|
+
nameOccurrences.get(originalName)!.add(path)
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// Second pass: Populate pathToNamesMap
|
|
88
|
+
this.map.forEach(({ path, originalName }, uniqueName) => {
|
|
89
|
+
if (!path) return
|
|
90
|
+
|
|
91
|
+
if (!pathToNamesMap.has(path)) {
|
|
92
|
+
pathToNamesMap.set(path, new Map())
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const isDuplicate = nameOccurrences.get(originalName)!.size > 1
|
|
96
|
+
if (isDuplicate) {
|
|
97
|
+
duplicateNames.add(uniqueName)
|
|
98
|
+
}
|
|
99
|
+
// Use uniqueName only if the originalName is duplicated across files
|
|
100
|
+
const nameToUse = isDuplicate ? uniqueName : originalName
|
|
101
|
+
pathToNamesMap.get(path)!.set(nameToUse, originalName)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const getName = (uniqueName: string) => {
|
|
105
|
+
if (duplicateNames.has(uniqueName)) {
|
|
106
|
+
return uniqueName
|
|
107
|
+
}
|
|
108
|
+
if (
|
|
109
|
+
uniqueName === 'string' ||
|
|
110
|
+
uniqueName === 'number' ||
|
|
111
|
+
uniqueName === 'boolean' ||
|
|
112
|
+
uniqueName === 'null'
|
|
113
|
+
) {
|
|
114
|
+
return uniqueName
|
|
115
|
+
}
|
|
116
|
+
if (!this.map.has(uniqueName)) {
|
|
117
|
+
const found = Array.from(this.map.entries()).find(
|
|
118
|
+
([_, { originalName }]) => originalName === uniqueName
|
|
119
|
+
)?.[1]
|
|
120
|
+
if (!found) {
|
|
121
|
+
throw new Error(`Type ${uniqueName} not found in typesMap`)
|
|
122
|
+
}
|
|
123
|
+
return found.originalName
|
|
124
|
+
}
|
|
125
|
+
return this.map.get(uniqueName)!.originalName
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return getName
|
|
129
|
+
}
|
|
130
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
import { FunctionsMeta } from '@pikku/core'
|
|
6
|
+
|
|
7
|
+
export type PathToNameAndType = Map<
|
|
8
|
+
string,
|
|
9
|
+
{ variable: string; type: string | null; typePath: string | null }[]
|
|
10
|
+
>
|
|
11
|
+
|
|
12
|
+
export type MetaInputTypes = Map<
|
|
13
|
+
string,
|
|
14
|
+
{
|
|
15
|
+
query: string[] | undefined
|
|
16
|
+
params: string[] | undefined
|
|
17
|
+
body: string[] | undefined
|
|
18
|
+
}
|
|
19
|
+
>
|
|
20
|
+
|
|
21
|
+
export interface InspectorHTTPState {
|
|
22
|
+
typesMap: TypesMap
|
|
23
|
+
metaInputTypes: MetaInputTypes
|
|
24
|
+
meta: HTTPRoutesMeta
|
|
25
|
+
files: Set<string>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface InspectorFunctionState {
|
|
29
|
+
typesMap: TypesMap
|
|
30
|
+
meta: FunctionsMeta
|
|
31
|
+
files: Set<string>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface InspectorChannelState {
|
|
35
|
+
typesMap: TypesMap
|
|
36
|
+
metaInputTypes: MetaInputTypes
|
|
37
|
+
meta: ChannelsMeta
|
|
38
|
+
files: Set<string>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type InspectorFilters = {
|
|
42
|
+
tags?: string[]
|
|
43
|
+
}
|
|
44
|
+
export interface InspectorState {
|
|
45
|
+
singletonServicesTypeImportMap: PathToNameAndType
|
|
46
|
+
sessionServicesTypeImportMap: PathToNameAndType
|
|
47
|
+
userSessionTypeImportMap: PathToNameAndType
|
|
48
|
+
singletonServicesFactories: PathToNameAndType
|
|
49
|
+
sessionServicesFactories: PathToNameAndType
|
|
50
|
+
configFactories: PathToNameAndType
|
|
51
|
+
http: InspectorHTTPState
|
|
52
|
+
functions: InspectorFunctionState
|
|
53
|
+
channels: InspectorChannelState
|
|
54
|
+
scheduledTasks: {
|
|
55
|
+
meta: ScheduledTasksMeta
|
|
56
|
+
files: Set<string>
|
|
57
|
+
}
|
|
58
|
+
}
|