vovk-cli 0.0.1-draft.333 → 0.0.1-draft.335

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 (52) hide show
  1. package/client-templates/readme/README.md.ejs +3 -2
  2. package/client-templates/schemaCjs/schema.cjs.ejs +1 -4
  3. package/client-templates/schemaTs/schema.ts.ejs +1 -5
  4. package/dist/bundle/index.mjs +10 -10
  5. package/dist/dev/ensureSchemaFiles.d.mts +1 -1
  6. package/dist/dev/index.d.mts +1 -1
  7. package/dist/dev/index.mjs +28 -19
  8. package/dist/dev/writeMetaJson.d.mts +1 -1
  9. package/dist/dev/writeMetaJson.mjs +5 -2
  10. package/dist/generate/generate.d.mts +2 -5
  11. package/dist/generate/generate.mjs +38 -40
  12. package/dist/generate/getClientTemplateFiles.mjs +1 -1
  13. package/dist/generate/getProjectFullSchema.d.mts +5 -2
  14. package/dist/generate/getProjectFullSchema.mjs +7 -7
  15. package/dist/generate/index.mjs +3 -1
  16. package/dist/generate/writeOneClientFile.d.mts +4 -3
  17. package/dist/generate/writeOneClientFile.mjs +11 -5
  18. package/dist/getProjectInfo/getConfig/getTemplateDefs.mjs +3 -3
  19. package/dist/getProjectInfo/getConfig/index.d.mts +9 -51
  20. package/dist/getProjectInfo/getConfig/index.mjs +18 -16
  21. package/dist/getProjectInfo/getMetaSchema.d.mts +10 -0
  22. package/dist/getProjectInfo/getMetaSchema.mjs +13 -0
  23. package/dist/getProjectInfo/index.d.mts +4 -2
  24. package/dist/getProjectInfo/index.mjs +5 -2
  25. package/dist/index.mjs +25 -6
  26. package/dist/init/createConfig.mjs +26 -4
  27. package/dist/init/createStandardSchemaValidatorFile.d.mts +4 -0
  28. package/dist/init/createStandardSchemaValidatorFile.mjs +38 -0
  29. package/dist/init/index.mjs +47 -21
  30. package/dist/init/updateNPMScripts.d.mts +0 -1
  31. package/dist/init/updateNPMScripts.mjs +1 -5
  32. package/dist/initProgram.mjs +1 -1
  33. package/dist/new/index.d.mts +2 -1
  34. package/dist/new/index.mjs +3 -2
  35. package/dist/new/newModule.d.mts +3 -1
  36. package/dist/new/newModule.mjs +2 -3
  37. package/dist/new/newSegment.d.mts +3 -1
  38. package/dist/new/newSegment.mjs +2 -3
  39. package/dist/types.d.mts +8 -3
  40. package/dist/utils/generateFnName.d.mts +23 -0
  41. package/dist/utils/generateFnName.mjs +76 -0
  42. package/dist/utils/normalizeOpenAPIMixin.d.mts +14 -0
  43. package/dist/utils/normalizeOpenAPIMixin.mjs +114 -0
  44. package/module-templates/arktype/controller.ts.ejs +68 -0
  45. package/module-templates/valibot/controller.ts.ejs +68 -0
  46. package/package.json +2 -2
  47. package/dist/generate/mergePackages.d.mts +0 -7
  48. package/dist/generate/mergePackages.mjs +0 -55
  49. package/dist/utils/normalizeOpenAPIMixins.d.mts +0 -7
  50. package/dist/utils/normalizeOpenAPIMixins.mjs +0 -67
  51. /package/module-templates/{controller.ts.ejs → type/controller.ts.ejs} +0 -0
  52. /package/module-templates/{service.ts.ejs → type/service.ts.ejs} +0 -0
@@ -3,13 +3,13 @@
3
3
 
4
4
  # <%= t.package.name %> v<%= t.package.version %> [![TypeScript](https://badgen.net/badge/-/TypeScript?icon=typescript&label&labelColor=blue&color=555555)](https://www.typescriptlang.org/) [![Vovk.ts](https://badgen.net/badge/Built%20with/Vovk.ts/333333?icon=https://vovk.dev/icon-white.svg)](https://vovk.dev)
5
5
 
6
- <%- t.package.description ? `> ${t.package.description}` : '' %>
6
+ <%- t.readme.description ?? (`${t.package.description ? `> ${t.package.description}` : ''}`) %>
7
7
 
8
8
  <%- t.package.license ? `License: **${t.package.license}**` : '' %>
9
9
 
10
10
  ```bash
11
11
  # Install the package
12
- npm install <%= t.package.name %>
12
+ <%= t.readme.installCommand ?? `npm install ${t.package.name}` %>
13
13
  ```
14
14
 
