@pikku/cli 0.7.2 → 0.7.4

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 (75) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/bin/pikku-all.ts +5 -2
  3. package/bin/pikku-channels-map.ts +2 -33
  4. package/bin/pikku-channels.ts +2 -30
  5. package/bin/pikku-fetch.ts +3 -3
  6. package/bin/pikku-function-types.ts +8 -42
  7. package/bin/pikku-functions.ts +6 -21
  8. package/bin/pikku-http-map.ts +2 -32
  9. package/bin/pikku-http-routes.ts +2 -30
  10. package/bin/pikku-nextjs.ts +1 -1
  11. package/bin/pikku-openapi.ts +1 -1
  12. package/bin/pikku-rpc-map.ts +25 -0
  13. package/bin/pikku-rpc.ts +62 -7
  14. package/bin/pikku-scheduler.ts +2 -30
  15. package/bin/pikku-schemas.ts +2 -2
  16. package/bin/pikku-websocket.ts +1 -1
  17. package/bin/pikku.ts +0 -10
  18. package/dist/bin/pikku-all.d.ts +1 -1
  19. package/dist/bin/pikku-all.js +5 -2
  20. package/dist/bin/pikku-channels-map.d.ts +0 -2
  21. package/dist/bin/pikku-channels-map.js +1 -16
  22. package/dist/bin/pikku-channels.d.ts +0 -2
  23. package/dist/bin/pikku-channels.js +1 -16
  24. package/dist/bin/pikku-fetch.d.ts +1 -1
  25. package/dist/bin/pikku-fetch.js +1 -1
  26. package/dist/bin/pikku-function-types.d.ts +2 -4
  27. package/dist/bin/pikku-function-types.js +3 -22
  28. package/dist/bin/pikku-functions.d.ts +1 -1
  29. package/dist/bin/pikku-functions.js +3 -6
  30. package/dist/bin/pikku-http-map.d.ts +0 -2
  31. package/dist/bin/pikku-http-map.js +1 -16
  32. package/dist/bin/pikku-http-routes.d.ts +0 -2
  33. package/dist/bin/pikku-http-routes.js +1 -16
  34. package/dist/bin/pikku-nextjs.d.ts +1 -1
  35. package/dist/bin/pikku-nextjs.js +1 -1
  36. package/dist/bin/pikku-openapi.js +1 -1
  37. package/dist/bin/pikku-rpc-map.d.ts +3 -0
  38. package/dist/bin/pikku-rpc-map.js +8 -0
  39. package/dist/bin/pikku-rpc.d.ts +5 -1
  40. package/dist/bin/pikku-rpc.js +33 -6
  41. package/dist/bin/pikku-scheduler.d.ts +0 -2
  42. package/dist/bin/pikku-scheduler.js +1 -16
  43. package/dist/bin/pikku-schemas.d.ts +1 -1
  44. package/dist/bin/pikku-schemas.js +2 -2
  45. package/dist/bin/pikku-websocket.d.ts +1 -1
  46. package/dist/bin/pikku-websocket.js +1 -1
  47. package/dist/bin/pikku.js +0 -10
  48. package/dist/src/inspector-glob.js +1 -1
  49. package/dist/src/pikku-cli-config.d.ts +7 -5
  50. package/dist/src/pikku-cli-config.js +6 -0
  51. package/dist/src/schema-generator.js +1 -1
  52. package/dist/src/serialize-pikku-types.d.ts +1 -1
  53. package/dist/src/serialize-pikku-types.js +6 -3
  54. package/dist/src/serialize-typed-channel-map.js +2 -2
  55. package/dist/src/serialize-typed-http-map.js +1 -1
  56. package/dist/src/serialize-typed-rpc-map.d.ts +4 -0
  57. package/dist/src/serialize-typed-rpc-map.js +66 -0
  58. package/dist/src/{utils.d.ts → utils/utils.d.ts} +2 -1
  59. package/dist/src/{utils.js → utils/utils.js} +15 -1
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +2 -2
  62. package/src/inspector-glob.ts +1 -1
  63. package/src/pikku-cli-config.ts +31 -5
  64. package/src/schema-generator.ts +1 -1
  65. package/src/serialize-pikku-types.ts +6 -3
  66. package/src/serialize-typed-channel-map.ts +2 -2
  67. package/src/serialize-typed-http-map.ts +1 -1
  68. package/src/serialize-typed-rpc-map.ts +105 -0
  69. package/src/{utils.ts → utils/utils.ts} +20 -2
  70. package/dist/src/serialize-typed-function-map.d.ts +0 -5
  71. package/dist/src/serialize-typed-function-map.js +0 -109
  72. package/src/serialize-typed-function-map.ts +0 -161
  73. /package/dist/src/{serialize-import-map.d.ts → utils/serialize-import-map.d.ts} +0 -0
  74. /package/dist/src/{serialize-import-map.js → utils/serialize-import-map.js} +0 -0
  75. /package/src/{serialize-import-map.ts → utils/serialize-import-map.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/cli",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@openapi-contrib/json-schema-to-openapi-schema": "^3.0.2",
25
- "@pikku/core": "^0.7.4",
25
+ "@pikku/core": "^0.7.7",
26
26
  "@pikku/inspector": "^0.7.4",
27
27
  "@types/cookie": "^0.6.0",
28
28
  "@types/uuid": "^10.0.0",
@@ -1,7 +1,7 @@
1
1
  import * as path from 'path'
2
2
  import { glob } from 'tinyglobby'
3
3
  import { InspectorFilters, InspectorState, inspect } from '@pikku/inspector'
4
- import { logCommandInfoAndTime } from './utils.js'
4
+ import { logCommandInfoAndTime } from './utils/utils.js'
5
5
 
6
6
  export const inspectorGlob = async (
7
7
  rootDir: string,
@@ -4,20 +4,37 @@ import { OpenAPISpecInfo } from './openapi-spec-generator.js'
4
4
  import { InspectorFilters } from '@pikku/inspector'
5
5
 
6
6
  export interface PikkuCLICoreOutputFiles {
7
+ // Base directory
7
8
  outDir?: string
9
+
10
+ // Schema and types
11
+ schemaDirectory: string
12
+ typesDeclarationFile: string
13
+
14
+ // Function definitions
8
15
  functionsFile: string
9
16
  functionsMetaFile: string
17
+
18
+ // HTTP routes
10
19
  httpRoutesFile: string
11
20
  httpRoutesMetaFile: string
21
+ httpRoutesMapDeclarationFile: string
22
+
23
+ // Channels
12
24
  channelsFile: string
13
25
  channelsMetaFile: string
26
+ channelsMapDeclarationFile: string
27
+
28
+ // RPC
29
+ rpcFile: string
30
+ rpcMetaFile: string
31
+ rpcMapDeclarationFile: string
32
+
33
+ // Schedulers
14
34
  schedulersFile: string
15
35
  schedulersMetaFile: string
16
- rpcFile: string
17
- schemaDirectory: string
18
- typesDeclarationFile: string
19
- httpRoutesMapDeclarationFile: string
20
- channelsMapDeclarationFile: string
36
+
37
+ // Application bootstrap
21
38
  bootstrapFile: string
22
39
  }
23
40
 
@@ -139,6 +156,15 @@ const _getPikkuCLIConfig = async (
139
156
  if (!result.rpcFile) {
140
157
  result.rpcFile = join(result.outDir, 'pikku-rpc.gen.ts')
141
158
  }
159
+ if (!result.rpcMetaFile) {
160
+ result.rpcMetaFile = join(result.outDir, 'pikku-rpc-meta.gen.ts')
161
+ }
162
+ if (!result.rpcMapDeclarationFile) {
163
+ result.rpcMapDeclarationFile = join(
164
+ result.outDir,
165
+ 'pikku-rpc-map.gen.ts'
166
+ )
167
+ }
142
168
  if (!result.httpRoutesFile) {
143
169
  result.httpRoutesFile = join(result.outDir, 'pikku-http-routes.gen.ts')
144
170
  }
@@ -1,5 +1,5 @@
1
1
  import { createGenerator, RootlessError } from 'ts-json-schema-generator'
2
- import { logInfo, writeFileInDir } from './utils.js'
2
+ import { logInfo, writeFileInDir } from './utils/utils.js'
3
3
  import { mkdir, writeFile } from 'fs/promises'
4
4
  import { FunctionsMeta, JSONValue } from '@pikku/core'
5
5
  import { HTTPRoutesMeta } from '@pikku/core/http'
@@ -7,7 +7,7 @@ export const serializePikkuTypes = (
7
7
  singletonServicesTypeImport: string,
8
8
  singletonServicesTypeName: string,
9
9
  sessionServicesTypeImport: string,
10
- servicesTypeName: string
10
+ rpcMapTypeImport: string
11
11
  ) => {
12
12
  return `/**
13
13
  * This is used to provide the application types in the typescript project
@@ -22,6 +22,7 @@ import { CoreAPIChannel, PikkuChannel, addChannel as addCoreChannel } from '@pik
22
22
  ${userSessionTypeImport}
23
23
  ${singletonServicesTypeImport}
24
24
  ${sessionServicesTypeImport}
25
+ ${rpcMapTypeImport}
25
26
 
26
27
  export type APIPermission<In = unknown, RequiredServices extends ${singletonServicesTypeName} = ${singletonServicesTypeName}> = CoreAPIPermission<In, RequiredServices, ${userSessionTypeName}>
27
28
  export type APIMiddleware<RequiredServices extends ${singletonServicesTypeName} = ${singletonServicesTypeName}> = PikkuMiddleware<RequiredServices, ${userSessionTypeName}>
@@ -30,7 +31,8 @@ type APIFunctionSessionless<
30
31
  In = unknown,
31
32
  Out = never,
32
33
  ChannelData = null, // null means optional channel
33
- RequiredServices extends Services = Services & (
34
+ RequiredServices extends Services = Services &
35
+ { rpc: TypedPikkuRPC } & (
34
36
  [ChannelData] extends [null]
35
37
  ? { channel?: PikkuChannel<unknown, Out> } // Optional channel
36
38
  : { channel: PikkuChannel<ChannelData, Out> } // Required channel with any data type
@@ -41,7 +43,8 @@ type APIFunction<
41
43
  In = unknown,
42
44
  Out = never,
43
45
  ChannelData = null, // null means optional channel
44
- RequiredServices extends Services = Services & (
46
+ RequiredServices extends Services = Services &
47
+ { rpc: TypedPikkuRPC } & (
45
48
  [ChannelData] extends [null]
46
49
  ? { channel?: PikkuChannel<unknown, Out> } // Optional channel
47
50
  : { channel: PikkuChannel<ChannelData, Out> } // Required channel with any data type
@@ -1,7 +1,7 @@
1
1
  import { ChannelsMeta } from '@pikku/core/channel'
2
- import { serializeImportMap } from './serialize-import-map.js'
2
+ import { serializeImportMap } from './utils/serialize-import-map.js'
3
3
  import { TypesMap } from '@pikku/inspector'
4
- import { generateCustomTypes } from './serialize-typed-http-map.js'
4
+ import { generateCustomTypes } from './utils/utils.js'
5
5
 
6
6
  export const serializeTypedChannelsMap = (
7
7
  relativeToPath: string,
@@ -1,5 +1,5 @@
1
1
  import { HTTPRoutesMeta } from '@pikku/core/http'
2
- import { serializeImportMap } from './serialize-import-map.js'
2
+ import { serializeImportMap } from './utils/serialize-import-map.js'
3
3
  import { MetaInputTypes, TypesMap } from '@pikku/inspector'
4
4
  import { FunctionsMeta } from '@pikku/core'
5
5
 
@@ -0,0 +1,105 @@
1
+ import { serializeImportMap } from './utils/serialize-import-map.js'
2
+ import { TypesMap } from '@pikku/inspector'
3
+ import { FunctionsMeta } from '@pikku/core'
4
+ import { generateCustomTypes } from './utils/utils.js'
5
+ import { RPCMeta } from '../../core/src/rpc/rpc-types.js'
6
+
7
+ export const serializeTypedRPCMap = (
8
+ relativeToPath: string,
9
+ packageMappings: Record<string, string>,
10
+ typesMap: TypesMap,
11
+ functionsMeta: FunctionsMeta,
12
+ rpcMeta: Record<string, RPCMeta>
13
+ ) => {
14
+ const requiredTypes = new Set<string>()
15
+ const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
16
+ const serializedRPCs = generateRPCs(
17
+ rpcMeta,
18
+ functionsMeta,
19
+ typesMap,
20
+ requiredTypes
21
+ )
22
+
23
+ const serializedImportMap = serializeImportMap(
24
+ relativeToPath,
25
+ packageMappings,
26
+ typesMap,
27
+ requiredTypes
28
+ )
29
+
30
+ return `/**
31
+ * This provides the structure needed for typescript to be aware of RPCs and their return types
32
+ */
33
+
34
+ ${serializedImportMap}
35
+ ${serializedCustomTypes}
36
+
37
+ interface RPCHandler<I, O> {
38
+ input: I;
39
+ output: O;
40
+ }
41
+
42
+ ${serializedRPCs}
43
+
44
+ type RPCInvoke = <Name extends keyof RPCMap>(
45
+ name: Name,
46
+ data: RPCMap[Name]['input'],
47
+ options?: {
48
+ location?: 'local' | 'remote' | 'auto'
49
+ }
50
+ ) => Promise<RPCMap[Name]['output']>
51
+
52
+ export type TypedPikkuRPC = {
53
+ depth: number;
54
+ global: boolean;
55
+ invoke: RPCInvoke;
56
+ }
57
+ `
58
+ }
59
+
60
+ function generateRPCs(
61
+ rpcMeta: Record<string, RPCMeta>,
62
+ functionsMeta: FunctionsMeta,
63
+ typesMap: TypesMap,
64
+ requiredTypes: Set<string>
65
+ ) {
66
+ // Initialize an object to collect RPCs
67
+ const rpcsObj: Record<string, { inputType: string; outputType: string }> = {}
68
+
69
+ // Iterate through RPC metadata
70
+ for (const [funcName, { pikkuFuncName }] of Object.entries(rpcMeta)) {
71
+ const functionMeta = functionsMeta[pikkuFuncName]
72
+ if (!functionMeta) {
73
+ throw new Error(
74
+ `Function ${funcName} not found in functionsMeta. Please check your configuration.`
75
+ )
76
+ }
77
+
78
+ const input = functionMeta.inputs ? functionMeta.inputs[0] : undefined
79
+ const output = functionMeta.outputs ? functionMeta.outputs[0] : undefined
80
+
81
+ // Store the input and output types for RPCHandler
82
+ const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null'
83
+ const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null'
84
+
85
+ requiredTypes.add(inputType)
86
+ requiredTypes.add(outputType)
87
+
88
+ // Add RPC entry
89
+ rpcsObj[funcName] = {
90
+ inputType,
91
+ outputType,
92
+ }
93
+ }
94
+
95
+ // Build the RPCs object as a string
96
+ let rpcsStr = 'export type RPCMap = {\n'
97
+
98
+ for (const [funcName, handler] of Object.entries(rpcsObj)) {
99
+ rpcsStr += ` readonly '${funcName}': RPCHandler<${handler.inputType}, ${handler.outputType}>,\n`
100
+ }
101
+
102
+ rpcsStr += '};\n'
103
+
104
+ return rpcsStr
105
+ }
@@ -1,5 +1,5 @@
1
1
  import { relative, dirname } from 'path'
2
- import { PathToNameAndType, InspectorState } from '@pikku/inspector'
2
+ import { PathToNameAndType, InspectorState, TypesMap } from '@pikku/inspector'
3
3
  import { mkdir, writeFile } from 'fs/promises'
4
4
  import chalk from 'chalk'
5
5
  import { fileURLToPath } from 'url'
@@ -248,7 +248,7 @@ export const logPikkuLogo = () => {
248
248
  logPrimary(logo)
249
249
 
250
250
  const packageJson = JSON.parse(
251
- readFileSync(`${dirname(__filename)}/../../package.json`, 'utf-8')
251
+ readFileSync(`${dirname(__filename)}/../../../package.json`, 'utf-8')
252
252
  )
253
253
  logPrimary(`⚙️ Welcome to the Pikku CLI (v${packageJson.version})\n`)
254
254
  }
@@ -282,3 +282,21 @@ export const serializeFileImports = (
282
282
 
283
283
  return serializedOutput.join('\n')
284
284
  }
285
+
286
+ export function generateCustomTypes(
287
+ typesMap: TypesMap,
288
+ requiredTypes: Set<string>
289
+ ) {
290
+ return `
291
+ // Custom types are those that are defined directly within generics
292
+ // or are broken into simpler types
293
+ ${Array.from(typesMap.customTypes.entries())
294
+ .map(([name, { type, references }]) => {
295
+ references.forEach((name) => {
296
+ const originalName = typesMap.getTypeMeta(name).originalName
297
+ requiredTypes.add(originalName)
298
+ })
299
+ return `export type ${name} = ${type}`
300
+ })
301
+ .join('\n')}`
302
+ }
@@ -1,5 +0,0 @@
1
- import { HTTPRoutesMeta } from '@pikku/core/http';
2
- import { MetaInputTypes, TypesMap } from '@pikku/inspector';
3
- import { FunctionsMeta } from '@pikku/core';
4
- export declare const serializeTypedRoutesMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, functionsMeta: FunctionsMeta, routesMeta: HTTPRoutesMeta, metaTypes: MetaInputTypes) => string;
5
- export declare function generateCustomTypes(typesMap: TypesMap, requiredTypes: Set<string>): string;
@@ -1,109 +0,0 @@
1
- import { serializeImportMap } from './serialize-import-map.js';
2
- export const serializeTypedRoutesMap = (relativeToPath, packageMappings, typesMap, functionsMeta, routesMeta, metaTypes) => {
3
- const requiredTypes = new Set();
4
- const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
5
- const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap);
6
- const serializedRoutes = generateRoutes(functionsMeta, routesMeta, typesMap, requiredTypes);
7
- const serializedImportMap = serializeImportMap(relativeToPath, packageMappings, typesMap, requiredTypes);
8
- return `/**
9
- * This provides the structure needed for typescript to be aware of routes and their return types
10
- */
11
-
12
- ${serializedImportMap}
13
- ${serializedCustomTypes}
14
- ${serializedMetaTypes}
15
-
16
- interface RouteHandler<I, O> {
17
- input: I;
18
- output: O;
19
- }
20
-
21
- ${serializedRoutes}
22
-
23
- export type RouteHandlerOf<Route extends keyof RoutesMap, Method extends keyof RoutesMap[Route]> =
24
- RoutesMap[Route][Method] extends { input: infer I; output: infer O }
25
- ? RouteHandler<I, O>
26
- : never;
27
-
28
- export type RoutesWithMethod<Method extends string> = {
29
- [Route in keyof RoutesMap]: Method extends keyof RoutesMap[Route] ? Route : never;
30
- }[keyof RoutesMap];
31
- `;
32
- };
33
- export function generateCustomTypes(typesMap, requiredTypes) {
34
- return `
35
- // Custom types are those that are defined directly within generics
36
- // or are broken into simpler types
37
- ${Array.from(typesMap.customTypes.entries())
38
- .map(([name, { type, references }]) => {
39
- references.forEach((name) => {
40
- const originalName = typesMap.getTypeMeta(name).originalName;
41
- requiredTypes.add(originalName);
42
- });
43
- return `export type ${name} = ${type}`;
44
- })
45
- .join('\n')}`;
46
- }
47
- function generateRoutes(functionsMeta, routesMeta, typesMap, requiredTypes) {
48
- // Initialize an object to collect routes
49
- const routesObj = {};
50
- for (const meta of routesMeta) {
51
- const { route, method, pikkuFuncName } = meta;
52
- const input = functionsMeta[pikkuFuncName]?.inputs?.[0];
53
- const output = functionsMeta[pikkuFuncName]?.outputs?.[0];
54
- // Initialize the route entry if it doesn't exist
55
- if (!routesObj[route]) {
56
- routesObj[route] = {};
57
- }
58
- // Store the input and output types separately for RouteHandler
59
- const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null';
60
- const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null';
61
- requiredTypes.add(inputType);
62
- requiredTypes.add(outputType);
63
- // Add method entry
64
- routesObj[route][method] = {
65
- inputType,
66
- outputType,
67
- };
68
- }
69
- // Build the routes object as a string
70
- let routesStr = 'export type RoutesMap = {\n';
71
- for (const [routePath, methods] of Object.entries(routesObj)) {
72
- routesStr += ` readonly '${routePath}': {\n`;
73
- for (const [method, handler] of Object.entries(methods)) {
74
- routesStr += ` readonly ${method.toUpperCase()}: RouteHandler<${handler.inputType}, ${handler.outputType}>,\n`;
75
- }
76
- routesStr += ' },\n';
77
- }
78
- routesStr += '};';
79
- return routesStr;
80
- }
81
- const generateMetaTypes = (metaTypes, typesMap) => {
82
- const nameToTypeMap = Array.from(metaTypes.entries()).reduce((result, [_name, { query, body, params }]) => {
83
- const { uniqueName } = typesMap.getTypeMeta(_name);
84
- const queryType = query && query.length > 0
85
- ? `Pick<${uniqueName}, '${query?.join("' | '")}'>`
86
- : undefined;
87
- if (queryType) {
88
- result.set(`${uniqueName}Query`, queryType);
89
- }
90
- const paramsType = params && params.length > 0
91
- ? `Pick<${uniqueName}, '${params.join("' | '")}'>`
92
- : undefined;
93
- if (paramsType) {
94
- result.set(`${uniqueName}Params`, paramsType);
95
- }
96
- const bodyType = (body && body.length > 0) || (params && params.length > 0)
97
- ? `Omit<${uniqueName}, '${[...new Set([...(query || []), ...(params || [])])].join("' | '")}'>`
98
- : uniqueName;
99
- if (bodyType) {
100
- result.set(`${uniqueName}Body`, bodyType);
101
- }
102
- return result;
103
- }, new Map());
104
- return `
105
- // The '& {}' is a workaround for not directly refering to a type since it confuses typescript
106
- ${Array.from(nameToTypeMap.entries())
107
- .map(([name, type]) => `export type ${name} = ${type} & {}`)
108
- .join('\n')}`;
109
- };
@@ -1,161 +0,0 @@
1
- import { HTTPRoutesMeta } from '@pikku/core/http'
2
- import { serializeImportMap } from './serialize-import-map.js'
3
- import { MetaInputTypes, TypesMap } from '@pikku/inspector'
4
- import { FunctionsMeta } from '@pikku/core'
5
-
6
- export const serializeTypedRoutesMap = (
7
- relativeToPath: string,
8
- packageMappings: Record<string, string>,
9
- typesMap: TypesMap,
10
- functionsMeta: FunctionsMeta,
11
- routesMeta: HTTPRoutesMeta,
12
- metaTypes: MetaInputTypes
13
- ) => {
14
- const requiredTypes = new Set<string>()
15
- const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
16
- const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap)
17
- const serializedRoutes = generateRoutes(
18
- functionsMeta,
19
- routesMeta,
20
- typesMap,
21
- requiredTypes
22
- )
23
-
24
- const serializedImportMap = serializeImportMap(
25
- relativeToPath,
26
- packageMappings,
27
- typesMap,
28
- requiredTypes
29
- )
30
-
31
- return `/**
32
- * This provides the structure needed for typescript to be aware of routes and their return types
33
- */
34
-
35
- ${serializedImportMap}
36
- ${serializedCustomTypes}
37
- ${serializedMetaTypes}
38
-
39
- interface RouteHandler<I, O> {
40
- input: I;
41
- output: O;
42
- }
43
-
44
- ${serializedRoutes}
45
-
46
- export type RouteHandlerOf<Route extends keyof RoutesMap, Method extends keyof RoutesMap[Route]> =
47
- RoutesMap[Route][Method] extends { input: infer I; output: infer O }
48
- ? RouteHandler<I, O>
49
- : never;
50
-
51
- export type RoutesWithMethod<Method extends string> = {
52
- [Route in keyof RoutesMap]: Method extends keyof RoutesMap[Route] ? Route : never;
53
- }[keyof RoutesMap];
54
- `
55
- }
56
-
57
- export function generateCustomTypes(
58
- typesMap: TypesMap,
59
- requiredTypes: Set<string>
60
- ) {
61
- return `
62
- // Custom types are those that are defined directly within generics
63
- // or are broken into simpler types
64
- ${Array.from(typesMap.customTypes.entries())
65
- .map(([name, { type, references }]) => {
66
- references.forEach((name) => {
67
- const originalName = typesMap.getTypeMeta(name).originalName
68
- requiredTypes.add(originalName)
69
- })
70
- return `export type ${name} = ${type}`
71
- })
72
- .join('\n')}`
73
- }
74
-
75
- function generateRoutes(
76
- functionsMeta: FunctionsMeta,
77
- routesMeta: HTTPRoutesMeta,
78
- typesMap: TypesMap,
79
- requiredTypes: Set<string>
80
- ) {
81
- // Initialize an object to collect routes
82
- const routesObj: Record<
83
- string,
84
- Record<string, { inputType: string; outputType: string }>
85
- > = {}
86
-
87
- for (const meta of routesMeta) {
88
- const { route, method, pikkuFuncName } = meta
89
- const input = functionsMeta[pikkuFuncName]?.inputs?.[0]
90
- const output = functionsMeta[pikkuFuncName]?.outputs?.[0]
91
-
92
- // Initialize the route entry if it doesn't exist
93
- if (!routesObj[route]) {
94
- routesObj[route] = {}
95
- }
96
-
97
- // Store the input and output types separately for RouteHandler
98
- const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null'
99
- const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null'
100
-
101
- requiredTypes.add(inputType)
102
- requiredTypes.add(outputType)
103
-
104
- // Add method entry
105
- routesObj[route][method] = {
106
- inputType,
107
- outputType,
108
- }
109
- }
110
-
111
- // Build the routes object as a string
112
- let routesStr = 'export type RoutesMap = {\n'
113
-
114
- for (const [routePath, methods] of Object.entries(routesObj)) {
115
- routesStr += ` readonly '${routePath}': {\n`
116
- for (const [method, handler] of Object.entries(methods)) {
117
- routesStr += ` readonly ${method.toUpperCase()}: RouteHandler<${handler.inputType}, ${handler.outputType}>,\n`
118
- }
119
- routesStr += ' },\n'
120
- }
121
-
122
- routesStr += '};'
123
-
124
- return routesStr
125
- }
126
-
127
- const generateMetaTypes = (metaTypes: MetaInputTypes, typesMap: TypesMap) => {
128
- const nameToTypeMap = Array.from(metaTypes.entries()).reduce<
129
- Map<string, string>
130
- >((result, [_name, { query, body, params }]) => {
131
- const { uniqueName } = typesMap.getTypeMeta(_name)
132
- const queryType =
133
- query && query.length > 0
134
- ? `Pick<${uniqueName}, '${query?.join("' | '")}'>`
135
- : undefined
136
- if (queryType) {
137
- result.set(`${uniqueName}Query`, queryType)
138
- }
139
- const paramsType =
140
- params && params.length > 0
141
- ? `Pick<${uniqueName}, '${params.join("' | '")}'>`
142
- : undefined
143
- if (paramsType) {
144
- result.set(`${uniqueName}Params`, paramsType)
145
- }
146
- const bodyType =
147
- (body && body.length > 0) || (params && params.length > 0)
148
- ? `Omit<${uniqueName}, '${[...new Set([...(query || []), ...(params || [])])].join("' | '")}'>`
149
- : uniqueName!
150
- if (bodyType) {
151
- result.set(`${uniqueName}Body`, bodyType)
152
- }
153
- return result
154
- }, new Map())
155
-
156
- return `
157
- // The '& {}' is a workaround for not directly refering to a type since it confuses typescript
158
- ${Array.from(nameToTypeMap.entries())
159
- .map(([name, type]) => `export type ${name} = ${type} & {}`)
160
- .join('\n')}`
161
- }