@pikku/cli 0.6.20 → 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 +13 -0
- package/bin/pikku-all.ts +41 -18
- package/bin/pikku-channels-map.ts +4 -4
- package/bin/pikku-channels.ts +17 -12
- package/bin/pikku-fetch.ts +3 -3
- package/bin/pikku-function-types.ts +4 -4
- package/bin/pikku-functions.ts +35 -0
- package/bin/{pikku-routes-map.ts → pikku-http-map.ts} +10 -10
- package/bin/{pikku-http.ts → pikku-http-routes.ts} +17 -10
- package/bin/pikku-nextjs.ts +9 -9
- package/bin/pikku-openapi.ts +10 -6
- package/bin/pikku-rpc.ts +22 -0
- package/bin/pikku-scheduler.ts +15 -13
- package/bin/pikku-schemas.ts +10 -6
- package/bin/pikku-websocket.ts +1 -1
- package/bin/pikku.ts +2 -2
- package/cli.schema.json +2 -2
- package/dist/bin/pikku-all.js +37 -16
- package/dist/bin/pikku-channels-map.js +4 -4
- package/dist/bin/pikku-channels.js +6 -10
- package/dist/bin/pikku-fetch.d.ts +1 -1
- package/dist/bin/pikku-fetch.js +3 -3
- package/dist/bin/pikku-function-types.js +4 -4
- package/dist/bin/pikku-functions.d.ts +3 -0
- package/dist/bin/pikku-functions.js +9 -0
- package/dist/bin/{pikku-routes-map.d.ts → pikku-http-map.d.ts} +1 -1
- package/dist/bin/{pikku-routes-map.js → pikku-http-map.js} +7 -7
- package/dist/bin/{pikku-http.js → pikku-http-routes.js} +6 -11
- package/dist/bin/pikku-nextjs.d.ts +1 -1
- package/dist/bin/pikku-nextjs.js +8 -8
- package/dist/bin/pikku-openapi.d.ts +1 -1
- package/dist/bin/pikku-openapi.js +6 -6
- package/dist/bin/pikku-rpc.d.ts +3 -0
- package/dist/bin/pikku-rpc.js +8 -0
- package/dist/bin/pikku-scheduler.js +7 -10
- package/dist/bin/pikku-schemas.d.ts +1 -1
- package/dist/bin/pikku-schemas.js +6 -6
- package/dist/bin/pikku-websocket.js +1 -1
- package/dist/bin/pikku.js +2 -2
- package/dist/src/inspector-glob.d.ts +1 -1
- package/dist/src/inspector-glob.js +2 -2
- package/dist/src/pikku-cli-config.d.ts +10 -4
- package/dist/src/pikku-cli-config.js +22 -4
- package/dist/src/{schema/schema-generator.d.ts → schema-generator.d.ts} +1 -1
- package/dist/src/{schema/schema-generator.js → schema-generator.js} +29 -8
- package/dist/src/{core/serialize-import-map.js → serialize-import-map.js} +2 -1
- package/dist/src/serialize-pikku-types.js +136 -0
- package/dist/src/{scheduler/serialize-schedulers.d.ts → serialize-scheduler-meta.d.ts} +0 -1
- package/dist/src/serialize-scheduler-meta.js +10 -0
- package/dist/src/{channels/serialize-typed-channel-map.js → serialize-typed-channel-map.js} +7 -4
- package/dist/src/{http/serialize-typed-route-map.js → serialize-typed-function-map.js} +2 -2
- package/dist/src/serialize-typed-http-map.d.ts +4 -0
- package/dist/src/serialize-typed-http-map.js +107 -0
- package/dist/src/utils.d.ts +1 -0
- package/dist/src/utils.js +17 -5
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/inspector-glob.ts +2 -2
- package/src/pikku-cli-config.ts +44 -8
- package/src/{schema/schema-generator.ts → schema-generator.ts} +31 -9
- package/src/{core/serialize-import-map.ts → serialize-import-map.ts} +2 -1
- package/src/serialize-pikku-types.ts +143 -0
- package/src/serialize-scheduler-meta.ts +18 -0
- package/src/{channels/serialize-typed-channel-map.ts → serialize-typed-channel-map.ts} +8 -6
- package/src/{http/serialize-typed-route-map.ts → serialize-typed-function-map.ts} +3 -2
- package/src/serialize-typed-http-map.ts +151 -0
- package/src/utils.ts +29 -5
- package/dist/src/channels/serialize-channels.d.ts +0 -3
- package/dist/src/channels/serialize-channels.js +0 -19
- package/dist/src/core/serialize-pikku-types.js +0 -48
- package/dist/src/http/serialize-route-imports.d.ts +0 -1
- package/dist/src/http/serialize-route-imports.js +0 -13
- package/dist/src/http/serialize-route-meta.d.ts +0 -2
- package/dist/src/http/serialize-route-meta.js +0 -6
- package/dist/src/scheduler/serialize-schedulers.js +0 -22
- package/src/channels/serialize-channels.ts +0 -34
- package/src/core/serialize-pikku-types.ts +0 -55
- package/src/http/serialize-route-imports.ts +0 -24
- package/src/http/serialize-route-meta.ts +0 -10
- package/src/scheduler/serialize-schedulers.ts +0 -41
- /package/dist/bin/{pikku-http.d.ts → pikku-http-routes.d.ts} +0 -0
- /package/dist/src/{openapi/openapi-spec-generator.d.ts → openapi-spec-generator.d.ts} +0 -0
- /package/dist/src/{openapi/openapi-spec-generator.js → openapi-spec-generator.js} +0 -0
- /package/dist/src/{http/serialize-fetch-wrapper.d.ts → serialize-fetch-wrapper.d.ts} +0 -0
- /package/dist/src/{http/serialize-fetch-wrapper.js → serialize-fetch-wrapper.js} +0 -0
- /package/dist/src/{core/serialize-import-map.d.ts → serialize-import-map.d.ts} +0 -0
- /package/dist/src/{nextjs/serialize-nextjs-backend-wrapper.d.ts → serialize-nextjs-backend-wrapper.d.ts} +0 -0
- /package/dist/src/{nextjs/serialize-nextjs-backend-wrapper.js → serialize-nextjs-backend-wrapper.js} +0 -0
- /package/dist/src/{nextjs/serialize-nextjs-http-wrapper.d.ts → serialize-nextjs-http-wrapper.d.ts} +0 -0
- /package/dist/src/{nextjs/serialize-nextjs-http-wrapper.js → serialize-nextjs-http-wrapper.js} +0 -0
- /package/dist/src/{core/serialize-pikku-types.d.ts → serialize-pikku-types.d.ts} +0 -0
- /package/dist/src/{channels/serialize-typed-channel-map.d.ts → serialize-typed-channel-map.d.ts} +0 -0
- /package/dist/src/{http/serialize-typed-route-map.d.ts → serialize-typed-function-map.d.ts} +0 -0
- /package/dist/src/{channels/serialize-websocket-wrapper.d.ts → serialize-websocket-wrapper.d.ts} +0 -0
- /package/dist/src/{channels/serialize-websocket-wrapper.js → serialize-websocket-wrapper.js} +0 -0
- /package/src/{openapi/openapi-spec-generator.ts → openapi-spec-generator.ts} +0 -0
- /package/src/{http/serialize-fetch-wrapper.ts → serialize-fetch-wrapper.ts} +0 -0
- /package/src/{nextjs/serialize-nextjs-backend-wrapper.ts → serialize-nextjs-backend-wrapper.ts} +0 -0
- /package/src/{nextjs/serialize-nextjs-http-wrapper.ts → serialize-nextjs-http-wrapper.ts} +0 -0
- /package/src/{channels/serialize-websocket-wrapper.ts → serialize-websocket-wrapper.ts} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createGenerator, RootlessError } from 'ts-json-schema-generator'
|
|
2
|
-
import { logInfo, writeFileInDir } from '
|
|
2
|
+
import { logInfo, writeFileInDir } from './utils.js'
|
|
3
3
|
import { mkdir, writeFile } from 'fs/promises'
|
|
4
4
|
import { JSONValue } from '@pikku/core'
|
|
5
5
|
import { HTTPRoutesMeta } from '@pikku/core/http'
|
|
@@ -7,17 +7,39 @@ import { TypesMap } from '@pikku/inspector'
|
|
|
7
7
|
|
|
8
8
|
export async function generateSchemas(
|
|
9
9
|
tsconfig: string,
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
typesMaps: TypesMap[],
|
|
11
|
+
httpRoutesMeta: HTTPRoutesMeta
|
|
12
12
|
): Promise<Record<string, JSONValue>> {
|
|
13
|
-
const schemasSet = new Set(
|
|
14
|
-
|
|
13
|
+
const schemasSet = new Set(
|
|
14
|
+
typesMaps.flatMap((tm) => [...tm.customTypes.keys()])
|
|
15
|
+
)
|
|
16
|
+
for (const { input, inputTypes } of httpRoutesMeta) {
|
|
15
17
|
if (input) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
let found = false
|
|
19
|
+
for (const typesMap of typesMaps) {
|
|
20
|
+
try {
|
|
21
|
+
const uniqueName = typesMap.getUniqueName(input)
|
|
22
|
+
if (uniqueName) {
|
|
23
|
+
found = true
|
|
24
|
+
schemasSet.add(uniqueName)
|
|
25
|
+
break
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {}
|
|
28
|
+
}
|
|
29
|
+
if (!found) {
|
|
30
|
+
console.error('Input type not found in any types map:', input)
|
|
31
|
+
}
|
|
20
32
|
}
|
|
33
|
+
// if (output) {
|
|
34
|
+
// for (const typesMap of typesMaps) {
|
|
35
|
+
// const uniqueName = typesMap.getUniqueName(output)
|
|
36
|
+
// if (uniqueName) {
|
|
37
|
+
// console.log('Adding output schema:', uniqueName)
|
|
38
|
+
// schemasSet.add(uniqueName)
|
|
39
|
+
// break
|
|
40
|
+
// }
|
|
41
|
+
// }
|
|
42
|
+
// }
|
|
21
43
|
if (inputTypes?.body) {
|
|
22
44
|
schemasSet.add(inputTypes.body)
|
|
23
45
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TypesMap } from '@pikku/inspector'
|
|
2
|
-
import { getFileImportRelativePath } from '
|
|
2
|
+
import { getFileImportRelativePath } from './utils.js'
|
|
3
3
|
|
|
4
4
|
export const serializeImportMap = (
|
|
5
5
|
relativeToPath: string,
|
|
@@ -12,6 +12,7 @@ export const serializeImportMap = (
|
|
|
12
12
|
const { originalName, uniqueName, path } =
|
|
13
13
|
typesMap.getTypeMeta(requiredType)
|
|
14
14
|
if (!path) {
|
|
15
|
+
// This is a custom type that exists in file, so we don't need to import it
|
|
15
16
|
return
|
|
16
17
|
}
|
|
17
18
|
const variables = paths.get(path) || []
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*/
|
|
4
|
+
export const serializePikkuTypes = (
|
|
5
|
+
userSessionTypeImport: string,
|
|
6
|
+
userSessionTypeName: string,
|
|
7
|
+
singletonServicesTypeImport: string,
|
|
8
|
+
singletonServicesTypeName: string,
|
|
9
|
+
sessionServicesTypeImport: string,
|
|
10
|
+
servicesTypeName: string
|
|
11
|
+
) => {
|
|
12
|
+
return `/**
|
|
13
|
+
* This is used to provide the application types in the typescript project
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { CoreAPIPermission, PikkuMiddleware } from '@pikku/core'
|
|
17
|
+
import { CoreAPIFunction, CoreAPIFunctionSessionless } from '@pikku/core/function'
|
|
18
|
+
import { CoreHTTPFunctionRoute, AssertRouteParams, addHTTPRoute as addCoreHTTPRoute } from '@pikku/core/http'
|
|
19
|
+
import { CoreScheduledTask, addScheduledTask as addCoreScheduledTask } from '@pikku/core/scheduler'
|
|
20
|
+
import { CoreAPIChannel, PikkuChannel, addChannel as addCoreChannel } from '@pikku/core/channel'
|
|
21
|
+
|
|
22
|
+
${userSessionTypeImport}
|
|
23
|
+
${singletonServicesTypeImport}
|
|
24
|
+
${sessionServicesTypeImport}
|
|
25
|
+
|
|
26
|
+
export type APIPermission<In = unknown, RequiredServices extends ${singletonServicesTypeName} = ${singletonServicesTypeName}> = CoreAPIPermission<In, RequiredServices, ${userSessionTypeName}>
|
|
27
|
+
export type APIMiddleware<RequiredServices extends ${singletonServicesTypeName} = ${singletonServicesTypeName}> = PikkuMiddleware<RequiredServices, ${userSessionTypeName}>
|
|
28
|
+
|
|
29
|
+
type APIFunctionSessionless<
|
|
30
|
+
In = unknown,
|
|
31
|
+
Out = never,
|
|
32
|
+
ChannelData = null, // null means optional channel
|
|
33
|
+
RequiredServices extends Services = Services & (
|
|
34
|
+
[ChannelData] extends [null]
|
|
35
|
+
? { channel?: PikkuChannel<unknown, Out> } // Optional channel
|
|
36
|
+
: { channel: PikkuChannel<ChannelData, Out> } // Required channel with any data type
|
|
37
|
+
)
|
|
38
|
+
> = CoreAPIFunctionSessionless<In, Out, ChannelData, RequiredServices, ${userSessionTypeName}>
|
|
39
|
+
|
|
40
|
+
type APIFunction<
|
|
41
|
+
In = unknown,
|
|
42
|
+
Out = never,
|
|
43
|
+
ChannelData = null, // null means optional channel
|
|
44
|
+
RequiredServices extends Services = Services & (
|
|
45
|
+
[ChannelData] extends [null]
|
|
46
|
+
? { channel?: PikkuChannel<unknown, Out> } // Optional channel
|
|
47
|
+
: { channel: PikkuChannel<ChannelData, Out> } // Required channel with any data type
|
|
48
|
+
)
|
|
49
|
+
> = CoreAPIFunction<In, Out, ChannelData, RequiredServices, ${userSessionTypeName}>
|
|
50
|
+
|
|
51
|
+
type APIRoute<In, Out, Route extends string> = CoreHTTPFunctionRoute<In, Out, Route, APIFunction<In, Out>, APIFunctionSessionless<In, Out>, APIPermission<In>, APIMiddleware>
|
|
52
|
+
type APIChannel<ChannelData, Channel extends string> = CoreAPIChannel<ChannelData, Channel, APIFunction<void, unknown> | APIFunction<void, unknown, ChannelData>, APIFunction<void, void> | APIFunction<void, void, ChannelData>, APIFunction<any, any> | APIFunction<any, any, ChannelData>, APIPermission>
|
|
53
|
+
type ScheduledTask = CoreScheduledTask<APIFunctionSessionless<void, void>, ${userSessionTypeName}>
|
|
54
|
+
|
|
55
|
+
export const pikkuFunc = <In, Out = unknown>(
|
|
56
|
+
func:
|
|
57
|
+
| APIFunction<In, Out>
|
|
58
|
+
| {
|
|
59
|
+
func: APIFunction<In, Out>
|
|
60
|
+
auth?: true
|
|
61
|
+
name?: string
|
|
62
|
+
}
|
|
63
|
+
| {
|
|
64
|
+
func: APIFunctionSessionless<In, Out>
|
|
65
|
+
auth: false
|
|
66
|
+
name?: string
|
|
67
|
+
}
|
|
68
|
+
) => {
|
|
69
|
+
return typeof func === 'function' ? func : func.func
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const pikkuSessionlessFunc = <In, Out = unknown>(
|
|
73
|
+
func:
|
|
74
|
+
| APIFunctionSessionless<In, Out>
|
|
75
|
+
| {
|
|
76
|
+
func: APIFunctionSessionless<In, Out>
|
|
77
|
+
name?: string
|
|
78
|
+
}
|
|
79
|
+
) => {
|
|
80
|
+
return typeof func === 'function' ? func : func.func
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const pikkuChannelConnectionFunc = <Out = unknown, ChannelData = unknown>(
|
|
84
|
+
func:
|
|
85
|
+
| APIFunctionSessionless<void, Out, ChannelData>
|
|
86
|
+
| {
|
|
87
|
+
func: APIFunctionSessionless<void, Out, ChannelData>
|
|
88
|
+
name?: string
|
|
89
|
+
}
|
|
90
|
+
) => {
|
|
91
|
+
return typeof func === 'function' ? func : func.func
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const pikkuChannelDisconnectionFunc = <ChannelData = unknown>(
|
|
95
|
+
func:
|
|
96
|
+
| APIFunctionSessionless<void, void, ChannelData>
|
|
97
|
+
| {
|
|
98
|
+
func: APIFunction<void, void, ChannelData>
|
|
99
|
+
name?: string
|
|
100
|
+
}
|
|
101
|
+
) => {
|
|
102
|
+
return typeof func === 'function' ? func : func.func
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const pikkuChannelFunc = <In = unknown, Out = unknown, ChannelData = unknown>(
|
|
106
|
+
func:
|
|
107
|
+
| APIFunctionSessionless<In, Out, ChannelData>
|
|
108
|
+
| {
|
|
109
|
+
func: APIFunctionSessionless<In, Out, ChannelData>
|
|
110
|
+
name?: string
|
|
111
|
+
}
|
|
112
|
+
) => {
|
|
113
|
+
return typeof func === 'function' ? func : func.func
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export const pikkuVoidFunc = (
|
|
117
|
+
func:
|
|
118
|
+
| APIFunctionSessionless<void, void>
|
|
119
|
+
| {
|
|
120
|
+
func: APIFunctionSessionless<void, void>
|
|
121
|
+
name?: string
|
|
122
|
+
}
|
|
123
|
+
) => {
|
|
124
|
+
return typeof func === 'function' ? func : func.func
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export const addChannel = <ChannelData, Channel extends string>(
|
|
128
|
+
channel: APIChannel<ChannelData, Channel> & AssertRouteParams<ChannelData, Channel>
|
|
129
|
+
) => {
|
|
130
|
+
addCoreChannel(channel as any) // TODO
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export const addHTTPRoute = <In, Out, Route extends string>(
|
|
134
|
+
route: APIRoute<In, Out, Route> & AssertRouteParams<In, Route>
|
|
135
|
+
) => {
|
|
136
|
+
addCoreHTTPRoute(route)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const addScheduledTask = (task: ScheduledTask) => {
|
|
140
|
+
addCoreScheduledTask(task as any) // TODO
|
|
141
|
+
}
|
|
142
|
+
`
|
|
143
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ScheduledTasksMeta } from '@pikku/core/scheduler'
|
|
2
|
+
|
|
3
|
+
export const serializeSchedulerMeta = (
|
|
4
|
+
scheduledTasksMeta: ScheduledTasksMeta
|
|
5
|
+
) => {
|
|
6
|
+
const serializedOutput: string[] = []
|
|
7
|
+
serializedOutput.push("import { pikkuState } from '@pikku/core'")
|
|
8
|
+
serializedOutput.push(
|
|
9
|
+
`pikkuState('scheduler', 'meta', ${JSON.stringify(scheduledTasksMeta, null, 2)})`
|
|
10
|
+
)
|
|
11
|
+
const scheduledTasksMetaValues = Object.values(scheduledTasksMeta)
|
|
12
|
+
if (scheduledTasksMetaValues.length > 0) {
|
|
13
|
+
serializedOutput.push(
|
|
14
|
+
`export type ScheduledTaskNames = '${scheduledTasksMetaValues.map((s) => s.name).join("' | '")}'`
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
return serializedOutput.join('\n')
|
|
18
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ChannelsMeta } from '@pikku/core/channel'
|
|
2
|
-
import { serializeImportMap } from '
|
|
2
|
+
import { serializeImportMap } from './serialize-import-map.js'
|
|
3
3
|
import { TypesMap } from '@pikku/inspector'
|
|
4
|
-
import { generateCustomTypes } from '
|
|
4
|
+
import { generateCustomTypes } from './serialize-typed-http-map.js'
|
|
5
5
|
|
|
6
6
|
export const serializeTypedChannelsMap = (
|
|
7
7
|
relativeToPath: string,
|
|
@@ -71,7 +71,7 @@ function generateChannels(channelsMeta: ChannelsMeta) {
|
|
|
71
71
|
}
|
|
72
72
|
> = {}
|
|
73
73
|
|
|
74
|
-
for (const meta of channelsMeta) {
|
|
74
|
+
for (const meta of Object.values(channelsMeta)) {
|
|
75
75
|
const { name, messageRoutes, message } = meta
|
|
76
76
|
|
|
77
77
|
if (!channelsObject[name]) {
|
|
@@ -107,9 +107,9 @@ function generateChannels(channelsMeta: ChannelsMeta) {
|
|
|
107
107
|
for (const [key, methods] of Object.entries(routes)) {
|
|
108
108
|
routesStr += ` readonly ${key}: {\n`
|
|
109
109
|
for (const [method, handler] of Object.entries(methods)) {
|
|
110
|
-
routesStr += ` readonly ${method}: ChannelHandler<${
|
|
111
|
-
handler.inputTypes
|
|
112
|
-
|
|
110
|
+
routesStr += ` readonly ${method}: ChannelHandler<${
|
|
111
|
+
formatTypeArray(handler.inputTypes) || 'void'
|
|
112
|
+
}, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`
|
|
113
113
|
}
|
|
114
114
|
routesStr += ' },\n'
|
|
115
115
|
}
|
|
@@ -120,6 +120,8 @@ function generateChannels(channelsMeta: ChannelsMeta) {
|
|
|
120
120
|
routesStr += ` readonly defaultMessage: ChannelHandler<${formatTypeArray(
|
|
121
121
|
message.inputs
|
|
122
122
|
)}, ${formatTypeArray(message.outputs)}>,\n`
|
|
123
|
+
} else {
|
|
124
|
+
routesStr += ` readonly defaultMessage: never,\n`
|
|
123
125
|
}
|
|
124
126
|
|
|
125
127
|
routesStr += ' },\n'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HTTPRoutesMeta } from '@pikku/core/http'
|
|
2
|
-
import { serializeImportMap } from '
|
|
2
|
+
import { serializeImportMap } from './serialize-import-map.js'
|
|
3
3
|
import { MetaInputTypes, TypesMap } from '@pikku/inspector'
|
|
4
4
|
|
|
5
5
|
export const serializeTypedRoutesMap = (
|
|
@@ -12,13 +12,14 @@ export const serializeTypedRoutesMap = (
|
|
|
12
12
|
const requiredTypes = new Set<string>()
|
|
13
13
|
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
|
|
14
14
|
const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap)
|
|
15
|
+
const serializedRoutes = generateRoutes(routesMeta, typesMap, requiredTypes)
|
|
16
|
+
|
|
15
17
|
const serializedImportMap = serializeImportMap(
|
|
16
18
|
relativeToPath,
|
|
17
19
|
packageMappings,
|
|
18
20
|
typesMap,
|
|
19
21
|
requiredTypes
|
|
20
22
|
)
|
|
21
|
-
const serializedRoutes = generateRoutes(routesMeta, typesMap, requiredTypes)
|
|
22
23
|
|
|
23
24
|
return `/**
|
|
24
25
|
* This provides the structure needed for typescript to be aware of routes and their return types
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { HTTPRoutesMeta } from '@pikku/core/http'
|
|
2
|
+
import { serializeImportMap } from './serialize-import-map.js'
|
|
3
|
+
import { MetaInputTypes, TypesMap } from '@pikku/inspector'
|
|
4
|
+
|
|
5
|
+
export const serializeTypedRoutesMap = (
|
|
6
|
+
relativeToPath: string,
|
|
7
|
+
packageMappings: Record<string, string>,
|
|
8
|
+
typesMap: TypesMap,
|
|
9
|
+
routesMeta: HTTPRoutesMeta,
|
|
10
|
+
metaTypes: MetaInputTypes
|
|
11
|
+
) => {
|
|
12
|
+
const requiredTypes = new Set<string>()
|
|
13
|
+
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
|
|
14
|
+
const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap)
|
|
15
|
+
const serializedRoutes = generateRoutes(routesMeta, typesMap, requiredTypes)
|
|
16
|
+
|
|
17
|
+
const serializedImportMap = serializeImportMap(
|
|
18
|
+
relativeToPath,
|
|
19
|
+
packageMappings,
|
|
20
|
+
typesMap,
|
|
21
|
+
requiredTypes
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
return `/**
|
|
25
|
+
* This provides the structure needed for typescript to be aware of routes and their return types
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
${serializedImportMap}
|
|
29
|
+
${serializedCustomTypes}
|
|
30
|
+
${serializedMetaTypes}
|
|
31
|
+
|
|
32
|
+
interface RouteHandler<I, O> {
|
|
33
|
+
input: I;
|
|
34
|
+
output: O;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
${serializedRoutes}
|
|
38
|
+
|
|
39
|
+
export type RouteHandlerOf<Route extends keyof RoutesMap, Method extends keyof RoutesMap[Route]> =
|
|
40
|
+
RoutesMap[Route][Method] extends { input: infer I; output: infer O }
|
|
41
|
+
? RouteHandler<I, O>
|
|
42
|
+
: never;
|
|
43
|
+
|
|
44
|
+
export type RoutesWithMethod<Method extends string> = {
|
|
45
|
+
[Route in keyof RoutesMap]: Method extends keyof RoutesMap[Route] ? Route : never;
|
|
46
|
+
}[keyof RoutesMap];
|
|
47
|
+
`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function generateCustomTypes(
|
|
51
|
+
typesMap: TypesMap,
|
|
52
|
+
requiredTypes: Set<string>
|
|
53
|
+
) {
|
|
54
|
+
return `
|
|
55
|
+
// Custom types are those that are defined directly within generics
|
|
56
|
+
// or are broken into simpler types
|
|
57
|
+
${Array.from(typesMap.customTypes.entries())
|
|
58
|
+
.map(([name, { type, references }]) => {
|
|
59
|
+
references.forEach((name) => {
|
|
60
|
+
const originalName = typesMap.getTypeMeta(name).originalName
|
|
61
|
+
requiredTypes.add(originalName)
|
|
62
|
+
})
|
|
63
|
+
return `export type ${name} = ${type}`
|
|
64
|
+
})
|
|
65
|
+
.join('\n')}`
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function generateRoutes(
|
|
69
|
+
routesMeta: HTTPRoutesMeta,
|
|
70
|
+
typesMap: TypesMap,
|
|
71
|
+
requiredTypes: Set<string>
|
|
72
|
+
) {
|
|
73
|
+
// Initialize an object to collect routes
|
|
74
|
+
const routesObj: Record<
|
|
75
|
+
string,
|
|
76
|
+
Record<string, { inputType: string; outputType: string }>
|
|
77
|
+
> = {}
|
|
78
|
+
|
|
79
|
+
for (const meta of routesMeta) {
|
|
80
|
+
const { route, method, input, output } = meta
|
|
81
|
+
|
|
82
|
+
// Initialize the route entry if it doesn't exist
|
|
83
|
+
if (!routesObj[route]) {
|
|
84
|
+
routesObj[route] = {}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Store the input and output types separately for RouteHandler
|
|
88
|
+
const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null'
|
|
89
|
+
const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null'
|
|
90
|
+
|
|
91
|
+
requiredTypes.add(inputType)
|
|
92
|
+
requiredTypes.add(outputType)
|
|
93
|
+
|
|
94
|
+
// Add method entry
|
|
95
|
+
routesObj[route][method] = {
|
|
96
|
+
inputType,
|
|
97
|
+
outputType,
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Build the routes object as a string
|
|
102
|
+
let routesStr = 'export type RoutesMap = {\n'
|
|
103
|
+
|
|
104
|
+
for (const [routePath, methods] of Object.entries(routesObj)) {
|
|
105
|
+
routesStr += ` readonly '${routePath}': {\n`
|
|
106
|
+
for (const [method, handler] of Object.entries(methods)) {
|
|
107
|
+
routesStr += ` readonly ${method.toUpperCase()}: RouteHandler<${handler.inputType}, ${handler.outputType}>,\n`
|
|
108
|
+
}
|
|
109
|
+
routesStr += ' },\n'
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
routesStr += '};'
|
|
113
|
+
|
|
114
|
+
return routesStr
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const generateMetaTypes = (metaTypes: MetaInputTypes, typesMap: TypesMap) => {
|
|
118
|
+
const nameToTypeMap = Array.from(metaTypes.entries()).reduce<
|
|
119
|
+
Map<string, string>
|
|
120
|
+
>((result, [_name, { query, body, params }]) => {
|
|
121
|
+
const { uniqueName } = typesMap.getTypeMeta(_name)
|
|
122
|
+
const queryType =
|
|
123
|
+
query && query.length > 0
|
|
124
|
+
? `Pick<${uniqueName}, '${query?.join("' | '")}'>`
|
|
125
|
+
: undefined
|
|
126
|
+
if (queryType) {
|
|
127
|
+
result.set(`${uniqueName}Query`, queryType)
|
|
128
|
+
}
|
|
129
|
+
const paramsType =
|
|
130
|
+
params && params.length > 0
|
|
131
|
+
? `Pick<${uniqueName}, '${params.join("' | '")}'>`
|
|
132
|
+
: undefined
|
|
133
|
+
if (paramsType) {
|
|
134
|
+
result.set(`${uniqueName}Params`, paramsType)
|
|
135
|
+
}
|
|
136
|
+
const bodyType =
|
|
137
|
+
(body && body.length > 0) || (params && params.length > 0)
|
|
138
|
+
? `Omit<${uniqueName}, '${[...new Set([...(query || []), ...(params || [])])].join("' | '")}'>`
|
|
139
|
+
: uniqueName!
|
|
140
|
+
if (bodyType) {
|
|
141
|
+
result.set(`${uniqueName}Body`, bodyType)
|
|
142
|
+
}
|
|
143
|
+
return result
|
|
144
|
+
}, new Map())
|
|
145
|
+
|
|
146
|
+
return `
|
|
147
|
+
// The '& {}' is a workaround for not directly refering to a type since it confuses typescript
|
|
148
|
+
${Array.from(nameToTypeMap.entries())
|
|
149
|
+
.map(([name, type]) => `export type ${name} = ${type} & {}`)
|
|
150
|
+
.join('\n')}`
|
|
151
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -28,17 +28,17 @@ export const getFileImportRelativePath = (
|
|
|
28
28
|
if (!/^\.+\//.test(filePath)) {
|
|
29
29
|
filePath = `./${filePath}`
|
|
30
30
|
}
|
|
31
|
-
let usesPackageName = false
|
|
31
|
+
// let usesPackageName = false
|
|
32
32
|
for (const [path, packageName] of Object.entries(packageMappings)) {
|
|
33
33
|
if (filePath.includes(path)) {
|
|
34
|
-
usesPackageName = true
|
|
34
|
+
// usesPackageName = true
|
|
35
35
|
filePath = filePath.replace(new RegExp(`.*${path}`), packageName)
|
|
36
36
|
break
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
if (usesPackageName) {
|
|
40
|
-
|
|
41
|
-
}
|
|
39
|
+
// if (usesPackageName) {
|
|
40
|
+
// return filePath.replace('.ts', '')
|
|
41
|
+
// }
|
|
42
42
|
return filePath.replace('.ts', '.js')
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -258,3 +258,27 @@ export const DO_NOT_MODIFY_COMMENT = `/**
|
|
|
258
258
|
* This file was generated by the @pikku/cli
|
|
259
259
|
*/
|
|
260
260
|
`
|
|
261
|
+
|
|
262
|
+
export const serializeFileImports = (
|
|
263
|
+
importType: string,
|
|
264
|
+
outputPath: string,
|
|
265
|
+
files: Set<string>,
|
|
266
|
+
packageMappings: Record<string, string> = {}
|
|
267
|
+
) => {
|
|
268
|
+
const serializedOutput: string[] = [
|
|
269
|
+
`/* The files with an ${importType} function call */`,
|
|
270
|
+
]
|
|
271
|
+
|
|
272
|
+
Array.from(files)
|
|
273
|
+
.sort()
|
|
274
|
+
.forEach((path) => {
|
|
275
|
+
const filePath = getFileImportRelativePath(
|
|
276
|
+
outputPath,
|
|
277
|
+
path,
|
|
278
|
+
packageMappings
|
|
279
|
+
)
|
|
280
|
+
serializedOutput.push(`import '${filePath}'`)
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
return serializedOutput.join('\n')
|
|
284
|
+
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { ChannelsMeta } from '@pikku/core/channel';
|
|
2
|
-
export declare const serializeChannels: (outputPath: string, filesWithChannels: Set<string>, packageMappings?: Record<string, string>) => string;
|
|
3
|
-
export declare const serializeChannelMeta: (channelsMeta: ChannelsMeta) => string;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { getFileImportRelativePath } from '../utils.js';
|
|
2
|
-
export const serializeChannels = (outputPath, filesWithChannels, packageMappings = {}) => {
|
|
3
|
-
const serializedOutput = [
|
|
4
|
-
'/* The files with an addChannel function call */',
|
|
5
|
-
];
|
|
6
|
-
Array.from(filesWithChannels)
|
|
7
|
-
.sort()
|
|
8
|
-
.forEach((path) => {
|
|
9
|
-
const filePath = getFileImportRelativePath(outputPath, path, packageMappings);
|
|
10
|
-
serializedOutput.push(`import '${filePath}'`);
|
|
11
|
-
});
|
|
12
|
-
return serializedOutput.join('\n');
|
|
13
|
-
};
|
|
14
|
-
export const serializeChannelMeta = (channelsMeta) => {
|
|
15
|
-
const serializedOutput = [];
|
|
16
|
-
serializedOutput.push("import { pikkuState } from '@pikku/core'");
|
|
17
|
-
serializedOutput.push(`pikkuState('channel', 'meta', ${JSON.stringify(channelsMeta, null, 2)})`);
|
|
18
|
-
return serializedOutput.join('\n');
|
|
19
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*/
|
|
4
|
-
export const serializePikkuTypes = (userSessionTypeImport, userSessionTypeName, singletonServicesTypeImport, singletonServicesTypeName, sessionServicesTypeImport, servicesTypeName) => {
|
|
5
|
-
return `/**
|
|
6
|
-
* This is used to provide the application types in the typescript project
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { CoreAPIFunction, CoreAPIFunctionSessionless, CoreAPIPermission, PikkuMiddleware, MakeRequired } from '@pikku/core'
|
|
10
|
-
import { CoreHTTPFunctionRoute, AssertRouteParams, addRoute as addCoreHTTP } from '@pikku/core/http'
|
|
11
|
-
import { CoreScheduledTask, addScheduledTask as addCoreScheduledTask } from '@pikku/core/scheduler'
|
|
12
|
-
import { CoreAPIChannel, PikkuChannel, addChannel as addCoreChannel } from '@pikku/core/channel'
|
|
13
|
-
|
|
14
|
-
${userSessionTypeImport}
|
|
15
|
-
${singletonServicesTypeImport}
|
|
16
|
-
${sessionServicesTypeImport}
|
|
17
|
-
|
|
18
|
-
export type APIPermission<In = unknown, RequiredServices extends ${singletonServicesTypeName} = ${singletonServicesTypeName}> = CoreAPIPermission<In, RequiredServices, ${userSessionTypeName}>
|
|
19
|
-
export type APIMiddleware<RequiredServices extends ${singletonServicesTypeName} = ${singletonServicesTypeName}> = PikkuMiddleware<RequiredServices, ${userSessionTypeName}>
|
|
20
|
-
|
|
21
|
-
export type APIFunctionSessionless<In = unknown, Out = never, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = CoreAPIFunctionSessionless<In, Out, RequiredServices, ${userSessionTypeName}>
|
|
22
|
-
export type APIFunction<In = unknown, Out = never, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = CoreAPIFunction<In, Out, RequiredServices, ${userSessionTypeName}>
|
|
23
|
-
type APIRoute<In, Out, Route extends string> = CoreHTTPFunctionRoute<In, Out, Route, APIFunction<In, Out>, APIFunctionSessionless<In, Out>, APIPermission<In>, APIMiddleware>
|
|
24
|
-
|
|
25
|
-
export type ChannelConnection<Out = unknown, ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: MakeRequired<RequiredServices, 'userSession'>, channel: PikkuChannel<ChannelData, Out>) => Promise<void>
|
|
26
|
-
export type ChannelDisconnection<ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: MakeRequired<RequiredServices, 'userSession'>, channel: PikkuChannel<ChannelData, never>) => Promise<void>
|
|
27
|
-
export type ChannelMessage<In, Out = unknown, ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: MakeRequired<RequiredServices, 'userSession'>, channel: PikkuChannel<ChannelData, Out>, data: In) => Promise<Out | void>
|
|
28
|
-
type APIChannel<ChannelData, Channel extends string> = CoreAPIChannel<ChannelData, Channel, ChannelConnection, ChannelDisconnection, ChannelMessage<any, any, ChannelData>, ChannelMessage<any, any, ChannelData>, APIPermission>
|
|
29
|
-
|
|
30
|
-
type ScheduledTask = CoreScheduledTask<APIFunctionSessionless<void, void>, ${userSessionTypeName}>
|
|
31
|
-
|
|
32
|
-
export const addChannel = <ChannelData, Channel extends string>(
|
|
33
|
-
channel: APIChannel<ChannelData, Channel> & AssertRouteParams<ChannelData, Channel>
|
|
34
|
-
) => {
|
|
35
|
-
addCoreChannel(channel as any) // TODO
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const addRoute = <In, Out, Route extends string>(
|
|
39
|
-
route: APIRoute<In, Out, Route> & AssertRouteParams<In, Route>
|
|
40
|
-
) => {
|
|
41
|
-
addCoreHTTP(route)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export const addScheduledTask = (task: ScheduledTask) => {
|
|
45
|
-
addCoreScheduledTask(task as any) // TODO
|
|
46
|
-
}
|
|
47
|
-
`;
|
|
48
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const serializeRoutes: (outputPath: string, filesWithRoutes: Set<string>, packageMappings?: Record<string, string>) => string;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { getFileImportRelativePath } from '../utils.js';
|
|
2
|
-
export const serializeRoutes = (outputPath, filesWithRoutes, packageMappings = {}) => {
|
|
3
|
-
const serializedOutput = [
|
|
4
|
-
'/* The files with an addRoute function call */',
|
|
5
|
-
];
|
|
6
|
-
Array.from(filesWithRoutes)
|
|
7
|
-
.sort()
|
|
8
|
-
.forEach((path) => {
|
|
9
|
-
const filePath = getFileImportRelativePath(outputPath, path, packageMappings);
|
|
10
|
-
serializedOutput.push(`import '${filePath}'`);
|
|
11
|
-
});
|
|
12
|
-
return serializedOutput.join('\n');
|
|
13
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export const serializeHTTPRoutesMeta = (routesMeta) => {
|
|
2
|
-
const serializedOutput = [];
|
|
3
|
-
serializedOutput.push("import { pikkuState } from '@pikku/core'");
|
|
4
|
-
serializedOutput.push(`pikkuState('http', 'meta', ${JSON.stringify(routesMeta, null, 2)})`);
|
|
5
|
-
return serializedOutput.join('\n');
|
|
6
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { getFileImportRelativePath } from '../utils.js';
|
|
2
|
-
export const serializeSchedulers = (outputPath, filesWithScheduledTasks, packageMappings = {}) => {
|
|
3
|
-
const serializedOutput = [
|
|
4
|
-
'/* The files with an addSerializedTasks function call */',
|
|
5
|
-
];
|
|
6
|
-
Array.from(filesWithScheduledTasks)
|
|
7
|
-
.sort()
|
|
8
|
-
.forEach((path) => {
|
|
9
|
-
const filePath = getFileImportRelativePath(outputPath, path, packageMappings);
|
|
10
|
-
serializedOutput.push(`import '${filePath}'`);
|
|
11
|
-
});
|
|
12
|
-
return serializedOutput.join('\n');
|
|
13
|
-
};
|
|
14
|
-
export const serializeSchedulerMeta = (scheduledTasksMeta) => {
|
|
15
|
-
const serializedOutput = [];
|
|
16
|
-
serializedOutput.push("import { pikkuState } from '@pikku/core'");
|
|
17
|
-
serializedOutput.push(`pikkuState('scheduler', 'meta', ${JSON.stringify(scheduledTasksMeta, null, 2)})`);
|
|
18
|
-
if (scheduledTasksMeta.length > 0) {
|
|
19
|
-
serializedOutput.push(`export type ScheduledTaskNames = '${scheduledTasksMeta.map((s) => s.name).join("' | '")}'`);
|
|
20
|
-
}
|
|
21
|
-
return serializedOutput.join('\n');
|
|
22
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { ChannelsMeta } from '@pikku/core/channel'
|
|
2
|
-
import { getFileImportRelativePath } from '../utils.js'
|
|
3
|
-
|
|
4
|
-
export const serializeChannels = (
|
|
5
|
-
outputPath: string,
|
|
6
|
-
filesWithChannels: Set<string>,
|
|
7
|
-
packageMappings: Record<string, string> = {}
|
|
8
|
-
) => {
|
|
9
|
-
const serializedOutput: string[] = [
|
|
10
|
-
'/* The files with an addChannel function call */',
|
|
11
|
-
]
|
|
12
|
-
|
|
13
|
-
Array.from(filesWithChannels)
|
|
14
|
-
.sort()
|
|
15
|
-
.forEach((path) => {
|
|
16
|
-
const filePath = getFileImportRelativePath(
|
|
17
|
-
outputPath,
|
|
18
|
-
path,
|
|
19
|
-
packageMappings
|
|
20
|
-
)
|
|
21
|
-
serializedOutput.push(`import '${filePath}'`)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
return serializedOutput.join('\n')
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const serializeChannelMeta = (channelsMeta: ChannelsMeta) => {
|
|
28
|
-
const serializedOutput: string[] = []
|
|
29
|
-
serializedOutput.push("import { pikkuState } from '@pikku/core'")
|
|
30
|
-
serializedOutput.push(
|
|
31
|
-
`pikkuState('channel', 'meta', ${JSON.stringify(channelsMeta, null, 2)})`
|
|
32
|
-
)
|
|
33
|
-
return serializedOutput.join('\n')
|
|
34
|
-
}
|