vovk-cli 0.0.1-draft.103 → 0.0.1-draft.105

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 (36) hide show
  1. package/client-templates/main/main.cjs.ejs +5 -6
  2. package/client-templates/main/main.d.cts.ejs +4 -4
  3. package/client-templates/module/module.d.mts.ejs +4 -4
  4. package/client-templates/module/module.mjs.ejs +5 -6
  5. package/client-templates/ts/index.ts.ejs +6 -8
  6. package/dist/dev/{diffSchema.d.mts → diffSegmentSchema.d.mts} +3 -3
  7. package/dist/dev/{diffSchema.mjs → diffSegmentSchema.mjs} +1 -1
  8. package/dist/dev/ensureSchemaFiles.mjs +22 -10
  9. package/dist/dev/index.mjs +29 -23
  10. package/dist/dev/isSegmentSchemaEmpty.d.mts +2 -0
  11. package/dist/dev/isSegmentSchemaEmpty.mjs +4 -0
  12. package/dist/dev/logDiffResult.d.mts +1 -1
  13. package/dist/dev/logDiffResult.mjs +1 -1
  14. package/dist/dev/writeConfigJson.d.mts +2 -0
  15. package/dist/dev/writeConfigJson.mjs +15 -0
  16. package/dist/dev/writeOneSegmentSchemaFile.d.mts +12 -0
  17. package/dist/dev/{writeOneSchemaFile.mjs → writeOneSegmentSchemaFile.mjs} +9 -6
  18. package/dist/generate/getClientTemplates.d.mts +2 -2
  19. package/dist/generate/index.d.mts +4 -4
  20. package/dist/generate/index.mjs +6 -6
  21. package/dist/getProjectInfo/getConfig.d.mts +2 -2
  22. package/dist/getProjectInfo/getConfig.mjs +7 -0
  23. package/dist/getProjectInfo/getUserConfig.d.mts +1 -1
  24. package/dist/getProjectInfo/index.d.mts +3 -3
  25. package/dist/getProjectInfo/index.mjs +2 -2
  26. package/dist/index.d.mts +0 -2
  27. package/dist/index.mjs +5 -5
  28. package/dist/locateSegments.d.mts +1 -1
  29. package/dist/new/render.d.mts +2 -1
  30. package/dist/new/render.mjs +0 -8
  31. package/dist/types.d.mts +1 -53
  32. package/dist/utils/debounceWithArgs.d.mts +1 -1
  33. package/package.json +2 -2
  34. package/dist/dev/isSchemaEmpty.d.mts +0 -2
  35. package/dist/dev/isSchemaEmpty.mjs +0 -4
  36. package/dist/dev/writeOneSchemaFile.d.mts +0 -12
@@ -1,14 +1,13 @@
1
1
  <%- `// auto-generated ${new Date().toISOString()}\n/* eslint-disable */` %>
2
2
  const { default: fetcher } = require('<%= t.imports.fetcher %>');
3
3
  const { default: createRPC } = require('<%= t.imports.createRPC %>');
4
- const schema = require('<%= t.imports.schema %>');
4
+ const fullSchema = require('<%= t.imports.fullSchema %>');
5
5
  const { default: validateOnClient = null } = <%- t.imports.validateOnClient ? `require('${t.imports.validateOnClient}')` : '{}'%>;
6
6
  const apiRoot = '<%= t.apiRoot %>';
