vovk-cli 0.0.1-draft.47 → 0.0.1-draft.48
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/README.md +1 -1
- package/client-templates/compiled/compiled.d.ts.ejs +7 -16
- package/client-templates/compiled/compiled.js.ejs +3 -12
- package/client-templates/ts/index.ts.ejs +7 -18
- package/dist/dev/diffSchema.d.mts +5 -11
- package/dist/dev/diffSchema.mjs +2 -10
- package/dist/dev/ensureSchemaFiles.mjs +0 -1
- package/dist/dev/index.mjs +5 -9
- package/dist/dev/isMetadataEmpty.mjs +1 -1
- package/dist/dev/logDiffResult.mjs +0 -37
- package/dist/generate/index.mjs +2 -1
- package/dist/getProjectInfo/getConfig.mjs +3 -4
- package/dist/getProjectInfo/index.d.mts +1 -0
- package/dist/getProjectInfo/index.mjs +10 -6
- package/dist/index.mjs +15 -15
- package/dist/init/createConfig.mjs +1 -3
- package/dist/new/addClassToSegmentCode.d.mts +1 -2
- package/dist/new/addClassToSegmentCode.mjs +3 -3
- package/dist/new/newModule.mjs +3 -6
- package/dist/new/newSegment.mjs +2 -4
- package/dist/types.d.mts +6 -7
- package/package.json +3 -3
- package/templates/worker.ejs +0 -24
package/README.md
CHANGED
|
@@ -24,6 +24,6 @@ npm install -D vovk-cli
|
|
|
24
24
|
- [vovk dev](https://vovk.dev/cli/vovk-dev) - starts the development script that watches the changes in controllers and regenerates the schema and client.
|
|
25
25
|
- [vovk generate](https://vovk.dev/cli/vovk-generate) - generates the client based on the schema.
|
|
26
26
|
- [vovk init](https://vovk.dev/cli/vovk-init) - initializes the Vovk.ts project.
|
|
27
|
-
- [vovk new](https://vovk.dev/cli/vovk-new) - generates a new controller, service
|
|
27
|
+
- [vovk new](https://vovk.dev/cli/vovk-new) - generates a new controller, service or a custom module.
|
|
28
28
|
|
|
29
29
|
For more information, please visit the [CLI documentation](https://vovk.dev/cli) or use `npx vovk-cli --help` to get the list of available commands and options.
|
|
@@ -1,24 +1,15 @@
|
|
|
1
1
|
|
|
2
2
|
<%- '// auto-generated\n/* eslint-disable */' %>
|
|
3
|
-
import type {
|
|
3
|
+
import type { VovkClientFetcher } from 'vovk';
|
|
4
4
|
import type fetcher from '<%= fetcherClientImportPath %>';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
%>
|
|
8
|
-
|
|
9
|
-
<% }) %>
|
|
5
|
+
import type createRPC from '<%= createRPCImportPath %>';
|
|
6
|
+
<% segments.forEach((segment, i) => { if(Object.keys(segmentsSchema[segment.segmentName].controllers).length) { %>
|
|
7
|
+
import type { Controllers as Controllers<%= i %> } from "<%= segment.segmentImportPath %>";
|
|
8
|
+
<% }}) %>
|
|
10
9
|
type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
|
|
11
10
|
|
|
12
|
-
<% segments.forEach((segment, i) => {
|
|
13
|
-
|
|
14
|
-
if (!segSchema || !segSchema.emitSchema) return;
|
|
15
|
-
const controllers = Object.keys(segSchema.controllers);
|
|
16
|
-
const workers = Object.keys(segSchema.workers);
|
|
17
|
-
%>
|
|
18
|
-
<% controllers.forEach((key) => { %>
|
|
11
|
+
<% segments.forEach((segment, i) => { %>
|
|
12
|
+
<% Object.keys(segmentsSchema[segment.segmentName].controllers).forEach((key) => { %>
|
|
19
13
|
export const <%= key %>: ReturnType<typeof createRPC<Controllers<%= i %>["<%= key %>"], Options>>;
|
|
20
14
|
<% }) %>
|
|
21
|
-
<% workers.forEach((key) => { %>
|
|
22
|
-
export const <%= key %>: ReturnType<typeof createWPC<Workers<%= i %>["<%= key %>"]>>;
|
|
23
|
-
<% }) %>
|
|
24
15
|
<% }) %>
|
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
<%- '// auto-generated\n/* eslint-disable */' %>
|
|
2
|
-
const { createRPC, createWPC } = require('vovk');
|
|
3
2
|
const { default: fetcher } = require('<%= fetcherClientImportPath %>');
|
|
3
|
+
const { default: createRPC } = require('<%= createRPCImportPath %>');
|
|
4
4
|
const schema = require('<%= schemaOutImportPath %>');
|
|
5
5
|
|
|
6
6
|
const { default: validateOnClient = null } = <%- validateOnClientImportPath ? `require('${validateOnClientImportPath}')` : '{}'%>;
|
|
7
7
|
const apiRoot = '<%= apiRoot %>';
|
|
8
|
-
|
|
9
|
-
<%
|
|
10
|
-
const segSchema = segmentsSchema[segment.segmentName];
|
|
11
|
-
if (!segSchema || !segSchema.emitSchema) return;
|
|
12
|
-
const controllers = Object.keys(segSchema.controllers);
|
|
13
|
-
const workers = Object.keys(segSchema.workers);
|
|
14
|
-
%>
|
|
15
|
-
<% controllers.forEach((key) => { %>
|
|
8
|
+
<% segments.forEach((segment) => { %>
|
|
9
|
+
<% Object.keys(segmentsSchema[segment.segmentName].controllers).forEach((key) => { %>
|
|
16
10
|
exports.<%= key %> = createRPC(
|
|
17
11
|
schema['<%= segment.segmentName %>'].controllers.<%= key %>,
|
|
18
12
|
'<%= segment.segmentName %>',
|
|
19
13
|
{ fetcher, validateOnClient, defaultOptions: { apiRoot } }
|
|
20
14
|
);
|
|
21
15
|
<% }) %>
|
|
22
|
-
<% workers.forEach((key) => { %>
|
|
23
|
-
exports.<%= key %> = createWPC(schema['<%= segment.segmentName %>'].workers.<%= key %>);
|
|
24
|
-
<% }) %>
|
|
25
16
|
<% }) %>
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
<%- '// auto-generated\n/* eslint-disable */' %>
|
|
2
|
-
import {
|
|
2
|
+
import type { VovkClientFetcher } from 'vovk';
|
|
3
3
|
import fetcher from '<%= fetcherClientImportPath %>';
|
|
4
|
+
import createRPC from '<%= createRPCImportPath %>';
|
|
4
5
|
import schema from '<%= schemaOutImportPath %>';
|
|
5
|
-
<% segments.forEach((segment, i) => {
|
|
6
|
-
|
|
7
|
-
%>
|
|
8
|
-
import type { Controllers as Controllers<%= i %><% if(hasWorkers) { %>, Workers as Workers<%= i %> <% } %> } from "<%= segment.segmentImportPath %>";
|
|
9
|
-
<% }) %>
|
|
6
|
+
<% segments.forEach((segment, i) => { if(Object.keys(segmentsSchema[segment.segmentName].controllers).length) { %>
|
|
7
|
+
import type { Controllers as Controllers<%= i %> } from "<%= segment.segmentImportPath %>";
|
|
8
|
+
<% }}) %>
|
|
10
9
|
<% if (validateOnClientImportPath) { %>
|
|
11
10
|
import validateOnClient from '<%= validateOnClientImportPath %>';
|
|
12
11
|
<% } else { %>
|
|
@@ -15,22 +14,12 @@ const validateOnClient = undefined;
|
|
|
15
14
|
type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
|
|
16
15
|
const apiRoot = '<%= apiRoot %>';
|
|
17
16
|
|
|
18
|
-
<% segments.forEach((segment, i) => {
|
|
19
|
-
|
|
20
|
-
if (!segSchema || !segSchema.emitSchema) return;
|
|
21
|
-
const hasWorkers = !!Object.keys(segmentsSchema[segment.segmentName].workers).length;
|
|
22
|
-
%>
|
|
23
|
-
<% Object.keys(segSchema.controllers).forEach((key) => { %>
|
|
17
|
+
<% segments.forEach((segment, i) => { %>
|
|
18
|
+
<% Object.keys(segmentsSchema[segment.segmentName].controllers).forEach((key) => { %>
|
|
24
19
|
export const <%= key %> = createRPC<Controllers<%= i %>["<%= key %>"], Options>(
|
|
25
20
|
schema['<%= segment.segmentName %>'].controllers.<%= key %>,
|
|
26
21
|
'<%= segment.segmentName %>',
|
|
27
22
|
{ fetcher, validateOnClient, defaultOptions: { apiRoot } }
|
|
28
|
-
);
|
|
29
|
-
<% }) %>
|
|
30
|
-
|
|
31
|
-
<% Object.keys(segSchema.workers).forEach((key) => { %>
|
|
32
|
-
export const <%= key %> = createWPC<Workers<%= i %>["<%= key %>"]>(
|
|
33
|
-
schema['<%= segment.segmentName %>'].workers.<%= key %>
|
|
34
23
|
);
|
|
35
24
|
<% }) %>
|
|
36
25
|
<% }) %>
|
|
@@ -1,29 +1,23 @@
|
|
|
1
|
-
import type { VovkControllerSchema,
|
|
1
|
+
import type { VovkControllerSchema, VovkSchema } from 'vovk';
|
|
2
2
|
interface HandlersDiff {
|
|
3
3
|
nameOfClass: string;
|
|
4
4
|
added: string[];
|
|
5
5
|
removed: string[];
|
|
6
6
|
changed: string[];
|
|
7
7
|
}
|
|
8
|
-
interface
|
|
8
|
+
interface ControllersDiff {
|
|
9
9
|
added: string[];
|
|
10
10
|
removed: string[];
|
|
11
11
|
handlers: HandlersDiff[];
|
|
12
12
|
}
|
|
13
13
|
export interface DiffResult {
|
|
14
|
-
|
|
15
|
-
controllers: WorkersOrControllersDiff;
|
|
14
|
+
controllers: ControllersDiff;
|
|
16
15
|
}
|
|
17
|
-
export declare function diffHandlers<T extends
|
|
18
|
-
export declare function
|
|
16
|
+
export declare function diffHandlers<T extends VovkControllerSchema['handlers']>(oldHandlers: T, newHandlers: T, nameOfClass: string): HandlersDiff;
|
|
17
|
+
export declare function diffControllers<T extends VovkSchema['controllers']>(oldItems: T, newItems: T): ControllersDiff;
|
|
19
18
|
/**
|
|
20
19
|
example output:
|
|
21
20
|
{
|
|
22
|
-
workers: {
|
|
23
|
-
added: ["WorkerC"],
|
|
24
|
-
removed: ["WorkerA"],
|
|
25
|
-
handlers: []
|
|
26
|
-
},
|
|
27
21
|
controllers: {
|
|
28
22
|
added: ["ControllerC"],
|
|
29
23
|
removed: ["ControllerB"],
|
package/dist/dev/diffSchema.mjs
CHANGED
|
@@ -18,7 +18,7 @@ export function diffHandlers(oldHandlers, newHandlers, nameOfClass) {
|
|
|
18
18
|
}
|
|
19
19
|
return { nameOfClass, added, removed, changed };
|
|
20
20
|
}
|
|
21
|
-
export function
|
|
21
|
+
export function diffControllers(oldItems, newItems) {
|
|
22
22
|
const added = [];
|
|
23
23
|
const removed = [];
|
|
24
24
|
const handlersDiff = [];
|
|
@@ -43,11 +43,6 @@ export function diffWorkersOrControllers(oldItems, newItems) {
|
|
|
43
43
|
/**
|
|
44
44
|
example output:
|
|
45
45
|
{
|
|
46
|
-
workers: {
|
|
47
|
-
added: ["WorkerC"],
|
|
48
|
-
removed: ["WorkerA"],
|
|
49
|
-
handlers: []
|
|
50
|
-
},
|
|
51
46
|
controllers: {
|
|
52
47
|
added: ["ControllerC"],
|
|
53
48
|
removed: ["ControllerB"],
|
|
@@ -63,10 +58,7 @@ example output:
|
|
|
63
58
|
}
|
|
64
59
|
*/
|
|
65
60
|
export default function diffSchema(oldJson, newJson) {
|
|
66
|
-
const workersDiff = diffWorkersOrControllers(oldJson.workers ?? {}, newJson.workers ?? {});
|
|
67
|
-
const controllersDiff = diffWorkersOrControllers(oldJson.controllers ?? {}, newJson.controllers ?? {});
|
|
68
61
|
return {
|
|
69
|
-
|
|
70
|
-
controllers: controllersDiff,
|
|
62
|
+
controllers: diffControllers(oldJson.controllers ?? {}, newJson.controllers ?? {}),
|
|
71
63
|
};
|
|
72
64
|
}
|
package/dist/dev/index.mjs
CHANGED
|
@@ -199,21 +199,17 @@ export class VovkDev {
|
|
|
199
199
|
}
|
|
200
200
|
const nameOfClasReg = /\bclass\s+([A-Za-z_]\w*)(?:\s*<[^>]*>)?\s*\{/g;
|
|
201
201
|
const namesOfClasses = [...code.matchAll(nameOfClasReg)].map((match) => match[1]);
|
|
202
|
-
const importRegex = /import\s*{[^}]*\b(get|post|put|del|head|options
|
|
202
|
+
const importRegex = /import\s*{[^}]*\b(get|post|put|del|head|options)\b[^}]*}\s*from\s*['"]vovk['"]/;
|
|
203
203
|
if (importRegex.test(code) && namesOfClasses.length) {
|
|
204
204
|
const affectedSegments = this.#segments.filter((s) => {
|
|
205
205
|
const schema = this.#schemas[s.segmentName];
|
|
206
206
|
if (!schema)
|
|
207
207
|
return false;
|
|
208
208
|
const controllersByOriginalName = keyBy(schema.controllers, 'originalControllerName');
|
|
209
|
-
|
|
210
|
-
return namesOfClasses.some((name) => schema.controllers[name] ||
|
|
211
|
-
schema.workers[name] ||
|
|
212
|
-
controllersByOriginalName[name] ||
|
|
213
|
-
workersByOriginalName[name]);
|
|
209
|
+
return namesOfClasses.some((name) => schema.controllers[name] || controllersByOriginalName[name]);
|
|
214
210
|
});
|
|
215
211
|
if (affectedSegments.length) {
|
|
216
|
-
log.debug(`A file with controller
|
|
212
|
+
log.debug(`A file with controller ${namesOfClasses.join(', ')} have been modified at path "${filePath}". Segment(s) affected: ${JSON.stringify(affectedSegments.map((s) => s.segmentName))}`);
|
|
217
213
|
for (const segment of affectedSegments) {
|
|
218
214
|
await this.#requestSchema(segment.segmentName);
|
|
219
215
|
}
|
|
@@ -223,7 +219,7 @@ export class VovkDev {
|
|
|
223
219
|
}
|
|
224
220
|
}
|
|
225
221
|
else {
|
|
226
|
-
log.debug(`The file does not contain any controller
|
|
222
|
+
log.debug(`The file does not contain any controller`);
|
|
227
223
|
}
|
|
228
224
|
};
|
|
229
225
|
#requestSchema = debounceWithArgs(async (segmentName) => {
|
|
@@ -283,7 +279,7 @@ export class VovkDev {
|
|
|
283
279
|
log.info(`Schema for ${formatLoggedSegmentName(segment.segmentName)} has been updated in ${timeTook}ms`);
|
|
284
280
|
}
|
|
285
281
|
}
|
|
286
|
-
else if (schema &&
|
|
282
|
+
else if (schema && !isEmpty(schema.controllers)) {
|
|
287
283
|
log.error(`Non-empty schema provided for ${formatLoggedSegmentName(segment.segmentName)} but "emitSchema" is false`);
|
|
288
284
|
}
|
|
289
285
|
if (this.#segments.every((s) => this.#schemas[s.segmentName])) {
|
|
@@ -3,23 +3,6 @@ import formatLoggedSegmentName from '../utils/formatLoggedSegmentName.mjs';
|
|
|
3
3
|
import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
|
|
4
4
|
export default function logDiffResult(segmentName, diffResult, projectInfo) {
|
|
5
5
|
const diffNormalized = [];
|
|
6
|
-
diffResult.workers.added.forEach((name) => {
|
|
7
|
-
diffNormalized.push({ what: 'worker', type: 'added', name });
|
|
8
|
-
});
|
|
9
|
-
diffResult.workers.removed.forEach((name) => {
|
|
10
|
-
diffNormalized.push({ what: 'worker', type: 'removed', name });
|
|
11
|
-
});
|
|
12
|
-
diffResult.workers.handlers.forEach((handler) => {
|
|
13
|
-
handler.added.forEach((name) => {
|
|
14
|
-
diffNormalized.push({ what: 'workerHandler', type: 'added', name: `${handler.nameOfClass}.${name}` });
|
|
15
|
-
});
|
|
16
|
-
handler.removed.forEach((name) => {
|
|
17
|
-
diffNormalized.push({ what: 'workerHandler', type: 'removed', name: `${handler.nameOfClass}.${name}` });
|
|
18
|
-
});
|
|
19
|
-
handler.changed.forEach((name) => {
|
|
20
|
-
diffNormalized.push({ what: 'workerHandler', type: 'changed', name: `${handler.nameOfClass}.${name}` });
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
6
|
diffResult.controllers.added.forEach((name) => {
|
|
24
7
|
diffNormalized.push({ what: 'controller', type: 'added', name });
|
|
25
8
|
});
|
|
@@ -43,16 +26,6 @@ export default function logDiffResult(segmentName, diffResult, projectInfo) {
|
|
|
43
26
|
const changedText = chalk.cyan('changed');
|
|
44
27
|
for (const diffNormalizedItem of diffNormalized.slice(0, LIMIT)) {
|
|
45
28
|
switch (diffNormalizedItem.what) {
|
|
46
|
-
case 'worker':
|
|
47
|
-
switch (diffNormalizedItem.type) {
|
|
48
|
-
case 'added':
|
|
49
|
-
projectInfo.log.info(`Schema for WPC ${chalkHighlightThing(diffNormalizedItem.name)} has been ${addedText} at ${formatLoggedSegmentName(segmentName)}`);
|
|
50
|
-
break;
|
|
51
|
-
case 'removed':
|
|
52
|
-
projectInfo.log.info(`Schema for WPC ${chalkHighlightThing(diffNormalizedItem.name)} has been ${removedText} from ${formatLoggedSegmentName(segmentName)}`);
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
break;
|
|
56
29
|
case 'controller':
|
|
57
30
|
switch (diffNormalizedItem.type) {
|
|
58
31
|
case 'added':
|
|
@@ -63,16 +36,6 @@ export default function logDiffResult(segmentName, diffResult, projectInfo) {
|
|
|
63
36
|
break;
|
|
64
37
|
}
|
|
65
38
|
break;
|
|
66
|
-
case 'workerHandler':
|
|
67
|
-
switch (diffNormalizedItem.type) {
|
|
68
|
-
case 'added':
|
|
69
|
-
projectInfo.log.info(`Schema for WPC method ${chalkHighlightThing(diffNormalizedItem.name)} has been ${addedText} at ${formatLoggedSegmentName(segmentName)}`);
|
|
70
|
-
break;
|
|
71
|
-
case 'removed':
|
|
72
|
-
projectInfo.log.info(`Schema for WPC method ${chalkHighlightThing(diffNormalizedItem.name)} has been ${removedText} from ${formatLoggedSegmentName(segmentName)}`);
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
break;
|
|
76
39
|
case 'controllerHandler':
|
|
77
40
|
switch (diffNormalizedItem.type) {
|
|
78
41
|
case 'added':
|
package/dist/generate/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import getClientTemplates from './getClientTemplates.mjs';
|
|
|
7
7
|
export default async function generate({ projectInfo, segments, segmentsSchema, templates, prettify: prettifyClient, fullSchema, }) {
|
|
8
8
|
templates = templates ?? projectInfo.config.experimental_clientGenerateTemplateNames;
|
|
9
9
|
const noClient = templates?.[0] === 'none';
|
|
10
|
-
const { config, cwd, log, validateOnClientImportPath, apiRoot, fetcherClientImportPath, schemaOutImportPath } = projectInfo;
|
|
10
|
+
const { config, cwd, log, validateOnClientImportPath, apiRoot, fetcherClientImportPath, createRPCImportPath, schemaOutImportPath, } = projectInfo;
|
|
11
11
|
const clientOutDirAbsolutePath = path.resolve(cwd, config.clientOutDir);
|
|
12
12
|
const templateFiles = getClientTemplates({ config, cwd, templateNames: templates });
|
|
13
13
|
// Ensure that each segment has a matching schema if it needs to be emitted:
|
|
@@ -27,6 +27,7 @@ export default async function generate({ projectInfo, segments, segmentsSchema,
|
|
|
27
27
|
fetcherClientImportPath,
|
|
28
28
|
schemaOutImportPath,
|
|
29
29
|
validateOnClientImportPath,
|
|
30
|
+
createRPCImportPath,
|
|
30
31
|
segments,
|
|
31
32
|
segmentsSchema,
|
|
32
33
|
};
|
|
@@ -7,9 +7,9 @@ export default async function getConfig({ clientOutDir, cwd }) {
|
|
|
7
7
|
const srcRoot = await getRelativeSrcRoot({ cwd });
|
|
8
8
|
const config = {
|
|
9
9
|
modulesDir: env.VOVK_MODULES_DIR ?? conf.modulesDir ?? './' + [srcRoot, 'modules'].filter(Boolean).join('/'),
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
validateOnClientPath: env.VOVK_VALIDATE_ON_CLIENT_PATH ?? conf.validateOnClientPath ?? null,
|
|
11
|
+
fetcherPath: env.VOVK_FETCHER_PATH ?? conf.fetcherPath ?? 'vovk/dist/client/defaultFetcher',
|
|
12
|
+
createRPCPath: env.VOVK_CREATE_RPC_PATH ?? conf.createRPCPath ?? 'vovk/dist/client/createRPC',
|
|
13
13
|
schemaOutDir: env.VOVK_SCHEMA_OUT_DIR ?? conf.schemaOutDir ?? './.vovk-schema',
|
|
14
14
|
clientOutDir: clientOutDir ?? env.VOVK_CLIENT_OUT_DIR ?? conf.clientOutDir ?? './node_modules/.vovk-client',
|
|
15
15
|
origin: (env.VOVK_ORIGIN ?? conf.origin ?? '').replace(/\/$/, ''), // Remove trailing slash
|
|
@@ -22,7 +22,6 @@ export default async function getConfig({ clientOutDir, cwd }) {
|
|
|
22
22
|
templates: {
|
|
23
23
|
service: 'vovk-cli/templates/service.ejs',
|
|
24
24
|
controller: 'vovk-cli/templates/controller.ejs',
|
|
25
|
-
worker: 'vovk-cli/templates/worker.ejs',
|
|
26
25
|
...conf.templates,
|
|
27
26
|
},
|
|
28
27
|
};
|
|
@@ -11,6 +11,7 @@ export default function getProjectInfo({ port: givenPort, clientOutDir, cwd, }?:
|
|
|
11
11
|
srcRoot: string;
|
|
12
12
|
schemaOutImportPath: string;
|
|
13
13
|
fetcherClientImportPath: string;
|
|
14
|
+
createRPCImportPath: string;
|
|
14
15
|
validateOnClientImportPath: string | null;
|
|
15
16
|
config: Required<import("../types.mjs").VovkConfig>;
|
|
16
17
|
log: {
|
|
@@ -9,12 +9,15 @@ export default async function getProjectInfo({ port: givenPort, clientOutDir, cw
|
|
|
9
9
|
const apiRoot = `${config.origin ?? ''}/${config.rootEntry}`;
|
|
10
10
|
const apiDir = path.join(srcRoot, 'app', config.rootEntry);
|
|
11
11
|
const schemaOutImportPath = path.relative(config.clientOutDir, config.schemaOutDir).replace(/\\/g, '/'); // windows fix
|
|
12
|
-
const fetcherClientImportPath = config.
|
|
13
|
-
? path.relative(config.clientOutDir, config.
|
|
14
|
-
: config.
|
|
15
|
-
const
|
|
16
|
-
? path.relative(config.clientOutDir, config.
|
|
17
|
-
: config.
|
|
12
|
+
const fetcherClientImportPath = config.fetcherPath.startsWith('.')
|
|
13
|
+
? path.relative(config.clientOutDir, config.fetcherPath)
|
|
14
|
+
: config.fetcherPath;
|
|
15
|
+
const createRPCImportPath = config.createRPCPath.startsWith('.')
|
|
16
|
+
? path.relative(config.clientOutDir, config.createRPCPath)
|
|
17
|
+
: config.createRPCPath;
|
|
18
|
+
const validateOnClientImportPath = config.validateOnClientPath?.startsWith('.')
|
|
19
|
+
? path.relative(config.clientOutDir, config.validateOnClientPath)
|
|
20
|
+
: config.validateOnClientPath;
|
|
18
21
|
const log = getLogger(config.logLevel);
|
|
19
22
|
if (configAbsolutePaths.length > 1) {
|
|
20
23
|
log.warn(`Multiple config files found. Using the first one: ${configAbsolutePaths[0]}`);
|
|
@@ -30,6 +33,7 @@ export default async function getProjectInfo({ port: givenPort, clientOutDir, cw
|
|
|
30
33
|
srcRoot,
|
|
31
34
|
schemaOutImportPath,
|
|
32
35
|
fetcherClientImportPath,
|
|
36
|
+
createRPCImportPath,
|
|
33
37
|
validateOnClientImportPath,
|
|
34
38
|
config,
|
|
35
39
|
log,
|
package/dist/index.mjs
CHANGED
|
@@ -19,9 +19,9 @@ initProgram(program.command('init'));
|
|
|
19
19
|
program
|
|
20
20
|
.command('dev')
|
|
21
21
|
.alias('d')
|
|
22
|
-
.description('
|
|
23
|
-
.option('--next-dev', '
|
|
24
|
-
.option('--exit', '
|
|
22
|
+
.description('start schema watcher (optional flag --next-dev to start it with Next.js)')
|
|
23
|
+
.option('--next-dev', 'start schema watcher and Next.js with automatic port allocation')
|
|
24
|
+
.option('--exit', 'kill the processe when schema and client is generated')
|
|
25
25
|
.allowUnknownOption(true)
|
|
26
26
|
.action(async (options, command) => {
|
|
27
27
|
const { nextDev, exit = false } = options;
|
|
@@ -31,8 +31,8 @@ program
|
|
|
31
31
|
: process.env.PORT ||
|
|
32
32
|
(await getAvailablePort(3000, portAttempts, 0, (failedPort, tryingPort) =>
|
|
33
33
|
// eslint-disable-next-line no-console
|
|
34
|
-
console.warn(`🐺
|
|
35
|
-
throw new Error(`🐺 ❌ Failed to find available
|
|
34
|
+
console.warn(`🐺 Port ${failedPort} is in use, trying ${tryingPort} instead.`)).catch(() => {
|
|
35
|
+
throw new Error(`🐺 ❌ Failed to find an available port after ${portAttempts} attempts`);
|
|
36
36
|
}));
|
|
37
37
|
if (!PORT) {
|
|
38
38
|
throw new Error('🐺 ❌ PORT env variable is required');
|
|
@@ -73,10 +73,10 @@ program
|
|
|
73
73
|
.command('generate')
|
|
74
74
|
.alias('g')
|
|
75
75
|
.description('Generate client')
|
|
76
|
-
.option('--out, --client-out-dir <path>', '
|
|
77
|
-
.option('--template, --templates <templates...>', '
|
|
78
|
-
.option('--full-schema [fileName]', '
|
|
79
|
-
.option('--prettify', '
|
|
76
|
+
.option('--out, --client-out-dir <path>', 'path to output directory')
|
|
77
|
+
.option('--template, --templates <templates...>', 'client code templates ("ts", "compiled", "python", "none", a custom path)')
|
|
78
|
+
.option('--full-schema [fileName]', 'generate client with full schema')
|
|
79
|
+
.option('--prettify', 'prettify output files')
|
|
80
80
|
.action(async (options) => {
|
|
81
81
|
const { clientOutDir, templates, prettify, fullSchema } = options;
|
|
82
82
|
const projectInfo = await getProjectInfo({ clientOutDir });
|
|
@@ -90,12 +90,12 @@ program
|
|
|
90
90
|
program
|
|
91
91
|
.command('new [components...]')
|
|
92
92
|
.alias('n')
|
|
93
|
-
.description('
|
|
94
|
-
.option('-o, --overwrite', '
|
|
95
|
-
.option('--template, --templates <templates...>', '
|
|
96
|
-
.option('--dir <dirname>', '
|
|
97
|
-
.option('--no-segment-update', '
|
|
98
|
-
.option('--dry-run', '
|
|
93
|
+
.description('create new components. "vovk new [...components] [segmentName/]moduleName" to create a new module or "vovk new segment [segmentName]" to create a new segment')
|
|
94
|
+
.option('-o, --overwrite', 'overwrite existing files')
|
|
95
|
+
.option('--template, --templates <templates...>', 'override config template; accepts an array of strings that correspond the order of the components')
|
|
96
|
+
.option('--dir <dirname>', 'override dirName in template file; relative to the root of the project')
|
|
97
|
+
.option('--no-segment-update', 'do not update segment files when creating a new module')
|
|
98
|
+
.option('--dry-run', 'do not write files to disk')
|
|
99
99
|
.action((components, options) => newComponents(components, options));
|
|
100
100
|
program
|
|
101
101
|
.command('help')
|
|
@@ -14,12 +14,10 @@ export default async function createConfig({ root, log, options: { validationLib
|
|
|
14
14
|
const templates = {
|
|
15
15
|
controller: 'vovk-cli/templates/controller.ejs',
|
|
16
16
|
service: 'vovk-cli/templates/service.ejs',
|
|
17
|
-
worker: 'vovk-cli/templates/worker.ejs',
|
|
18
17
|
};
|
|
19
18
|
if (validationLibrary) {
|
|
20
|
-
config.validationLibrary = validationLibrary;
|
|
21
19
|
if (validateOnClient) {
|
|
22
|
-
config.
|
|
20
|
+
config.validateOnClientPath = `${validationLibrary}/validateOnClient`;
|
|
23
21
|
}
|
|
24
22
|
try {
|
|
25
23
|
const validationTemplates = await getTemplateFilesFromPackage(validationLibrary, channel);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export default function addClassToSegmentCode(segmentSourceCode: string, { sourceName, compiledName,
|
|
1
|
+
export default function addClassToSegmentCode(segmentSourceCode: string, { sourceName, compiledName, importPath, }: {
|
|
2
2
|
sourceName: string;
|
|
3
3
|
compiledName: string;
|
|
4
|
-
type: 'worker' | 'controller';
|
|
5
4
|
importPath: string;
|
|
6
5
|
}): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Project, QuoteKind, SyntaxKind } from 'ts-morph';
|
|
2
|
-
export default function addClassToSegmentCode(segmentSourceCode, { sourceName, compiledName,
|
|
2
|
+
export default function addClassToSegmentCode(segmentSourceCode, { sourceName, compiledName, importPath, }) {
|
|
3
3
|
const project = new Project({
|
|
4
4
|
manipulationSettings: {
|
|
5
5
|
quoteKind: QuoteKind.Single,
|
|
@@ -16,8 +16,8 @@ export default function addClassToSegmentCode(segmentSourceCode, { sourceName, c
|
|
|
16
16
|
moduleSpecifier: importPath,
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
-
// Get the variable declaration for controllers
|
|
20
|
-
const variableDeclaration = sourceFile.getVariableDeclaration(
|
|
19
|
+
// Get the variable declaration for controllers
|
|
20
|
+
const variableDeclaration = sourceFile.getVariableDeclaration('controllers');
|
|
21
21
|
if (variableDeclaration) {
|
|
22
22
|
const initializer = variableDeclaration.getInitializer();
|
|
23
23
|
if (initializer && initializer.getKind() === SyntaxKind.ObjectLiteralExpression) {
|
package/dist/new/newModule.mjs
CHANGED
|
@@ -22,15 +22,13 @@ export default async function newModule({ what, moduleNameWithOptionalSegment, d
|
|
|
22
22
|
const { config, log, apiDir, cwd } = await getProjectInfo();
|
|
23
23
|
let templates = config.templates;
|
|
24
24
|
const [segmentName, moduleName] = splitByLast(moduleNameWithOptionalSegment);
|
|
25
|
-
// replace c by controller, s by service,
|
|
25
|
+
// replace c by controller, s by service, everything else keeps the same
|
|
26
26
|
what = what.map((s) => {
|
|
27
27
|
switch (s) {
|
|
28
28
|
case 'c':
|
|
29
29
|
return 'controller';
|
|
30
30
|
case 's':
|
|
31
31
|
return 'service';
|
|
32
|
-
case 'w':
|
|
33
|
-
return 'worker';
|
|
34
32
|
default:
|
|
35
33
|
return s;
|
|
36
34
|
}
|
|
@@ -87,12 +85,12 @@ export default async function newModule({ what, moduleNameWithOptionalSegment, d
|
|
|
87
85
|
log.info(`Created ${chalkHighlightThing(fileName)} using ${chalkHighlightThing(`"${type}"`)} template for ${formatLoggedSegmentName(segmentName)}`);
|
|
88
86
|
}
|
|
89
87
|
}
|
|
90
|
-
if (type === 'controller'
|
|
88
|
+
if (type === 'controller') {
|
|
91
89
|
if (!sourceName) {
|
|
92
90
|
throw new Error(`The template for "${type}" does not provide a sourceName`);
|
|
93
91
|
}
|
|
94
92
|
if (!compiledName) {
|
|
95
|
-
throw new Error(
|
|
93
|
+
throw new Error(`The template for "${type}" does not provide a compiledName`);
|
|
96
94
|
}
|
|
97
95
|
const { routeFilePath } = segment;
|
|
98
96
|
const segmentSourceCode = await fs.readFile(routeFilePath, 'utf-8');
|
|
@@ -101,7 +99,6 @@ export default async function newModule({ what, moduleNameWithOptionalSegment, d
|
|
|
101
99
|
const newSegmentCode = await prettify(addClassToSegmentCode(segmentSourceCode, {
|
|
102
100
|
sourceName,
|
|
103
101
|
compiledName,
|
|
104
|
-
type,
|
|
105
102
|
importPath,
|
|
106
103
|
}), routeFilePath);
|
|
107
104
|
if (!dryRun) {
|
package/dist/new/newSegment.mjs
CHANGED
|
@@ -16,14 +16,11 @@ export default async function newSegment({ segmentName, overwrite, dryRun, }) {
|
|
|
16
16
|
export const runtime = 'edge';
|
|
17
17
|
|
|
18
18
|
const controllers = {};
|
|
19
|
-
const workers = {};
|
|
20
19
|
|
|
21
20
|
export type Controllers = typeof controllers;
|
|
22
|
-
export type Workers = typeof workers;
|
|
23
21
|
|
|
24
22
|
export const { GET, POST, PATCH, PUT, HEAD, OPTIONS, DELETE } = initVovk({
|
|
25
23
|
${segmentName ? ` segmentName: '${segmentName}',\n` : ''} emitSchema: true,
|
|
26
|
-
workers,
|
|
27
24
|
controllers,
|
|
28
25
|
});
|
|
29
26
|
`, absoluteSegmentRoutePath);
|
|
@@ -31,5 +28,6 @@ ${segmentName ? ` segmentName: '${segmentName}',\n` : ''} emitSchema: true,
|
|
|
31
28
|
await fs.mkdir(path.dirname(absoluteSegmentRoutePath), { recursive: true });
|
|
32
29
|
await fs.writeFile(absoluteSegmentRoutePath, code);
|
|
33
30
|
}
|
|
34
|
-
log.info(`${formatLoggedSegmentName(segmentName, { upperFirst: true })} created at ${absoluteSegmentRoutePath}
|
|
31
|
+
log.info(`${formatLoggedSegmentName(segmentName, { upperFirst: true })} created at ${absoluteSegmentRoutePath}.`);
|
|
32
|
+
log.info(`Run ${chalkHighlightThing(`npx vovk new service controller ${[segmentName, 'thing'].filter(Boolean).join('/')}`)} to create a new controller with a service at /modules/thing/ folder.`);
|
|
35
33
|
}
|
package/dist/types.d.mts
CHANGED
|
@@ -4,10 +4,10 @@ export type VovkEnv = {
|
|
|
4
4
|
PORT?: string;
|
|
5
5
|
VOVK_CLIENT_OUT_DIR?: string;
|
|
6
6
|
VOVK_SCHEMA_OUT_DIR?: string;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
VOVK_FETCHER_PATH?: string;
|
|
8
|
+
VOVK_VALIDATE_ON_CLIENT_PATH?: string;
|
|
9
|
+
VOVK_CREATE_RPC_PATH?: string;
|
|
9
10
|
VOVK_MODULES_DIR?: string;
|
|
10
|
-
VOVK_VALIDATION_LIBRARY?: string;
|
|
11
11
|
VOVK_ORIGIN?: string;
|
|
12
12
|
VOVK_ROOT_ENTRY?: string;
|
|
13
13
|
VOVK_API_ENTRY_POINT?: string;
|
|
@@ -21,10 +21,10 @@ export type VovkEnv = {
|
|
|
21
21
|
export type VovkConfig = {
|
|
22
22
|
clientOutDir?: string;
|
|
23
23
|
schemaOutDir?: string;
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
fetcherPath?: string;
|
|
25
|
+
validateOnClientPath?: string | null;
|
|
26
|
+
createRPCPath?: string;
|
|
26
27
|
modulesDir?: string;
|
|
27
|
-
validationLibrary?: string | null;
|
|
28
28
|
rootEntry?: string;
|
|
29
29
|
origin?: string;
|
|
30
30
|
rootSegmentModulesDirName?: string;
|
|
@@ -35,7 +35,6 @@ export type VovkConfig = {
|
|
|
35
35
|
templates?: {
|
|
36
36
|
service?: string;
|
|
37
37
|
controller?: string;
|
|
38
|
-
worker?: string;
|
|
39
38
|
[key: string]: string | undefined;
|
|
40
39
|
};
|
|
41
40
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vovk-cli",
|
|
3
|
-
"version": "0.0.1-draft.
|
|
3
|
+
"version": "0.0.1-draft.48",
|
|
4
4
|
"bin": {
|
|
5
5
|
"vovk": "./dist/index.mjs"
|
|
6
6
|
},
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
},
|
|
37
37
|
"homepage": "https://vovk.dev",
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"vovk": "^3.0.0-draft.
|
|
39
|
+
"vovk": "^3.0.0-draft.57"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@inquirer/prompts": "^7.
|
|
42
|
+
"@inquirer/prompts": "^7.3.1",
|
|
43
43
|
"@npmcli/package-json": "^6.1.1",
|
|
44
44
|
"chalk": "^5.4.1",
|
|
45
45
|
"chokidar": "^4.0.3",
|
package/templates/worker.ejs
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
<% var modulePascalName = _.upperFirst(_.camelCase(moduleName)); %>
|
|
2
|
-
<% var modulePascalNamePlural = pluralize(modulePascalName); %>
|
|
3
|
-
<% var workerName = modulePascalName + 'Worker'; %>
|
|
4
|
-
<% var compiledName = modulePascalName + 'WPC'; %>
|
|
5
|
-
---
|
|
6
|
-
dir: <%= getModuleDirName(segmentName, moduleName) %>
|
|
7
|
-
fileName: <%= workerName + '.ts' %>
|
|
8
|
-
sourceName: <%= workerName %>
|
|
9
|
-
compiledName: <%= compiledName %>
|
|
10
|
-
---
|
|
11
|
-
import { worker } from 'vovk';
|
|
12
|
-
|
|
13
|
-
@worker()
|
|
14
|
-
export default class <%= workerName %> {
|
|
15
|
-
static heavyComputation = () => {
|
|
16
|
-
return 'Hello, World';
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
static heavyComputationGenerator = function* () {
|
|
20
|
-
for(const str of ['Hello', 'World'] as const) {
|
|
21
|
-
yield str;
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
}
|