@pikku/cli 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.
Files changed (89) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/bin/pikku-all.ts +203 -0
  3. package/bin/pikku-channels-map.ts +55 -0
  4. package/bin/pikku-channels.ts +63 -0
  5. package/bin/pikku-fetch.ts +55 -0
  6. package/bin/pikku-function-types.ts +84 -0
  7. package/bin/pikku-functions.ts +35 -0
  8. package/bin/pikku-http-map.ts +55 -0
  9. package/bin/pikku-http-routes.ts +63 -0
  10. package/bin/pikku-nextjs.test.ts +279 -0
  11. package/bin/pikku-nextjs.ts +152 -0
  12. package/bin/pikku-openapi.ts +74 -0
  13. package/bin/pikku-rpc.ts +22 -0
  14. package/bin/pikku-scheduler.ts +64 -0
  15. package/bin/pikku-schemas.ts +56 -0
  16. package/bin/pikku-websocket.ts +58 -0
  17. package/bin/pikku.ts +26 -0
  18. package/dist/bin/pikku-all.js +3 -0
  19. package/dist/bin/pikku-functions.d.ts +0 -2
  20. package/dist/bin/pikku-functions.js +2 -17
  21. package/dist/bin/pikku-rpc.d.ts +3 -0
  22. package/dist/bin/pikku-rpc.js +8 -0
  23. package/dist/bin/pikku.js +0 -0
  24. package/dist/src/pikku-cli-config.d.ts +1 -0
  25. package/dist/src/pikku-cli-config.js +3 -0
  26. package/dist/src/schema-generator.js +1 -2
  27. package/dist/tsconfig.tsbuildinfo +1 -0
  28. package/package.json +3 -3
  29. package/src/inspector-glob.ts +28 -0
  30. package/src/openapi-spec-generator.ts +227 -0
  31. package/src/pikku-cli-config.ts +240 -0
  32. package/src/schema-generator.ts +136 -0
  33. package/{dist/src/events/http/serialize-fetch-wrapper.js → src/serialize-fetch-wrapper.ts} +4 -4
  34. package/src/serialize-import-map.ts +34 -0
  35. package/{dist/src/nextjs/serialize-nextjs-backend-wrapper.js → src/serialize-nextjs-backend-wrapper.ts} +11 -4
  36. package/{dist/src/nextjs/serialize-nextjs-http-wrapper.js → src/serialize-nextjs-http-wrapper.ts} +7 -4
  37. package/{dist/src/core/serialize-pikku-types.js → src/serialize-pikku-types.ts} +46 -35
  38. package/src/serialize-scheduler-meta.ts +18 -0
  39. package/src/serialize-typed-channel-map.ts +138 -0
  40. package/src/serialize-typed-function-map.ts +151 -0
  41. package/src/serialize-typed-http-map.ts +151 -0
  42. package/{dist/src/channels/serialize-websocket-wrapper.js → src/serialize-websocket-wrapper.ts} +4 -4
  43. package/src/utils.ts +284 -0
  44. package/tsconfig.json +21 -0
  45. package/dist/bin/pikku-http.d.ts +0 -5
  46. package/dist/bin/pikku-http.js +0 -27
  47. package/dist/bin/pikku-routes-map.d.ts +0 -5
  48. package/dist/bin/pikku-routes-map.js +0 -23
  49. package/dist/src/channels/serialize-channels.d.ts +0 -3
  50. package/dist/src/channels/serialize-channels.js +0 -19
  51. package/dist/src/channels/serialize-typed-channel-map.d.ts +0 -3
  52. package/dist/src/channels/serialize-typed-channel-map.js +0 -93
  53. package/dist/src/channels/serialize-websocket-wrapper.d.ts +0 -1
  54. package/dist/src/core/serialize-import-map.d.ts +0 -2
  55. package/dist/src/core/serialize-import-map.js +0 -24
  56. package/dist/src/core/serialize-pikku-types.d.ts +0 -4
  57. package/dist/src/events/channels/serialize-channels.d.ts +0 -3
  58. package/dist/src/events/channels/serialize-channels.js +0 -19
  59. package/dist/src/events/channels/serialize-typed-channel-map.d.ts +0 -3
  60. package/dist/src/events/channels/serialize-typed-channel-map.js +0 -90
  61. package/dist/src/events/channels/serialize-websocket-wrapper.d.ts +0 -1
  62. package/dist/src/events/channels/serialize-websocket-wrapper.js +0 -61
  63. package/dist/src/events/http/serialize-fetch-wrapper.d.ts +0 -1
  64. package/dist/src/events/http/serialize-route-imports.d.ts +0 -1
  65. package/dist/src/events/http/serialize-route-imports.js +0 -13
  66. package/dist/src/events/http/serialize-route-meta.d.ts +0 -2
  67. package/dist/src/events/http/serialize-route-meta.js +0 -6
  68. package/dist/src/events/http/serialize-typed-route-map.d.ts +0 -4
  69. package/dist/src/events/http/serialize-typed-route-map.js +0 -107
  70. package/dist/src/events/scheduler/serialize-schedulers.d.ts +0 -3
  71. package/dist/src/events/scheduler/serialize-schedulers.js +0 -23
  72. package/dist/src/http/serialize-fetch-wrapper.d.ts +0 -1
  73. package/dist/src/http/serialize-fetch-wrapper.js +0 -67
  74. package/dist/src/http/serialize-route-imports.d.ts +0 -1
  75. package/dist/src/http/serialize-route-imports.js +0 -13
  76. package/dist/src/http/serialize-route-meta.d.ts +0 -2
  77. package/dist/src/http/serialize-route-meta.js +0 -6
  78. package/dist/src/http/serialize-typed-route-map.d.ts +0 -4
  79. package/dist/src/http/serialize-typed-route-map.js +0 -107
  80. package/dist/src/nextjs/serialize-nextjs-backend-wrapper.d.ts +0 -1
  81. package/dist/src/nextjs/serialize-nextjs-http-wrapper.d.ts +0 -1
  82. package/dist/src/openapi/openapi-spec-generator.d.ts +0 -79
  83. package/dist/src/openapi/openapi-spec-generator.js +0 -136
  84. package/dist/src/scheduler/serialize-schedulers.d.ts +0 -3
  85. package/dist/src/scheduler/serialize-schedulers.js +0 -23
  86. package/dist/src/schema/schema-generator.d.ts +0 -5
  87. package/dist/src/schema/schema-generator.js +0 -89
  88. package/dist/src/serialize-typed-route-map.d.ts +0 -4
  89. package/dist/src/serialize-typed-route-map.js +0 -107
