vovk-cli 0.1.3 → 0.3.0-beta.0

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 (138) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/client-templates/{schemaTs → schema-ts}/schema.ts.ejs +1 -1
  3. package/client-templates/{tsBase → ts-base}/index.ts.ejs +1 -1
  4. package/dist/bundle/index.d.mts +1 -1
  5. package/dist/bundle/index.mjs +67 -45
  6. package/dist/dev/{diffSegmentSchema.d.mts → diff-segment-schema.d.mts} +0 -17
  7. package/dist/dev/{diffSegmentSchema.mjs → diff-segment-schema.mjs} +1 -17
  8. package/dist/dev/{ensureSchemaFiles.d.mts → ensure-schema-files.d.mts} +1 -1
  9. package/dist/dev/{ensureSchemaFiles.mjs → ensure-schema-files.mjs} +30 -12
  10. package/dist/dev/index.mjs +23 -17
  11. package/dist/dev/log-diff-result.d.mts +3 -0
  12. package/dist/dev/{logDiffResult.mjs → log-diff-result.mjs} +2 -2
  13. package/dist/dev/{writeMetaJson.d.mts → write-meta-json.d.mts} +1 -1
  14. package/dist/dev/{writeMetaJson.mjs → write-meta-json.mjs} +3 -3
  15. package/dist/dev/{writeOneSegmentSchemaFile.d.mts → write-one-segment-schema-file.d.mts} +1 -1
  16. package/dist/dev/{writeOneSegmentSchemaFile.mjs → write-one-segment-schema-file.mjs} +8 -3
  17. package/dist/generate/ensure-client.d.mts +3 -0
  18. package/dist/generate/{ensureClient.mjs → ensure-client.mjs} +1 -1
  19. package/dist/generate/generate.d.mts +2 -2
  20. package/dist/generate/generate.mjs +41 -28
  21. package/dist/generate/{getClientTemplateFiles.d.mts → get-client-template-files.d.mts} +1 -1
  22. package/dist/generate/{getClientTemplateFiles.mjs → get-client-template-files.mjs} +8 -4
  23. package/dist/generate/{getProjectFullSchema.d.mts → get-project-full-schema.d.mts} +1 -1
  24. package/dist/generate/{getProjectFullSchema.mjs → get-project-full-schema.mjs} +3 -3
  25. package/dist/generate/{getTemplateClientImports.mjs → get-template-client-imports.mjs} +2 -2
  26. package/dist/generate/index.d.mts +2 -2
  27. package/dist/generate/index.mjs +46 -34
  28. package/dist/generate/{writeOneClientFile.d.mts → write-one-client-file.d.mts} +5 -5
  29. package/dist/generate/{writeOneClientFile.mjs → write-one-client-file.mjs} +10 -8
  30. package/dist/{getProjectInfo/getConfig/getRelativeSrcRoot.mjs → get-project-info/get-config/get-relative-src-root.mjs} +1 -1
  31. package/dist/get-project-info/get-config/get-template-defs.d.mts +22 -0
  32. package/dist/{getProjectInfo/getConfig/getTemplateDefs.mjs → get-project-info/get-config/get-template-defs.mjs} +35 -61
  33. package/dist/{getProjectInfo/getConfig/getUserConfig.mjs → get-project-info/get-config/get-user-config.mjs} +2 -2
  34. package/dist/{getProjectInfo/getConfig → get-project-info/get-config}/index.d.mts +2 -2
  35. package/dist/{getProjectInfo/getConfig → get-project-info/get-config}/index.mjs +17 -12
  36. package/dist/{getProjectInfo/getMetaSchema.d.mts → get-project-info/get-meta-schema.d.mts} +1 -1
  37. package/dist/{getProjectInfo → get-project-info}/index.mjs +3 -3
  38. package/dist/index.mjs +25 -16
  39. package/dist/init/{createConfig.d.mts → create-config.d.mts} +1 -1
  40. package/dist/init/{createConfig.mjs → create-config.mjs} +6 -6
  41. package/dist/init/index.d.mts +1 -1
  42. package/dist/init/index.mjs +54 -22
  43. package/dist/init/{installDependencies.d.mts → install-dependencies.d.mts} +2 -1
  44. package/dist/init/{installDependencies.mjs → install-dependencies.mjs} +11 -3
  45. package/dist/init/{logUpdateDependenciesError.d.mts → log-update-dependencies-error.d.mts} +2 -2
  46. package/dist/init/{logUpdateDependenciesError.mjs → log-update-dependencies-error.mjs} +1 -1
  47. package/dist/init/{updateDependenciesWithoutInstalling.d.mts → update-dependencies-without-installing.d.mts} +1 -1
  48. package/dist/init/{updateDependenciesWithoutInstalling.mjs → update-dependencies-without-installing.mjs} +1 -2
  49. package/dist/init/update-gitignore.d.mts +2 -0
  50. package/dist/init/update-gitignore.mjs +20 -0
  51. package/dist/new/index.d.mts +1 -1
  52. package/dist/new/index.mjs +2 -2
  53. package/dist/new/{newModule.d.mts → new-module.d.mts} +1 -1
  54. package/dist/new/{newModule.mjs → new-module.mjs} +15 -9
  55. package/dist/new/{newSegment.d.mts → new-segment.d.mts} +1 -1
  56. package/dist/new/{newSegment.mjs → new-segment.mjs} +11 -6
  57. package/dist/new/render.mjs +3 -3
  58. package/dist/types.d.mts +1 -1
  59. package/dist/utils/{compileJSONSchemaToTypeScriptType.mjs → compile-json-schema-to-typescript-type.mjs} +1 -1
  60. package/dist/utils/{formatLoggedSegmentName.mjs → format-logged-segment-name.mjs} +1 -1
  61. package/dist/utils/{generateFnName.d.mts → generate-fn-name.d.mts} +0 -9
  62. package/dist/utils/{generateFnName.mjs → generate-fn-name.mjs} +2 -9
  63. package/dist/utils/generated-banner.d.mts +1 -0
  64. package/dist/utils/generated-banner.mjs +3 -0
  65. package/dist/utils/get-available-port.d.mts +1 -0
  66. package/dist/utils/{getAvailablePort.mjs → get-available-port.mjs} +2 -14
  67. package/dist/utils/get-file-system-entry-type.d.mts +6 -0
  68. package/dist/utils/{getFileSystemEntryType.mjs → get-file-system-entry-type.mjs} +5 -5
  69. package/dist/utils/{getPackageJson.d.mts → get-package-json.d.mts} +1 -1
  70. package/dist/utils/{getPackageJson.mjs → get-package-json.mjs} +1 -1
  71. package/dist/utils/{locateSegments.d.mts → locate-segments.d.mts} +1 -1
  72. package/dist/utils/{locateSegments.mjs → locate-segments.mjs} +1 -1
  73. package/dist/utils/{normalizeOpenAPIMixin.d.mts → normalize-openapi-mixin.d.mts} +2 -2
  74. package/dist/utils/{normalizeOpenAPIMixin.mjs → normalize-openapi-mixin.mjs} +20 -5
  75. package/dist/utils/prettify.d.mts +4 -0
  76. package/dist/utils/prettify.mjs +39 -3
  77. package/dist/utils/remove-unlisted-directories.d.mts +1 -0
  78. package/dist/utils/remove-unlisted-directories.mjs +99 -0
  79. package/dist/utils/{resolveAbsoluteModulePath.mjs → resolve-absolute-module-path.mjs} +2 -3
  80. package/dist/utils/{updateConfigProperty.mjs → update-config-property.mjs} +1 -1
  81. package/module-templates/arktype/controller.ts.ejs +2 -2
  82. package/module-templates/type/controller.ts.ejs +2 -2
  83. package/module-templates/type/service.ts.ejs +2 -2
  84. package/module-templates/valibot/controller.ts.ejs +2 -2
  85. package/module-templates/zod/controller.ts.ejs +2 -2
  86. package/package.json +23 -30
  87. package/client-templates/jsBase/index.d.ts.ejs +0 -21
  88. package/client-templates/jsBase/index.js.ejs +0 -18
  89. package/client-templates/openapiJs/openapi.d.ts.ejs +0 -4
  90. package/client-templates/openapiJs/openapi.js.ejs +0 -4
  91. package/client-templates/schemaJs/schema.d.ts.ejs +0 -10
  92. package/client-templates/schemaJs/schema.js.ejs +0 -29
  93. package/dist/dev/logDiffResult.d.mts +0 -3
  94. package/dist/generate/ensureClient.d.mts +0 -3
  95. package/dist/getProjectInfo/getConfig/getTemplateDefs.d.mts +0 -25
  96. package/dist/utils/getAvailablePort.d.mts +0 -9
  97. package/dist/utils/getFileSystemEntryType.d.mts +0 -5
  98. package/dist/utils/removeUnlistedDirectories.d.mts +0 -9
  99. package/dist/utils/removeUnlistedDirectories.mjs +0 -60
  100. package/client-templates/{openapiJson → openapi-json}/openapi.json.ejs +0 -0
  101. package/client-templates/{openapiTs → openapi-ts}/openapi.ts.ejs +0 -0
  102. package/client-templates/{packageJson → package-json}/package.json.ejs +0 -0
  103. package/client-templates/{schemaJson → schema-json}/schema.json.ejs +0 -0
  104. package/dist/generate/{getTemplateClientImports.d.mts → get-template-client-imports.d.mts} +0 -0
  105. package/dist/{getProjectInfo/getConfig/getConfigAbsolutePaths.d.mts → get-project-info/get-config/get-config-absolute-paths.d.mts} +0 -0
  106. package/dist/{getProjectInfo/getConfig/getConfigAbsolutePaths.mjs → get-project-info/get-config/get-config-absolute-paths.mjs} +0 -0
  107. package/dist/{getProjectInfo/getConfig/getRelativeSrcRoot.d.mts → get-project-info/get-config/get-relative-src-root.d.mts} +0 -0
  108. package/dist/{getProjectInfo/getConfig/getUserConfig.d.mts → get-project-info/get-config/get-user-config.d.mts} +0 -0
  109. package/dist/{getProjectInfo/getMetaSchema.mjs → get-project-info/get-meta-schema.mjs} +1 -1
  110. package/dist/{getProjectInfo → get-project-info}/index.d.mts +0 -0
  111. package/dist/init/{checkTSConfigForExperimentalDecorators.d.mts → check-tsconfig-for-experimental-decorators.d.mts} +0 -0
  112. package/dist/init/{checkTSConfigForExperimentalDecorators.mjs → check-tsconfig-for-experimental-decorators.mjs} +1 -1
  113. package/dist/init/{updateNPMScripts.d.mts → update-npm-scripts.d.mts} +0 -0
  114. package/dist/init/{updateNPMScripts.mjs → update-npm-scripts.mjs} +0 -0
  115. package/dist/init/{updateTypeScriptConfig.d.mts → update-typescript-config.d.mts} +0 -0
  116. package/dist/init/{updateTypeScriptConfig.mjs → update-typescript-config.mjs} +1 -1
  117. package/dist/new/{addClassToSegmentCode.d.mts → add-class-to-segment-code.d.mts} +0 -0
  118. package/dist/new/{addClassToSegmentCode.mjs → add-class-to-segment-code.mjs} +0 -0
  119. package/dist/new/{addCommonTerms.d.mts → add-common-terms.d.mts} +0 -0
  120. package/dist/new/{addCommonTerms.mjs → add-common-terms.mjs} +0 -0
  121. package/dist/utils/{chalkHighlightThing.d.mts → chalk-highlight-thing.d.mts} +0 -0
  122. package/dist/utils/{chalkHighlightThing.mjs → chalk-highlight-thing.mjs} +0 -0
  123. package/dist/utils/{compileJSONSchemaToTypeScriptType.d.mts → compile-json-schema-to-typescript-type.d.mts} +1 -1
  124. package/dist/utils/{compileTs.d.mts → compile-ts.d.mts} +0 -0
  125. package/dist/utils/{compileTs.mjs → compile-ts.mjs} +1 -1
  126. /package/dist/utils/{debounceWithArgs.d.mts → debounce-with-args.d.mts} +0 -0
  127. /package/dist/utils/{debounceWithArgs.mjs → debounce-with-args.mjs} +0 -0
  128. /package/dist/utils/{formatLoggedSegmentName.d.mts → format-logged-segment-name.d.mts} +0 -0
  129. /package/dist/utils/{getLogger.d.mts → get-logger.d.mts} +0 -0
  130. /package/dist/utils/{getLogger.mjs → get-logger.mjs} +0 -0
  131. /package/dist/utils/{getNPMPackageMetadata.d.mts → get-npm-package-metadata.d.mts} +0 -0
  132. /package/dist/utils/{getNPMPackageMetadata.mjs → get-npm-package-metadata.mjs} +0 -0
  133. /package/dist/utils/{getPublicModuleNameFromPath.d.mts → get-public-module-name-from-path.d.mts} +0 -0
  134. /package/dist/utils/{getPublicModuleNameFromPath.mjs → get-public-module-name-from-path.mjs} +0 -0
  135. /package/dist/utils/{pickSegmentFullSchema.d.mts → pick-segment-full-schema.d.mts} +0 -0
  136. /package/dist/utils/{pickSegmentFullSchema.mjs → pick-segment-full-schema.mjs} +0 -0
  137. /package/dist/utils/{resolveAbsoluteModulePath.d.mts → resolve-absolute-module-path.d.mts} +0 -0
  138. /package/dist/utils/{updateConfigProperty.d.mts → update-config-property.d.mts} +0 -0