7
- <% t.segments.forEach((segment) => {
8
- Object.keys(t.fullSchema[segment.segmentName].controllers).forEach((key) => { %>
9
- exports.<%= key %> = createRPC(
10
- schema['<%= segment.segmentName %>'].controllers.<%= key %>,
11
- '<%= segment.segmentName %>',
7
+ <% Object.values(t.fullSchema.segments).forEach((segment) => {
8
+ Object.keys(segment.controllers).forEach((controllerName) => { %>
9
+ exports.<%= controllerName %> = createRPC(
10
+ fullSchema, '<%= segment.segmentName %>', '<%= controllerName %>',
12
11
  { fetcher, validateOnClient, defaultOptions: { apiRoot } }
13
12
  );
14
13
  <% })
@@ -3,12 +3,12 @@
3
3
  import type { VovkClientFetcher } from 'vovk';
4
4
  import type fetcher from '<%= t.imports.fetcher %>';
5
5
  import type createRPC from '<%= t.imports.createRPC %>';
6
- <% t.segments.forEach((segment, i) => { if(Object.keys(t.fullSchema[segment.segmentName].controllers).length) { %>
6
+ <% Object.values(t.fullSchema.segments).forEach((segment, i) => { if(Object.keys(segment.controllers).length) { %>
7
7
  import type { Controllers as Controllers<%= i %> } from "<%= segment.segmentImportPath %>";
8
8
  <% }}) %>
9
9
  type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
10
- <% t.segments.forEach((segment, i) => {
11
- Object.keys(t.fullSchema[segment.segmentName].controllers).forEach((key) => { %>
12
- export const <%= key %>: ReturnType<typeof createRPC<Controllers<%= i %>["<%= key %>"], Options>>;
10
+ <% Object.values(t.fullSchema.segments).forEach((segment, i) => {
11
+ Object.keys(segment.controllers).forEach((controllerName) => { %>
12
+ export const <%= controllerName %>: ReturnType<typeof createRPC<Controllers<%= i %>["<%= controllerName %>"], Options>>;
13
13
  <% })
14
14
  }) %>
@@ -3,12 +3,12 @@
3
3
  import type { VovkClientFetcher } from 'vovk';
4
4
  import type fetcher from '<%= t.imports.module.fetcher %>';
5
5
  import type createRPC from '<%= t.imports.module.createRPC %>';
6
- <% t.segments.forEach((segment, i) => { if(Object.keys(t.fullSchema[segment.segmentName].controllers).length) { %>
6
+ <% Object.values(t.fullSchema.segments).forEach((segment, i) => { if(Object.keys(segment.controllers).length) { %>
7
7
  import type { Controllers as Controllers<%= i %> } from "<%= segment.segmentImportPath %>";
8
8
  <% }}) %>
9
9
  type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
10
- <% t.segments.forEach((segment, i) => {
11
- Object.keys(t.fullSchema[segment.segmentName].controllers).forEach((key) => { %>
12
- export const <%= key %>: ReturnType<typeof createRPC<Controllers<%= i %>["<%= key %>"], Options>>;
10
+ <% Object.values(t.fullSchema.segments).forEach((segment, i) => {
11
+ Object.keys(segment.controllers).forEach((controllerName) => { %>
12
+ export const <%= controllerName %>: ReturnType<typeof createRPC<Controllers<%= i %>["<%= controllerName %>"], Options>>;
13
13
  <% })
14
14
  }) %>
@@ -1,7 +1,7 @@
1
1
  <%- `// auto-generated ${new Date().toISOString()}\n/* eslint-disable */` %>
2
2
  import fetcherImport from '<%= t.imports.module.fetcher %>';
3
3
  import createRPCImport from '<%= t.imports.module.createRPC %>';
4
- import schema from '<%= t.imports.module.schema %>';
4
+ import fullSchema from '<%= t.imports.module.fullSchema %>';
5
5
  <% if (t.imports.module.validateOnClient) { %>
6
6
  import validateOnClientImport from '<%= t.imports.module.validateOnClient %>';
7
7
  const validateOnClient = validateOnClientImport.default || validateOnClientImport;
@@ -11,11 +11,10 @@ const validateOnClient = undefined;
11
11
  const apiRoot = '<%= t.apiRoot %>';
12
12
  const fetcher = fetcherImport.default || fetcherImport;
13
13
  const createRPC = createRPCImport.default || createRPCImport;
14
- <% t.segments.forEach((segment, i) => {
15
- Object.keys(t.fullSchema[segment.segmentName].controllers).forEach((key) => { %>
16
- export const <%= key %> = createRPC(
17
- schema['<%= segment.segmentName %>'].controllers.<%= key %>,
18
- '<%= segment.segmentName %>',
14
+ <% Object.values(t.fullSchema.segments).forEach((segment, i) => {
15
+ Object.keys(segment.controllers).forEach((controllerName) => { %>
16
+ export const <%= controllerName %> = createRPC(
17
+ fullSchema, '<%= segment.segmentName %>', '<%= controllerName %>',
19
18
  { fetcher, validateOnClient, defaultOptions: { apiRoot } }
20
19
  );
21
20
  <%
@@ -2,8 +2,8 @@
2
2
  import type { VovkClientFetcher } from 'vovk';
3
3
  import fetcher from '<%= t.imports.fetcher %>';
4
4
  import createRPC from '<%= t.imports.createRPC %>';
5
- import schema from '<%= t.imports.schema %>';
6
- <% t.segments.forEach((segment, i) => { if(Object.keys(t.fullSchema[segment.segmentName].controllers).length) { %>
5
+ import fullSchema from '<%= t.imports.fullSchema %>';
6
+ <% Object.values(t.fullSchema.segments).forEach((segment, i) => { if(Object.keys(segment.controllers).length) { %>
7
7
  import type { Controllers as Controllers<%= i %> } from "<%= segment.segmentImportPath %>";
8
8
  <% }}) %>
9
9
  <% if (t.imports.validateOnClient) { %>
@@ -13,12 +13,10 @@ const validateOnClient = undefined;
13
13
  <% } %>
14
14
  type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
15
15
  const apiRoot = '<%= t.apiRoot %>';
16
-
17
- <% t.segments.forEach((segment, i) => { %>
18
- <% Object.keys(t.fullSchema[segment.segmentName].controllers).forEach((key) => { %>
19
- export const <%= key %> = createRPC<Controllers<%= i %>["<%= key %>"], Options>(
20
- schema['<%= segment.segmentName %>'].controllers.<%= key %>,
21
- '<%= segment.segmentName %>',
16
+ <% Object.values(t.fullSchema.segments).forEach((segment, i) => { %>
17
+ <% Object.keys(segment.controllers).forEach((controllerName) => { %>
18
+ export const <%= controllerName %> = createRPC<Controllers<%= i %>["<%= controllerName %>"], Options>(
19
+ fullSchema, '<%= segment.segmentName %>', '<%= controllerName %>',
22
20
  { fetcher, validateOnClient, defaultOptions: { apiRoot } }
23
21
  );
24
22
  <% }) %>
@@ -1,4 +1,4 @@
1
- import type { VovkControllerSchema, VovkSchema } from 'vovk';
1
+ import type { VovkControllerSchema, VovkSegmentSchema } from 'vovk';
2
2
  interface HandlersDiff {
3
3
  nameOfClass: string;
4
4
  added: string[];
@@ -14,7 +14,7 @@ export interface DiffResult {
14
14
  controllers: ControllersDiff;
15
15
  }
16
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;
17
+ export declare function diffControllers<T extends VovkSegmentSchema['controllers']>(oldItems: T, newItems: T): ControllersDiff;
18
18
  /**
19
19
  example output:
20
20
  {
@@ -32,5 +32,5 @@ example output:
32
32
  }
33
33
  }
34
34
  */
35
- export default function diffSchema(oldJson: VovkSchema, newJson: VovkSchema): DiffResult;
35
+ export default function diffSegmentSchema(oldJson: VovkSegmentSchema, newJson: VovkSegmentSchema): DiffResult;
36
36
  export {};
@@ -57,7 +57,7 @@ example output:
57
57
  }
58
58
  }
59
59
  */
60
- export default function diffSchema(oldJson, newJson) {
60
+ export default function diffSegmentSchema(oldJson, newJson) {
61
61
  return {
62
62
  controllers: diffControllers(oldJson.controllers ?? {}, newJson.controllers ?? {}),
63
63
  };
@@ -1,32 +1,43 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import debounce from 'lodash/debounce.js';
4
- import writeOneSchemaFile, { JSON_DIR_NAME, ROOT_SEGMENT_SCHEMA_NAME } from './writeOneSchemaFile.mjs';
4
+ import writeOneSchemaFile, { SEGMENTS_SCHEMA_DIR_NAME, ROOT_SEGMENT_SCHEMA_NAME, } from './writeOneSegmentSchemaFile.mjs';
5
5
  import formatLoggedSegmentName from '../utils/formatLoggedSegmentName.mjs';
6
+ import writeConfigJson from './writeConfigJson.mjs';
6
7
  /**
7
8
  * Ensure that the schema files are created to avoid any import errors.
8
9
  */
9
10
  export default async function ensureSchemaFiles(projectInfo, schemaOutAbsolutePath, segmentNames) {
10
11
  const now = Date.now();
11
12
  let hasChanged = false;
12
- const schemaJsonOutAbsolutePath = path.join(schemaOutAbsolutePath, JSON_DIR_NAME);
13
+ const schemaJsonOutAbsolutePath = path.join(schemaOutAbsolutePath, SEGMENTS_SCHEMA_DIR_NAME);
13
14
  const jsContent = `// auto-generated ${new Date().toISOString()}
15
+ module.exports.config = require('./config.json');
16
+ module.exports.segments = {
14
17
  ${segmentNames
15
18
  .map((segmentName) => {
16
- return `module.exports['${segmentName}'] = require('./${JSON_DIR_NAME}/${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json');`;
19
+ return ` '${segmentName}': require('./${SEGMENTS_SCHEMA_DIR_NAME}/${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json'),`;
17
20
  })
18
- .join('\n')}`;
21
+ .join('\n')}
22
+ }`;
19
23
  const dTsContent = `// auto-generated ${new Date().toISOString()}
20
- import type { VovkSchema } from 'vovk';
24
+ import type { VovkSegmentSchema, VovkStrictConfig } from 'vovk';
21
25
  declare const fullSchema: {
22
- ${segmentNames.map((segmentName) => ` '${segmentName}': VovkSchema;`).join('\n')}
26
+ config: Partial<VovkStrictConfig>;
27
+ segments: {
28
+ ${segmentNames.map((segmentName) => ` '${segmentName}': VovkSegmentSchema;`).join('\n')}
29
+ };
23
30
  };
24
31
  export default fullSchema;`;
25
32
  const tsContent = `// auto-generated ${new Date().toISOString()}
26
- import type { VovkSchema } from 'vovk';
27
- ${segmentNames.map((segmentName, i) => `import segment${i} from './${JSON_DIR_NAME}/${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json';`).join('\n')}
33
+ import type { VovkSegmentSchema, VovkStrictConfig } from 'vovk';
34
+ import config from './config.json';
35
+ ${segmentNames.map((segmentName, i) => `import segment${i} from './${SEGMENTS_SCHEMA_DIR_NAME}/${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json';`).join('\n')}
28
36
  const fullSchema = {
29
- ${segmentNames.map((segmentName, i) => ` '${segmentName}': segment${i} as unknown as VovkSchema,`).join('\n')}
37
+ config: config as unknown as Partial<VovkStrictConfig>,
38
+ segments: {
39
+ ${segmentNames.map((segmentName, i) => ` '${segmentName}': segment${i} as unknown as VovkSegmentSchema,`).join('\n')}
40
+ }
30
41
  };
31
42
  export default fullSchema;`;
32
43
  const jsAbsolutePath = path.join(schemaOutAbsolutePath, 'main.cjs');
@@ -36,11 +47,12 @@ export default fullSchema;`;
36
47
  const existingDTs = await fs.readFile(dTsAbsolutePath, 'utf-8').catch(() => null);
37
48
  const existingTs = await fs.readFile(tsAbsolutePath, 'utf-8').catch(() => null);
38
49
  await fs.mkdir(schemaJsonOutAbsolutePath, { recursive: true });
50
+ await writeConfigJson(schemaOutAbsolutePath, projectInfo);
39
51
  // Create JSON files (if not exist) with name [segmentName].json (where segmentName can include /, which means the folder structure can be nested)
40
52
  await Promise.all(segmentNames.map(async (segmentName) => {
41
53
  const { isCreated } = await writeOneSchemaFile({
42
54
  schemaOutAbsolutePath,
43
- schema: {
55
+ segmentSchema: {
44
56
  emitSchema: false,
45
57
  segmentName,
46
58
  controllers: {},
@@ -7,7 +7,7 @@ import capitalize from 'lodash/capitalize.js';
7
7
  import debounce from 'lodash/debounce.js';
8
8
  import once from 'lodash/once.js';
9
9
  import { debouncedEnsureSchemaFiles } from './ensureSchemaFiles.mjs';
10
- import writeOneSchemaFile from './writeOneSchemaFile.mjs';
10
+ import writeOneSegmentSchemaFile from './writeOneSegmentSchemaFile.mjs';
11
11
  import logDiffResult from './logDiffResult.mjs';
12
12
  import ensureClient from '../generate/ensureClient.mjs';
13
13
  import getProjectInfo from '../getProjectInfo/index.mjs';
@@ -15,11 +15,15 @@ import generate from '../generate/index.mjs';
15
15
  import locateSegments from '../locateSegments.mjs';
16
16
  import debounceWithArgs from '../utils/debounceWithArgs.mjs';
17
17
  import formatLoggedSegmentName from '../utils/formatLoggedSegmentName.mjs';
18
- import isSchemaEmpty from './isSchemaEmpty.mjs';
18
+ import isSegmentSchemaEmpty from './isSegmentSchemaEmpty.mjs';
19
+ import writeConfigJson from './writeConfigJson.mjs';
19
20
  export class VovkDev {
20
21
  #projectInfo;
21
22
  #segments = [];
22
- #schemas = {};
23
+ #fullSchema = {
24
+ segments: {},
25
+ config: {},
26
+ };
23
27
  #isWatching = false;
24
28
  #modulesWatcher = null;
25
29
  #segmentWatcher = null;
@@ -145,6 +149,7 @@ export class VovkDev {
145
149
  new Promise((resolve) => this.#watchModules(() => resolve(0))),
146
150
  new Promise((resolve) => this.#watchSegments(() => resolve(0))),
147
151
  ]);
152
+ const schemaOutAbsolutePath = path.join(cwd, this.#projectInfo.config.schemaOutDir);
148
153
  if (isInitial) {
149
154
  callback();
150
155
  }
@@ -152,6 +157,7 @@ export class VovkDev {
152
157
  log.info('Config file has been updated');
153
158
  this.#generate();
154
159
  }
160
+ await writeConfigJson(schemaOutAbsolutePath, this.#projectInfo);
155
161
  isInitial = false;
156
162
  }, 1000);
157
163
  chokidar
@@ -203,11 +209,11 @@ export class VovkDev {
203
209
  const importRegex = /import\s*{[^}]*\b(get|post|put|del|head|options)\b[^}]*}\s*from\s*['"]vovk['"]/;
204
210
  if (importRegex.test(code) && namesOfClasses.length) {
205
211
  const affectedSegments = this.#segments.filter((s) => {
206
- const schema = this.#schemas[s.segmentName];
207
- if (!schema)
212
+ const segmentSchema = this.#fullSchema.segments[s.segmentName];
213
+ if (!segmentSchema)
208
214
  return false;
209
- const controllersByOriginalName = keyBy(schema.controllers, 'originalControllerName');
210
- return namesOfClasses.some((name) => schema.controllers[name] || controllersByOriginalName[name]);
215
+ const controllersByOriginalName = keyBy(segmentSchema.controllers, 'originalControllerName');
216
+ return namesOfClasses.some((name) => segmentSchema.controllers[name] || controllersByOriginalName[name]);
211
217
  });
212
218
  if (affectedSegments.length) {
213
219
  log.debug(`A file with controller ${namesOfClasses.join(', ')} have been modified at path "${filePath}". Segment(s) affected: ${JSON.stringify(affectedSegments.map((s) => s.segmentName))}`);
@@ -237,14 +243,14 @@ export class VovkDev {
237
243
  log.warn(`Schema request to ${formatLoggedSegmentName(segmentName)} failed with status code ${resp.status} but expected 200.${probableCause ? ` Probable cause: ${probableCause}` : ''}`);
238
244
  return { isError: true };
239
245
  }
240
- let schema = null;
246
+ let segmentSchema = null;
241
247
  try {
242
- ({ schema } = (await resp.json()));
248
+ ({ schema: segmentSchema } = (await resp.json()));
243
249
  }
244
250
  catch (error) {
245
251
  log.error(`Error parsing schema for ${formatLoggedSegmentName(segmentName)}: ${error.message}`);
246
252
  }
247
- await this.#handleSchema(schema);
253
+ await this.#handleSegmentSchema(segmentName, segmentSchema);
248
254
  }
249
255
  catch (error) {
250
256
  log.error(`Error requesting schema for ${formatLoggedSegmentName(segmentName)} at ${endpoint}: ${error.message}`);
@@ -252,26 +258,26 @@ export class VovkDev {
252
258
  }
253
259
  return { isError: false };
254
260
  }, 500);
255
- #generate = debounce(() => generate({ projectInfo: this.#projectInfo, segments: this.#segments, segmentsSchema: this.#schemas }).then(this.#onFirstTimeGenerate), 1000);
256
- async #handleSchema(schema) {
261
+ #generate = debounce(() => generate({ projectInfo: this.#projectInfo, segments: this.#segments, fullSchema: this.#fullSchema }).then(this.#onFirstTimeGenerate), 1000);
262
+ async #handleSegmentSchema(segmentName, segmentSchema) {
257
263
  const { log, config, cwd } = this.#projectInfo;
258
- if (!schema) {
259
- log.warn('Segment schema is null');
264
+ if (!segmentSchema) {
265
+ log.warn(`${formatLoggedSegmentName(segmentName)} schema is null`);
260
266
  return;
261
267
  }
262
- log.debug(`Handling received schema from ${formatLoggedSegmentName(schema.segmentName)}`);
268
+ log.debug(`Handling received schema from ${formatLoggedSegmentName(segmentName)}`);
263
269
  const schemaOutAbsolutePath = path.join(cwd, config.schemaOutDir);
264
- const segment = this.#segments.find((s) => s.segmentName === schema.segmentName);
270
+ const segment = this.#segments.find((s) => s.segmentName === segmentName);
265
271
  if (!segment) {
266
- log.warn(`Segment "${schema.segmentName}" not found`);
272
+ log.warn(`${formatLoggedSegmentName(segmentName)} not found`);
267
273
  return;
268
274
  }
269
- this.#schemas[schema.segmentName] = schema;
270
- if (schema.emitSchema) {
275
+ this.#fullSchema.segments[segmentName] = segmentSchema;
276
+ if (segmentSchema.emitSchema) {
271
277
  const now = Date.now();
272
- const { diffResult } = await writeOneSchemaFile({
278
+ const { diffResult } = await writeOneSegmentSchemaFile({
273
279
  schemaOutAbsolutePath,
274
- schema,
280
+ segmentSchema,
275
281
  skipIfExists: false,
276
282
  });
277
283
  const timeTook = Date.now() - now;
@@ -280,10 +286,10 @@ export class VovkDev {
280
286
  log.info(`Schema for ${formatLoggedSegmentName(segment.segmentName)} has been updated in ${timeTook}ms`);
281
287
  }
282
288
  }
283
- else if (schema && !isSchemaEmpty(schema)) {
289
+ else if (segmentSchema && !isSegmentSchemaEmpty(segmentSchema)) {
284
290
  log.error(`Non-empty schema provided for ${formatLoggedSegmentName(segment.segmentName)} but "emitSchema" is false`);
285
291
  }
286
- if (this.#segments.every((s) => this.#schemas[s.segmentName])) {
292
+ if (this.#segments.every((s) => this.#fullSchema.segments[s.segmentName])) {
287
293
  log.debug(`All segments with "emitSchema" have schema.`);
288
294
  this.#generate();
289
295
  }
@@ -0,0 +1,2 @@
1
+ import type { VovkSegmentSchema } from 'vovk';
2
+ export default function isSegmentSchemaEmpty(segmentSchema: VovkSegmentSchema): boolean;
@@ -0,0 +1,4 @@
1
+ import isEmpty from 'lodash/isEmpty.js';
2
+ export default function isSegmentSchemaEmpty(segmentSchema) {
3
+ return isEmpty(segmentSchema.controllers);
4
+ }
@@ -1,3 +1,3 @@
1
- import type { DiffResult } from './diffSchema.mjs';
1
+ import type { DiffResult } from './diffSegmentSchema.mjs';
2
2
  import type { ProjectInfo } from '../getProjectInfo/index.mjs';
3
3
  export default function logDiffResult(segmentName: string, diffResult: DiffResult, projectInfo: ProjectInfo): void;
@@ -20,7 +20,7 @@ export default function logDiffResult(segmentName, diffResult, projectInfo) {
20
20
  diffNormalized.push({ what: 'controllerHandler', type: 'changed', name: `${handler.nameOfClass}.${name}` });
21
21
  });
22
22
  });
23
- const LIMIT = diffNormalized.length < 12 ? diffNormalized.length : 10;
23
+ const LIMIT = diffNormalized.length < 17 ? diffNormalized.length : 15;
24
24
  const addedText = chalk.green('added');
25
25
  const removedText = chalk.red('removed');
26
26
  const changedText = chalk.cyan('changed');
@@ -0,0 +1,2 @@
1
+ import type { ProjectInfo } from '../getProjectInfo/index.mjs';
2
+ export default function writeConfigJson(schemaOutAbsolutePath: string, projectInfo: ProjectInfo | null): Promise<void>;
@@ -0,0 +1,15 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import pick from 'lodash/pick.js';
4
+ export default async function writeConfigJson(schemaOutAbsolutePath, projectInfo) {
5
+ const configJsonPath = path.join(schemaOutAbsolutePath, 'config.json');
6
+ const configStr = JSON.stringify(projectInfo ? pick(projectInfo.config, projectInfo.config.emitConfig) : {}, null, 2);
7
+ const existingStr = await fs.readFile(configJsonPath, 'utf-8').catch(() => null);
8
+ if (existingStr !== configStr) {
9
+ await fs.writeFile(configJsonPath, configStr);
10
+ projectInfo?.log.info(`config.json written to ${configJsonPath}`);
11
+ }
12
+ else {
13
+ projectInfo?.log.debug(`config.json is up to date at ${configJsonPath}`);
14
+ }
15
+ }
@@ -0,0 +1,12 @@
1
+ import type { VovkSegmentSchema } from 'vovk';
2
+ import { type DiffResult } from './diffSegmentSchema.mjs';
3
+ export declare const ROOT_SEGMENT_SCHEMA_NAME = "_root";
4
+ export declare const SEGMENTS_SCHEMA_DIR_NAME = "segments";
5
+ export default function writeOneSegmentSchemaFile({ schemaOutAbsolutePath, segmentSchema, skipIfExists, }: {
6
+ schemaOutAbsolutePath: string;
7
+ segmentSchema: VovkSegmentSchema;
8
+ skipIfExists?: boolean;
9
+ }): Promise<{
10
+ isCreated: boolean;
11
+ diffResult: DiffResult | null;
12
+ }>;
@@ -1,11 +1,11 @@
1
1
  import path from 'node:path';
2
2
  import fs from 'node:fs/promises';
3
- import diffSchema from './diffSchema.mjs';
3
+ import diffSegmentSchema from './diffSegmentSchema.mjs';
4
4
  import getFileSystemEntryType from '../utils/getFileSystemEntryType.mjs';
5
5
  export const ROOT_SEGMENT_SCHEMA_NAME = '_root';
6
- export const JSON_DIR_NAME = 'json';
7
- export default async function writeOneSchemaFile({ schemaOutAbsolutePath, schema, skipIfExists = false, }) {
8
- const segmentPath = path.join(schemaOutAbsolutePath, JSON_DIR_NAME, `${schema.segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json`);
6
+ export const SEGMENTS_SCHEMA_DIR_NAME = 'segments';
7
+ export default async function writeOneSegmentSchemaFile({ schemaOutAbsolutePath, segmentSchema, skipIfExists = false, }) {
8
+ const segmentPath = path.join(schemaOutAbsolutePath, SEGMENTS_SCHEMA_DIR_NAME, `${segmentSchema.segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json`);
9
9
  if (skipIfExists && (await getFileSystemEntryType(segmentPath))) {
10
10
  try {
11
11
  await fs.stat(segmentPath);
@@ -16,14 +16,17 @@ export default async function writeOneSchemaFile({ schemaOutAbsolutePath, schema
16
16
  }
17
17
  }
18
18
  await fs.mkdir(path.dirname(segmentPath), { recursive: true });
19
- const schemaStr = JSON.stringify(schema, null, 2);
19
+ const schemaStr = JSON.stringify(segmentSchema, null, 2);
20
20
  const existing = await fs.readFile(segmentPath, 'utf-8').catch(() => null);
21
21
  if (existing === schemaStr) {
22
22
  return { isCreated: false, diffResult: null };
23
23
  }
24
24
  await fs.writeFile(segmentPath, schemaStr);
25
25
  if (existing) {
26
- return { isCreated: false, diffResult: diffSchema(JSON.parse(existing), schema) };
26
+ return {
27
+ isCreated: false,
28
+ diffResult: diffSegmentSchema(JSON.parse(existing), segmentSchema),
29
+ };
27
30
  }
28
31
  return { isCreated: true, diffResult: null };
29
32
  }
@@ -1,9 +1,9 @@
1
- import type { VovkStrictConfig } from '../types.mjs';
1
+ import type { VovkStrictConfig } from 'vovk';
2
2
  interface ClientTemplate {
3
3
  templateName: string;
4
4
  templatePath: string;
5
5
  outPath: string;
6
- fullSchema?: string | boolean;
6
+ emitFullSchema?: string | boolean;
7
7
  }
8
8
  export default function getClientTemplates({ config, cwd, generateFrom, }: {
9
9
  config: VovkStrictConfig;
@@ -1,13 +1,13 @@
1
- import type { VovkSchema } from 'vovk';
1
+ import type { VovkFullSchema } from 'vovk';
2
2
  import type { ProjectInfo } from '../getProjectInfo/index.mjs';
3
3
  import type { Segment } from '../locateSegments.mjs';
4
4
  import { GenerateOptions } from '../types.mjs';
5
- export default function generate({ projectInfo, segments, segmentsSchema, forceNothingWrittenLog, templates, prettify: prettifyClient, fullSchema, }: {
5
+ export default function generate({ projectInfo, segments, forceNothingWrittenLog, templates, prettify: prettifyClient, fullSchema, emitFullSchema, }: {
6
6
  projectInfo: ProjectInfo;
7
7
  segments: Segment[];
8
- segmentsSchema: Record<string, VovkSchema>;
9
8
  forceNothingWrittenLog?: boolean;
10
- } & Pick<GenerateOptions, 'templates' | 'prettify' | 'fullSchema'>): Promise<{
9
+ fullSchema: VovkFullSchema;
10
+ } & Pick<GenerateOptions, 'templates' | 'prettify' | 'emitFullSchema'>): Promise<{
11
11
  written: boolean;
12
12
  path: string;
13
13
  }>;
@@ -6,7 +6,8 @@ import prettify from '../utils/prettify.mjs';
6
6
  import getClientTemplates from './getClientTemplates.mjs';
7
7
  import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
8
8
  import uniq from 'lodash/uniq.js';
9
- export default async function generate({ projectInfo, segments, segmentsSchema, forceNothingWrittenLog, templates, prettify: prettifyClient, fullSchema, }) {
9
+ export default async function generate({ projectInfo, segments, forceNothingWrittenLog, templates, prettify: prettifyClient, fullSchema, emitFullSchema, }) {
10
+ const segmentsSchema = fullSchema.segments;
10
11
  const generateFrom = templates ?? projectInfo.config.generateFrom;
11
12
  const noClient = templates?.[0] === 'none';
12
13
  const { config, cwd, log, clientImports, apiRoot } = projectInfo;
@@ -26,8 +27,7 @@ export default async function generate({ projectInfo, segments, segmentsSchema,
26
27
  const t = {
27
28
  apiRoot,
28
29
  imports: clientImports,
29
- segments,
30
- fullSchema: segmentsSchema,
30
+ fullSchema,
31
31
  };
32
32
  // Process each template in parallel
33
33
  const processedTemplates = noClient
@@ -59,11 +59,11 @@ export default async function generate({ projectInfo, segments, segmentsSchema,
59
59
  const usedTemplateNames = uniq(processedTemplates.filter(({ needsWriting }) => needsWriting).map(({ templateName }) => templateName));
60
60
  let fullSchemaNames = [];
61
61
  const DEFAULT_NAME = 'full-schema.json';
62
- if (fullSchema) {
62
+ if (emitFullSchema) {
63
63
  fullSchemaNames.push(typeof fullSchema === 'string' ? fullSchema : DEFAULT_NAME);
64
64
  fullSchemaNames.push(...templateFiles
65
- .filter(({ fullSchema }) => fullSchema)
66
- .map(({ fullSchema }) => (typeof fullSchema === 'string' ? fullSchema : DEFAULT_NAME)));
65
+ .filter(({ emitFullSchema }) => emitFullSchema)
66
+ .map(({ emitFullSchema }) => (typeof emitFullSchema === 'string' ? emitFullSchema : DEFAULT_NAME)));
67
67
  }
68
68
  fullSchemaNames = uniq(fullSchemaNames);
69
69
  if (fullSchemaNames.length || usedTemplateNames.length > 0) {
@@ -1,4 +1,4 @@
1
- import type { VovkStrictConfig } from '../types.mjs';
1
+ import type { VovkStrictConfig } from 'vovk';
2
2
  export default function getConfig({ clientOutDir, cwd }: {
3
3
  clientOutDir?: string;
4
4
  cwd: string;
@@ -6,6 +6,6 @@ export default function getConfig({ clientOutDir, cwd }: {
6
6
  config: VovkStrictConfig;
7
7
  srcRoot: string;
8
8
  configAbsolutePaths: string[];
9
- userConfig: import("../types.mjs").VovkConfig | null;
9
+ userConfig: import("vovk").VovkConfig | null;
10
10
  error: Error | undefined;
11
11
  }>;
@@ -10,6 +10,7 @@ export default async function getConfig({ clientOutDir, cwd }) {
10
10
  const createRPCImport = env.VOVK_CREATE_RPC_PATH ?? conf.createRPCImport ?? 'vovk/dist/client/createRPC.js';
11
11
  const defaultClientTemplates = ['ts', 'module', 'main'];
12
12
  const config = {
13
+ emitConfig: [],
13
14
  modulesDir: env.VOVK_MODULES_DIR ?? conf.modulesDir ?? './' + [srcRoot, 'modules'].filter(Boolean).join('/'),
14
15
  validateOnClientImport: typeof validateOnClientImport === 'string' ? [validateOnClientImport] : validateOnClientImport,
15
16
  fetcherImport: typeof fetcherImport === 'string' ? [fetcherImport] : fetcherImport,
@@ -31,5 +32,11 @@ export default async function getConfig({ clientOutDir, cwd }) {
31
32
  ...conf.templates,
32
33
  },
33
34
  };
35
+ if (typeof conf.emitConfig === 'undefined' || conf.emitConfig === true) {
36
+ config.emitConfig = Object.keys(config);
37
+ }
38
+ else if (Array.isArray(conf.emitConfig)) {
39
+ config.emitConfig = conf.emitConfig;
40
+ }
34
41
  return { config, srcRoot, configAbsolutePaths, userConfig, error };
35
42
  }
@@ -1,4 +1,4 @@
1
- import type { VovkConfig } from '../types.mjs';
1
+ import type { VovkConfig } from 'vovk';
2
2
  declare function getUserConfig({ cwd, }: {
3
3
  cwd: string;
4
4
  }): Promise<{
@@ -9,14 +9,14 @@ export default function getProjectInfo({ port: givenPort, clientOutDir, cwd, }?:
9
9
  apiRoot: string;
10
10
  apiDir: string;
11
11
  srcRoot: string;
12
- config: import("../types.mjs").VovkStrictConfig;
12
+ config: import("vovk").VovkStrictConfig;
13
13
  clientImports: {
14
- schema: string;
14
+ fullSchema: string;
15
15
  fetcher: string;
16
16
  createRPC: string;
17
17
  validateOnClient: string | null;
18
18
  module: {
19
- schema: string;
19
+ fullSchema: string;
20
20
  fetcher: string;
21
21
  createRPC: string;
22
22
  validateOnClient: string | null;
@@ -19,12 +19,12 @@ export default async function getProjectInfo({ port: givenPort, clientOutDir, cw
19
19
  }
20
20
  const getImportPath = (p) => (p.startsWith('.') ? path.relative(config.clientOutDir, p) : p);
21
21
  const clientImports = {
22
- schema: schemaOutImportPath,
22
+ fullSchema: schemaOutImportPath,
23
23
  fetcher: getImportPath(config.fetcherImport[0]),
24
24
  createRPC: getImportPath(config.createRPCImport[0]),
25
25
  validateOnClient: config.validateOnClientImport ? getImportPath(config.validateOnClientImport[0]) : null,
26
26
  module: {
27
- schema: schemaOutImportPath,
27
+ fullSchema: schemaOutImportPath,
28
28
  fetcher: getImportPath(config.fetcherImport[1] ?? config.fetcherImport[0]),
29
29
  createRPC: getImportPath(config.createRPCImport[1] ?? config.createRPCImport[0]),
30
30
  validateOnClient: config.validateOnClientImport
package/dist/index.d.mts CHANGED
@@ -1,4 +1,2 @@
1
1
  #!/usr/bin/env node
2
2
  import 'dotenv/config';
3
- import type { VovkConfig, VovkEnv } from './types.mjs';
4
- export type { VovkConfig, VovkEnv };
package/dist/index.mjs CHANGED
@@ -75,24 +75,24 @@ program
75
75
  .description('Generate RPC client from schema')
76
76
  .option('--out, --client-out-dir <path>', 'path to output directory')
77
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')
78
+ .option('--emit-full-schema, --full-schema [fileName]', 'generate client with full schema')
79
79
  .option('--prettify', 'prettify output files')
80
80
  .action(async (options) => {
81
- const { clientOutDir, templates, prettify, fullSchema } = options;
81
+ const { clientOutDir, templates, prettify, emitFullSchema } = options;
82
82
  const projectInfo = await getProjectInfo({ clientOutDir });
83
83
  const { cwd, config, apiDir } = projectInfo;
84
84
  const segments = await locateSegments({ dir: apiDir, config });
85
85
  const schemaOutAbsolutePath = path.join(cwd, config.schemaOutDir);
86
86
  const schemaImportUrl = pathToFileURL(path.join(schemaOutAbsolutePath, 'main.cjs')).href;
87
- const { default: segmentsSchema } = (await import(schemaImportUrl));
87
+ const { default: fullSchema } = (await import(schemaImportUrl));
88
88
  await generate({
89
89
  projectInfo,
90
90
  segments,
91
- segmentsSchema,
91
+ fullSchema,
92
92
  templates,
93
93
  prettify,
94
- fullSchema,
95
94
  forceNothingWrittenLog: true,
95
+ emitFullSchema,
96
96
  });
97
97
  });
98
98
  program
@@ -1,4 +1,4 @@
1
- import type { VovkConfig } from './types.mjs';
1
+ import type { VovkConfig } from 'vovk';
2
2
  export type Segment = {
3
3
  routeFilePath: string;
4
4
  segmentName: string;
@@ -1,4 +1,5 @@
1
- import type { VovkConfig, VovkModuleRenderResult } from '../types.mjs';
1
+ import type { VovkConfig } from 'vovk';
2
+ import type { VovkModuleRenderResult } from '../types.mjs';
2
3
  export default function render(codeTemplate: string, { config, withService, segmentName, moduleName, empty, templateFileName, }: {
3
4
  cwd: string;
4
5
  config: VovkConfig;
@@ -8,14 +8,6 @@ export default async function render(codeTemplate, { config, withService, segmen
8
8
  const getModuleDirName = (givenSegmentName, givenModuleName) => [config.modulesDir, givenSegmentName || config.rootSegmentModulesDirName, _.camelCase(givenModuleName)]
9
9
  .filter(Boolean)
10
10
  .join('/');
11
- /*
12
- <% var modulePascalName = _.upperFirst(_.camelCase(moduleName)); %>
13
- <% var modulePascalNamePlural = pluralize(modulePascalName); %>
14
- <% var controllerName = modulePascalName + 'Controller'; %>
15
- <% var compiledName = modulePascalName + 'RPC'; %>
16
- <% var serviceName = modulePascalName + 'Service'; %>
17
- <% var prefix = pluralize(_.kebabCase(moduleName).toLowerCase()); %>
18
- */
19
11
  const theThing = _.camelCase(moduleName);
20
12
  const TheThing = _.upperFirst(theThing);
21
13
  const the_thing = _.snakeCase(moduleName);
package/dist/types.d.mts CHANGED
@@ -1,55 +1,4 @@
1
1
  import type { LogLevelNames } from 'loglevel';
2
- export type KnownAny = any;
3
- export type VovkEnv = {
4
- PORT?: string;
5
- VOVK_CLIENT_OUT_DIR?: string;
6
- VOVK_SCHEMA_OUT_DIR?: string;
7
- VOVK_FETCHER_PATH?: string;
8
- VOVK_VALIDATE_ON_CLIENT_PATH?: string;
9
- VOVK_CREATE_RPC_PATH?: string;
10
- VOVK_MODULES_DIR?: string;
11
- VOVK_ORIGIN?: string;
12
- VOVK_ROOT_ENTRY?: string;
13
- VOVK_API_ENTRY_POINT?: string;
14
- VOVK_ROOT_SEGMENT_MODULES_DIR_NAME?: string;
15
- VOVK_LOG_LEVEL?: LogLevelNames;
16
- VOVK_PRETTIFY_CLIENT?: string;
17
- VOVK_DEV_HTTPS?: string;
18
- __VOVK_START_WATCHER_IN_STANDALONE_MODE__?: 'true';
19
- __VOVK_EXIT__?: 'true' | 'false';
20
- };
21
- type GenerateFrom = (string | {
22
- templatePath: string;
23
- outDir?: string;
24
- templateName?: string;
25
- fullSchema?: string | boolean;
26
- })[];
27
- export type VovkConfig = {
28
- clientOutDir?: string;
29
- schemaOutDir?: string;
30
- fetcherImport?: string | string[];
31
- validateOnClientImport?: string | string[] | null;
32
- createRPCImport?: string | string[];
33
- modulesDir?: string;
34
- rootEntry?: string;
35
- origin?: string;
36
- rootSegmentModulesDirName?: string;
37
- logLevel?: LogLevelNames;
38
- prettifyClient?: boolean;
39
- devHttps?: boolean;
40
- generateFrom?: GenerateFrom | ((value: GenerateFrom) => GenerateFrom);
41
- templates?: {
42
- service?: string;
43
- controller?: string;
44
- [key: string]: string | undefined;
45
- };
46
- };
47
- export type VovkStrictConfig = Required<Omit<VovkConfig, 'validateOnClientImport' | 'fetcherImport' | 'createRPCImport' | 'generateFrom'>> & {
48
- validateOnClientImport: string[] | null;
49
- fetcherImport: string[];
50
- createRPCImport: string[];
51
- generateFrom: GenerateFrom;
52
- };
53
2
  export type VovkModuleRenderResult = {
54
3
  fileName: string;
55
4
  dir: string;
@@ -65,7 +14,7 @@ export interface GenerateOptions {
65
14
  clientOutDir?: string;
66
15
  templates?: string[];
67
16
  prettify?: boolean;
68
- fullSchema?: string | boolean;
17
+ emitFullSchema?: string | boolean;
69
18
  }
70
19
  export interface InitOptions {
71
20
  yes?: boolean;
@@ -91,4 +40,3 @@ export interface NewOptions {
91
40
  noSegmentUpdate?: boolean;
92
41
  empty?: boolean;
93
42
  }
94
- export {};
@@ -1,2 +1,2 @@
1
- import { KnownAny } from '../types.mjs';
1
+ import type { KnownAny } from 'vovk';
2
2
  export default function debounceWithArgs<Callback extends (...args: KnownAny[]) => KnownAny>(callback: Callback, wait: number): (...args: Parameters<Callback>) => Promise<Awaited<ReturnType<Callback>>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vovk-cli",
3
- "version": "0.0.1-draft.103",
3
+ "version": "0.0.1-draft.105",
4
4
  "bin": {
5
5
  "vovk": "./dist/index.mjs"
6
6
  },
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "homepage": "https://vovk.dev",
38
38
  "peerDependencies": {
39
- "vovk": "^3.0.0-draft.87"
39
+ "vovk": "^3.0.0-draft.90"
40
40
  },
41
41
  "dependencies": {
42
42
  "@inquirer/prompts": "^7.3.1",
@@ -1,2 +0,0 @@
1
- import type { VovkSchema } from 'vovk';
2
- export default function isSchemaEmpty(schema: VovkSchema): boolean;
@@ -1,4 +0,0 @@
1
- import isEmpty from 'lodash/isEmpty.js';
2
- export default function isSchemaEmpty(schema) {
3
- return isEmpty(schema.controllers);
4
- }
@@ -1,12 +0,0 @@
1
- import type { VovkSchema } from 'vovk';
2
- import { type DiffResult } from './diffSchema.mjs';
3
- export declare const ROOT_SEGMENT_SCHEMA_NAME = "_root";
4
- export declare const JSON_DIR_NAME = "json";
5
- export default function writeOneSchemaFile({ schemaOutAbsolutePath, schema, skipIfExists, }: {
6
- schemaOutAbsolutePath: string;
7
- schema: VovkSchema;
8
- skipIfExists?: boolean;
9
- }): Promise<{
10
- isCreated: boolean;
11
- diffResult: DiffResult | null;
12
- }>;