@pikku/cli 0.6.19 → 0.7.0

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 (111) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/cli.schema.json +2 -2
  3. package/dist/bin/pikku-all.js +34 -16
  4. package/dist/bin/pikku-channels-map.js +4 -4
  5. package/dist/bin/pikku-channels.js +6 -10
  6. package/dist/bin/pikku-fetch.d.ts +1 -1
  7. package/dist/bin/pikku-fetch.js +3 -3
  8. package/dist/bin/pikku-function-types.js +4 -4
  9. package/dist/bin/pikku-functions.d.ts +5 -0
  10. package/dist/bin/pikku-functions.js +24 -0
  11. package/dist/bin/pikku-http-map.d.ts +5 -0
  12. package/dist/bin/pikku-http-map.js +23 -0
  13. package/dist/bin/pikku-http-routes.d.ts +5 -0
  14. package/dist/bin/pikku-http-routes.js +24 -0
  15. package/dist/bin/pikku-http.js +3 -5
  16. package/dist/bin/pikku-nextjs.d.ts +1 -1
  17. package/dist/bin/pikku-nextjs.js +8 -8
  18. package/dist/bin/pikku-openapi.d.ts +1 -1
  19. package/dist/bin/pikku-openapi.js +6 -6
  20. package/dist/bin/pikku-routes-map.d.ts +1 -1
  21. package/dist/bin/pikku-routes-map.js +3 -3
  22. package/dist/bin/pikku-scheduler.js +7 -10
  23. package/dist/bin/pikku-schemas.d.ts +1 -1
  24. package/dist/bin/pikku-schemas.js +6 -7
  25. package/dist/bin/pikku-websocket.js +1 -1
  26. package/dist/bin/pikku.js +2 -2
  27. package/dist/src/channels/serialize-typed-channel-map.js +5 -2
  28. package/dist/src/core/serialize-import-map.js +1 -0
  29. package/dist/src/core/serialize-pikku-types.js +90 -6
  30. package/dist/src/events/channels/serialize-channels.d.ts +3 -0
  31. package/dist/src/events/channels/serialize-channels.js +19 -0
  32. package/dist/src/events/channels/serialize-typed-channel-map.d.ts +3 -0
  33. package/dist/src/events/channels/serialize-typed-channel-map.js +90 -0
  34. package/dist/src/events/channels/serialize-websocket-wrapper.d.ts +1 -0
  35. package/{src/channels/serialize-websocket-wrapper.ts → dist/src/events/channels/serialize-websocket-wrapper.js} +4 -4
  36. package/dist/src/events/http/serialize-fetch-wrapper.d.ts +1 -0
  37. package/{src/http/serialize-fetch-wrapper.ts → dist/src/events/http/serialize-fetch-wrapper.js} +4 -4
  38. package/dist/src/events/http/serialize-route-imports.d.ts +1 -0
  39. package/dist/src/events/http/serialize-route-imports.js +13 -0
  40. package/dist/src/events/http/serialize-route-meta.d.ts +2 -0
  41. package/dist/src/events/http/serialize-route-meta.js +6 -0
  42. package/dist/src/events/http/serialize-typed-route-map.d.ts +4 -0
  43. package/dist/src/events/http/serialize-typed-route-map.js +107 -0
  44. package/dist/src/events/scheduler/serialize-schedulers.d.ts +3 -0
  45. package/dist/src/events/scheduler/serialize-schedulers.js +23 -0
  46. package/dist/src/http/serialize-typed-route-map.js +1 -1
  47. package/dist/src/inspector-glob.d.ts +1 -1
  48. package/dist/src/inspector-glob.js +2 -2
  49. package/dist/src/openapi-spec-generator.d.ts +79 -0
  50. package/dist/src/openapi-spec-generator.js +136 -0
  51. package/dist/src/pikku-cli-config.d.ts +9 -4
  52. package/dist/src/pikku-cli-config.js +19 -4
  53. package/dist/src/scheduler/serialize-schedulers.js +3 -2
  54. package/dist/src/schema/schema-generator.d.ts +1 -1
  55. package/dist/src/schema/schema-generator.js +20 -7
  56. package/dist/src/schema-generator.d.ts +5 -0
  57. package/dist/src/schema-generator.js +98 -0
  58. package/dist/src/serialize-fetch-wrapper.d.ts +1 -0
  59. package/dist/src/serialize-fetch-wrapper.js +67 -0
  60. package/dist/src/serialize-import-map.d.ts +2 -0
  61. package/dist/src/serialize-import-map.js +24 -0
  62. package/dist/src/serialize-nextjs-backend-wrapper.d.ts +1 -0
  63. package/{src/nextjs/serialize-nextjs-backend-wrapper.ts → dist/src/serialize-nextjs-backend-wrapper.js} +4 -11
  64. package/dist/src/serialize-nextjs-http-wrapper.d.ts +1 -0
  65. package/{src/nextjs/serialize-nextjs-http-wrapper.ts → dist/src/serialize-nextjs-http-wrapper.js} +4 -7
  66. package/dist/src/serialize-pikku-types.d.ts +4 -0
  67. package/dist/src/serialize-pikku-types.js +136 -0
  68. package/dist/src/serialize-scheduler-meta.d.ts +2 -0
  69. package/dist/src/serialize-scheduler-meta.js +10 -0
  70. package/dist/src/serialize-typed-channel-map.d.ts +3 -0
  71. package/dist/src/serialize-typed-channel-map.js +93 -0
  72. package/dist/src/serialize-typed-function-map.d.ts +4 -0
  73. package/dist/src/serialize-typed-function-map.js +107 -0
  74. package/dist/src/serialize-typed-http-map.d.ts +4 -0
  75. package/dist/src/serialize-typed-http-map.js +107 -0
  76. package/dist/src/serialize-typed-route-map.d.ts +4 -0
  77. package/dist/src/serialize-typed-route-map.js +107 -0
  78. package/dist/src/serialize-websocket-wrapper.d.ts +1 -0
  79. package/dist/src/serialize-websocket-wrapper.js +61 -0
  80. package/dist/src/utils.d.ts +1 -0
  81. package/dist/src/utils.js +17 -5
  82. package/package.json +3 -3
  83. package/bin/pikku-all.ts +0 -180
  84. package/bin/pikku-channels-map.ts +0 -55
  85. package/bin/pikku-channels.ts +0 -58
  86. package/bin/pikku-fetch.ts +0 -55
  87. package/bin/pikku-function-types.ts +0 -84
  88. package/bin/pikku-http.ts +0 -56
  89. package/bin/pikku-nextjs.test.ts +0 -279
  90. package/bin/pikku-nextjs.ts +0 -152
  91. package/bin/pikku-openapi.ts +0 -70
  92. package/bin/pikku-routes-map.ts +0 -55
  93. package/bin/pikku-scheduler.ts +0 -62
  94. package/bin/pikku-schemas.ts +0 -53
  95. package/bin/pikku-websocket.ts +0 -58
  96. package/bin/pikku.ts +0 -26
  97. package/dist/tsconfig.tsbuildinfo +0 -1
  98. package/src/channels/serialize-channels.ts +0 -34
  99. package/src/channels/serialize-typed-channel-map.ts +0 -136
  100. package/src/core/serialize-import-map.ts +0 -33
  101. package/src/core/serialize-pikku-types.ts +0 -55
  102. package/src/http/serialize-route-imports.ts +0 -24
  103. package/src/http/serialize-route-meta.ts +0 -10
  104. package/src/http/serialize-typed-route-map.ts +0 -150
  105. package/src/inspector-glob.ts +0 -28
  106. package/src/openapi/openapi-spec-generator.ts +0 -227
  107. package/src/pikku-cli-config.ts +0 -204
  108. package/src/scheduler/serialize-schedulers.ts +0 -41
  109. package/src/schema/schema-generator.ts +0 -114
  110. package/src/utils.ts +0 -260
  111. package/tsconfig.json +0 -21