package/dist/index.mjs CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env -S node --experimental-vm-modules --disable-warning=ExperimentalWarning
2
- import path from 'node:path';
3
2
  import { readFileSync } from 'node:fs';
3
+ import path from 'node:path';
4
4
  import 'dotenv/config';
5
5
  import { Command } from 'commander';
6
6
  import concurrently from 'concurrently';
7
- import { getAvailablePort } from './utils/getAvailablePort.mjs';
8
- import { getProjectInfo } from './getProjectInfo/index.mjs';
9
- import { VovkGenerate } from './generate/index.mjs';
10
7
  import { bundle } from './bundle/index.mjs';
11
8
  import { VovkDev } from './dev/index.mjs';
9
+ import { getProjectFullSchema } from './generate/get-project-full-schema.mjs';
10
+ import { VovkGenerate } from './generate/index.mjs';
11
+ import { getProjectInfo } from './get-project-info/index.mjs';
12
12
  import { newComponents } from './new/index.mjs';
13
- import { getProjectFullSchema } from './generate/getProjectFullSchema.mjs';
13
+ import { getAvailablePort } from './utils/get-available-port.mjs';
14
14
  import { Init } from './init/index.mjs';
15
15
  const program = new Command();
16
16
  const vovkCliPackage = JSON.parse(readFileSync(path.join(import.meta.dirname, '../package.json'), 'utf-8'));