15
15
  <% Object.entries(t.schema.segments).forEach(([segmentName, segment]) => {
@@ -31,6 +31,7 @@ npm install <%= t.package.name %>
31
31
  handlerName,
32
32
  controllerSchema,
33
33
  package: t.package,
34
+ config: t.snippets,
34
35
  }).ts %>
35
36
  ```
36
37
  <% }) %>
@@ -16,10 +16,7 @@ const schema = {
16
16
  $schema: '<%- t.VovkSchemaIdEnum.SCHEMA %>',
17
17
  segments,
18
18
  meta: {
19
- apiRoot: '<%= t.apiRoot %>', // for debugging purposes
20
- <% if(t.isVovkProject) { %>
21
- ...meta
22
- <% } %>
19
+ <% if(t.isVovkProject) { %>...meta<% } %>
23
20
  }
24
21
  };
25
22
 
@@ -22,11 +22,7 @@ export const schema = {
22
22
  $schema: '<%- t.VovkSchemaIdEnum.SCHEMA %>',
23
23
  segments,
24
24
  meta: {
25
- $schema: '<%- t.VovkSchemaIdEnum.META %>',
26
- apiRoot: '<%= t.apiRoot %>', // for debugging purposes
27
- <% if(t.isVovkProject) { %>
28
- ...meta,
29
- <% } %>
25
+ <% if(t.isVovkProject) { %>...meta,<% } %>
30
26
  }
31
27
  };
32
28
 
@@ -17,9 +17,11 @@ export async function bundle({ projectInfo, fullSchema, cliBundleOptions, }) {
17
17
  throw new Error('No output directory specified for composed client');
18
18
  }
19
19
  const outDir = cliBundleOptions?.outDir ?? bundleConfig.tsdownBuildOptions.outDir;
20
+ const tsconfig = cliBundleOptions?.tsconfig ?? bundleConfig.tsdownBuildOptions.tsconfig;
20
21
  if (!outDir) {
21
22
  throw new Error('No output directory specified for bundling');
22
23
  }
24
+ const outDirAbsolute = path.resolve(cwd, outDir);
23
25
  await generate({
24
26
  isEnsuringClient: false,
25
27
  isBundle: true,
@@ -27,10 +29,8 @@ export async function bundle({ projectInfo, fullSchema, cliBundleOptions, }) {
27
29
  forceNothingWrittenLog: true,
28
30
  fullSchema,
29
31
  locatedSegments,
30
- package: bundleConfig.package,
31
- readme: bundleConfig.readme,
32
32
  cliGenerateOptions: {
33
- origin: cliBundleOptions?.origin ?? bundleConfig.origin,
33
+ origin: cliBundleOptions?.origin,
34
34
  openapiSpec: cliBundleOptions?.openapiSpec,
35
35
  openapiGetModuleName: cliBundleOptions?.openapiGetModuleName,
36
36
  openapiGetMethodName: cliBundleOptions?.openapiGetMethodName,
@@ -47,18 +47,20 @@ export async function bundle({ projectInfo, fullSchema, cliBundleOptions, }) {
47
47
  dts: true,
48
48
  format: ['cjs', 'esm'],
49
49
  fixedExtension: true,
50
- outDir,
50
+ clean: true,
51
51
  ...bundleConfig.tsdownBuildOptions,
52
+ outDir: outDirAbsolute,
53
+ tsconfig,
52
54
  });
53
- const outDirAbsolute = path.resolve(cwd, outDir);
54
55
  log.debug(`Bundled index.ts to ${chalkHighlightThing(outDirAbsolute)}`);
55
56
  await build({
56
57
  entry: path.join(tsFullClientOutAbsoluteDirInput, './schema.ts'),
57
58
  dts: true,
58
59
  format: ['cjs'],
59
60
  fixedExtension: true,
60
- outDir,
61
+ outDir: outDirAbsolute,
61
62
  clean: false,
63
+ tsconfig,
62
64
  });
63
65
  log.debug(`Bundled schema.ts to ${chalkHighlightThing(outDirAbsolute)}`);
64
66
  const requiresGroup = groupBy(Object.entries(bundleConfig.requires), ([, relativePath]) => relativePath);
@@ -69,12 +71,10 @@ export async function bundle({ projectInfo, fullSchema, cliBundleOptions, }) {
69
71
  forceNothingWrittenLog: true,
70
72
  fullSchema,
71
73
  locatedSegments,
72
- package: bundleConfig.package,
73
- readme: bundleConfig.readme,
74
74
  cliGenerateOptions: {
75
- origin: cliBundleOptions?.origin ?? bundleConfig.origin,
75
+ origin: cliBundleOptions?.origin,
76
76
  composedFrom: group.map(([templateName]) => templateName),
77
- composedOut: path.resolve(outDir, relativePath),
77
+ composedOut: path.resolve(outDirAbsolute, relativePath),
78
78
  composedOnly: true,
79
79
  },
80
80
  });
@@ -2,5 +2,5 @@ import { ProjectInfo } from '../getProjectInfo/index.mjs';
2
2
  /**
3
3
  * Ensure that the schema files are created to avoid any import errors.
4
4
  */
5
- export default function ensureSchemaFiles(projectInfo: ProjectInfo | null, schemaOutAbsolutePath: string, segmentNames: string[]): Promise<void>;
5
+ export default function ensureSchemaFiles(projectInfo: ProjectInfo, schemaOutAbsolutePath: string, segmentNames: string[]): Promise<void>;
6
6
  export declare const debouncedEnsureSchemaFiles: import("lodash").DebouncedFunc<typeof ensureSchemaFiles>;
@@ -1,7 +1,7 @@
1
1
  import type { DevOptions } from '../types.mjs';
2
2
  export declare class VovkDev {
3
3
  #private;
4
- constructor({ schemaOut, devHttps }: Pick<DevOptions, 'schemaOut' | 'devHttps'>);
4
+ constructor({ schemaOut, devHttps, logLevel }: Pick<DevOptions, 'schemaOut' | 'devHttps' | 'logLevel'>);
5
5
  start({ exit }: {
6
6
  exit: boolean;
7
7
  }): Promise<void>;
@@ -19,28 +19,22 @@ import debounceWithArgs from '../utils/debounceWithArgs.mjs';
19
19
  import formatLoggedSegmentName from '../utils/formatLoggedSegmentName.mjs';
20
20
  import writeMetaJson from './writeMetaJson.mjs';
21
21
  import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
22
+ import getMetaSchema from '../getProjectInfo/getMetaSchema.mjs';
22
23
  export class VovkDev {
23
24
  #projectInfo;
24
25
  #segments = [];
25
- #fullSchema = {
26
- $schema: VovkSchemaIdEnum.SCHEMA,
27
- segments: {},
28
- meta: {
29
- $schema: VovkSchemaIdEnum.META,
30
- config: {
31
- $schema: VovkSchemaIdEnum.CONFIG,
32
- },
33
- },
34
- };
26
+ #schemaSegments = {};
35
27
  #isWatching = false;
36
28
  #modulesWatcher = null;
37
29
  #segmentWatcher = null;
38
30
  #onFirstTimeGenerate = null;
39
31
  #schemaOut = null;
40
32
  #devHttps;
41
- constructor({ schemaOut, devHttps }) {
42
- this.#schemaOut = schemaOut ?? null;
43
- this.#devHttps = devHttps ?? false;
33
+ #logLevel;
34
+ constructor({ schemaOut, devHttps, logLevel }) {
35
+ this.#schemaOut = schemaOut || null;
36
+ this.#devHttps = devHttps || false;
37
+ this.#logLevel = logLevel || 'info';
44
38
  }
45
39
  #watchSegments = (callback) => {
46
40
  const segmentReg = /\/?\[\[\.\.\.[a-zA-Z-_]+\]\]\/route.ts$/;
@@ -165,7 +159,7 @@ export class VovkDev {
165
159
  let isInitial = true;
166
160
  let isReady = false;
167
161
  const handle = debounce(async () => {
168
- this.#projectInfo = await getProjectInfo();
162
+ this.#projectInfo = await getProjectInfo({ logLevel: this.#logLevel });
169
163
  const { config, apiDirAbsolutePath } = this.#projectInfo;
170
164
  this.#segments = await locateSegments({ dir: apiDirAbsolutePath, config, log });
171
165
  await this.#modulesWatcher?.close();
@@ -233,7 +227,7 @@ export class VovkDev {
233
227
  const importRegex = /import\s*{[^}]*\b(get|post|put|del|head|options)\b[^}]*}\s*from\s*['"]vovk['"]/;
234
228
  if (importRegex.test(code) && namesOfClasses.length) {
235
229
  const affectedSegments = this.#segments.filter((s) => {
236
- const segmentSchema = this.#fullSchema.segments[s.segmentName];
230
+ const segmentSchema = this.#schemaSegments[s.segmentName];
237
231
  if (!segmentSchema)
238
232
  return false;
239
233
  const controllersByOriginalName = keyBy(segmentSchema.controllers, 'originalControllerName');
@@ -285,7 +279,21 @@ export class VovkDev {
285
279
  }
286
280
  return { isError: false };
287
281
  }, 500);
288
- #generate = debounce(() => generate({ projectInfo: this.#projectInfo, fullSchema: this.#fullSchema, locatedSegments: this.#segments }).then(this.#onFirstTimeGenerate), 1000);
282
+ #generate = debounce(() => {
283
+ const fullSchema = {
284
+ $schema: VovkSchemaIdEnum.SCHEMA,
285
+ segments: this.#schemaSegments,
286
+ meta: getMetaSchema({
287
+ config: this.#projectInfo.config,
288
+ package: this.#projectInfo.packageJson,
289
+ }),
290
+ };
291
+ return generate({
292
+ projectInfo: this.#projectInfo,
293
+ fullSchema,
294
+ locatedSegments: this.#segments,
295
+ }).then(this.#onFirstTimeGenerate);
296
+ }, 1000);
289
297
  async #handleSegmentSchema(segmentName, segmentSchema) {
290
298
  const { log, config, cwd } = this.#projectInfo;
291
299
  if (!segmentSchema) {
@@ -299,7 +307,7 @@ export class VovkDev {
299
307
  log.warn(`${formatLoggedSegmentName(segmentName)} not found`);
300
308
  return;
301
309
  }
302
- this.#fullSchema.segments[segmentName] = segmentSchema;
310
+ this.#schemaSegments[segmentName] = segmentSchema;
303
311
  if (segmentSchema.emitSchema) {
304
312
  const now = Date.now();
305
313
  const { diffResult } = await writeOneSegmentSchemaFile({
@@ -316,14 +324,14 @@ export class VovkDev {
316
324
  else if (segmentSchema && !isEmpty(segmentSchema.controllers)) {
317
325
  log.error(`Non-empty schema provided for ${formatLoggedSegmentName(segment.segmentName)} but "emitSchema" is false`);
318
326
  }
319
- if (this.#segments.every((s) => this.#fullSchema.segments[s.segmentName])) {
327
+ if (this.#segments.every((s) => this.#schemaSegments[s.segmentName])) {
320
328
  log.debug(`All segments with "emitSchema" have schema.`);
321
329
  this.#generate();
322
330
  }
323
331
  }
324
332
  async start({ exit }) {
325
333
  const now = Date.now();
326
- this.#projectInfo = await getProjectInfo();
334
+ this.#projectInfo = await getProjectInfo({ logLevel: this.#logLevel });
327
335
  const { log, config, cwd, apiDirAbsolutePath } = this.#projectInfo;
328
336
  this.#segments = await locateSegments({ dir: apiDirAbsolutePath, config, log });
329
337
  log.info('Starting...');
@@ -392,6 +400,7 @@ if (env.__VOVK_START_WATCHER_IN_STANDALONE_MODE__ === 'true') {
392
400
  void new VovkDev({
393
401
  schemaOut: env.__VOVK_SCHEMA_OUT_FLAG__ || undefined,
394
402
  devHttps: env.__VOVK_DEV_HTTPS_FLAG__ === 'true',
403
+ logLevel: env.__VOVK_LOG_LEVEL__,
395
404
  }).start({
396
405
  exit: env.__VOVK_EXIT__ === 'true',
397
406
  });
@@ -1,2 +1,2 @@
1
1
  import type { ProjectInfo } from '../getProjectInfo/index.mjs';
2
- export default function writeMetaJson(schemaOutAbsolutePath: string, projectInfo: ProjectInfo | null): Promise<void>;
2
+ export default function writeMetaJson(schemaOutAbsolutePath: string, projectInfo: ProjectInfo): Promise<void>;
@@ -1,11 +1,14 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- import pick from 'lodash/pick.js';
4
3
  import { META_FILE_NAME } from './writeOneSegmentSchemaFile.mjs';
5
4
  import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
5
+ import getMetaSchema from '../getProjectInfo/getMetaSchema.mjs';
6
6
  export default async function writeMetaJson(schemaOutAbsolutePath, projectInfo) {
7
7
  const metaJsonPath = path.join(schemaOutAbsolutePath, META_FILE_NAME + '.json');
8
- const metaStr = JSON.stringify({ config: projectInfo ? pick(projectInfo.config, [...projectInfo.config.emitConfig, '$schema']) : {} }, null, 2);
8
+ const metaStr = JSON.stringify(getMetaSchema({
9
+ config: projectInfo.config,
10
+ package: projectInfo.packageJson,
11
+ }), null, 2);
9
12
  const existingStr = await fs.readFile(metaJsonPath, 'utf-8').catch(() => null);
10
13
  if (existingStr !== metaStr) {
11
14
  await fs.writeFile(metaJsonPath, metaStr);
@@ -1,9 +1,8 @@
1
- import { type VovkSchema, type VovkStrictConfig } from 'vovk';
2
- import type { PackageJson } from 'type-fest';
1
+ import { type VovkSchema } from 'vovk';
3
2
  import type { ProjectInfo } from '../getProjectInfo/index.mjs';
4
3
  import type { GenerateOptions } from '../types.mjs';
5
4
  import type { Segment } from '../locateSegments.mjs';
6
- export declare function generate({ isEnsuringClient, isBundle, projectInfo, forceNothingWrittenLog, fullSchema, locatedSegments, cliGenerateOptions, package: argPackageJson, readme: argReadme, }: {
5
+ export declare function generate({ isEnsuringClient, isBundle, projectInfo, forceNothingWrittenLog, fullSchema, locatedSegments, cliGenerateOptions, }: {
7
6
  isEnsuringClient?: boolean;
8
7
  isBundle?: boolean;
9
8
  projectInfo: ProjectInfo;
@@ -11,6 +10,4 @@ export declare function generate({ isEnsuringClient, isBundle, projectInfo, forc
11
10
  fullSchema: VovkSchema;
12
11
  locatedSegments: Segment[];
13
12
  cliGenerateOptions?: GenerateOptions;
14
- package?: PackageJson;
15
- readme?: VovkStrictConfig['bundle']['readme'];
16
13
  }): Promise<void>;
@@ -2,17 +2,16 @@ import path from 'node:path';
2
2
  import fs from 'node:fs/promises';
3
3
  import matter from 'gray-matter';
4
4
  import _ from 'lodash';
5
- import { openAPIToVovkSchema } from 'vovk';
5
+ import { getGeneratorConfig, openAPIToVovkSchema, } from 'vovk';
6
6
  import getClientTemplateFiles from './getClientTemplateFiles.mjs';
7
7
  import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
8
8
  import pickSegmentFullSchema from '../utils/pickSegmentFullSchema.mjs';
9
9
  import removeUnlistedDirectories from '../utils/removeUnlistedDirectories.mjs';
10
10
  import getTemplateClientImports from './getTemplateClientImports.mjs';
11
- import mergePackages from './mergePackages.mjs';
12
11
  import writeOneClientFile, { normalizeOutTemplatePath } from './writeOneClientFile.mjs';
13
12
  import { ROOT_SEGMENT_FILE_NAME } from '../dev/writeOneSegmentSchemaFile.mjs';
14
13
  import { getTsconfig } from 'get-tsconfig';
15
- import { normalizeOpenAPIMixins } from '../utils/normalizeOpenAPIMixins.mjs';
14
+ import { normalizeOpenAPIMixin } from '../utils/normalizeOpenAPIMixin.mjs';
16
15
  import { BuiltInTemplateName } from '../getProjectInfo/getConfig/getTemplateDefs.mjs';
17
16
  const getIncludedSegmentNames = (config, fullSchema, configKey, cliGenerateOptions) => {
18
17
  const segments = Object.values(fullSchema.segments);
@@ -86,30 +85,35 @@ const cliOptionsToOpenAPIMixins = ({ openapiGetMethodName, openapiGetModuleName,
86
85
  },
87
86
  ]));
88
87
  };
89
- export async function generate({ isEnsuringClient = false, isBundle = false, projectInfo, forceNothingWrittenLog, fullSchema, locatedSegments, cliGenerateOptions, package: argPackageJson, readme: argReadme, }) {
88
+ export async function generate({ isEnsuringClient = false, isBundle = false, projectInfo, forceNothingWrittenLog, fullSchema, locatedSegments, cliGenerateOptions, }) {
90
89
  fullSchema = {
91
90
  ...fullSchema,
92
91
  // sort segments by name to avoid unnecessary rendering
93
- segments: Object.fromEntries(Object.entries(fullSchema.segments).sort(([a], [b]) => a.localeCompare(b))),
92
+ segments: Object.fromEntries(Object.entries(fullSchema.segments)
93
+ .sort(([a], [b]) => a.localeCompare(b))
94
+ // preserve original object, so segments can be extended
95
+ .map((segment) => ({ ...segment }))),
94
96
  };
95
- const { config, cwd, log, srcRoot, packageJson: rootPackageJson, vovkCliPackage } = projectInfo;
96
- const allOpenAPIMixins = {
97
- ...config.openApiMixins,
98
- ...cliOptionsToOpenAPIMixins(cliGenerateOptions ?? {}),
99
- };
100
- if (Object.keys(allOpenAPIMixins).length) {
101
- const mixins = Object.fromEntries(Object.entries(await normalizeOpenAPIMixins({ mixinModules: allOpenAPIMixins, log })).map(([mixinName, conf]) => [
102
- mixinName,
103
- openAPIToVovkSchema({ ...conf, mixinName }).segments[mixinName],
104
- ]));
105
- fullSchema = {
106
- ...fullSchema,
107
- segments: {
108
- ...fullSchema.segments,
109
- ...mixins,
97
+ const { config, cwd, log, srcRoot, vovkCliPackage } = projectInfo;
98
+ Object.entries(config.projectConfig.segments ?? {}).forEach(([segmentName, segmentConfig]) => {
99
+ fullSchema.segments = {
100
+ ...fullSchema.segments,
101
+ [segmentName]: {
102
+ ...fullSchema.segments[segmentName],
103
+ ...openAPIToVovkSchema({ ...segmentConfig.openAPIMixin, segmentName }).segments[segmentName],
110
104
  },
111
105
  };
112
- }
106
+ });
107
+ const cliMixins = cliOptionsToOpenAPIMixins(cliGenerateOptions ?? {});
108
+ await Promise.all(Object.entries(cliMixins).map(async ([mixinName, mixinModule]) => {
109
+ fullSchema.segments = {
110
+ ...fullSchema.segments,
111
+ [mixinName]: {
112
+ ...fullSchema.segments[mixinName],
113
+ ...openAPIToVovkSchema(await normalizeOpenAPIMixin({ mixinModule, log })).segments[mixinName],
114
+ },
115
+ };
116
+ }));
113
117
  const isNodeNextResolution = ['node16', 'nodenext'].includes((await getTsconfig(cwd)?.config?.compilerOptions?.moduleResolution?.toLowerCase()) ?? '');
114
118
  const isVovkProject = !!srcRoot;
115
119
  const isComposedEnabled = cliGenerateOptions?.composedOnly ||
@@ -141,12 +145,11 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
141
145
  fullSchema,
142
146
  outCwdRelativeDir,
143
147
  });
144
- const packageJson = await mergePackages({
145
- log,
146
- rootPackageJson,
147
- packages: [config.composedClient.package, templateDef.composedClient?.package, argPackageJson],
148
+ const { package: packageJson, readme, origin, snippets, } = getGeneratorConfig({
149
+ schema: fullSchema,
150
+ config: templateDef.projectConfig,
151
+ isBundle,
148
152
  });
149
- const readme = Object.assign({}, config.composedClient.readme, templateDef.composedClient?.readme, argReadme);
150
153
  const composedFullSchema = pickSegmentFullSchema(fullSchema, segmentNames);
151
154
  const hasMixins = Object.values(composedFullSchema.segments).some((segment) => segment.segmentType === 'mixin');
152
155
  if (templateName === BuiltInTemplateName.mixins && !hasMixins) {
@@ -164,6 +167,7 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
164
167
  matterResult,
165
168
  package: packageJson,
166
169
  readme,
170
+ snippets,
167
171
  isEnsuringClient,
168
172
  outCwdRelativeDir,
169
173
  templateDef,
@@ -173,7 +177,7 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
173
177
  isVovkProject,
174
178
  vovkCliPackage,
175
179
  isBundle,
176
- origin: cliGenerateOptions?.origin ?? templateDef.origin ?? config.origin,
180
+ origin: cliGenerateOptions?.origin ?? origin,
177
181
  });
178
182
  const outAbsoluteDir = path.resolve(cwd, outCwdRelativeDir);
179
183
  return {
@@ -220,19 +224,12 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
220
224
  outCwdRelativeDir,
221
225
  });
222
226
  const results = await Promise.all(segmentNames.map(async (segmentName) => {
223
- const packageJson = await mergePackages({
224
- log,
225
- rootPackageJson,
226
- packages: [
227
- fullSchema.segments[segmentName]?.meta?.package,
228
- config.segmentedClient.packages?.[segmentName],
229
- templateDef.segmentedClient?.packages?.[segmentName],
230
- argPackageJson,
231
- ],
227
+ const { package: packageJson, readme, origin, snippets, } = getGeneratorConfig({
228
+ schema: fullSchema,
229
+ config: templateDef.projectConfig,
230
+ segmentName,
231
+ isBundle,
232
232
  });
233
- const readme = Object.assign({},
234
- // TODO fullSchema.segments[segmentName]?.meta?.readme,
235
- config.segmentedClient.readmes?.[segmentName], templateDef.segmentedClient?.readmes?.[segmentName], argReadme);
236
233
  const segmentedFullSchema = pickSegmentFullSchema(fullSchema, [segmentName]);
237
234
  const hasMixins = Object.values(segmentedFullSchema.segments).some((segment) => segment.segmentType === 'mixin');
238
235
  if (templateName === BuiltInTemplateName.mixins && !hasMixins) {
@@ -250,6 +247,7 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
250
247
  matterResult,
251
248
  package: packageJson,
252
249
  readme,
250
+ snippets,
253
251
  isEnsuringClient,
254
252
  outCwdRelativeDir,
255
253
  templateDef,
@@ -259,7 +257,7 @@ export async function generate({ isEnsuringClient = false, isBundle = false, pro
259
257
  isVovkProject,
260
258
  vovkCliPackage,
261
259
  isBundle,
262
- origin: cliGenerateOptions?.origin ?? templateDef.origin ?? config.origin,
260
+ origin: cliGenerateOptions?.origin ?? origin,
263
261
  });
264
262
  return {
265
263
  written,
@@ -73,7 +73,7 @@ export default async function getClientTemplateFiles({ config, cwd, log, configK
73
73
  }
74
74
  def = {
75
75
  ...def,
76
- origin: templateDef.origin ?? def.origin,
76
+ projectConfig: merge({}, templateDef?.projectConfig, def.projectConfig),
77
77
  composedClient: merge(omit(templateDef?.composedClient ?? {}, ['outDir']), def.composedClient),
78
78
  segmentedClient: merge(omit(templateDef?.segmentedClient ?? {}, ['outDir']), def.segmentedClient),
79
79
  };
@@ -1,7 +1,10 @@
1
- import { type VovkSchema } from 'vovk';
1
+ import { VovkStrictConfig, type VovkSchema } from 'vovk';
2
2
  import type { ProjectInfo } from '../getProjectInfo/index.mjs';
3
- export declare function getProjectFullSchema({ schemaOutAbsolutePath, isNextInstalled, log, }: {
3
+ import { PackageJson } from 'type-fest';
4
+ export declare function getProjectFullSchema({ schemaOutAbsolutePath, isNextInstalled, log, package: packageJson, config, }: {
4
5
  schemaOutAbsolutePath: string;
5
6
  isNextInstalled: boolean;
6
7
  log: ProjectInfo['log'];
8
+ package: PackageJson;
9
+ config: VovkStrictConfig;
7
10
  }): Promise<VovkSchema>;
@@ -3,17 +3,17 @@ import path from 'node:path';
3
3
  import { glob } from 'glob';
4
4
  import { VovkSchemaIdEnum } from 'vovk';
5
5
  import { META_FILE_NAME, ROOT_SEGMENT_FILE_NAME } from '../dev/writeOneSegmentSchemaFile.mjs';
6
- export async function getProjectFullSchema({ schemaOutAbsolutePath, isNextInstalled, log, }) {
6
+ import getMetaSchema from '../getProjectInfo/getMetaSchema.mjs';
7
+ export async function getProjectFullSchema({ schemaOutAbsolutePath, isNextInstalled, log, package: packageJson, config, }) {
7
8
  const result = {
8
9
  $schema: VovkSchemaIdEnum.SCHEMA,
9
10
  segments: {},
10
- meta: {
11
- $schema: VovkSchemaIdEnum.META,
12
- config: {
13
- $schema: VovkSchemaIdEnum.CONFIG,
14
- },
15
- },
11
+ meta: getMetaSchema({
12
+ config,
13
+ package: packageJson,
14
+ }),
16
15
  };
16
+ console.log('result', result);
17
17
  const isEmptyLogOrWarn = isNextInstalled ? log.warn : log.debug;
18
18
  // Handle config.json
19
19
  const metaPath = path.join(schemaOutAbsolutePath, `${META_FILE_NAME}.json`);
@@ -37,12 +37,14 @@ export class VovkGenerate {
37
37
  });
38
38
  }
39
39
  async getFullSchema() {
40
- const { log, config, cwd, isNextInstalled } = this.#projectInfo;
40
+ const { log, config, cwd, isNextInstalled, packageJson } = this.#projectInfo;
41
41
  const { schemaPath } = this.#cliGenerateOptions;
42
42
  const fullSchema = await getProjectFullSchema({
43
43
  schemaOutAbsolutePath: path.resolve(cwd, schemaPath ?? config.schemaOutDir),
44
44
  isNextInstalled,
45
45
  log,
46
+ package: packageJson,
47
+ config,
46
48
  });
47
49
  return fullSchema;
48
50
  }
@@ -1,11 +1,11 @@
1
- import { type VovkSchema, type VovkStrictConfig } from 'vovk';
1
+ import { VovkReadmeConfig, VovkSnippetsConfig, type VovkSchema, type VovkStrictConfig } from 'vovk';
2
2
  import type { PackageJson } from 'type-fest';
3
3
  import type { ProjectInfo } from '../getProjectInfo/index.mjs';
4
4
  import type { ClientTemplateFile } from './getClientTemplateFiles.mjs';
5
5
  import type { ClientImports } from './getTemplateClientImports.mjs';
6
6
  import type { Segment } from '../locateSegments.mjs';
7
7
  export declare function normalizeOutTemplatePath(out: string, packageJson: PackageJson): string;
8
- export default function writeOneClientFile({ cwd, projectInfo, clientTemplateFile, fullSchema, prettifyClient, segmentName, imports, templateContent, matterResult: { data, content }, package: packageJson, readme, isEnsuringClient, outCwdRelativeDir, templateDef, locatedSegments, isNodeNextResolution, hasMixins, isVovkProject, vovkCliPackage, isBundle, origin, }: {
8
+ export default function writeOneClientFile({ cwd, projectInfo, clientTemplateFile, fullSchema, prettifyClient, segmentName, imports, templateContent, matterResult: { data, content }, package: packageJson, readme, snippets, isEnsuringClient, outCwdRelativeDir, locatedSegments, isNodeNextResolution, hasMixins, isVovkProject, vovkCliPackage, isBundle, origin, }: {
9
9
  cwd: string;
10
10
  projectInfo: ProjectInfo;
11
11
  clientTemplateFile: ClientTemplateFile;
@@ -21,7 +21,8 @@ export default function writeOneClientFile({ cwd, projectInfo, clientTemplateFil
21
21
  content: string;
22
22
  };
23
23
  package: PackageJson;
24
- readme: VovkStrictConfig['bundle']['readme'];
24
+ readme: VovkReadmeConfig;
25
+ snippets: VovkSnippetsConfig;
25
26
  isEnsuringClient: boolean;
26
27
  outCwdRelativeDir: string;
27
28
  templateDef: VovkStrictConfig['clientTemplateDefs'][string];
@@ -2,7 +2,7 @@ import fs from 'fs/promises';
2
2
  import path from 'node:path';
3
3
  import ejs from 'ejs';
4
4
  import _ from 'lodash';
5
- import { createCodeExamples, VovkSchemaIdEnum } from 'vovk';
5
+ import { createCodeExamples, VovkSchemaIdEnum, } from 'vovk';
6
6
  import * as YAML from 'yaml';
7
7
  import TOML from '@iarna/toml';
8
8
  import prettify from '../utils/prettify.mjs';
@@ -11,7 +11,9 @@ import { compileJSONSchemaToTypeScriptType } from '../utils/compileJSONSchemaToT
11
11
  export function normalizeOutTemplatePath(out, packageJson) {
12
12
  return out.replace('[package_name]', packageJson.name?.replace(/-/g, '_') ?? 'my_package_name');
13
13
  }
14
- export default async function writeOneClientFile({ cwd, projectInfo, clientTemplateFile, fullSchema, prettifyClient, segmentName, imports, templateContent, matterResult: { data, content }, package: packageJson, readme, isEnsuringClient, outCwdRelativeDir, templateDef, locatedSegments, isNodeNextResolution, hasMixins, isVovkProject, vovkCliPackage, isBundle, origin, }) {
14
+ export default async function writeOneClientFile({ cwd, projectInfo, clientTemplateFile, fullSchema, prettifyClient, segmentName, imports, templateContent, matterResult: { data, content }, package: packageJson, readme, snippets, isEnsuringClient, outCwdRelativeDir,
15
+ // templateDef,
16
+ locatedSegments, isNodeNextResolution, hasMixins, isVovkProject, vovkCliPackage, isBundle, origin, }) {
15
17
  const { config, apiRoot } = projectInfo;
16
18
  const { templateFilePath, relativeDir } = clientTemplateFile;
17
19
  const locatedSegmentsByName = _.keyBy(locatedSegments, 'segmentName');
@@ -38,6 +40,7 @@ export default async function writeOneClientFile({ cwd, projectInfo, clientTempl
38
40
  isVovkProject,
39
41
  package: packageJson,
40
42
  readme,
43
+ snippets,
41
44
  ROOT_SEGMENT_FILE_NAME,
42
45
  apiRoot: origin ? `${origin}/${config.rootEntry}` : apiRoot,
43
46
  imports,
@@ -63,11 +66,14 @@ export default async function writeOneClientFile({ cwd, projectInfo, clientTempl
63
66
  ? path.relative(path.resolve(cwd, outCwdRelativeDir, typeof segmentName === 'string' ? segmentName || ROOT_SEGMENT_FILE_NAME : '.'), path.resolve(cwd, routeFilePath))
64
67
  : null;
65
68
  const segmentConfig = {
66
- ...(config.segmentConfig ? config.segmentConfig[sName] : {}),
67
- ...(templateDef.segmentConfig ? templateDef.segmentConfig[sName] : {}),
69
+ ...config.projectConfig.segments?.[sName],
70
+ // ...templateDef.projectConfig?.segments?.[sName],
68
71
  };
69
72
  const { origin: segmentConfigOrigin, rootEntry: segmentConfigRootEntry, segmentNameOverride } = segmentConfig;
70
- const reExports = { ...segmentConfig.reExports, ...(isBundle ? projectInfo.config.bundle.reExports : {}) };
73
+ const reExports = {
74
+ ...segmentConfig.reExports,
75
+ ...(isBundle ? projectInfo.config.projectConfig?.bundle?.reExports : {}),
76
+ };
71
77
  return [
72
78
  sName,
73
79
  {
@@ -129,9 +129,9 @@ export default function getTemplateDefs(userTemplateDefs = {}) {
129
129
  ...builtIn.segmentedClient,
130
130
  ...templateDef.segmentedClient,
131
131
  },
132
- segmentConfig: {
133
- ...builtIn.segmentConfig,
134
- ...templateDef.segmentConfig,
132
+ projectConfig: {
133
+ ...builtIn.projectConfig,
134
+ ...templateDef.projectConfig,
135
135
  },
136
136
  // 'requires' and other props will be overridden
137
137
  };