@pikku/cli 0.6.6 → 0.6.9
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 +22 -0
- package/bin/pikku-all.ts +3 -4
- package/bin/pikku-fetch.ts +2 -2
- package/bin/pikku-websocket.ts +5 -2
- package/dist/bin/pikku-all.js +3 -3
- package/dist/bin/pikku-fetch.js +2 -2
- package/dist/bin/pikku-websocket.js +5 -2
- package/dist/package.json +43 -0
- package/dist/src/channels/serialize-typed-channel-map.js +4 -1
- package/dist/src/core/serialize-pikku-types.js +20 -22
- package/dist/src/http/serialize-typed-route-map.d.ts +1 -0
- package/dist/src/http/serialize-typed-route-map.js +1 -1
- package/dist/src/pikku-cli-config.js +1 -1
- package/dist/src/schema/schema-generator.js +3 -3
- package/dist/src/utils.d.ts +3 -0
- package/dist/src/utils.js +25 -5
- package/package.json +4 -3
- package/src/channels/serialize-typed-channel-map.ts +4 -1
- package/src/core/serialize-pikku-types.ts +20 -22
- package/src/http/serialize-typed-route-map.ts +4 -1
- package/src/pikku-cli-config.ts +1 -4
- package/src/schema/schema-generator.ts +3 -3
- package/src/utils.ts +29 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @pikku/cli
|
|
2
2
|
|
|
3
|
+
## 0.6.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7e7ec0c: chore: show packageVersion in cli header
|
|
8
|
+
|
|
9
|
+
## 0.6.8
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- bdcc89a: feat: adding intro logo to cli based commands
|
|
14
|
+
|
|
15
|
+
## 0.6.7
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 7859b28: breaking: changing overrides for addRoute to wrap instead due to random conflict override errors
|
|
20
|
+
- 269a532: fix: fixing some typing issues
|
|
21
|
+
- Updated dependencies [7859b28]
|
|
22
|
+
- Updated dependencies [269a532]
|
|
23
|
+
- @pikku/core@0.6.11
|
|
24
|
+
|
|
3
25
|
## 0.6.6
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/bin/pikku-all.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
import {
|
|
3
3
|
getFileImportRelativePath,
|
|
4
|
+
logInfo,
|
|
4
5
|
logPikkuLogo,
|
|
5
6
|
PikkuCLIOptions,
|
|
6
7
|
writeFileInDir,
|
|
@@ -45,7 +46,7 @@ export const action = async (options: PikkuCLIOptions): Promise<void> => {
|
|
|
45
46
|
|
|
46
47
|
// This is needed since the addRoutes function will add the routes to the visitState
|
|
47
48
|
if (!typesDeclarationFileExists) {
|
|
48
|
-
|
|
49
|
+
logInfo(`• Type file first created, inspecting again...\x1b[0m`)
|
|
49
50
|
visitState = await inspectorGlob(
|
|
50
51
|
cliConfig.rootDir,
|
|
51
52
|
cliConfig.routeDirectories
|
|
@@ -79,9 +80,7 @@ export const action = async (options: PikkuCLIOptions): Promise<void> => {
|
|
|
79
80
|
await pikkuNext(cliConfig, visitState, options)
|
|
80
81
|
|
|
81
82
|
if (cliConfig.openAPI) {
|
|
82
|
-
|
|
83
|
-
`\x1b[34m• OpenAPI requires a reinspection to pickup new generated types..\x1b[0m`
|
|
84
|
-
)
|
|
83
|
+
logInfo(`• OpenAPI requires a reinspection to pickup new generated types..`)
|
|
85
84
|
visitState = await inspectorGlob(
|
|
86
85
|
cliConfig.rootDir,
|
|
87
86
|
cliConfig.routeDirectories
|
package/bin/pikku-fetch.ts
CHANGED
|
@@ -17,10 +17,10 @@ export const pikkuFetch = async ({
|
|
|
17
17
|
await logCommandInfoAndTime(
|
|
18
18
|
'Generating fetch wrapper',
|
|
19
19
|
'Generated fetch wrapper',
|
|
20
|
-
[fetchFile === undefined,
|
|
20
|
+
[fetchFile === undefined, "fetchFile isn't set in the pikku config"],
|
|
21
21
|
async () => {
|
|
22
22
|
if (!fetchFile) {
|
|
23
|
-
throw new Error(
|
|
23
|
+
throw new Error("fetchFile is isn't set in the pikku config")
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const routesMapDeclarationPath = getFileImportRelativePath(
|
package/bin/pikku-websocket.ts
CHANGED
|
@@ -17,10 +17,13 @@ export const pikkuWebSocket = async ({
|
|
|
17
17
|
await logCommandInfoAndTime(
|
|
18
18
|
'Generating websocket wrapper',
|
|
19
19
|
'Generated websocket wrapper',
|
|
20
|
-
[
|
|
20
|
+
[
|
|
21
|
+
websocketFile === undefined,
|
|
22
|
+
"websocketFile isn't set in the pikku config",
|
|
23
|
+
],
|
|
21
24
|
async () => {
|
|
22
25
|
if (!websocketFile) {
|
|
23
|
-
throw new Error(
|
|
26
|
+
throw new Error("fetchFile is isn't set in the pikku config")
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
const channelsMapDeclarationPath = getFileImportRelativePath(
|
package/dist/bin/pikku-all.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getFileImportRelativePath, logPikkuLogo, writeFileInDir, } from '../src/utils.js';
|
|
1
|
+
import { getFileImportRelativePath, logInfo, logPikkuLogo, writeFileInDir, } from '../src/utils.js';
|
|
2
2
|
import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
|
|
3
3
|
import { pikkuRoutes } from './pikku-routes.js';
|
|
4
4
|
import { pikkuFunctionTypes } from './pikku-function-types.js';
|
|
@@ -28,7 +28,7 @@ export const action = async (options) => {
|
|
|
28
28
|
await pikkuFunctionTypes(cliConfig, options, visitState);
|
|
29
29
|
// This is needed since the addRoutes function will add the routes to the visitState
|
|
30
30
|
if (!typesDeclarationFileExists) {
|
|
31
|
-
|
|
31
|
+
logInfo(`• Type file first created, inspecting again...\x1b[0m`);
|
|
32
32
|
visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories);
|
|
33
33
|
}
|
|
34
34
|
const routes = await pikkuRoutes(cliConfig, visitState);
|
|
@@ -53,7 +53,7 @@ export const action = async (options) => {
|
|
|
53
53
|
}
|
|
54
54
|
await pikkuNext(cliConfig, visitState, options);
|
|
55
55
|
if (cliConfig.openAPI) {
|
|
56
|
-
|
|
56
|
+
logInfo(`• OpenAPI requires a reinspection to pickup new generated types..`);
|
|
57
57
|
visitState = await inspectorGlob(cliConfig.rootDir, cliConfig.routeDirectories);
|
|
58
58
|
await pikkuOpenAPI(cliConfig, visitState);
|
|
59
59
|
}
|
package/dist/bin/pikku-fetch.js
CHANGED
|
@@ -2,9 +2,9 @@ import { getFileImportRelativePath, logCommandInfoAndTime, logPikkuLogo, writeFi
|
|
|
2
2
|
import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
|
|
3
3
|
import { serializeFetchWrapper } from '../src/http/serialize-fetch-wrapper.js';
|
|
4
4
|
export const pikkuFetch = async ({ fetchFile, routesMapDeclarationFile, packageMappings, }) => {
|
|
5
|
-
await logCommandInfoAndTime('Generating fetch wrapper', 'Generated fetch wrapper', [fetchFile === undefined,
|
|
5
|
+
await logCommandInfoAndTime('Generating fetch wrapper', 'Generated fetch wrapper', [fetchFile === undefined, "fetchFile isn't set in the pikku config"], async () => {
|
|
6
6
|
if (!fetchFile) {
|
|
7
|
-
throw new Error(
|
|
7
|
+
throw new Error("fetchFile is isn't set in the pikku config");
|
|
8
8
|
}
|
|
9
9
|
const routesMapDeclarationPath = getFileImportRelativePath(fetchFile, routesMapDeclarationFile, packageMappings);
|
|
10
10
|
const content = [serializeFetchWrapper(routesMapDeclarationPath)];
|
|
@@ -2,9 +2,12 @@ import { getFileImportRelativePath, logCommandInfoAndTime, logPikkuLogo, writeFi
|
|
|
2
2
|
import { getPikkuCLIConfig } from '../src/pikku-cli-config.js';
|
|
3
3
|
import { serializeWebsocketWrapper } from '../src/channels/serialize-websocket-wrapper.js';
|
|
4
4
|
export const pikkuWebSocket = async ({ websocketFile, channelsMapDeclarationFile, packageMappings, }) => {
|
|
5
|
-
await logCommandInfoAndTime('Generating websocket wrapper', 'Generated websocket wrapper', [
|
|
5
|
+
await logCommandInfoAndTime('Generating websocket wrapper', 'Generated websocket wrapper', [
|
|
6
|
+
websocketFile === undefined,
|
|
7
|
+
"websocketFile isn't set in the pikku config",
|
|
8
|
+
], async () => {
|
|
6
9
|
if (!websocketFile) {
|
|
7
|
-
throw new Error(
|
|
10
|
+
throw new Error("fetchFile is isn't set in the pikku config");
|
|
8
11
|
}
|
|
9
12
|
const channelsMapDeclarationPath = getFileImportRelativePath(websocketFile, channelsMapDeclarationFile, packageMappings);
|
|
10
13
|
const content = [serializeWebsocketWrapper(channelsMapDeclarationPath)];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pikku/cli",
|
|
3
|
+
"version": "0.6.9",
|
|
4
|
+
"author": "yasser.fadl@gmail.com",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"bin": {
|
|
7
|
+
"pikku": "dist/bin/pikku.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "dist/bin/pikku.js",
|
|
11
|
+
"module": "dist/bin/pikku.js",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"tsc": "tsc",
|
|
14
|
+
"build:esm": "tsc -b",
|
|
15
|
+
"schema": "ts-json-schema-generator -o cli.schema.json --path 'src/pikku-cli-config.ts' --type 'PikkuCLIConfig'",
|
|
16
|
+
"build": "yarn build:esm && yarn schema",
|
|
17
|
+
"ncu": "npx npm-check-updates -x '/.*glob.*/'",
|
|
18
|
+
"release": "yarn build && npm test",
|
|
19
|
+
"test": "bash run-tests.sh",
|
|
20
|
+
"test:watch": "bash run-tests.sh --watch",
|
|
21
|
+
"test:coverage": "bash run-tests.sh --coverage"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@openapi-contrib/json-schema-to-openapi-schema": "^3.0.2",
|
|
25
|
+
"@pikku/core": "^0.6.11",
|
|
26
|
+
"@pikku/inspector": "^0.6.2",
|
|
27
|
+
"@types/cookie": "^0.6.0",
|
|
28
|
+
"@types/uuid": "^10.0.0",
|
|
29
|
+
"chalk": "^5.4.1",
|
|
30
|
+
"commander": "^12",
|
|
31
|
+
"glob": "^10",
|
|
32
|
+
"path-to-regexp": "^8.2.0",
|
|
33
|
+
"ts-json-schema-generator": "^2.3.0",
|
|
34
|
+
"typescript": "^5.6",
|
|
35
|
+
"yaml": "^2.6.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^22.7.8"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { serializeImportMap } from '../core/serialize-import-map.js';
|
|
2
|
+
import { generateCustomTypes } from '../http/serialize-typed-route-map.js';
|
|
2
3
|
export const serializeTypedChannelsMap = (relativeToPath, packageMappings, typesMap, channelsMeta) => {
|
|
3
4
|
const { channels, requiredTypes } = generateChannels(channelsMeta);
|
|
4
5
|
typesMap.customTypes.forEach(({ references }) => {
|
|
@@ -7,11 +8,13 @@ export const serializeTypedChannelsMap = (relativeToPath, packageMappings, types
|
|
|
7
8
|
}
|
|
8
9
|
});
|
|
9
10
|
const imports = serializeImportMap(relativeToPath, packageMappings, typesMap, requiredTypes);
|
|
11
|
+
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes);
|
|
10
12
|
return `/**
|
|
11
13
|
* This provides the structure needed for TypeScript to be aware of channels
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
${imports}
|
|
17
|
+
${serializedCustomTypes}
|
|
15
18
|
|
|
16
19
|
interface ChannelHandler<I, O> {
|
|
17
20
|
input: I;
|
|
@@ -67,7 +70,7 @@ function generateChannels(channelsMeta) {
|
|
|
67
70
|
for (const [key, methods] of Object.entries(routes)) {
|
|
68
71
|
routesStr += ` readonly ${key}: {\n`;
|
|
69
72
|
for (const [method, handler] of Object.entries(methods)) {
|
|
70
|
-
routesStr += ` readonly ${method}: ChannelHandler<${formatTypeArray(handler.inputTypes)}, ${formatTypeArray(handler.outputTypes)}>,\n`;
|
|
73
|
+
routesStr += ` readonly ${method}: ChannelHandler<${formatTypeArray(handler.inputTypes)}, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`;
|
|
71
74
|
}
|
|
72
75
|
routesStr += ' },\n';
|
|
73
76
|
}
|
|
@@ -6,10 +6,10 @@ export const serializePikkuTypes = (userSessionTypeImport, userSessionTypeName,
|
|
|
6
6
|
* This is used to provide the application types in the typescript project
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { CoreAPIFunction, CoreAPIFunctionSessionless, CoreAPIPermission
|
|
10
|
-
import { CoreHTTPFunctionRoute, AssertRouteParams } from '@pikku/core/http'
|
|
11
|
-
import { CoreScheduledTask } from '@pikku/core/scheduler'
|
|
12
|
-
import { CoreAPIChannel,
|
|
9
|
+
import { CoreAPIFunction, CoreAPIFunctionSessionless, CoreAPIPermission } 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
13
|
|
|
14
14
|
${userSessionTypeImport}
|
|
15
15
|
${sessionServicesTypeImport}
|
|
@@ -20,29 +20,27 @@ export type APIFunctionSessionless<In = unknown, Out = never, RequiredServices =
|
|
|
20
20
|
export type APIFunction<In = unknown, Out = never, RequiredServices = ${servicesTypeName}> = CoreAPIFunction<In, Out, RequiredServices, ${userSessionTypeName}>
|
|
21
21
|
type APIRoute<In, Out, Route extends string> = CoreHTTPFunctionRoute<In, Out, Route, APIFunction<In, Out>, APIFunctionSessionless<In, Out>, APIPermission<In>>
|
|
22
22
|
|
|
23
|
-
export type ChannelConnection<Out =
|
|
24
|
-
export type ChannelDisconnection<ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services:
|
|
25
|
-
export type ChannelMessage<In, Out =
|
|
26
|
-
type APIChannel<ChannelData, Channel extends string
|
|
23
|
+
export type ChannelConnection<Out = unknown, ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: RequiredServices, channel: PikkuChannel<${userSessionTypeName}, ChannelData, Out>) => Promise<void>
|
|
24
|
+
export type ChannelDisconnection<ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: RequiredServices, channel: PikkuChannel<${userSessionTypeName}, ChannelData, never>) => Promise<void>
|
|
25
|
+
export type ChannelMessage<In, Out = unknown, ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: RequiredServices, channel: PikkuChannel<${userSessionTypeName}, ChannelData, Out>, data: In) => Promise<Out | void>
|
|
26
|
+
type APIChannel<ChannelData, Channel extends string> = CoreAPIChannel<ChannelData, Channel, ChannelConnection, ChannelDisconnection, ChannelMessage<any, any, ChannelData>, ChannelMessage<any, any, ChannelData>, APIPermission>
|
|
27
27
|
|
|
28
28
|
type ScheduledTask = CoreScheduledTask<APIFunctionSessionless<void, void>, ${userSessionTypeName}>
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
function addChannel<ChannelData, Channel extends string>(
|
|
36
|
-
channel: APIChannel<ChannelData, Channel> & AssertRouteParams<ChannelData, Channel>
|
|
37
|
-
): void;
|
|
30
|
+
export const addChannel = <ChannelData, Channel extends string>(
|
|
31
|
+
channel: APIChannel<ChannelData, Channel> & AssertRouteParams<ChannelData, Channel>
|
|
32
|
+
) => {
|
|
33
|
+
addCoreChannel(channel as any) // TODO
|
|
34
|
+
}
|
|
38
35
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
export const addRoute = <In, Out, Route extends string>(
|
|
37
|
+
route: APIRoute<In, Out, Route> & AssertRouteParams<In, Route>
|
|
38
|
+
) => {
|
|
39
|
+
addCoreHTTP(route)
|
|
40
|
+
}
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
): void;
|
|
42
|
+
export const addScheduledTask = (task: ScheduledTask) => {
|
|
43
|
+
addCoreScheduledTask(task as any) // TODO
|
|
46
44
|
}
|
|
47
45
|
`;
|
|
48
46
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { HTTPRoutesMeta } from '@pikku/core/http';
|
|
2
2
|
import { MetaInputTypes, TypesMap } from '@pikku/inspector';
|
|
3
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;
|
|
@@ -30,7 +30,7 @@ export type RoutesWithMethod<Method extends string> = {
|
|
|
30
30
|
}[keyof RoutesMap];
|
|
31
31
|
`;
|
|
32
32
|
};
|
|
33
|
-
function generateCustomTypes(typesMap, requiredTypes) {
|
|
33
|
+
export function generateCustomTypes(typesMap, requiredTypes) {
|
|
34
34
|
return `
|
|
35
35
|
// Custom types are those that are defined directly within generics
|
|
36
36
|
// or are broken into simpler types
|
|
@@ -61,7 +61,7 @@ const _getPikkuCLIConfig = async (configFile = undefined, requiredFields, exitPr
|
|
|
61
61
|
result.channelsFile = join(result.outDir, 'pikku-channels.gen.ts');
|
|
62
62
|
}
|
|
63
63
|
if (!result.typesDeclarationFile) {
|
|
64
|
-
result.typesDeclarationFile = join(result.outDir, 'pikku-types.gen.
|
|
64
|
+
result.typesDeclarationFile = join(result.outDir, 'pikku-types.gen.ts');
|
|
65
65
|
}
|
|
66
66
|
if (!result.routesMapDeclarationFile) {
|
|
67
67
|
result.routesMapDeclarationFile = join(result.outDir, 'pikku-routes-map.gen.d.ts');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createGenerator, RootlessError } from 'ts-json-schema-generator';
|
|
2
|
-
import { writeFileInDir } from '../utils.js';
|
|
2
|
+
import { logInfo, writeFileInDir } from '../utils.js';
|
|
3
3
|
import { mkdir, writeFile } from 'fs/promises';
|
|
4
4
|
export async function generateSchemas(tsconfig, typesMap, routesMeta) {
|
|
5
5
|
const schemasSet = new Set(typesMap.customTypes.keys());
|
|
@@ -34,7 +34,7 @@ export async function generateSchemas(tsconfig, typesMap, routesMeta) {
|
|
|
34
34
|
catch (e) {
|
|
35
35
|
// Ignore rootless errors
|
|
36
36
|
if (e instanceof RootlessError) {
|
|
37
|
-
console.
|
|
37
|
+
console.error('Error generating schema since it has no root:', schema);
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
40
|
throw e;
|
|
@@ -56,7 +56,7 @@ export async function saveSchemas(schemaParentDir, schemas, typesMap, routesMeta
|
|
|
56
56
|
...typesMap.customTypes.keys(),
|
|
57
57
|
]);
|
|
58
58
|
if (desiredSchemas.size === 0) {
|
|
59
|
-
|
|
59
|
+
logInfo(`• Skipping schemas since none found.\x1b[0m`);
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
await mkdir(`${schemaParentDir}/schemas`, { recursive: true });
|
package/dist/src/utils.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { InspectorState } from '@pikku/inspector';
|
|
2
|
+
export declare const logPrimary: (message: string) => void;
|
|
3
|
+
export declare const logSuccess: (message: string) => void;
|
|
4
|
+
export declare const logInfo: (message: string) => void;
|
|
2
5
|
export declare const getFileImportRelativePath: (from: string, to: string, packageMappings: Record<string, string>) => string;
|
|
3
6
|
interface Meta {
|
|
4
7
|
file: string;
|
package/dist/src/utils.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
// import packageInfo from '../package.json'
|
|
2
2
|
import { relative, dirname } from 'path';
|
|
3
3
|
import { mkdir, writeFile } from 'fs/promises';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import packageJson from '../package.json';
|
|
6
|
+
export const logPrimary = (message) => {
|
|
7
|
+
console.log(chalk.green(message));
|
|
8
|
+
};
|
|
9
|
+
export const logSuccess = (message) => {
|
|
10
|
+
console.log(chalk.green(message));
|
|
11
|
+
};
|
|
12
|
+
export const logInfo = (message) => {
|
|
13
|
+
console.log(chalk.blue(message));
|
|
14
|
+
};
|
|
4
15
|
export const getFileImportRelativePath = (from, to, packageMappings) => {
|
|
5
16
|
let filePath = relative(dirname(from), to);
|
|
6
17
|
if (!/^\.+\//.test(filePath)) {
|
|
@@ -86,21 +97,30 @@ export const writeFileInDir = async (path, content, ignoreModifyComment = false)
|
|
|
86
97
|
}
|
|
87
98
|
await mkdir(dirname(path), { recursive: true });
|
|
88
99
|
await writeFile(path, content, 'utf-8');
|
|
89
|
-
|
|
100
|
+
logSuccess(`✓ File written to ${path}`);
|
|
90
101
|
};
|
|
91
102
|
export const logCommandInfoAndTime = async (commandStart, commandEnd, [skipCondition, skipMessage = 'none found'], callback) => {
|
|
92
103
|
if (skipCondition === true) {
|
|
93
|
-
|
|
104
|
+
logInfo(`• Skipping ${commandStart} since ${skipMessage}.`);
|
|
94
105
|
return false;
|
|
95
106
|
}
|
|
96
107
|
const start = Date.now();
|
|
97
|
-
|
|
108
|
+
chalk.blue(`• ${commandStart}...`);
|
|
98
109
|
await callback();
|
|
99
|
-
|
|
110
|
+
logSuccess(`✓ ${commandEnd} in ${Date.now() - start}ms.`);
|
|
100
111
|
return true;
|
|
101
112
|
};
|
|
113
|
+
const logo = `
|
|
114
|
+
______ _ _ _
|
|
115
|
+
(_____ (_) | | |
|
|
116
|
+
_____) )| | _| | _ _ _
|
|
117
|
+
| ____/ | |_/ ) |_/ ) | | |
|
|
118
|
+
| | | | _ (| _ (| |_| |
|
|
119
|
+
|_| |_|_| \_)_| \_)____/
|
|
120
|
+
`;
|
|
102
121
|
export const logPikkuLogo = () => {
|
|
103
|
-
|
|
122
|
+
logPrimary(logo);
|
|
123
|
+
logPrimary(`⚙️ Welcome to the Pikku CLI (v${packageJson})\n`);
|
|
104
124
|
};
|
|
105
125
|
// TODO: add version back in once the ESM dust settles
|
|
106
126
|
export const DO_NOT_MODIFY_COMMENT = `/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.9",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"build:esm": "tsc -b",
|
|
15
15
|
"schema": "ts-json-schema-generator -o cli.schema.json --path 'src/pikku-cli-config.ts' --type 'PikkuCLIConfig'",
|
|
16
16
|
"build": "yarn build:esm && yarn schema",
|
|
17
|
-
"ncu": "
|
|
17
|
+
"ncu": "npx npm-check-updates -x '/.*glob.*/'",
|
|
18
18
|
"release": "yarn build && npm test",
|
|
19
19
|
"test": "bash run-tests.sh",
|
|
20
20
|
"test:watch": "bash run-tests.sh --watch",
|
|
@@ -22,10 +22,11 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@openapi-contrib/json-schema-to-openapi-schema": "^3.0.2",
|
|
25
|
-
"@pikku/core": "^0.6.
|
|
25
|
+
"@pikku/core": "^0.6.11",
|
|
26
26
|
"@pikku/inspector": "^0.6.2",
|
|
27
27
|
"@types/cookie": "^0.6.0",
|
|
28
28
|
"@types/uuid": "^10.0.0",
|
|
29
|
+
"chalk": "^5.4.1",
|
|
29
30
|
"commander": "^12",
|
|
30
31
|
"glob": "^10",
|
|
31
32
|
"path-to-regexp": "^8.2.0",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ChannelsMeta } from '@pikku/core/channel'
|
|
2
2
|
import { serializeImportMap } from '../core/serialize-import-map.js'
|
|
3
3
|
import { TypesMap } from '@pikku/inspector'
|
|
4
|
+
import { generateCustomTypes } from '../http/serialize-typed-route-map.js'
|
|
4
5
|
|
|
5
6
|
export const serializeTypedChannelsMap = (
|
|
6
7
|
relativeToPath: string,
|
|
@@ -20,11 +21,13 @@ export const serializeTypedChannelsMap = (
|
|
|
20
21
|
typesMap,
|
|
21
22
|
requiredTypes
|
|
22
23
|
)
|
|
24
|
+
const serializedCustomTypes = generateCustomTypes(typesMap, requiredTypes)
|
|
23
25
|
return `/**
|
|
24
26
|
* This provides the structure needed for TypeScript to be aware of channels
|
|
25
27
|
*/
|
|
26
28
|
|
|
27
29
|
${imports}
|
|
30
|
+
${serializedCustomTypes}
|
|
28
31
|
|
|
29
32
|
interface ChannelHandler<I, O> {
|
|
30
33
|
input: I;
|
|
@@ -106,7 +109,7 @@ function generateChannels(channelsMeta: ChannelsMeta) {
|
|
|
106
109
|
for (const [method, handler] of Object.entries(methods)) {
|
|
107
110
|
routesStr += ` readonly ${method}: ChannelHandler<${formatTypeArray(
|
|
108
111
|
handler.inputTypes
|
|
109
|
-
)}, ${formatTypeArray(handler.outputTypes)}>,\n`
|
|
112
|
+
)}, ${formatTypeArray(handler.outputTypes) || 'never'}>,\n`
|
|
110
113
|
}
|
|
111
114
|
routesStr += ' },\n'
|
|
112
115
|
}
|
|
@@ -11,10 +11,10 @@ export const serializePikkuTypes = (
|
|
|
11
11
|
* This is used to provide the application types in the typescript project
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { CoreAPIFunction, CoreAPIFunctionSessionless, CoreAPIPermission
|
|
15
|
-
import { CoreHTTPFunctionRoute, AssertRouteParams } from '@pikku/core/http'
|
|
16
|
-
import { CoreScheduledTask } from '@pikku/core/scheduler'
|
|
17
|
-
import { CoreAPIChannel,
|
|
14
|
+
import { CoreAPIFunction, CoreAPIFunctionSessionless, CoreAPIPermission } from '@pikku/core'
|
|
15
|
+
import { CoreHTTPFunctionRoute, AssertRouteParams, addRoute as addCoreHTTP } from '@pikku/core/http'
|
|
16
|
+
import { CoreScheduledTask, addScheduledTask as addCoreScheduledTask } from '@pikku/core/scheduler'
|
|
17
|
+
import { CoreAPIChannel, PikkuChannel, addChannel as addCoreChannel } from '@pikku/core/channel'
|
|
18
18
|
|
|
19
19
|
${userSessionTypeImport}
|
|
20
20
|
${sessionServicesTypeImport}
|
|
@@ -25,29 +25,27 @@ export type APIFunctionSessionless<In = unknown, Out = never, RequiredServices =
|
|
|
25
25
|
export type APIFunction<In = unknown, Out = never, RequiredServices = ${servicesTypeName}> = CoreAPIFunction<In, Out, RequiredServices, ${userSessionTypeName}>
|
|
26
26
|
type APIRoute<In, Out, Route extends string> = CoreHTTPFunctionRoute<In, Out, Route, APIFunction<In, Out>, APIFunctionSessionless<In, Out>, APIPermission<In>>
|
|
27
27
|
|
|
28
|
-
export type ChannelConnection<Out =
|
|
29
|
-
export type ChannelDisconnection<ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services:
|
|
30
|
-
export type ChannelMessage<In, Out =
|
|
31
|
-
type APIChannel<ChannelData, Channel extends string
|
|
28
|
+
export type ChannelConnection<Out = unknown, ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: RequiredServices, channel: PikkuChannel<${userSessionTypeName}, ChannelData, Out>) => Promise<void>
|
|
29
|
+
export type ChannelDisconnection<ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: RequiredServices, channel: PikkuChannel<${userSessionTypeName}, ChannelData, never>) => Promise<void>
|
|
30
|
+
export type ChannelMessage<In, Out = unknown, ChannelData = unknown, RequiredServices extends ${servicesTypeName} = ${servicesTypeName}> = (services: RequiredServices, channel: PikkuChannel<${userSessionTypeName}, ChannelData, Out>, data: In) => Promise<Out | void>
|
|
31
|
+
type APIChannel<ChannelData, Channel extends string> = CoreAPIChannel<ChannelData, Channel, ChannelConnection, ChannelDisconnection, ChannelMessage<any, any, ChannelData>, ChannelMessage<any, any, ChannelData>, APIPermission>
|
|
32
32
|
|
|
33
33
|
type ScheduledTask = CoreScheduledTask<APIFunctionSessionless<void, void>, ${userSessionTypeName}>
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
function addChannel<ChannelData, Channel extends string>(
|
|
41
|
-
channel: APIChannel<ChannelData, Channel> & AssertRouteParams<ChannelData, Channel>
|
|
42
|
-
): void;
|
|
35
|
+
export const addChannel = <ChannelData, Channel extends string>(
|
|
36
|
+
channel: APIChannel<ChannelData, Channel> & AssertRouteParams<ChannelData, Channel>
|
|
37
|
+
) => {
|
|
38
|
+
addCoreChannel(channel as any) // TODO
|
|
39
|
+
}
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
export const addRoute = <In, Out, Route extends string>(
|
|
42
|
+
route: APIRoute<In, Out, Route> & AssertRouteParams<In, Route>
|
|
43
|
+
) => {
|
|
44
|
+
addCoreHTTP(route)
|
|
45
|
+
}
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
): void;
|
|
47
|
+
export const addScheduledTask = (task: ScheduledTask) => {
|
|
48
|
+
addCoreScheduledTask(task as any) // TODO
|
|
51
49
|
}
|
|
52
50
|
`
|
|
53
51
|
}
|
|
@@ -46,7 +46,10 @@ export type RoutesWithMethod<Method extends string> = {
|
|
|
46
46
|
`
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
function generateCustomTypes(
|
|
49
|
+
export function generateCustomTypes(
|
|
50
|
+
typesMap: TypesMap,
|
|
51
|
+
requiredTypes: Set<string>
|
|
52
|
+
) {
|
|
50
53
|
return `
|
|
51
54
|
// Custom types are those that are defined directly within generics
|
|
52
55
|
// or are broken into simpler types
|
package/src/pikku-cli-config.ts
CHANGED
|
@@ -118,10 +118,7 @@ const _getPikkuCLIConfig = async (
|
|
|
118
118
|
result.channelsFile = join(result.outDir, 'pikku-channels.gen.ts')
|
|
119
119
|
}
|
|
120
120
|
if (!result.typesDeclarationFile) {
|
|
121
|
-
result.typesDeclarationFile = join(
|
|
122
|
-
result.outDir,
|
|
123
|
-
'pikku-types.gen.d.ts'
|
|
124
|
-
)
|
|
121
|
+
result.typesDeclarationFile = join(result.outDir, 'pikku-types.gen.ts')
|
|
125
122
|
}
|
|
126
123
|
if (!result.routesMapDeclarationFile) {
|
|
127
124
|
result.routesMapDeclarationFile = join(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createGenerator, RootlessError } from 'ts-json-schema-generator'
|
|
2
|
-
import { writeFileInDir } from '../utils.js'
|
|
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'
|
|
@@ -42,7 +42,7 @@ export async function generateSchemas(
|
|
|
42
42
|
} catch (e) {
|
|
43
43
|
// Ignore rootless errors
|
|
44
44
|
if (e instanceof RootlessError) {
|
|
45
|
-
console.
|
|
45
|
+
console.error('Error generating schema since it has no root:', schema)
|
|
46
46
|
return
|
|
47
47
|
}
|
|
48
48
|
throw e
|
|
@@ -80,7 +80,7 @@ export async function saveSchemas(
|
|
|
80
80
|
])
|
|
81
81
|
|
|
82
82
|
if (desiredSchemas.size === 0) {
|
|
83
|
-
|
|
83
|
+
logInfo(`• Skipping schemas since none found.\x1b[0m`)
|
|
84
84
|
return
|
|
85
85
|
}
|
|
86
86
|
|
package/src/utils.ts
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
import { relative, dirname } from 'path'
|
|
3
3
|
import { PathToNameAndType, InspectorState } from '@pikku/inspector'
|
|
4
4
|
import { mkdir, writeFile } from 'fs/promises'
|
|
5
|
+
import chalk from 'chalk'
|
|
6
|
+
import packageJson from '../package.json'
|
|
7
|
+
|
|
8
|
+
export const logPrimary = (message: string) => {
|
|
9
|
+
console.log(chalk.green(message))
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const logSuccess = (message: string) => {
|
|
13
|
+
console.log(chalk.green(message))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const logInfo = (message: string) => {
|
|
17
|
+
console.log(chalk.blue(message))
|
|
18
|
+
}
|
|
5
19
|
|
|
6
20
|
export const getFileImportRelativePath = (
|
|
7
21
|
from: string,
|
|
@@ -184,7 +198,7 @@ export const writeFileInDir = async (
|
|
|
184
198
|
|
|
185
199
|
await mkdir(dirname(path), { recursive: true })
|
|
186
200
|
await writeFile(path, content, 'utf-8')
|
|
187
|
-
|
|
201
|
+
logSuccess(`✓ File written to ${path}`)
|
|
188
202
|
}
|
|
189
203
|
|
|
190
204
|
export const logCommandInfoAndTime = async (
|
|
@@ -194,22 +208,30 @@ export const logCommandInfoAndTime = async (
|
|
|
194
208
|
callback: (...args: any[]) => Promise<unknown>
|
|
195
209
|
): Promise<boolean> => {
|
|
196
210
|
if (skipCondition === true) {
|
|
197
|
-
|
|
198
|
-
`\x1b[34m• Skipping ${commandStart} since ${skipMessage}.\x1b[0m`
|
|
199
|
-
)
|
|
211
|
+
logInfo(`• Skipping ${commandStart} since ${skipMessage}.`)
|
|
200
212
|
return false
|
|
201
213
|
}
|
|
202
214
|
|
|
203
215
|
const start = Date.now()
|
|
204
|
-
|
|
216
|
+
chalk.blue(`• ${commandStart}...`)
|
|
205
217
|
await callback()
|
|
206
218
|
|
|
207
|
-
|
|
219
|
+
logSuccess(`✓ ${commandEnd} in ${Date.now() - start}ms.`)
|
|
208
220
|
return true
|
|
209
221
|
}
|
|
210
222
|
|
|
223
|
+
const logo = `
|
|
224
|
+
______ _ _ _
|
|
225
|
+
(_____ (_) | | |
|
|
226
|
+
_____) )| | _| | _ _ _
|
|
227
|
+
| ____/ | |_/ ) |_/ ) | | |
|
|
228
|
+
| | | | _ (| _ (| |_| |
|
|
229
|
+
|_| |_|_| \_)_| \_)____/
|
|
230
|
+
`
|
|
231
|
+
|
|
211
232
|
export const logPikkuLogo = () => {
|
|
212
|
-
|
|
233
|
+
logPrimary(logo)
|
|
234
|
+
logPrimary(`⚙️ Welcome to the Pikku CLI (v${packageJson})\n`)
|
|
213
235
|
}
|
|
214
236
|
|
|
215
237
|
// TODO: add version back in once the ESM dust settles
|