@@ -31,13 +31,11 @@ program
31
31
  const PORT = !nextDev
32
32
  ? process.env.PORT
33
33
  : process.env.PORT ||
34
- (await getAvailablePort(3000, portAttempts, 0, (failedPort, tryingPort) =>
35
- // eslint-disable-next-line no-console
36
- console.warn(`🐺 Port ${failedPort} is in use, trying ${tryingPort} instead.`)).catch(() => {
37
- throw new Error(`🐺 ❌ Failed to find an available port after ${portAttempts} attempts`);
34
+ (await getAvailablePort(3000, portAttempts, 0, (failedPort, tryingPort) => console.warn(`🐺 Port ${failedPort} is in use, trying ${tryingPort} instead.`)).catch(() => {
35
+ throw new Error(`Failed to find an available port after ${portAttempts} attempts`);
38
36
  }));
39
37
  if (!PORT) {
40
- throw new Error('🐺 ❌ PORT env variable is required');
38
+ throw new Error('PORT env variable is required');
41
39
  }
42
40
  if (nextDev) {
43
41
  const { result } = concurrently([
@@ -54,7 +52,7 @@ program
54
52
  __VOVK_START_WATCHER_IN_STANDALONE_MODE__: 'true',
55
53
  // TODO: Pass these as flags
56
54
  __VOVK_SCHEMA_OUT_FLAG__: schemaOut ?? '',
57
- __VOVK_DEV_HTTPS_FLAG__: devHttps ? 'true' : 'false',
55
+ __VOVK_DEV_HTTPS_FLAG__: devHttps ? 'true' : '',
58
56
  __VOVK_EXIT__: exit ? 'true' : 'false',
59
57
  __VOVK_LOG_LEVEL__: logLevel ?? undefined,
60
58
  },
@@ -67,12 +65,16 @@ program
67
65
  try {
68
66
  await result;
69
67
  }
70
- finally {
71
- // do nothing, all processes are killed
68
+ catch (closeEvents) {
69
+ // concurrently rejects with child close events on shutdown; children already logged the reason
70
+ const hasFailure = Array.isArray(closeEvents) &&
71
+ closeEvents.some((event) => typeof event?.exitCode === 'number' && event.exitCode !== 0);
72
+ if (hasFailure)
73
+ process.exit(1);
72
74
  }
73
75
  }
74
76
  else {
75
- void new VovkDev({ schemaOut, devHttps, logLevel }).start({ exit });
77
+ await new VovkDev({ schemaOut, devHttps, logLevel }).start({ exit });
76
78
  }
77
79
  });
78
80
  program
@@ -120,7 +122,8 @@ program
120
122
  .option('--out, --out-dir <path>', 'path to output directory for bundle')
121
123
  .option('--include, --include-segments <segments...>', 'include segments')
122
124
  .option('--exclude, --exclude-segments <segments...>', 'exclude segments')
123
- .option('--prebundle-out-dir, --prebundle-out <path>', 'path to output directory for prebundle')
125
+ // the last long flag names the option, it has to stay prebundleOutDir
126
+ .option('--prebundle-out, --prebundle-out-dir <path>', 'path to output directory for prebundle')
124
127
  .option('--keep-prebundle-dir', 'do not delete prebundle directory after bundling')
125
128
  .option('--schema, --schema-path <path>', 'path to schema folder (default: .vovk-schema)')
126
129
  .option('--config, --config-path <config>', 'path to config file')
@@ -189,7 +192,13 @@ program
189
192
  .command('help')
190
193
  .description('Show help message')
191
194
  .action(() => program.help());
192
- program.parse(process.argv);
195
+ program.parseAsync(process.argv).catch((error) => {
196
+ const logLevelFlagIndex = process.argv.indexOf('--log-level');
197
+ const isDebug = ['debug', 'trace'].includes(process.argv[logLevelFlagIndex + 1] ?? '');
198
+ const err = error instanceof Error ? error : new Error(String(error));
199
+ console.error(`🐺 ❌ ${isDebug ? (err.stack ?? err.message) : err.message}`);
200
+ process.exit(1);
201
+ });
193
202
  if (!process.argv.slice(2).length) {
194
203
  program.outputHelp();
195
204
  }
@@ -1,6 +1,6 @@
1
1
  import type { VovkStrictConfig } from 'vovk/internal';
2
- import type { getLogger } from '../utils/getLogger.mjs';
3
2
  import type { InitOptions } from '../types.mjs';
3
+ import type { getLogger } from '../utils/get-logger.mjs';
4
4
  export declare const BUNDLE_BUILD_TSDOWN: ({ entry, outDir }: Parameters<VovkStrictConfig["bundle"]["build"]>[0]) => Promise<void>;
5
5
  export declare function createConfig({ root, options: { validationLibrary, bundle, lang, dryRun }, }: {
6
6
  root: string;
@@ -1,8 +1,8 @@
1
- import path from 'node:path';
2
1
  import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { FileSystemEntryType, getFileSystemEntryType } from '../utils/get-file-system-entry-type.mjs';
3
4
  import { prettify } from '../utils/prettify.mjs';
4
- import { getFileSystemEntryType, FileSystemEntryType } from '../utils/getFileSystemEntryType.mjs';
5
- import { updateConfigProperty } from '../utils/updateConfigProperty.mjs';
5
+ import { updateConfigProperty } from '../utils/update-config-property.mjs';
6
6
  export const BUNDLE_BUILD_TSDOWN = async ({ entry, outDir }) => {
7
7
  const { build } = await import('tsdown');
8
8
  await build({
@@ -16,14 +16,14 @@ export const BUNDLE_BUILD_TSDOWN = async ({ entry, outDir }) => {
16
16
  platform: 'neutral',
17
17
  outExtensions: () => ({ js: '.js', dts: '.d.ts' }),
18
18
  outputOptions: {
19
- inlineDynamicImports: true,
19
+ codeSplitting: false,
20
20
  },
21
21
  inputOptions: {
22
22
  resolve: {
23
23
  mainFields: ['module', 'main'],
24
24
  },
25
25
  },
26
- noExternal: ['!next/**'],
26
+ deps: { alwaysBundle: ['!next/**'] },
27
27
  });
28
28
  };
29
29
  export async function createConfig({ root, options: { validationLibrary, bundle, lang, dryRun }, }) {
@@ -55,7 +55,7 @@ export async function createConfig({ root, options: { validationLibrary, bundle,
55
55
  config.outputConfig.imports.validateOnClient = 'vovk-ajv';
56
56
  if (lang?.length) {
57
57
  config.composedClient ??= {};
58
- config.composedClient.fromTemplates = ['js', ...lang];
58
+ config.composedClient.fromTemplates = ['ts', ...lang];
59
59
  }
60
60
  config.moduleTemplates = moduleTemplates;
61
61
  if (bundle) {
@@ -1,5 +1,5 @@
1
- import { getLogger } from '../utils/getLogger.mjs';
2
1
  import type { InitOptions } from '../types.mjs';
2
+ import { getLogger } from '../utils/get-logger.mjs';
3
3
  export declare class Init {
4
4
  #private;
5
5
  root: string;
@@ -1,25 +1,30 @@
1
- import { confirm, select, checkbox } from '@inquirer/prompts';
2
- import path from 'node:path';
3
1
  import fs from 'node:fs/promises';
4
- import chalk from 'chalk';
2
+ import path from 'node:path';
3
+ import { checkbox, confirm, select } from '@inquirer/prompts';
5
4
  import NPMCliPackageJson from '@npmcli/package-json';
6
- import { getConfigAbsolutePaths } from '../getProjectInfo/getConfig/getConfigAbsolutePaths.mjs';
7
- import { getFileSystemEntryType } from '../utils/getFileSystemEntryType.mjs';
8
- import { installDependencies, getPackageManager } from './installDependencies.mjs';
9
- import { getLogger } from '../utils/getLogger.mjs';
10
- import { createConfig } from './createConfig.mjs';
11
- import { updateNPMScripts, getDevScript } from './updateNPMScripts.mjs';
12
- import { checkTSConfigForExperimentalDecorators } from './checkTSConfigForExperimentalDecorators.mjs';
13
- import { updateTypeScriptConfig } from './updateTypeScriptConfig.mjs';
14
- import { updateDependenciesWithoutInstalling } from './updateDependenciesWithoutInstalling.mjs';
15
- import { logUpdateDependenciesError } from './logUpdateDependenciesError.mjs';
16
- import { chalkHighlightThing } from '../utils/chalkHighlightThing.mjs';
5
+ import chalk from 'chalk';
6
+ import { getConfigAbsolutePaths } from '../get-project-info/get-config/get-config-absolute-paths.mjs';
7
+ import { chalkHighlightThing } from '../utils/chalk-highlight-thing.mjs';
8
+ import { getFileSystemEntryType } from '../utils/get-file-system-entry-type.mjs';
9
+ import { getLogger } from '../utils/get-logger.mjs';
10
+ import { checkTSConfigForExperimentalDecorators } from './check-tsconfig-for-experimental-decorators.mjs';
11
+ import { createConfig } from './create-config.mjs';
12
+ import { getPackageManager, installDependencies } from './install-dependencies.mjs';
13
+ import { logUpdateDependenciesError } from './log-update-dependencies-error.mjs';
14
+ import { updateDependenciesWithoutInstalling } from './update-dependencies-without-installing.mjs';
15
+ import { updateGitignore } from './update-gitignore.mjs';
16
+ import { getDevScript, updateNPMScripts } from './update-npm-scripts.mjs';
17
+ import { updateTypeScriptConfig } from './update-typescript-config.mjs';
18
+ const VALIDATION_LIBRARIES = ['zod', 'valibot', 'arktype', 'none'];
19
+ const LANGS = ['py', 'rs'];
20
+ const UPDATE_SCRIPTS_MODES = ['implicit', 'explicit'];
21
+ const CHANNELS = ['latest', 'beta', 'draft'];
17
22
  export class Init {
18
23
  root;
19
24
  log;
20
25
  async #init({ configPaths, pkgJson, }, { useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, bundle, lang, dryRun, channel, }) {
21
26
  const { log, root } = this;
22
- const dependencies = ['vovk', 'vovk-client', 'vovk-ajv'];
27
+ const dependencies = ['vovk', 'vovk-ajv'];
23
28
  const devDependencies = ['vovk-cli'];
24
29
  if (lang?.includes('py')) {
25
30
  devDependencies.push('vovk-python');
@@ -29,8 +34,9 @@ export class Init {
29
34
  }
30
35
  // delete older config files
31
36
  if (configPaths.length) {
32
- await Promise.all(configPaths.map((configPath) => fs.rm(configPath)));
33
- log.debug(`Deleted existing config file${configPaths.length > 1 ? 's' : ''} at ${configPaths.join(', ')}`);
37
+ if (!dryRun)
38
+ await Promise.all(configPaths.map((configPath) => fs.rm(configPath)));
39
+ log.debug(`${dryRun ? 'Dry run: would delete' : 'Deleted'} existing config file${configPaths.length > 1 ? 's' : ''} at ${configPaths.join(', ')}`);
34
40
  }
35
41
  if (validationLibrary) {
36
42
  dependencies.push(...({
@@ -40,14 +46,14 @@ export class Init {
40
46
  }[validationLibrary] ?? []));
41
47
  }
42
48
  if (bundle) {
43
- const TSDOWN_VERSION = '0.19.0';
49
+ const TSDOWN_VERSION = '0.22.14';
44
50
  devDependencies.push(`tsdown@${TSDOWN_VERSION}`);
45
51
  }
46
52
  if (updateScripts) {
47
53
  try {
48
54
  if (!dryRun && pkgJson)
49
55
  await updateNPMScripts({ pkgJson, root, bundle, updateScriptsMode: updateScripts });
50
- log.info('Updated scripts at package.json');
56
+ log.info(`${dryRun ? 'Dry run: would update' : 'Updated'} scripts at package.json`);
51
57
  }
52
58
  catch (error) {
53
59
  log.error(`Failed to update scripts at package.json: ${error.message}`);
@@ -63,7 +69,7 @@ export class Init {
63
69
  };
64
70
  if (!dryRun)
65
71
  await updateTypeScriptConfig(root, compilerOptions);
66
- log.info(`Added ${Object.keys(compilerOptions)
72
+ log.info(`${dryRun ? 'Dry run: would add' : 'Added'} ${Object.keys(compilerOptions)
67
73
  .map((k) => `"${k}"`)
68
74
  .join(' and ')} to tsconfig.json`);
69
75
  }
@@ -73,7 +79,7 @@ export class Init {
73
79
  }
74
80
  if (!dryRun && pkgJson) {
75
81
  let depsUpdated = false;
76
- const packageManager = getPackageManager({ useNpm, useYarn, usePnpm, useBun, pkgJson });
82
+ const packageManager = getPackageManager({ useNpm, useYarn, usePnpm, useBun, pkgJson, log });
77
83
  try {
78
84
  await updateDependenciesWithoutInstalling({
79
85
  log,
@@ -114,13 +120,23 @@ export class Init {
114
120
  }
115
121
  }
116
122
  }
123
+ try {
124
+ if (!dryRun) {
125
+ const gitignoreEntry = await updateGitignore(root);
126
+ if (gitignoreEntry)
127
+ log.info(`Added ${chalkHighlightThing(gitignoreEntry)} to .gitignore`);
128
+ }
129
+ }
130
+ catch (error) {
131
+ log.error(`Failed to update .gitignore: ${error.message}`);
132
+ }
117
133
  try {
118
134
  const { configAbsolutePath } = await createConfig({
119
135
  root,
120
136
  log,
121
137
  options: { validationLibrary, channel, bundle, lang, dryRun },
122
138
  });
123
- log.info(`Config created successfully at ${chalkHighlightThing(configAbsolutePath)}`);
139
+ log.info(`Config ${dryRun ? 'would be created (dry run)' : 'created successfully'} at ${chalkHighlightThing(configAbsolutePath)}`);
124
140
  log.info(`You can now create a root segment with ${chalkHighlightThing('npx vovk new segment')} command`);
125
141
  }
126
142
  catch (error) {
@@ -131,6 +147,22 @@ export class Init {
131
147
  const cwd = process.cwd();
132
148
  const root = path.resolve(cwd, prefix ?? '.');
133
149
  const log = getLogger(logLevel ?? 'info');
150
+ validationLibrary = validationLibrary?.toLowerCase();
151
+ lang = lang?.map((l) => l.toLowerCase());
152
+ if (validationLibrary && !VALIDATION_LIBRARIES.includes(validationLibrary)) {
153
+ throw new Error(`Unknown --validation-library value "${validationLibrary}". Supported values: ${VALIDATION_LIBRARIES.join(', ')}`);
154
+ }
155
+ for (const l of lang ?? []) {
156
+ if (!LANGS.includes(l)) {
157
+ throw new Error(`Unknown --lang value "${l}". Supported values: ${LANGS.join(', ')}`);
158
+ }
159
+ }
160
+ if (updateScripts && !UPDATE_SCRIPTS_MODES.includes(updateScripts)) {
161
+ throw new Error(`Unknown --update-scripts value "${updateScripts}". Supported values: ${UPDATE_SCRIPTS_MODES.join(', ')}`);
162
+ }
163
+ if (channel && !CHANNELS.includes(channel)) {
164
+ throw new Error(`Unknown --channel value "${channel}". Supported values: ${CHANNELS.join(', ')}`);
165
+ }
134
166
  const pkgJson = await NPMCliPackageJson.load(root).catch(() => null);
135
167
  this.root = root;
136
168
  this.log = log;
@@ -1,9 +1,10 @@
1
1
  import type NPMCliPackageJson from '@npmcli/package-json';
2
- import type { getLogger } from '../utils/getLogger.mjs';
3
2
  import type { InitOptions } from '../types.mjs';
3
+ import type { getLogger } from '../utils/get-logger.mjs';
4
4
  export type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun';
5
5
  export declare function getPackageManager(options: Pick<InitOptions, 'useNpm' | 'useYarn' | 'usePnpm' | 'useBun'> & {
6
6
  pkgJson: NPMCliPackageJson;
7
+ log?: ReturnType<typeof getLogger>;
7
8
  }): PackageManager;
8
9
  export declare function installDependencies({ log, cwd, packageManager, }: {
9
10
  log: ReturnType<typeof getLogger>;
@@ -1,5 +1,6 @@
1
1
  import { spawn } from 'node:child_process';
2
- import { chalkHighlightThing } from '../utils/chalkHighlightThing.mjs';
2
+ import { chalkHighlightThing } from '../utils/chalk-highlight-thing.mjs';
3
+ const KNOWN_PACKAGE_MANAGERS = ['npm', 'yarn', 'pnpm', 'bun'];
3
4
  export function getPackageManager(options) {
4
5
  if (options.useNpm)
5
6
  return 'npm';
@@ -9,8 +10,15 @@ export function getPackageManager(options) {
9
10
  return 'pnpm';
10
11
  if (options.useBun)
11
12
  return 'bun';
12
- const packageManager = options.pkgJson.content?.packageManager;
13
- return packageManager ? packageManager.split('@')[0] : 'npm'; // Default to npm if no options are true
13
+ const packageManager = options.pkgJson.content?.packageManager?.split('@')[0];
14
+ if (!packageManager)
15
+ return 'npm'; // Default to npm if no options are true
16
+ // this name gets spawned, so an unknown one from package.json is not executed
17
+ if (!KNOWN_PACKAGE_MANAGERS.includes(packageManager)) {
18
+ options.log?.warn(`Unknown "packageManager" ${JSON.stringify(packageManager)} in package.json, using ${chalkHighlightThing('npm')} instead`);
19
+ return 'npm';
20
+ }
21
+ return packageManager;
14
22
  }
15
23
  export async function installDependencies({ log, cwd, packageManager, }) {
16
24
  log.info(`Installing dependencies at ${chalkHighlightThing(cwd)} using ${chalkHighlightThing(packageManager)}...`);
@@ -1,6 +1,6 @@
1
1
  import type { InitOptions } from '../types.mjs';
2
- import type { getLogger } from '../utils/getLogger.mjs';
3
- import type { PackageManager } from './installDependencies.mjs';
2
+ import type { getLogger } from '../utils/get-logger.mjs';
3
+ import type { PackageManager } from './install-dependencies.mjs';
4
4
  export declare function logUpdateDependenciesError({ packageManager, log, dependencies, devDependencies, error, channel, }: {
5
5
  packageManager: PackageManager;
6
6
  log: ReturnType<typeof getLogger>;
@@ -1,4 +1,4 @@
1
- import { chalkHighlightThing } from '../utils/chalkHighlightThing.mjs';
1
+ import { chalkHighlightThing } from '../utils/chalk-highlight-thing.mjs';
2
2
  export function logUpdateDependenciesError({ packageManager, log, dependencies, devDependencies, error, channel, }) {
3
3
  const installCommands = [];
4
4
  const addChannel = (packageName) => {
@@ -1,5 +1,5 @@
1
- import type { getLogger } from '../utils/getLogger.mjs';
2
1
  import type { InitOptions } from '../types.mjs';
2
+ import type { getLogger } from '../utils/get-logger.mjs';
3
3
  export declare function updateDependenciesWithoutInstalling({ log, dir, dependencyNames, devDependencyNames, channel, }: {
4
4
  log: ReturnType<typeof getLogger>;
5
5
  dir: string;
@@ -1,14 +1,13 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import chalk from 'chalk';
4
- import { getNPMPackageMetadata } from '../utils/getNPMPackageMetadata.mjs';
4
+ import { getNPMPackageMetadata } from '../utils/get-npm-package-metadata.mjs';
5
5
  /** Root of the monorepo packages directory (…/packages) resolved from the compiled CLI location (dist/init/). */
6
6
  const packagesRoot = path.resolve(import.meta.dirname, '../../..');
7
7
  /** Vovk package names that have a matching local directory under packages/. */
8
8
  const localPackageDirs = {
9
9
  vovk: 'vovk',
10
10
  'vovk-cli': 'vovk-cli',
11
- 'vovk-client': 'vovk-client',
12
11
  'vovk-ajv': 'vovk-ajv',
13
12
  'vovk-python': 'vovk-python',
14
13
  'vovk-rust': 'vovk-rust',
@@ -0,0 +1,2 @@
1
+ /** Adds the default composed client outDir to .gitignore. Returns the added entry or null if already present. */
2
+ export declare function updateGitignore(root: string): Promise<string | null>;
@@ -0,0 +1,20 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { getRelativeSrcRoot } from '../get-project-info/get-config/get-relative-src-root.mjs';
4
+ /** Adds the default composed client outDir to .gitignore. Returns the added entry or null if already present. */
5
+ export async function updateGitignore(root) {
6
+ const srcRoot = await getRelativeSrcRoot({ cwd: root });
7
+ const outDir = path.join(srcRoot ?? '.', 'client');
8
+ const entry = `/${outDir}`;
9
+ const gitignorePath = path.join(root, '.gitignore');
10
+ const content = await fs.readFile(gitignorePath, 'utf-8').catch(() => '');
11
+ const hasEntry = content.split('\n').some((line) => {
12
+ const trimmed = line.trim().replace(/\/$/, '');
13
+ return trimmed === entry || trimmed === outDir;
14
+ });
15
+ if (hasEntry)
16
+ return null;
17
+ const updated = `${content.length && !content.endsWith('\n') ? `${content}\n` : content}\n# vovk generated client\n${entry}\n`;
18
+ await fs.writeFile(gitignorePath, updated, 'utf-8');
19
+ return entry;
20
+ }
@@ -1,3 +1,3 @@
1
+ import type { ProjectInfo } from '../get-project-info/index.mts';
1
2
  import type { NewOptions } from '../types.mjs';
2
- import type { ProjectInfo } from '../getProjectInfo/index.mts';
3
3
  export declare function newComponents(components: string[], projectInfo: ProjectInfo, { dryRun, outDir, templates, overwrite, noSegmentUpdate, empty, static: isStaticSegment }: NewOptions): Promise<void>;
@@ -1,5 +1,5 @@
1
- import { newModule } from './newModule.mjs';
2
- import { newSegment } from './newSegment.mjs';
1
+ import { newModule } from './new-module.mjs';
2
+ import { newSegment } from './new-segment.mjs';
3
3
  export async function newComponents(components, projectInfo, { dryRun, outDir, templates, overwrite, noSegmentUpdate, empty, static: isStaticSegment }) {
4
4
  if (components[0] === 'segment' || components[0] === 'segments') {
5
5
  // vovk new segment [segmentName]
@@ -1,4 +1,4 @@
1
- import type { ProjectInfo } from '../getProjectInfo/index.mjs';
1
+ import type { ProjectInfo } from '../get-project-info/index.mjs';
2
2
  export declare function newModule({ projectInfo, what, moduleNameWithOptionalSegment, dryRun, outDir: outDirFlag, templates: templatesFlag, noSegmentUpdate, overwrite, empty, }: {
3
3
  projectInfo: ProjectInfo;
4
4
  what: string[];
@@ -1,15 +1,15 @@
1
- import path from 'node:path';
2
1
  import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
3
  import chalk from 'chalk';
4
4
  import { getTsconfig } from 'get-tsconfig';
5
- import { render } from './render.mjs';
6
- import { addClassToSegmentCode } from './addClassToSegmentCode.mjs';
7
- import { chalkHighlightThing } from '../utils/chalkHighlightThing.mjs';
8
- import { formatLoggedSegmentName } from '../utils/formatLoggedSegmentName.mjs';
9
- import { getFileSystemEntryType } from '../utils/getFileSystemEntryType.mjs';
5
+ import { chalkHighlightThing } from '../utils/chalk-highlight-thing.mjs';
6
+ import { formatLoggedSegmentName } from '../utils/format-logged-segment-name.mjs';
7
+ import { getFileSystemEntryType } from '../utils/get-file-system-entry-type.mjs';
8
+ import { locateSegments } from '../utils/locate-segments.mjs';
10
9
  import { prettify } from '../utils/prettify.mjs';
11
- import { resolveAbsoluteModulePath } from '../utils/resolveAbsoluteModulePath.mjs';
12
- import { locateSegments } from '../utils/locateSegments.mjs';
10
+ import { resolveAbsoluteModulePath } from '../utils/resolve-absolute-module-path.mjs';
11
+ import { addClassToSegmentCode } from './add-class-to-segment-code.mjs';
12
+ import { render } from './render.mjs';
13
13
  function splitByLast(str, delimiter = '/') {
14
14
  const index = str.lastIndexOf(delimiter);
15
15
  if (index === -1) {
@@ -93,6 +93,9 @@ export async function newModule({ projectInfo, what, moduleNameWithOptionalSegme
93
93
  log.info(`${chalk.green('Created')}${empty ? ' empty' : ''} ${chalkHighlightThing(absoluteModulePath)} using ${chalkHighlightThing(`"${type}"`)} template for ${formatLoggedSegmentName(segmentName)}`);
94
94
  }
95
95
  }
96
+ else {
97
+ log.info(`Dry run: would create${empty ? ' empty' : ''} ${chalkHighlightThing(absoluteModulePath)} using ${chalkHighlightThing(`"${type}"`)} template for ${formatLoggedSegmentName(segmentName)}`);
98
+ }
96
99
  if (type === 'controller') {
97
100
  if (!sourceName) {
98
101
  throw new Error(`The template for "${type}" does not provide a sourceName`);
@@ -112,9 +115,12 @@ export async function newModule({ projectInfo, what, moduleNameWithOptionalSegme
112
115
  }), routeFilePath);
113
116
  if (!dryRun) {
114
117
  await fs.writeFile(routeFilePath, newSegmentCode);
118
+ log.info(`${chalk.green('Added')} ${chalkHighlightThing(sourceName)} ${type} as ${chalkHighlightThing(compiledName)} to ${formatLoggedSegmentName(segmentName)}`);
119
+ }
120
+ else {
121
+ log.info(`Dry run: would add ${chalkHighlightThing(sourceName)} ${type} as ${chalkHighlightThing(compiledName)} to ${formatLoggedSegmentName(segmentName)}`);
115
122
  }
116
123
  }
117
- log.info(`${chalk.green('Added')} ${chalkHighlightThing(sourceName)} ${type} as ${chalkHighlightThing(compiledName)} to ${formatLoggedSegmentName(segmentName)}`);
118
124
  }
119
125
  }
120
126
  }
@@ -1,4 +1,4 @@
1
- import type { ProjectInfo } from '../getProjectInfo/index.mjs';
1
+ import type { ProjectInfo } from '../get-project-info/index.mjs';
2
2
  export declare function newSegment({ projectInfo, segmentName, isStaticSegment, overwrite, dryRun, }: {
3
3
  projectInfo: ProjectInfo;
4
4
  segmentName: string;
@@ -1,10 +1,10 @@
1
- import path from 'node:path';
2
1
  import fs from 'node:fs/promises';
3
- import { getFileSystemEntryType } from '../utils/getFileSystemEntryType.mjs';
4
- import { chalkHighlightThing } from '../utils/chalkHighlightThing.mjs';
5
- import { formatLoggedSegmentName } from '../utils/formatLoggedSegmentName.mjs';
6
- import { prettify } from '../utils/prettify.mjs';
2
+ import path from 'node:path';
7
3
  import chalk from 'chalk';
4
+ import { chalkHighlightThing } from '../utils/chalk-highlight-thing.mjs';
5
+ import { formatLoggedSegmentName } from '../utils/format-logged-segment-name.mjs';
6
+ import { getFileSystemEntryType } from '../utils/get-file-system-entry-type.mjs';
7
+ import { prettify } from '../utils/prettify.mjs';
8
8
  export async function newSegment({ projectInfo, segmentName, isStaticSegment, overwrite, dryRun, }) {
9
9
  const { apiDirAbsolutePath, log, config } = projectInfo;
10
10
  if (!apiDirAbsolutePath) {
@@ -22,6 +22,8 @@ const controllers = {};
22
22
  export type Controllers = typeof controllers;
23
23
  ${isStaticSegment
24
24
  ? `
25
+ export const dynamic = 'force-static';
26
+
25
27
  export function generateStaticParams() {
26
28
  return controllersToStaticParams(controllers);
27
29
  }
@@ -35,8 +37,11 @@ ${segmentName ? ` segmentName: '${segmentName}',\n` : ''} emitSchema: true,
35
37
  if (!dryRun) {
36
38
  await fs.mkdir(path.dirname(absoluteSegmentRoutePath), { recursive: true });
37
39
  await fs.writeFile(absoluteSegmentRoutePath, code);
40
+ log.info(`${chalk.green('Created')} ${formatLoggedSegmentName(segmentName, { isStatic: isStaticSegment })} at ${absoluteSegmentRoutePath}.`);
41
+ }
42
+ else {
43
+ log.info(`Dry run: would create ${formatLoggedSegmentName(segmentName, { isStatic: isStaticSegment })} at ${absoluteSegmentRoutePath}.`);
38
44
  }
39
- log.info(`${chalk.green('Created')} ${formatLoggedSegmentName(segmentName, { isStatic: isStaticSegment })} at ${absoluteSegmentRoutePath}.`);
40
45
  const dir = chalk.cyanBright([segmentName, 'thing'].filter(Boolean).join('/'));
41
46
  log.info(`Run ${chalkHighlightThing(`npx vovk new service controller ${dir}`)} to create a new controller with a service at ./${path.join(config.modulesDir, dir)}/ directory for this segment`);
42
47
  }
@@ -1,12 +1,12 @@
1
+ import path from 'node:path';
1
2
  import ejs from 'ejs';
2
3
  import matter from 'gray-matter';
3
4
  import _ from 'lodash';
4
5
  import pluralize from 'pluralize';
5
- import { addCommonTerms } from './addCommonTerms.mjs';
6
- import path from 'node:path';
6
+ import { addCommonTerms } from './add-common-terms.mjs';
7
7
  addCommonTerms();
8
8
  export async function render(codeTemplate, { cwd, config, withService, segmentName, moduleName, empty, templateFileName, isNodeNextResolution, srcRoot, }) {
9
- const defaultOutDir = [config.modulesDir, segmentName || config.rootSegmentModulesDirName, _.camelCase(moduleName)]
9
+ const defaultOutDir = [config.modulesDir, segmentName || config.rootSegmentModulesDirName, _.kebabCase(moduleName)]
10
10
  .filter(Boolean)
11
11
  .join('/');
12
12
  const relativePathToSourceRoot = path.relative(path.resolve(cwd, defaultOutDir), path.join(cwd, srcRoot ?? '.')) || '.';
package/dist/types.d.mts CHANGED
@@ -88,7 +88,7 @@ export type VovkEnv = {
88
88
  VOVK_API_ENTRY_POINT?: string;
89
89
  __VOVK_START_WATCHER_IN_STANDALONE_MODE__?: 'true';
90
90
  __VOVK_SCHEMA_OUT_FLAG__?: string;
91
- __VOVK_DEV_HTTPS_FLAG__?: 'true' | 'false';
91
+ __VOVK_DEV_HTTPS_FLAG__?: 'true' | '';
92
92
  __VOVK_EXIT__?: 'true' | 'false';
93
93
  __VOVK_LOG_LEVEL__?: LogLevelNames;
94
94
  };
@@ -1,4 +1,4 @@
1
- import { compileTs } from './compileTs.mjs';
1
+ import { compileTs } from './compile-ts.mjs';
2
2
  export function compileJSONSchemaToTypeScriptType(schema, typeName, components = {}, options = {}) {
3
3
  if (!schema)
4
4
  return '';
@@ -1,5 +1,5 @@
1
1
  import upperFirstLodash from 'lodash/upperFirst.js';
2
- import { chalkHighlightThing } from './chalkHighlightThing.mjs';
2
+ import { chalkHighlightThing } from './chalk-highlight-thing.mjs';
3
3
  export function formatLoggedSegmentName(segmentName, { withChalk = true, upperFirst = false, isStatic = false, segmentType = 'segment', // TODO: Apply to all formatLoggedSegmentName invocations
4
4
  } = {}) {
5
5
  let text = segmentName ? `${isStatic ? 'static ' : ''}${segmentType} "${segmentName}"` : 'the root segment';
@@ -10,14 +10,5 @@ interface GenerateFnNameOptions {
10
10
  /** Segments to strip out (e.g. ['api','v1']) */
11
11
  ignoreSegments?: string[];
12
12
  }
13
- /**
14
- * Turn an HTTP method + OpenAPI path into a camelCased function name.
15
- *
16
- * Examples:
17
- * generateFnName('GET', '/users') // "listUsers"
18
- * generateFnName('GET', '/users/{id}') // "getUsersById"
19
- * generateFnName('POST', '/v1/api/orders') // "createOrders"
20
- * generateFnName('PATCH', '/users/{userId}/profile') // "patchUsersProfileByUserId"
21
- */
22
13
  export declare function generateFnName(method: HttpMethod, rawPath: string, opts?: GenerateFnNameOptions): string;
23
14
  export {};
@@ -15,15 +15,8 @@ export function capitalize(str) {
15
15
  const DEFAULT_OPTIONS = {
16
16
  ignoreSegments: ['api'],
17
17
  };
18
- /**
19
- * Turn an HTTP method + OpenAPI path into a camelCased function name.
20
- *
21
- * Examples:
22
- * generateFnName('GET', '/users') // "listUsers"
23
- * generateFnName('GET', '/users/{id}') // "getUsersById"
24
- * generateFnName('POST', '/v1/api/orders') // "createOrders"
25
- * generateFnName('PATCH', '/users/{userId}/profile') // "patchUsersProfileByUserId"
26
- */
18
+ // HTTP method + OpenAPI path to a camelCased fn name,
19
+ // e.g. GET /users -> "listUsers", GET /users/{id} -> "getUsersById", POST /v1/api/orders -> "createOrders"
27
20
  export function generateFnName(method, rawPath, opts = {}) {
28
21
  const { ignoreSegments } = {
29
22
  ...DEFAULT_OPTIONS,
@@ -0,0 +1 @@
1
+ export declare const GENERATED_BANNER_PREFIX = "Generated by vovk-cli";
@@ -0,0 +1,3 @@
1
+ // stamped as the first line of every generated file that can hold a comment,
2
+ // the pruner relies on it to tell generated files from user files
3
+ export const GENERATED_BANNER_PREFIX = 'Generated by vovk-cli';
@@ -0,0 +1 @@
1
+ export declare function getAvailablePort(startPort: number, maxAttempts: number, attempt: number, onWarning: (failedPort: number, tryingPort: number) => void): Promise<string>;