@@ -0,0 +1,10 @@
1
+ export const serializeSchedulerMeta = (scheduledTasksMeta) => {
2
+ const serializedOutput = [];
3
+ serializedOutput.push("import { pikkuState } from '@pikku/core'");
4
+ serializedOutput.push(`pikkuState('scheduler', 'meta', ${JSON.stringify(scheduledTasksMeta, null, 2)})`);
5
+ const scheduledTasksMetaValues = Object.values(scheduledTasksMeta);
6
+ if (scheduledTasksMetaValues.length > 0) {
7
+ serializedOutput.push(`export type ScheduledTaskNames = '${scheduledTasksMetaValues.map((s) => s.name).join("' | '")}'`);
8
+ }
9
+ return serializedOutput.join('\n');
10
+ };
@@ -0,0 +1,3 @@
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;
@@ -0,0 +1,93 @@
1
+ import { serializeImportMap } from './serialize-import-map.js';
2
+ import { generateCustomTypes } from './serialize-typed-http-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
+ }
@@ -0,0 +1,4 @@
1
+ import { HTTPRoutesMeta } from '@pikku/core/http';
2
+ import { MetaInputTypes, TypesMap } from '@pikku/inspector';
3
+ export declare const serializeTypedRoutesMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, routesMeta: HTTPRoutesMeta, metaTypes: MetaInputTypes) => string;
4
+ export declare function generateCustomTypes(typesMap: TypesMap, requiredTypes: Set<string>): string;
@@ -0,0 +1,107 @@
1
+ import { serializeImportMap } from './serialize-import-map.js';
2
+ export const serializeTypedRoutesMap = (relativeToPath, packageMappings, typesMap, routesMeta, metaTypes) => {
3
+ const requiredTypes = new Set();
4
+ const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
5
+ const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap);
6
+ const serializedRoutes = generateRoutes(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(routesMeta, typesMap, requiredTypes) {
48
+ // Initialize an object to collect routes
49
+ const routesObj = {};
50
+ for (const meta of routesMeta) {
51
+ const { route, method, input, output } = meta;
52
+ // Initialize the route entry if it doesn't exist
53
+ if (!routesObj[route]) {
54
+ routesObj[route] = {};
55
+ }
56
+ // Store the input and output types separately for RouteHandler
57
+ const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null';
58
+ const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null';
59
+ requiredTypes.add(inputType);
60
+ requiredTypes.add(outputType);
61
+ // Add method entry
62
+ routesObj[route][method] = {
63
+ inputType,
64
+ outputType,
65
+ };
66
+ }
67
+ // Build the routes object as a string
68
+ let routesStr = 'export type RoutesMap = {\n';
69
+ for (const [routePath, methods] of Object.entries(routesObj)) {
70
+ routesStr += ` readonly '${routePath}': {\n`;
71
+ for (const [method, handler] of Object.entries(methods)) {
72
+ routesStr += ` readonly ${method.toUpperCase()}: RouteHandler<${handler.inputType}, ${handler.outputType}>,\n`;
73
+ }
74
+ routesStr += ' },\n';
75
+ }
76
+ routesStr += '};';
77
+ return routesStr;
78
+ }
79
+ const generateMetaTypes = (metaTypes, typesMap) => {
80
+ const nameToTypeMap = Array.from(metaTypes.entries()).reduce((result, [_name, { query, body, params }]) => {
81
+ const { uniqueName } = typesMap.getTypeMeta(_name);
82
+ const queryType = query && query.length > 0
83
+ ? `Pick<${uniqueName}, '${query?.join("' | '")}'>`
84
+ : undefined;
85
+ if (queryType) {
86
+ result.set(`${uniqueName}Query`, queryType);
87
+ }
88
+ const paramsType = params && params.length > 0
89
+ ? `Pick<${uniqueName}, '${params.join("' | '")}'>`
90
+ : undefined;
91
+ if (paramsType) {
92
+ result.set(`${uniqueName}Params`, paramsType);
93
+ }
94
+ const bodyType = (body && body.length > 0) || (params && params.length > 0)
95
+ ? `Omit<${uniqueName}, '${[...new Set([...(query || []), ...(params || [])])].join("' | '")}'>`
96
+ : uniqueName;
97
+ if (bodyType) {
98
+ result.set(`${uniqueName}Body`, bodyType);
99
+ }
100
+ return result;
101
+ }, new Map());
102
+ return `
103
+ // The '& {}' is a workaround for not directly refering to a type since it confuses typescript
104
+ ${Array.from(nameToTypeMap.entries())
105
+ .map(([name, type]) => `export type ${name} = ${type} & {}`)
106
+ .join('\n')}`;
107
+ };
@@ -0,0 +1,4 @@
1
+ import { HTTPRoutesMeta } from '@pikku/core/http';
2
+ import { MetaInputTypes, TypesMap } from '@pikku/inspector';
3
+ export declare const serializeTypedRoutesMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, routesMeta: HTTPRoutesMeta, metaTypes: MetaInputTypes) => string;
4
+ export declare function generateCustomTypes(typesMap: TypesMap, requiredTypes: Set<string>): string;
@@ -0,0 +1,107 @@
1
+ import { serializeImportMap } from './serialize-import-map.js';
2
+ export const serializeTypedRoutesMap = (relativeToPath, packageMappings, typesMap, routesMeta, metaTypes) => {
3
+ const requiredTypes = new Set();
4
+ const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
5
+ const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap);
6
+ const serializedRoutes = generateRoutes(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(routesMeta, typesMap, requiredTypes) {
48
+ // Initialize an object to collect routes
49
+ const routesObj = {};
50
+ for (const meta of routesMeta) {
51
+ const { route, method, input, output } = meta;
52
+ // Initialize the route entry if it doesn't exist
53
+ if (!routesObj[route]) {
54
+ routesObj[route] = {};
55
+ }
56
+ // Store the input and output types separately for RouteHandler
57
+ const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null';
58
+ const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null';
59
+ requiredTypes.add(inputType);
60
+ requiredTypes.add(outputType);
61
+ // Add method entry
62
+ routesObj[route][method] = {
63
+ inputType,
64
+ outputType,
65
+ };
66
+ }
67
+ // Build the routes object as a string
68
+ let routesStr = 'export type RoutesMap = {\n';
69
+ for (const [routePath, methods] of Object.entries(routesObj)) {
70
+ routesStr += ` readonly '${routePath}': {\n`;
71
+ for (const [method, handler] of Object.entries(methods)) {
72
+ routesStr += ` readonly ${method.toUpperCase()}: RouteHandler<${handler.inputType}, ${handler.outputType}>,\n`;
73
+ }
74
+ routesStr += ' },\n';
75
+ }
76
+ routesStr += '};';
77
+ return routesStr;
78
+ }
79
+ const generateMetaTypes = (metaTypes, typesMap) => {
80
+ const nameToTypeMap = Array.from(metaTypes.entries()).reduce((result, [_name, { query, body, params }]) => {
81
+ const { uniqueName } = typesMap.getTypeMeta(_name);
82
+ const queryType = query && query.length > 0
83
+ ? `Pick<${uniqueName}, '${query?.join("' | '")}'>`
84
+ : undefined;
85
+ if (queryType) {
86
+ result.set(`${uniqueName}Query`, queryType);
87
+ }
88
+ const paramsType = params && params.length > 0
89
+ ? `Pick<${uniqueName}, '${params.join("' | '")}'>`
90
+ : undefined;
91
+ if (paramsType) {
92
+ result.set(`${uniqueName}Params`, paramsType);
93
+ }
94
+ const bodyType = (body && body.length > 0) || (params && params.length > 0)
95
+ ? `Omit<${uniqueName}, '${[...new Set([...(query || []), ...(params || [])])].join("' | '")}'>`
96
+ : uniqueName;
97
+ if (bodyType) {
98
+ result.set(`${uniqueName}Body`, bodyType);
99
+ }
100
+ return result;
101
+ }, new Map());
102
+ return `
103
+ // The '& {}' is a workaround for not directly refering to a type since it confuses typescript
104
+ ${Array.from(nameToTypeMap.entries())
105
+ .map(([name, type]) => `export type ${name} = ${type} & {}`)
106
+ .join('\n')}`;
107
+ };
@@ -0,0 +1,4 @@
1
+ import { HTTPRoutesMeta } from '@pikku/core/http';
2
+ import { MetaInputTypes, TypesMap } from '@pikku/inspector';
3
+ export declare const serializeTypedRoutesMap: (relativeToPath: string, packageMappings: Record<string, string>, typesMap: TypesMap, routesMeta: HTTPRoutesMeta, metaTypes: MetaInputTypes) => string;
4
+ export declare function generateCustomTypes(typesMap: TypesMap, requiredTypes: Set<string>): string;
@@ -0,0 +1,107 @@
1
+ import { serializeImportMap } from './serialize-import-map.js';
2
+ export const serializeTypedRoutesMap = (relativeToPath, packageMappings, typesMap, routesMeta, metaTypes) => {
3
+ const requiredTypes = new Set();
4
+ const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
5
+ const serializedMetaTypes = generateMetaTypes(metaTypes, typesMap);
6
+ const serializedRoutes = generateRoutes(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(routesMeta, typesMap, requiredTypes) {
48
+ // Initialize an object to collect routes
49
+ const routesObj = {};
50
+ for (const meta of routesMeta) {
51
+ const { route, method, input, output } = meta;
52
+ // Initialize the route entry if it doesn't exist
53
+ if (!routesObj[route]) {
54
+ routesObj[route] = {};
55
+ }
56
+ // Store the input and output types separately for RouteHandler
57
+ const inputType = input ? typesMap.getTypeMeta(input).uniqueName : 'null';
58
+ const outputType = output ? typesMap.getTypeMeta(output).uniqueName : 'null';
59
+ requiredTypes.add(inputType);
60
+ requiredTypes.add(outputType);
61
+ // Add method entry
62
+ routesObj[route][method] = {
63
+ inputType,
64
+ outputType,
65
+ };
66
+ }
67
+ // Build the routes object as a string
68
+ let routesStr = 'export type RoutesMap = {\n';
69
+ for (const [routePath, methods] of Object.entries(routesObj)) {
70
+ routesStr += ` readonly '${routePath}': {\n`;
71
+ for (const [method, handler] of Object.entries(methods)) {
72
+ routesStr += ` readonly ${method.toUpperCase()}: RouteHandler<${handler.inputType}, ${handler.outputType}>,\n`;
73
+ }
74
+ routesStr += ' },\n';
75
+ }
76
+ routesStr += '};';
77
+ return routesStr;
78
+ }
79
+ const generateMetaTypes = (metaTypes, typesMap) => {
80
+ const nameToTypeMap = Array.from(metaTypes.entries()).reduce((result, [_name, { query, body, params }]) => {
81
+ const { uniqueName } = typesMap.getTypeMeta(_name);
82
+ const queryType = query && query.length > 0
83
+ ? `Pick<${uniqueName}, '${query?.join("' | '")}'>`
84
+ : undefined;
85
+ if (queryType) {
86
+ result.set(`${uniqueName}Query`, queryType);
87
+ }
88
+ const paramsType = params && params.length > 0
89
+ ? `Pick<${uniqueName}, '${params.join("' | '")}'>`
90
+ : undefined;
91
+ if (paramsType) {
92
+ result.set(`${uniqueName}Params`, paramsType);
93
+ }
94
+ const bodyType = (body && body.length > 0) || (params && params.length > 0)
95
+ ? `Omit<${uniqueName}, '${[...new Set([...(query || []), ...(params || [])])].join("' | '")}'>`
96
+ : uniqueName;
97
+ if (bodyType) {
98
+ result.set(`${uniqueName}Body`, bodyType);
99
+ }
100
+ return result;
101
+ }, new Map());
102
+ return `
103
+ // The '& {}' is a workaround for not directly refering to a type since it confuses typescript
104
+ ${Array.from(nameToTypeMap.entries())
105
+ .map(([name, type]) => `export type ${name} = ${type} & {}`)
106
+ .join('\n')}`;
107
+ };
@@ -0,0 +1 @@
1
+ export declare const serializeWebsocketWrapper: (channelsMapPath: string) => string;
@@ -0,0 +1,61 @@
1
+ export const serializeWebsocketWrapper = (channelsMapPath) => {
2
+ return `import { CorePikkuWebsocket, CorePikkuRouteHandler } from '@pikku/websocket'
3
+ import { ChannelDefaultHandlerOf, ChannelRouteHandlerOf, ChannelsMap } from '${channelsMapPath}';
4
+
5
+ class PikkuWebSocketRoute<Channel extends keyof ChannelsMap, Route extends keyof ChannelsMap[Channel]['routes']> extends CorePikkuRouteHandler {
6
+ public subscribe<
7
+ Method extends keyof ChannelsMap[Channel]['routes'][Route],
8
+ Data extends ChannelRouteHandlerOf<Channel, Route, Method>['output']
9
+ >(method: Method, callback: (data: Data) => void
10
+ ) {
11
+ super.subscribe(method.toString(), callback)
12
+ }
13
+
14
+ public unsubscribe<
15
+ Method extends keyof ChannelsMap[Channel]['routes'][Route],
16
+ Data extends ChannelRouteHandlerOf<Channel, Route, Method>['output']
17
+ >(method: Method, callback?: (data: Data) => void) {
18
+ super.unsubscribe(method.toString(), callback)
19
+ }
20
+
21
+ public send<
22
+ Method extends keyof ChannelsMap[Channel]['routes'][Route],
23
+ Data extends ChannelRouteHandlerOf<Channel, Route, Method>['input']
24
+ >(method: Method, data: Data) {
25
+ super.send(method.toString(), data)
26
+ }
27
+ }
28
+
29
+ export class PikkuWebSocket<Channel extends keyof ChannelsMap> extends CorePikkuWebsocket {
30
+ /**
31
+ * Send a message to a specific route and method.
32
+ * Validates the input data type.
33
+ */
34
+ public getRoute<Route extends keyof ChannelsMap[Channel]['routes']>(route: Route): PikkuWebSocketRoute<Channel, Route> {
35
+ return super.getRoute(route)
36
+ }
37
+
38
+ /**
39
+ * Subscribe to a specific route and method.
40
+ */
41
+ public subscribe<Data extends ChannelDefaultHandlerOf<Channel>['output']>(
42
+ callback: (data: Data) => void
43
+ ) {
44
+ super.subscribe(callback)
45
+ }
46
+
47
+ /**
48
+ * Subscribe to a specific route and method.
49
+ */
50
+ public unsubscribe<Data extends ChannelDefaultHandlerOf<Channel>['output']>(
51
+ callback?: (data: Data) => void
52
+ ) {
53
+ super.unsubscribe(callback)
54
+ }
55
+
56
+ public send(data: ChannelDefaultHandlerOf<Channel>['input']) {
57
+ super.send(data)
58
+ }
59
+ }
60
+ `;
61
+ };
@@ -38,4 +38,5 @@ export declare const writeFileInDir: (path: string, content: string, ignoreModif
38
38
  export declare const logCommandInfoAndTime: (commandStart: string, commandEnd: string, [skipCondition, skipMessage]: [boolean] | [boolean, string], callback: (...args: any[]) => Promise<unknown>) => Promise<boolean>;
39
39
  export declare const logPikkuLogo: () => void;
40
40
  export declare const DO_NOT_MODIFY_COMMENT = "/**\n * This file was generated by the @pikku/cli\n */\n";
41
+ export declare const serializeFileImports: (importType: string, outputPath: string, files: Set<string>, packageMappings?: Record<string, string>) => string;
41
42
  export {};
package/dist/src/utils.js CHANGED
@@ -18,17 +18,17 @@ export const getFileImportRelativePath = (from, to, packageMappings) => {
18
18
  if (!/^\.+\//.test(filePath)) {
19
19
  filePath = `./${filePath}`;
20
20
  }
21
- let usesPackageName = false;
21
+ // let usesPackageName = false
22
22
  for (const [path, packageName] of Object.entries(packageMappings)) {
23
23
  if (filePath.includes(path)) {
24
- usesPackageName = true;
24
+ // usesPackageName = true
25
25
  filePath = filePath.replace(new RegExp(`.*${path}`), packageName);
26
26
  break;
27
27
  }
28
28
  }
29
- if (usesPackageName) {
30
- return filePath.replace('.ts', '');
31
- }
29
+ // if (usesPackageName) {
30
+ // return filePath.replace('.ts', '')
31
+ // }
32
32
  return filePath.replace('.ts', '.js');
33
33
  };
34
34
  const getMetaTypes = (type, errors, map, desiredType) => {
@@ -131,3 +131,15 @@ export const DO_NOT_MODIFY_COMMENT = `/**
131
131
  * This file was generated by the @pikku/cli
132
132
  */
133
133
  `;
134
+ export const serializeFileImports = (importType, outputPath, files, packageMappings = {}) => {
135
+ const serializedOutput = [
136
+ `/* The files with an ${importType} function call */`,
137
+ ];
138
+ Array.from(files)
139
+ .sort()
140
+ .forEach((path) => {
141
+ const filePath = getFileImportRelativePath(outputPath, path, packageMappings);
142
+ serializedOutput.push(`import '${filePath}'`);
143
+ });
144
+ return serializedOutput.join('\n');
145
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/cli",
3
- "version": "0.6.19",
3
+ "version": "0.7.0",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -22,8 +22,8 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@openapi-contrib/json-schema-to-openapi-schema": "^3.0.2",
25
- "@pikku/core": "^0.6.23",
26
- "@pikku/inspector": "^0.6.4",
25
+ "@pikku/core": "^0.7.0",
26
+ "@pikku/inspector": "^0.7.0",
27
27
  "@types/cookie": "^0.6.0",
28
28
  "@types/uuid": "^10.0.0",
29
29
  "chalk": "^5.4.1",