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
@@ -1,7 +1,9 @@
1
1
  import { VovkSchemaIdEnum, type VovkStrictConfig } from 'vovk';
2
- export default function getConfig({ configPath, cwd }: {
2
+ import type { LogLevelNames } from 'loglevel';
3
+ export default function getConfig({ configPath, cwd, logLevel, }: {
3
4
  configPath?: string;
4
5
  cwd: string;
6
+ logLevel?: LogLevelNames;
5
7
  }): Promise<{
6
8
  config: VovkStrictConfig;
7
9
  srcRoot: string | null;
@@ -12,14 +14,13 @@ export default function getConfig({ configPath, cwd }: {
12
14
  schemaOutDir?: string;
13
15
  modulesDir?: string;
14
16
  rootEntry?: string;
15
- origin?: string;
16
17
  logLevel?: "error" | "trace" | "debug" | "info" | "warn" | (string & {});
17
18
  libs?: {
18
19
  ajv: import("vovk").KnownAny;
19
20
  [key: string]: import("vovk").KnownAny;
20
21
  };
21
22
  devHttps?: boolean;
22
- composedClient?: ({
23
+ composedClient?: {
23
24
  enabled?: boolean;
24
25
  outDir?: string;
25
26
  fromTemplates?: string[];
@@ -30,13 +31,8 @@ export default function getConfig({ configPath, cwd }: {
30
31
  } | {
31
32
  excludeSegments?: string[];
32
33
  includeSegments?: never;
33
- })) & {
34
- package?: import("type-fest").PackageJson;
35
- readme?: {
36
- banner?: string;
37
- };
38
- };
39
- segmentedClient?: ({
34
+ });
35
+ segmentedClient?: {
40
36
  enabled?: boolean;
41
37
  outDir?: string;
42
38
  fromTemplates?: string[];
@@ -47,22 +43,11 @@ export default function getConfig({ configPath, cwd }: {
47
43
  } | {
48
44
  excludeSegments?: string[];
49
45
  includeSegments?: never;
50
- })) & {
51
- packages?: Record<string, import("type-fest").PackageJson>;
52
- readmes?: Record<string, {
53
- banner?: string;
54
- }>;
55
- };
46
+ });
56
47
  bundle?: {
57
48
  requires?: Record<string, string>;
58
49
  prebundleOutDir?: string;
59
50
  keepPrebundleDir?: boolean;
60
- origin?: string;
61
- package?: import("type-fest").PackageJson;
62
- readme?: {
63
- banner?: string;
64
- };
65
- reExports?: Record<string, string>;
66
51
  tsdownBuildOptions?: Parameters<typeof import("tsdown/config-9hj-APNF.mjs").build>[0];
67
52
  } & ({
68
53
  excludeSegments?: never;
@@ -71,7 +56,7 @@ export default function getConfig({ configPath, cwd }: {
71
56
  excludeSegments?: string[];
72
57
  includeSegments?: never;
73
58
  });
74
- clientTemplateDefs?: Record<string, import("vovk/mjs/types").ClientTemplateDef>;
59
+ clientTemplateDefs?: Record<string, import("vovk/types").ClientTemplateDef>;
75
60
  imports?: {
76
61
  fetcher?: string | [string, string] | [string];
77
62
  validateOnClient?: string | [string, string] | [string];
@@ -83,34 +68,7 @@ export default function getConfig({ configPath, cwd }: {
83
68
  controller?: string;
84
69
  [key: string]: string | undefined;
85
70
  };
86
- segmentConfig?: false | {
87
- [x: string]: {
88
- origin?: string;
89
- rootEntry?: string;
90
- segmentNameOverride?: string;
91
- reExports?: Record<string, string>;
92
- };
93
- };
94
- openApiMixins?: {
95
- [mixinName: string]: {
96
- source: {
97
- file: string;
98
- } | {
99
- url: string;
100
- fallback?: string;
101
- } | {
102
- object: import("openapi3-ts/oas31").OpenAPIObject;
103
- };
104
- package?: import("type-fest").PackageJson;
105
- readme?: {
106
- banner?: string;
107
- };
108
- apiRoot?: string;
109
- getModuleName?: "nestjs-operation-id" | (string & {}) | "api" | import("vovk/mjs/types").GetOpenAPINameFn;
110
- getMethodName?: "nestjs-operation-id" | "camel-case-operation-id" | "auto" | import("vovk/mjs/types").GetOpenAPINameFn;
111
- errorMessageKey?: string;
112
- };
113
- };
71
+ projectConfig?: import("vovk").VovkProjectConfig;
114
72
  } | null;
115
73
  log: {
116
74
  info: (msg: string) => void;
@@ -4,14 +4,15 @@ import getLogger from '../../utils/getLogger.mjs';
4
4
  import getUserConfig from './getUserConfig.mjs';
5
5
  import getRelativeSrcRoot from './getRelativeSrcRoot.mjs';
6
6
  import getTemplateDefs, { BuiltInTemplateName } from './getTemplateDefs.mjs';
7
- import { normalizeOpenAPIMixins } from '../../utils/normalizeOpenAPIMixins.mjs';
7
+ import { normalizeOpenAPIMixin } from '../../utils/normalizeOpenAPIMixin.mjs';
8
8
  import chalkHighlightThing from '../../utils/chalkHighlightThing.mjs';
9
- export default async function getConfig({ configPath, cwd }) {
9
+ export default async function getConfig({ configPath, cwd, logLevel, }) {
10
10
  const { configAbsolutePaths, error, userConfig } = await getUserConfig({
11
11
  configPath,
12
12
  cwd,
13
13
  });
14
14
  const conf = userConfig ?? {};
15
+ const log = getLogger(logLevel ?? conf.logLevel);
15
16
  const env = process.env;
16
17
  const clientTemplateDefs = getTemplateDefs(conf.clientTemplateDefs);
17
18
  const srcRoot = await getRelativeSrcRoot({ cwd });
@@ -51,9 +52,6 @@ export default async function getConfig({ configPath, cwd }) {
51
52
  [BuiltInTemplateName.readme]: '.',
52
53
  [BuiltInTemplateName.packageJson]: '.',
53
54
  },
54
- package: {},
55
- readme: {},
56
- reExports: {},
57
55
  ...conf.bundle,
58
56
  tsdownBuildOptions: {
59
57
  outDir: conf.bundle?.tsdownBuildOptions?.outDir ?? 'dist',
@@ -62,10 +60,9 @@ export default async function getConfig({ configPath, cwd }) {
62
60
  },
63
61
  modulesDir: conf.modulesDir ?? path.join(srcRoot ?? '.', 'modules'),
64
62
  schemaOutDir: env.VOVK_SCHEMA_OUT_DIR ?? conf.schemaOutDir ?? './.vovk-schema',
65
- origin: (env.VOVK_ORIGIN ?? conf.origin ?? '').replace(/\/$/, ''), // Remove trailing slash
66
63
  rootEntry: env.VOVK_ROOT_ENTRY ?? conf.rootEntry ?? 'api',
67
64
  rootSegmentModulesDirName: conf.rootSegmentModulesDirName ?? '',
68
- logLevel: env.VOVK_LOG_LEVEL ?? conf.logLevel ?? 'info',
65
+ logLevel: conf.logLevel ?? 'info',
69
66
  devHttps: conf.devHttps ?? false,
70
67
  moduleTemplates: {
71
68
  service: 'vovk-cli/module-templates/service.ts.ejs',
@@ -73,11 +70,22 @@ export default async function getConfig({ configPath, cwd }) {
73
70
  ...conf.moduleTemplates,
74
71
  },
75
72
  libs: conf.libs ?? {},
76
- segmentConfig: conf.segmentConfig ?? {},
77
- openApiMixins: {},
73
+ projectConfig: {
74
+ ...conf.projectConfig,
75
+ origin: (env.VOVK_ORIGIN ?? conf?.projectConfig?.origin ?? '').replace(/\/$/, ''), // Remove trailing slash
76
+ segments: Object.fromEntries(await Promise.all(Object.entries(conf.projectConfig?.segments ?? {}).map(async ([key, value]) => [
77
+ key,
78
+ {
79
+ ...value,
80
+ openAPIMixin: value.openAPIMixin
81
+ ? await normalizeOpenAPIMixin({ mixinModule: value.openAPIMixin, log, cwd })
82
+ : undefined,
83
+ },
84
+ ]))),
85
+ },
78
86
  };
79
87
  if (typeof conf.emitConfig === 'undefined') {
80
- config.emitConfig = ['libs'];
88
+ config.emitConfig = ['libs', 'projectConfig'];
81
89
  }
82
90
  else if (conf.emitConfig === true) {
83
91
  config.emitConfig = Object.keys(config);
@@ -85,12 +93,6 @@ export default async function getConfig({ configPath, cwd }) {
85
93
  else if (Array.isArray(conf.emitConfig)) {
86
94
  config.emitConfig = conf.emitConfig;
87
95
  } // else it's false and emitConfig already is []
88
- const log = getLogger(config.logLevel);
89
- config.openApiMixins = await normalizeOpenAPIMixins({
90
- mixinModules: conf.openApiMixins ?? {},
91
- cwd,
92
- log,
93
- });
94
96
  if (!userConfig) {
95
97
  log.warn(`Unable to load config at ${chalkHighlightThing(cwd)}. Using default values. ${error ?? ''}`);
96
98
  }
@@ -0,0 +1,10 @@
1
+ import { VovkSchemaIdEnum, VovkStrictConfig } from 'vovk';
2
+ import { PackageJson } from 'type-fest';
3
+ export default function getMetaSchema({ config, package: packageJson, }: {
4
+ config: VovkStrictConfig;
5
+ package: PackageJson;
6
+ }): {
7
+ config: VovkStrictConfig;
8
+ $schema: VovkSchemaIdEnum;
9
+ package: Pick<PackageJson, "name" | "version" | "description" | "author" | "license">;
10
+ };
@@ -0,0 +1,13 @@
1
+ import { VovkSchemaIdEnum } from 'vovk';
2
+ import pick from 'lodash/pick.js';
3
+ export default function getMetaSchema({ config, package: packageJson, }) {
4
+ return {
5
+ $schema: VovkSchemaIdEnum.META,
6
+ package: pick(packageJson, ['name', 'version', 'description', 'author', 'license']),
7
+ ...{
8
+ config: (config
9
+ ? pick(config, [...config.emitConfig, '$schema'])
10
+ : {}),
11
+ },
12
+ };
13
+ }
@@ -1,9 +1,11 @@
1
+ import { LogLevelNames } from 'loglevel';
1
2
  export type ProjectInfo = Awaited<ReturnType<typeof getProjectInfo>>;
2
- export default function getProjectInfo({ port: givenPort, cwd, configPath, srcRootRequired, }?: {
3
+ export default function getProjectInfo({ port: givenPort, cwd, configPath, srcRootRequired, logLevel, }?: {
3
4
  port?: number;
4
5
  cwd?: string;
5
6
  configPath?: string;
6
7
  srcRootRequired?: boolean;
8
+ logLevel?: LogLevelNames;
7
9
  }): Promise<{
8
10
  cwd: string;
9
11
  port: string;
@@ -13,7 +15,7 @@ export default function getProjectInfo({ port: givenPort, cwd, configPath, srcRo
13
15
  vovkCliPackage: {
14
16
  version: string;
15
17
  };
16
- config: import("vovk").VovkStrictConfig;
18
+ config: import("vovk/types").VovkStrictConfig;
17
19
  packageJson: import("type-fest").PackageJson;
18
20
  isNextInstalled: boolean;
19
21
  log: {
@@ -2,20 +2,23 @@ import path from 'node:path';
2
2
  import getConfig from './getConfig/index.mjs';
3
3
  import { getPackageJson } from '../utils/getPackageJson.mjs';
4
4
  import { readFile } from 'node:fs/promises';
5
- export default async function getProjectInfo({ port: givenPort, cwd = process.cwd(), configPath, srcRootRequired = true, } = {}) {
5
+ export default async function getProjectInfo({ port: givenPort, cwd = process.cwd(), configPath, srcRootRequired = true, logLevel, } = {
6
+ logLevel: 'info',
7
+ }) {
6
8
  const port = givenPort?.toString() ?? process.env.PORT ?? '3000';
7
9
  // Make PORT available to the config file at getConfig
8
10
  process.env.PORT = port;
9
11
  const { config, srcRoot, configAbsolutePaths, log } = await getConfig({
10
12
  configPath,
11
13
  cwd,
14
+ logLevel,
12
15
  });
13
16
  const packageJson = await getPackageJson(cwd, log);
14
17
  const isNextInstalled = !!packageJson?.dependencies?.next || !!packageJson?.devDependencies?.next;
15
18
  if (srcRootRequired && !srcRoot) {
16
19
  throw new Error(`Could not find app router directory at ${cwd}. Check Next.js docs for more info.`);
17
20
  }
18
- const apiRoot = `${config.origin ?? ''}/${config.rootEntry}`;
21
+ const apiRoot = `${config.projectConfig.origin ?? ''}/${config.rootEntry}`;
19
22
  const apiDirAbsolutePath = srcRoot ? path.resolve(cwd, srcRoot, 'app', config.rootEntry) : null;
20
23
  if (configAbsolutePaths.length > 1) {
21
24
  log.warn(`Multiple config files found. Using the first one: ${configAbsolutePaths[0]}`);
package/dist/index.mjs CHANGED
@@ -25,8 +25,9 @@ program
25
25
  .option('--exit', 'kill the processes when schema and client is generated')
26
26
  .option('--schema-out <path>', 'path to schema output directory (default: .vovk-schema)')
27
27
  .option('--https, --dev-https', 'use HTTPS for the dev server (default: false)')
28
+ .option('--log-level <level>', 'set the log level')
28
29
  .action(async (nextArgs, options) => {
29
- const { nextDev, exit = false, schemaOut, devHttps } = options;
30
+ const { nextDev, exit = false, schemaOut, devHttps, logLevel } = options;
30
31
  const portAttempts = 30;
31
32
  const PORT = !nextDev
32
33
  ? process.env.PORT
@@ -52,9 +53,11 @@ program
52
53
  env: {
53
54
  PORT,
54
55
  __VOVK_START_WATCHER_IN_STANDALONE_MODE__: 'true',
56
+ // TODO: Pass these as flags
55
57
  __VOVK_SCHEMA_OUT_FLAG__: schemaOut ?? '',
56
58
  __VOVK_DEV_HTTPS_FLAG__: devHttps ? 'true' : 'false',
57
59
  __VOVK_EXIT__: exit ? 'true' : 'false',
60
+ __VOVK_LOG_LEVEL__: logLevel ?? undefined,
58
61
  },
59
62
  },
60
63
  ], {
@@ -70,7 +73,7 @@ program
70
73
  }
71
74
  }
72
75
  else {
73
- void new VovkDev({ schemaOut, devHttps }).start({ exit });
76
+ void new VovkDev({ schemaOut, devHttps, logLevel }).start({ exit });
74
77
  }
75
78
  });
76
79
  program
@@ -98,8 +101,13 @@ program
98
101
  .option('--openapi-root-url <urls...>', 'root URLs corresponding to the index of --openapi option')
99
102
  .option('--openapi-mixin-name <names...>', 'mixin names corresponding to the index of --openapi option')
100
103
  .option('--openapi-fallback <paths...>', 'save OpenAPI spec and use it as a fallback if URL is not available')
104
+ .option('--log-level <level>', 'set the log level')
101
105
  .action(async (cliGenerateOptions) => {
102
- const projectInfo = await getProjectInfo({ configPath: cliGenerateOptions.configPath, srcRootRequired: false });
106
+ const projectInfo = await getProjectInfo({
107
+ configPath: cliGenerateOptions.configPath,
108
+ srcRootRequired: false,
109
+ logLevel: cliGenerateOptions.logLevel,
110
+ });
103
111
  await new VovkGenerate({
104
112
  projectInfo,
105
113
  forceNothingWrittenLog: true,
@@ -118,17 +126,25 @@ program
118
126
  .option('--config <config>', 'path to config file')
119
127
  .option('--schema <path>', 'path to schema folder (default: .vovk-schema)')
120
128
  .option('--origin <url>', 'set the origin URL for the generated client')
129
+ .option('--tsconfig <path>', 'path to tsconfig.json for bundling by tsdown')
121
130
  .option('--openapi, --openapi-spec <openapi_path_or_urls...>', 'use OpenAPI schema instead of Vovk schema')
122
131
  .option('--openapi-get-module-name <names...>', 'module names corresponding to the index of --openapi option')
123
132
  .option('--openapi-get-method-name <names...>', 'method names corresponding to the index of --openapi option')
124
133
  .option('--openapi-root-url <urls...>', 'root URLs corresponding to the index of --openapi option')
134
+ .option('--log-level <level>', 'set the log level')
125
135
  .action(async (cliBundleOptions) => {
126
- const projectInfo = await getProjectInfo({ configPath: cliBundleOptions.config, srcRootRequired: false });
127
- const { cwd, config, log, isNextInstalled } = projectInfo;
136
+ const projectInfo = await getProjectInfo({
137
+ configPath: cliBundleOptions.config,
138
+ srcRootRequired: false,
139
+ logLevel: cliBundleOptions.logLevel,
140
+ });
141
+ const { cwd, config, log, isNextInstalled, packageJson } = projectInfo;
128
142
  const fullSchema = await getProjectFullSchema({
129
143
  schemaOutAbsolutePath: path.resolve(cwd, cliBundleOptions?.schema ?? config.schemaOutDir),
130
144
  log,
131
145
  isNextInstalled,
146
+ package: packageJson,
147
+ config,
132
148
  });
133
149
  await bundle({
134
150
  projectInfo,
@@ -147,7 +163,10 @@ program
147
163
  .option('--no-segment-update', 'do not update segment files when creating a new module')
148
164
  .option('--dry-run', 'do not write files to disk')
149
165
  .option('--static', 'if the segment is static')
150
- .action((components, newOptions) => newComponents(components, newOptions));
166
+ .option('--log-level <level>', 'set the log level')
167
+ .action(async (components, newOptions) => newComponents(components, await getProjectInfo({
168
+ logLevel: newOptions.logLevel,
169
+ }), newOptions));
151
170
  program
152
171
  .command('help')
153
172
  .description('Show help message')
@@ -11,14 +11,36 @@ export default async function createConfig({ root, log, options: { validationLib
11
11
  .readFile(path.join(root, 'package.json'), 'utf-8')
12
12
  .then((content) => JSON.parse(content).type === 'module');
13
13
  const configAbsolutePath = path.join(dir, isModule ? 'vovk.config.mjs' : 'vovk.config.js');
14
+ const typeTemplates = {
15
+ controller: 'vovk-cli/module-templates/type/controller.ts.ejs',
16
+ service: 'vovk-cli/module-templates/type/service.ts.ejs',
17
+ };
14
18
  const moduleTemplates = {
15
- controller: 'vovk-cli/module-templates/controller.ts.ejs',
16
- service: 'vovk-cli/module-templates/service.ts.ejs',
19
+ ...typeTemplates,
20
+ ...{
21
+ type: typeTemplates,
22
+ zod: {
23
+ controller: 'vovk-zod/module-templates/controller.ts.ejs',
24
+ },
25
+ yup: {
26
+ controller: 'vovk-yup/module-templates/controller.ts.ejs',
27
+ },
28
+ 'class-validator': {
29
+ controller: 'vovk-dto/module-templates/controller.ts.ejs',
30
+ },
31
+ valibot: {
32
+ controller: 'vovk-cli/module-templates/valibot/controller.ts.ejs',
33
+ },
34
+ arktype: {
35
+ controller: 'vovk-cli/module-templates/arktype/controller.ts.ejs',
36
+ },
37
+ }[validationLibrary ?? 'type'],
17
38
  };
18
39
  config.imports ??= {};
19
- config.imports.validateOnClient = validationLibrary === 'vovk-dto' ? 'vovk-dto/validateOnClient' : 'vovk-ajv';
20
- if (validationLibrary) {
40
+ config.imports.validateOnClient = validationLibrary === 'class-validator' ? 'vovk-dto/validateOnClient' : 'vovk-ajv';
41
+ if (validationLibrary && !moduleTemplates) {
21
42
  try {
43
+ // TODO: Legacy, is it useful to keep it?
22
44
  const validationTemplates = await getTemplateFilesFromPackage(validationLibrary, channel);
23
45
  Object.assign(moduleTemplates, validationTemplates);
24
46
  }
@@ -0,0 +1,4 @@
1
+ export declare function createStandardSchemaValidatorFile({ cwd, validationLibrary, }: {
2
+ cwd: string;
3
+ validationLibrary: 'arktype' | 'valibot';
4
+ }): Promise<void>;
@@ -0,0 +1,38 @@
1
+ import fs from 'fs/promises';
2
+ import getRelativeSrcRoot from '../getProjectInfo/getConfig/getRelativeSrcRoot.mjs';
3
+ import path from 'path';
4
+ function getCode(validationLibrary) {
5
+ if (validationLibrary === 'valibot') {
6
+ return `
7
+ import { createStandardValidation, KnownAny } from 'vovk';
8
+ import { toJsonSchema } from '@valibot/to-json-schema';
9
+ import * as v from 'valibot';
10
+
11
+ const withValibot = createStandardValidation({
12
+ toJSONSchema: (model: v.BaseSchema<KnownAny, KnownAny, KnownAny>) => toJsonSchema(model),
13
+ });
14
+
15
+ export default withValibot;
16
+ `.trimStart();
17
+ }
18
+ if (validationLibrary === 'arktype') {
19
+ return `
20
+ import { createStandardValidation } from 'vovk';
21
+ import { type } from 'arktype';
22
+
23
+ const withArk = createStandardValidation({
24
+ toJSONSchema: (model: type) => model.toJsonSchema(),
25
+ });
26
+
27
+ export default withArk;
28
+ `.trimStart();
29
+ }
30
+ throw new Error(`Unknown validation library: ${validationLibrary}`);
31
+ }
32
+ export async function createStandardSchemaValidatorFile({ cwd, validationLibrary, }) {
33
+ const code = getCode(validationLibrary);
34
+ const srcRoot = (await getRelativeSrcRoot({ cwd })) ?? '.';
35
+ const libDir = path.join(cwd, srcRoot, 'lib');
36
+ await fs.mkdir(libDir, { recursive: true });
37
+ await fs.writeFile(path.join(libDir, `${validationLibrary === 'arktype' ? 'withArk' : 'withValibot'}.ts`), code);
38
+ }
@@ -8,18 +8,19 @@ import getFileSystemEntryType from '../utils/getFileSystemEntryType.mjs';
8
8
  import installDependencies, { getPackageManager } from './installDependencies.mjs';
9
9
  import getLogger from '../utils/getLogger.mjs';
10
10
  import createConfig from './createConfig.mjs';
11
- import updateNPMScripts, { getBuildScript, getDevScript } from './updateNPMScripts.mjs';
11
+ import updateNPMScripts, { getDevScript } from './updateNPMScripts.mjs';
12
12
  import checkTSConfigForExperimentalDecorators from './checkTSConfigForExperimentalDecorators.mjs';
13
13
  import updateTypeScriptConfig from './updateTypeScriptConfig.mjs';
14
14
  import updateDependenciesWithoutInstalling from './updateDependenciesWithoutInstalling.mjs';
15
15
  import logUpdateDependenciesError from './logUpdateDependenciesError.mjs';
16
16
  import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
17
+ import { createStandardSchemaValidatorFile } from './createStandardSchemaValidatorFile.mjs';
17
18
  export class Init {
18
19
  root;
19
20
  log;
20
- async #init({ configPaths, pkgJson, }, { useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, lang, dryRun, channel, }) {
21
+ async #init({ configPaths, pkgJson, cwd = process.cwd(), }, { useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, lang, dryRun, channel, }) {
21
22
  const { log, root } = this;
22
- const dependencies = ['vovk', 'vovk-client', 'vovk-ajv', 'openapi3-ts'];
23
+ const dependencies = ['vovk', 'vovk-client', 'openapi3-ts', 'vovk-ajv', 'ajv'];
23
24
  const devDependencies = ['vovk-cli'];
24
25
  if (lang?.includes('py')) {
25
26
  devDependencies.push('vovk-python');
@@ -33,9 +34,18 @@ export class Init {
33
34
  log.debug(`Deleted existing config file${configPaths.length > 1 ? 's' : ''} at ${configPaths.join(', ')}`);
34
35
  }
35
36
  if (validationLibrary) {
36
- dependencies.push(validationLibrary, ...({
37
- 'vovk-zod': ['zod'],
38
- 'vovk-dto': ['class-validator', 'class-transformer', 'dto-mapped-types', 'reflect-metadata'],
37
+ dependencies.push(...({
38
+ zod: ['zod', 'vovk-zod'],
39
+ 'class-validator': [
40
+ 'class-validator',
41
+ 'class-transformer',
42
+ 'dto-mapped-types',
43
+ 'reflect-metadata',
44
+ 'vovk-dto',
45
+ ],
46
+ yup: ['yup', 'vovk-yup'],
47
+ valibot: ['valibot', '@valibot/to-json-schema'],
48
+ arktype: ['arktype'],
39
49
  }[validationLibrary] ?? []));
40
50
  }
41
51
  if (updateScripts) {
@@ -56,7 +66,7 @@ export class Init {
56
66
  const compilerOptions = {
57
67
  experimentalDecorators: true,
58
68
  };
59
- if (validationLibrary === 'vovk-dto') {
69
+ if (validationLibrary === 'class-validator') {
60
70
  compilerOptions.emitDecoratorMetadata = true;
61
71
  }
62
72
  if (!dryRun)
@@ -120,6 +130,12 @@ export class Init {
120
130
  }
121
131
  }
122
132
  }
133
+ if (validationLibrary === 'valibot' || validationLibrary === 'arktype') {
134
+ createStandardSchemaValidatorFile({
135
+ cwd,
136
+ validationLibrary,
137
+ });
138
+ }
123
139
  try {
124
140
  const { configAbsolutePath } = await createConfig({
125
141
  root,
@@ -135,13 +151,13 @@ export class Init {
135
151
  async main({ prefix, yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, lang, dryRun, channel, }) {
136
152
  const cwd = process.cwd();
137
153
  const root = path.resolve(cwd, prefix ?? '.');
138
- const log = getLogger(logLevel);
154
+ const log = getLogger(logLevel ?? 'info');
139
155
  const pkgJson = await NPMCliPackageJson.load(root);
140
156
  this.root = root;
141
157
  this.log = log;
142
158
  const configPaths = await getConfigPaths({ cwd, relativePath: prefix });
143
159
  if (yes) {
144
- return this.#init({ configPaths, pkgJson }, {
160
+ return this.#init({ configPaths, pkgJson, cwd }, {
145
161
  prefix: prefix ?? '.',
146
162
  useNpm: useNpm ?? (!useYarn && !usePnpm && !useBun),
147
163
  useYarn: useYarn ?? false,
@@ -150,7 +166,7 @@ export class Init {
150
166
  skipInstall: skipInstall ?? false,
151
167
  updateTsConfig: updateTsConfig ?? true,
152
168
  updateScripts: updateScripts ?? 'implicit',
153
- validationLibrary: validationLibrary?.toLocaleLowerCase() === 'none' ? null : (validationLibrary ?? 'vovk-zod'),
169
+ validationLibrary: validationLibrary?.toLocaleLowerCase() === 'none' ? null : (validationLibrary ?? 'zod'),
154
170
  dryRun: dryRun ?? false,
155
171
  channel: channel ?? 'latest',
156
172
  lang: lang ?? [],
@@ -174,17 +190,27 @@ export class Init {
174
190
  : (validationLibrary ??
175
191
  (await select({
176
192
  message: 'Choose validation library',
177
- default: 'vovk-zod',
193
+ default: 'zod',
178
194
  choices: [
179
195
  {
180
- name: 'vovk-zod',
181
- value: 'vovk-zod',
196
+ name: 'Zod',
197
+ value: 'zod',
182
198
  description: 'Use Zod for data validation',
183
199
  },
184
200
  {
185
- name: 'vovk-dto',
186
- value: 'vovk-dto',
187
- description: 'Use class-validator for data validation. Also installs class-transformer, dto-mapped-types and reflect-metadata',
201
+ name: 'class-validator',
202
+ value: 'class-validator',
203
+ description: 'Use class-validator for data validation',
204
+ },
205
+ {
206
+ name: 'Valibot',
207
+ value: 'valibot',
208
+ description: 'Use valibot for data validation.',
209
+ },
210
+ {
211
+ name: 'ArkType',
212
+ value: 'arktype',
213
+ description: 'Use arktype for data validation.',
188
214
  },
189
215
  { name: 'None', value: null, description: 'Install validation library later' },
190
216
  ],
@@ -196,12 +222,12 @@ export class Init {
196
222
  {
197
223
  name: 'Yes, use "concurrently" implicitly',
198
224
  value: 'implicit',
199
- description: `The "dev" script will use "concurrently" API to run "next dev" and "vovk dev" commands together and automatically find an available port ${chalk.whiteBright.bold(`"${getDevScript(pkgJson, 'implicit')}"`)} and the "build" scrilt will run "vovk generate" before "next build" ${chalk.whiteBright.bold(`"${getBuildScript(pkgJson)}"`)}`,
225
+ description: `The "dev" script will use "concurrently" API to run "next dev" and "vovk dev" commands together and automatically find an available port ${chalk.whiteBright.bold(`"${getDevScript(pkgJson, 'implicit')}"`)} and the "prebuild" script will run "vovk generate"`,
200
226
  },
201
227
  {
202
228
  name: 'Yes, use "concurrently" explicitly',
203
229
  value: 'explicit',
204
- description: `The "dev" script will use pre-defined PORT variable and run "next dev" and "vovk dev" as "concurrently" CLI arguments ${chalk.whiteBright.bold(`"${getDevScript(pkgJson, 'explicit')}"`)} and the "build" scrilt will run "vovk generate" before "next build" ${chalk.whiteBright.bold(`"${getBuildScript(pkgJson)}"`)}`,
230
+ description: `The "dev" script will use pre-defined PORT variable and run "next dev" and "vovk dev" as "concurrently" CLI arguments ${chalk.whiteBright.bold(`"${getDevScript(pkgJson, 'explicit')}"`)} and the "prebuild" script will run "vovk generate"`,
205
231
  },
206
232
  {
207
233
  name: 'No',
@@ -220,7 +246,7 @@ export class Init {
220
246
  }
221
247
  if (shouldAsk) {
222
248
  const keys = ['experimentalDecorators'];
223
- if (validationLibrary === 'vovk-dto') {
249
+ if (validationLibrary === 'class-validator') {
224
250
  keys.push('emitDecoratorMetadata');
225
251
  }
226
252
  updateTsConfig = await confirm({
@@ -229,13 +255,13 @@ export class Init {
229
255
  }
230
256
  }
231
257
  lang ??= await checkbox({
232
- message: 'Do you want to generate RPC client for other languages besides TypeScript (beta)?',
258
+ message: 'Do you want to generate RPC client for other languages besides TypeScript (experimental)?',
233
259
  choices: [
234
260
  { name: 'Python', value: 'py' },
235
261
  { name: 'Rust', value: 'rs' },
236
262
  ],
237
263
  });
238
- await this.#init({ configPaths, pkgJson }, {
264
+ await this.#init({ configPaths, pkgJson, cwd }, {
239
265
  useNpm: useNpm ?? (!useYarn && !usePnpm && !useBun),
240
266
  useYarn: useYarn ?? false,
241
267
  usePnpm: usePnpm ?? false,
@@ -1,4 +1,3 @@
1
1
  import NPMCliPackageJson from '@npmcli/package-json';
2
2
  export declare function getDevScript(pkgJson: NPMCliPackageJson, updateScriptsMode: 'implicit' | 'explicit'): string;
3
- export declare function getBuildScript(pkgJson: NPMCliPackageJson): string;
4
3
  export default function updateNPMScripts(pkgJson: NPMCliPackageJson, root: string, updateScriptsMode: 'implicit' | 'explicit'): Promise<void>;
@@ -5,16 +5,12 @@ export function getDevScript(pkgJson, updateScriptsMode) {
5
5
  ? `PORT=3000 concurrently '${nextDev}' 'vovk dev' --kill-others`
6
6
  : `vovk dev --next-dev${nextDevFlags ? ` -- ${nextDevFlags}` : ''}`;
7
7
  }
8
- export function getBuildScript(pkgJson) {
9
- const nextBuild = pkgJson.content.scripts?.build ?? 'next build';
10
- return `vovk generate && ${nextBuild}`;
11
- }
12
8
  export default async function updateNPMScripts(pkgJson, root, updateScriptsMode) {
13
9
  pkgJson.update({
14
10
  scripts: {
15
11
  ...pkgJson.content.scripts,
16
12
  dev: getDevScript(pkgJson, updateScriptsMode),
17
- build: getBuildScript(pkgJson),
13
+ prebuild: 'vovk generate',
18
14
  },
19
15
  });
20
16
  await pkgJson.save();
@@ -14,7 +14,7 @@ export function initProgram(program) {
14
14
  .option('--update-ts-config', 'update tsconfig.json')
15
15
  .option('--update-scripts <mode>', 'update package.json scripts ("implicit" or "explicit")')
16
16
  .option('--lang <languages...>', 'generate client for other programming languages by default ("py" for Python and "rs" for Rust are supported)')
17
- .option('--validation-library <library>', 'validation library to use ("vovk-zod", "vovk-dto" or another); set to "none" to skip')
17
+ .option('--validation-library <library>', 'validation library to use ("zod", "class-validator", "valibot", "arktype" or another); set to "none" to skip')
18
18
  .option('--channel <channel>', 'channel to use for fetching packages', 'latest')
19
19
  .option('--dry-run', 'do not write files to disk')
20
20
  .action((options) => new Init().main(options));
@@ -1,2 +1,3 @@
1
1
  import type { NewOptions } from '../types.mjs';
2
- export declare function newComponents(components: string[], { dryRun, dir, templates, overwrite, noSegmentUpdate, empty, static: isStaticSegment }: NewOptions): Promise<void>;
2
+ import type { ProjectInfo } from '../getProjectInfo/index.mts';
3
+ export declare function newComponents(components: string[], projectInfo: ProjectInfo, { dryRun, dir, templates, overwrite, noSegmentUpdate, empty, static: isStaticSegment }: NewOptions): Promise<void>;