package/src/utils.ts ADDED
@@ -0,0 +1,284 @@
1
+ import { relative, dirname } from 'path'
2
+ import { PathToNameAndType, InspectorState } from '@pikku/inspector'
3
+ import { mkdir, writeFile } from 'fs/promises'
4
+ import chalk from 'chalk'
5
+ import { fileURLToPath } from 'url'
6
+ import { readFileSync } from 'fs'
7
+
8
+ const __filename = fileURLToPath(import.meta.url)
9
+
10
+ export const logPrimary = (message: string) => {
11
+ console.log(chalk.green(message))
12
+ }
13
+
14
+ export const logSuccess = (message: string) => {
15
+ console.log(chalk.green(message))
16
+ }
17
+
18
+ export const logInfo = (message: string) => {
19
+ console.log(chalk.blue(message))
20
+ }
21
+
22
+ export const getFileImportRelativePath = (
23
+ from: string,
24
+ to: string,
25
+ packageMappings: Record<string, string>
26
+ ): string => {
27
+ let filePath = relative(dirname(from), to)
28
+ if (!/^\.+\//.test(filePath)) {
29
+ filePath = `./${filePath}`
30
+ }
31
+ // let usesPackageName = false
32
+ for (const [path, packageName] of Object.entries(packageMappings)) {
33
+ if (filePath.includes(path)) {
34
+ // usesPackageName = true
35
+ filePath = filePath.replace(new RegExp(`.*${path}`), packageName)
36
+ break
37
+ }
38
+ }
39
+ // if (usesPackageName) {
40
+ // return filePath.replace('.ts', '')
41
+ // }
42
+ return filePath.replace('.ts', '.js')
43
+ }
44
+
45
+ interface Meta {
46
+ file: string
47
+ variable: string
48
+ type: string
49
+ typePath: string
50
+ }
51
+
52
+ export type FilesAndMethods = {
53
+ userSessionType: Meta
54
+ sessionServicesType: Meta
55
+ singletonServicesType: Meta
56
+ pikkuConfigFactory: Meta
57
+ singletonServicesFactory: Meta
58
+ sessionServicesFactory: Meta
59
+ }
60
+
61
+ export interface PikkuCLIOptions {
62
+ watch?: boolean
63
+ config?: string
64
+ configFileType?: string
65
+ userSessionType?: string
66
+ singletonServicesFactoryType?: string
67
+ sessionServicesFactoryType?: string
68
+ tags?: string[]
69
+ }
70
+
71
+ const getMetaTypes = (
72
+ type: string,
73
+ errors: Map<string, PathToNameAndType>,
74
+ map: PathToNameAndType,
75
+ desiredType?: string
76
+ ) => {
77
+ if (desiredType) {
78
+ const entries = Object.entries(map)
79
+ for (const [file, meta] of entries) {
80
+ for (const { type, variable, typePath } of meta) {
81
+ if (type === desiredType) {
82
+ return { file, variable, type, typePath }
83
+ }
84
+ }
85
+ }
86
+ errors.set(`No ${desiredType} found that extends ${type}`, map)
87
+ return undefined
88
+ }
89
+
90
+ const totalValues = Object.values(map).flat()
91
+ if (totalValues.length === 0) {
92
+ errors.set(`No ${type} found`, map)
93
+ } else if (totalValues.length > 1) {
94
+ errors.set(`More than one ${type} found`, map)
95
+ } else {
96
+ const entry = Object.entries(map)[0]
97
+ if (entry) {
98
+ const [file, [{ type, variable, typePath }]] = entry
99
+ return { file, type, variable, typePath }
100
+ }
101
+ }
102
+
103
+ return undefined
104
+ }
105
+
106
+ export const getPikkuFilesAndMethods = async (
107
+ {
108
+ singletonServicesTypeImportMap,
109
+ sessionServicesTypeImportMap,
110
+ userSessionTypeImportMap,
111
+ sessionServicesFactories,
112
+ singletonServicesFactories,
113
+ configFactories,
114
+ }: InspectorState,
115
+ packageMappings: Record<string, string>,
116
+ outputFile: string,
117
+ {
118
+ configFileType,
119
+ singletonServicesFactoryType,
120
+ sessionServicesFactoryType,
121
+ }: PikkuCLIOptions,
122
+ requires: Partial<{
123
+ config: boolean
124
+ sessionServiceType: boolean
125
+ singletonServicesType: boolean
126
+ userSessionType: boolean
127
+ singletonServicesFactory: boolean
128
+ sessionServicesFactory: boolean
129
+ }> = {
130
+ config: false,
131
+ singletonServicesType: false,
132
+ sessionServiceType: false,
133
+ userSessionType: false,
134
+ singletonServicesFactory: false,
135
+ sessionServicesFactory: false,
136
+ }
137
+ ): Promise<FilesAndMethods> => {
138
+ let errors = new Map<string, PathToNameAndType>()
139
+
140
+ const result: Partial<FilesAndMethods> = {
141
+ userSessionType: getMetaTypes(
142
+ 'CoreUserSession',
143
+ requires.userSessionType ? errors : new Map(),
144
+ userSessionTypeImportMap,
145
+ configFileType
146
+ ),
147
+ singletonServicesType: getMetaTypes(
148
+ 'CoreSingletonServices',
149
+ requires.singletonServicesType ? errors : new Map(),
150
+ singletonServicesTypeImportMap
151
+ ),
152
+ sessionServicesType: getMetaTypes(
153
+ 'CoreServices',
154
+ requires.sessionServiceType ? errors : new Map(),
155
+ sessionServicesTypeImportMap
156
+ ),
157
+ pikkuConfigFactory: getMetaTypes(
158
+ 'CoreConfig',
159
+ requires.config ? errors : new Map(),
160
+ configFactories,
161
+ configFileType
162
+ ),
163
+ singletonServicesFactory: getMetaTypes(
164
+ 'CreateSingletonServices',
165
+ requires.singletonServicesFactory ? errors : new Map(),
166
+ singletonServicesFactories,
167
+ singletonServicesFactoryType
168
+ ),
169
+ sessionServicesFactory: getMetaTypes(
170
+ 'CreateSessionServices',
171
+ requires.sessionServicesFactory ? errors : new Map(),
172
+ sessionServicesFactories,
173
+ sessionServicesFactoryType
174
+ ),
175
+ }
176
+
177
+ if (errors.size > 0) {
178
+ const result: string[] = ['Found errors:']
179
+ errors.forEach((filesAndMethods, message) => {
180
+ result.push(`- ${message}`)
181
+ for (const [file, methods] of Object.entries(filesAndMethods)) {
182
+ result.push(
183
+ `\t* file: ${getFileImportRelativePath(outputFile, file, packageMappings)}`
184
+ )
185
+ result.push(
186
+ `\t* methods: ${methods.map(({ variable, type }) => `${variable}: ${type}`).join(', ')}`
187
+ )
188
+ }
189
+ })
190
+
191
+ console.error(result.join('\n'))
192
+ process.exit(1)
193
+ }
194
+
195
+ return result as FilesAndMethods
196
+ }
197
+
198
+ export const writeFileInDir = async (
199
+ path: string,
200
+ content: string,
201
+ ignoreModifyComment: boolean = false
202
+ ) => {
203
+ if (content.includes('server-only')) {
204
+ content = content.replace(
205
+ "'server-only'",
206
+ `'server-only'\n\n${ignoreModifyComment ? '' : DO_NOT_MODIFY_COMMENT}`
207
+ )
208
+ } else {
209
+ content = `${ignoreModifyComment ? '' : DO_NOT_MODIFY_COMMENT}${content}`
210
+ }
211
+
212
+ await mkdir(dirname(path), { recursive: true })
213
+ await writeFile(path, content, 'utf-8')
214
+ logSuccess(`✓ File written to ${path}`)
215
+ }
216
+
217
+ export const logCommandInfoAndTime = async (
218
+ commandStart: string,
219
+ commandEnd: string,
220
+ [skipCondition, skipMessage = 'none found']: [boolean] | [boolean, string],
221
+ callback: (...args: any[]) => Promise<unknown>
222
+ ): Promise<boolean> => {
223
+ if (skipCondition === true) {
224
+ logInfo(
225
+ `• Skipping ${commandStart.charAt(0).toLocaleLowerCase()}${commandStart.slice(1)} since ${skipMessage}.`
226
+ )
227
+ return false
228
+ }
229
+
230
+ const start = Date.now()
231
+ chalk.blue(`• ${commandStart}...`)
232
+ await callback()
233
+
234
+ logSuccess(`✓ ${commandEnd} in ${Date.now() - start}ms.`)
235
+ return true
236
+ }
237
+
238
+ const logo = `
239
+ ______ _ _ _
240
+ (_____ (_) | | |
241
+ _____) )| | _| | _ _ _
242
+ | ____/ | |_/ ) |_/ ) | | |
243
+ | | | | _ (| _ (| |_| |
244
+ |_| |_|_| \_)_| \_)____/
245
+ `
246
+
247
+ export const logPikkuLogo = () => {
248
+ logPrimary(logo)
249
+
250
+ const packageJson = JSON.parse(
251
+ readFileSync(`${dirname(__filename)}/../../package.json`, 'utf-8')
252
+ )
253
+ logPrimary(`⚙️ Welcome to the Pikku CLI (v${packageJson.version})\n`)
254
+ }
255
+
256
+ // TODO: add version back in once the ESM dust settles
257
+ export const DO_NOT_MODIFY_COMMENT = `/**
258
+ * This file was generated by the @pikku/cli
259
+ */
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
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": ".",
5
+ "module": "Node16",
6
+ "outDir": "dist",
7
+ "target": "esnext",
8
+ "declaration": true,
9
+ "resolveJsonModule": true
10
+ },
11
+ "include": ["bin/**/*.ts", "src/**/*.ts"],
12
+ "exclude": ["**/*.test.ts", "node_modules", "bin/dist"],
13
+ "references": [
14
+ {
15
+ "path": "../core/tsconfig.json"
16
+ },
17
+ {
18
+ "path": "../inspector/tsconfig.json"
19
+ }
20
+ ]
21
+ }
@@ -1,5 +0,0 @@
1
- import { Command } from 'commander';
2
- import { PikkuCLIConfig } from '../src/pikku-cli-config.js';
3
- import { InspectorState } from '@pikku/inspector';
4
- export declare const pikkuHTTP: (cliConfig: PikkuCLIConfig, visitState: InspectorState) => Promise<boolean>;
5
- export declare const routes: (program: Command) => void;
@@ -1,27 +0,0 @@
1
- import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
2
- import { logCommandInfoAndTime, logPikkuLogo, serializeFileImports, writeFileInDir, } from '../src/utils.js';
3
- import { inspectorGlob } from '../src/inspector-glob.js';
4
- export const pikkuHTTP = async (cliConfig, visitState) => {
5
- return await logCommandInfoAndTime('Finding HTTP routes', 'Found HTTP routes', [visitState.http.files.size === 0], async () => {
6
- const { routesFile, packageMappings } = cliConfig;
7
- const { http } = visitState;
8
- const content = [
9
- serializeFileImports('addHTTPRoute', routesFile, http.files, packageMappings),
10
- `import { pikkuState } from '@pikku/core'\npikkuState('http', 'meta', ${JSON.stringify(http.meta, null, 2)})`
11
- ];
12
- await writeFileInDir(routesFile, content.join('\n\n'));
13
- });
14
- };
15
- async function action(cliOptions) {
16
- logPikkuLogo();
17
- const cliConfig = await getPikkuCLIConfig(cliOptions.config, ['rootDir', 'routeDirectories', 'routesFile'], cliOptions.tags);
18
- const visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories, cliConfig.filters);
19
- await pikkuHTTP(cliConfig, visitState);
20
- }
21
- export const routes = (program) => {
22
- program
23
- .command('routes')
24
- .description('Find all routes to import')
25
- .option('-c | --config <string>', 'The path to pikku cli config file')
26
- .action(action);
27
- };
@@ -1,5 +0,0 @@
1
- import { Command } from 'commander';
2
- import { PikkuCLIConfig } from '../src/pikku-cli-config.js';
3
- import { InspectorState } from '@pikku/inspector';
4
- export declare const pikkuHTTPMap: ({ routesMapDeclarationFile, packageMappings }: PikkuCLIConfig, { http, functions }: InspectorState) => Promise<boolean>;
5
- export declare const routesMap: (program: Command) => void;
@@ -1,23 +0,0 @@
1
- import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
2
- import { logCommandInfoAndTime, logPikkuLogo, writeFileInDir, } from '../src/utils.js';
3
- import { serializeTypedRoutesMap } from '../src/serialize-typed-route-map.js';
4
- import { inspectorGlob } from '../src/inspector-glob.js';
5
- export const pikkuHTTPMap = async ({ routesMapDeclarationFile, packageMappings }, { http, functions }) => {
6
- return await logCommandInfoAndTime('Creating routes map', 'Created routes map', [http.files.size === 0], async () => {
7
- const content = serializeTypedRoutesMap(routesMapDeclarationFile, packageMappings, functions.typesMap, http.meta, http.metaInputTypes);
8
- await writeFileInDir(routesMapDeclarationFile, content);
9
- });
10
- };
11
- async function action(cliOptions) {
12
- logPikkuLogo();
13
- const cliConfig = await getPikkuCLIConfig(cliOptions.config, ['rootDir', 'routeDirectories', 'routesFile'], cliOptions.tags);
14
- const visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories, cliConfig.filters);
15
- await pikkuHTTPMap(cliConfig, visitState);
16
- }
17
- export const routesMap = (program) => {
18
- program
19
- .command('map')
20
- .description('Generate a map of all routes to aid in type checking')
21
- .option('-c | --config <string>', 'The path to pikku cli config file')
22
- .action(action);
23
- };
@@ -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,3 +0,0 @@
1
- import { ChannelsMeta } from '@pikku/core/channel';
2
- import { TypesMap } from '@pikku/inspector';
3
- export declare const serializeTypedChannelsMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, channelsMeta: ChannelsMeta) => string;
@@ -1,93 +0,0 @@
1
- import { serializeImportMap } from '../core/serialize-import-map.js';
2
- import { generateCustomTypes } from '../http/serialize-typed-route-map.js';
3
- export const serializeTypedChannelsMap = (relativeToPath, packageMappings, typesMap, channelsMeta) => {
4
- const { channels, requiredTypes } = generateChannels(channelsMeta);
5
- typesMap.customTypes.forEach(({ references }) => {
6
- for (const reference of references) {
7
- requiredTypes.add(reference);
8
- }
9
- });
10
- const imports = serializeImportMap(relativeToPath, packageMappings, typesMap, requiredTypes);
11
- const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
12
- return `/**
13
- * This provides the structure needed for TypeScript to be aware of channels
14
- */
15
-
16
- ${imports}
17
- ${serializedCustomTypes}
18
-
19
- interface ChannelHandler<I, O> {
20
- input: I;
21
- output: O;
22
- }
23
-
24
- ${channels}
25
-
26
- export type ChannelDefaultHandlerOf<Channel extends keyof ChannelsMap> =
27
- ChannelsMap[Channel]['defaultMessage'] extends { input: infer I; output: infer O }
28
- ? ChannelHandler<I, O>
29
- : never;
30
-
31
- export type ChannelRouteHandlerOf<
32
- Channel extends keyof ChannelsMap,
33
- Route extends keyof ChannelsMap[Channel]['routes'],
34
- Method extends keyof ChannelsMap[Channel]['routes'][Route],
35
- > =
36
- ChannelsMap[Channel]['routes'][Route][Method] extends { input: infer I; output: infer O }
37
- ? ChannelHandler<I, O>
38
- : never;
39
- `;
40
- };
41
- function generateChannels(channelsMeta) {
42
- const requiredTypes = new Set();
43
- const channelsObject = {};
44
- for (const meta of Object.values(channelsMeta)) {
45
- const { name, messageRoutes, message } = meta;
46
- if (!channelsObject[name]) {
47
- channelsObject[name] = { message, routes: {} };
48
- }
49
- for (const [key, route] of Object.entries(messageRoutes)) {
50
- if (!channelsObject[name].routes[key]) {
51
- channelsObject[name].routes[key] = {};
52
- }
53
- for (const [method, { inputs, outputs }] of Object.entries(route)) {
54
- const inputTypes = inputs || null;
55
- const outputTypes = outputs || null;
56
- channelsObject[name].routes[key][method] = {
57
- inputTypes,
58
- outputTypes,
59
- };
60
- inputTypes?.forEach((type) => requiredTypes.add(type));
61
- outputTypes?.forEach((type) => requiredTypes.add(type));
62
- }
63
- }
64
- }
65
- let routesStr = 'export type ChannelsMap = {\n';
66
- for (const [channelPath, { routes, message }] of Object.entries(channelsObject)) {
67
- routesStr += ` readonly '${channelPath}': {\n`;
68
- // Add `routes` object
69
- routesStr += ` readonly routes: {\n`;
70
- for (const [key, methods] of Object.entries(routes)) {
71
- routesStr += ` readonly ${key}: {\n`;
72
- for (const [method, handler] of Object.entries(methods)) {
73
- routesStr += ` readonly ${method}: ChannelHandler<${formatTypeArray(handler.inputTypes) || 'void'}, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`;
74
- }
75
- routesStr += ' },\n';
76
- }
77
- routesStr += ' },\n';
78
- // Add `defaultMessage` outside `routes`
79
- if (message) {
80
- routesStr += ` readonly defaultMessage: ChannelHandler<${formatTypeArray(message.inputs)}, ${formatTypeArray(message.outputs)}>,\n`;
81
- }
82
- else {
83
- routesStr += ` readonly defaultMessage: never,\n`;
84
- }
85
- routesStr += ' },\n';
86
- }
87
- routesStr += '};';
88
- return { channels: routesStr, requiredTypes };
89
- }
90
- // Utility to format type arrays
91
- function formatTypeArray(types) {
92
- return types ? types.join(' | ') : 'null';
93
- }
@@ -1 +0,0 @@
1
- export declare const serializeWebsocketWrapper: (channelsMapPath: string) => string;
@@ -1,2 +0,0 @@
1
- import { TypesMap } from '@pikku/inspector';
2
- export declare const serializeImportMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, requiredTypes: Set<string>) => string;
@@ -1,24 +0,0 @@
1
- import { getFileImportRelativePath } from '../utils.js';
2
- export const serializeImportMap = (relativeToPath, packageMappings, typesMap, requiredTypes) => {
3
- const paths = new Map();
4
- Array.from(requiredTypes).forEach((requiredType) => {
5
- const { originalName, uniqueName, path } = typesMap.getTypeMeta(requiredType);
6
- if (!path) {
7
- // This is a custom type that exists in file, so we don't need to import it
8
- return;
9
- }
10
- const variables = paths.get(path) || [];
11
- if (originalName === uniqueName) {
12
- variables.push(originalName);
13
- }
14
- else {
15
- variables.push(`${originalName} as ${uniqueName}`);
16
- }
17
- paths.set(path, variables);
18
- });
19
- const imports = [];
20
- for (const [path, variables] of paths.entries()) {
21
- imports.push(`import type { ${variables.join(', ')} } from '${getFileImportRelativePath(relativeToPath, path, packageMappings)}'`);
22
- }
23
- return imports.join('\n');
24
- };
@@ -1,4 +0,0 @@
1
- /**
2
- *
3
- */
4
- export declare const serializePikkuTypes: (userSessionTypeImport: string, userSessionTypeName: string, singletonServicesTypeImport: string, singletonServicesTypeName: string, sessionServicesTypeImport: string, servicesTypeName: string) => string;
@@ -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,3 +0,0 @@
1
- import { ChannelsMeta } from '@pikku/core/channel';
2
- import { TypesMap } from '@pikku/inspector';
3
- export declare const serializeTypedChannelsMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, channelsMeta: ChannelsMeta) => string;
@@ -1,90 +0,0 @@
1
- import { serializeImportMap } from '../core/serialize-import-map.js';
2
- import { generateCustomTypes } from '../http/serialize-typed-route-map.js';
3
- export const serializeTypedChannelsMap = (relativeToPath, packageMappings, typesMap, channelsMeta) => {
4
- const { channels, requiredTypes } = generateChannels(channelsMeta);
5
- typesMap.customTypes.forEach(({ references }) => {
6
- for (const reference of references) {
7
- requiredTypes.add(reference);
8
- }
9
- });
10
- const imports = serializeImportMap(relativeToPath, packageMappings, typesMap, requiredTypes);
11
- const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
12
- return `/**
13
- * This provides the structure needed for TypeScript to be aware of channels
14
- */
15
-
16
- ${imports}
17
- ${serializedCustomTypes}
18
-
19
- interface ChannelHandler<I, O> {
20
- input: I;
21
- output: O;
22
- }
23
-
24
- ${channels}
25
-
26
- export type ChannelDefaultHandlerOf<Channel extends keyof ChannelsMap> =
27
- ChannelsMap[Channel]['defaultMessage'] extends { input: infer I; output: infer O }
28
- ? ChannelHandler<I, O>
29
- : never;
30
-
31
- export type ChannelRouteHandlerOf<
32
- Channel extends keyof ChannelsMap,
33
- Route extends keyof ChannelsMap[Channel]['routes'],
34
- Method extends keyof ChannelsMap[Channel]['routes'][Route],
35
- > =
36
- ChannelsMap[Channel]['routes'][Route][Method] extends { input: infer I; output: infer O }
37
- ? ChannelHandler<I, O>
38
- : never;
39
- `;
40
- };
41
- function generateChannels(channelsMeta) {
42
- const requiredTypes = new Set();
43
- const channelsObject = {};
44
- for (const meta of channelsMeta) {
45
- const { name, messageRoutes, message } = meta;
46
- if (!channelsObject[name]) {
47
- channelsObject[name] = { message, routes: {} };
48
- }
49
- for (const [key, route] of Object.entries(messageRoutes)) {
50
- if (!channelsObject[name].routes[key]) {
51
- channelsObject[name].routes[key] = {};
52
- }
53
- for (const [method, { inputs, outputs }] of Object.entries(route)) {
54
- const inputTypes = inputs || null;
55
- const outputTypes = outputs || null;
56
- channelsObject[name].routes[key][method] = {
57
- inputTypes,
58
- outputTypes,
59
- };
60
- inputTypes?.forEach((type) => requiredTypes.add(type));
61
- outputTypes?.forEach((type) => requiredTypes.add(type));
62
- }
63
- }
64
- }
65
- let routesStr = 'export type ChannelsMap = {\n';
66
- for (const [channelPath, { routes, message }] of Object.entries(channelsObject)) {
67
- routesStr += ` readonly '${channelPath}': {\n`;
68
- // Add `routes` object
69
- routesStr += ` readonly routes: {\n`;
70
- for (const [key, methods] of Object.entries(routes)) {
71
- routesStr += ` readonly ${key}: {\n`;
72
- for (const [method, handler] of Object.entries(methods)) {
73
- routesStr += ` readonly ${method}: ChannelHandler<${formatTypeArray(handler.inputTypes) || 'void'}, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`;
74
- }
75
- routesStr += ' },\n';
76
- }
77
- routesStr += ' },\n';
78
- // Add `defaultMessage` outside `routes`
79
- if (message) {
80
- routesStr += ` readonly defaultMessage: ChannelHandler<${formatTypeArray(message.inputs)}, ${formatTypeArray(message.outputs)}>,\n`;
81
- }
82
- routesStr += ' },\n';
83
- }
84
- routesStr += '};';
85
- return { channels: routesStr, requiredTypes };
86
- }
87
- // Utility to format type arrays
88
- function formatTypeArray(types) {
89
- return types ? types.join(' | ') : 'null';
90
- }
@@ -1 +0,0 @@
1
- export declare const serializeWebsocketWrapper: (channelsMapPath: string) => string;