vovk-cli 0.0.1-draft.99 → 0.0.3

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 (164) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +24 -16
  3. package/client-templates/jsBase/index.d.ts.ejs +21 -0
  4. package/client-templates/jsBase/index.js.ejs +18 -0
  5. package/client-templates/mixins/mixins.d.ts.ejs +64 -0
  6. package/client-templates/mixins/mixins.json.ejs +1 -0
  7. package/client-templates/openapiJs/openapi.d.ts.ejs +4 -0
  8. package/client-templates/openapiJs/openapi.js.ejs +4 -0
  9. package/client-templates/openapiJson/openapi.json.ejs +1 -0
  10. package/client-templates/openapiTs/openapi.ts.ejs +4 -0
  11. package/client-templates/packageJson/package.json.ejs +1 -0
  12. package/client-templates/readme/README.md.ejs +39 -0
  13. package/client-templates/schemaJs/schema.d.ts.ejs +10 -0
  14. package/client-templates/schemaJs/schema.js.ejs +29 -0
  15. package/client-templates/schemaJson/schema.json.ejs +1 -0
  16. package/client-templates/schemaTs/schema.ts.ejs +28 -0
  17. package/client-templates/tsBase/index.ts.ejs +27 -0
  18. package/dist/bundle/index.d.mts +8 -0
  19. package/dist/bundle/index.mjs +76 -0
  20. package/dist/dev/{diffSchema.d.mts → diffSegmentSchema.d.mts} +3 -3
  21. package/dist/dev/{diffSchema.mjs → diffSegmentSchema.mjs} +1 -1
  22. package/dist/dev/ensureSchemaFiles.d.mts +2 -2
  23. package/dist/dev/ensureSchemaFiles.mjs +16 -47
  24. package/dist/dev/index.d.mts +2 -0
  25. package/dist/dev/index.mjs +113 -64
  26. package/dist/dev/logDiffResult.d.mts +2 -2
  27. package/dist/dev/logDiffResult.mjs +6 -6
  28. package/dist/dev/writeMetaJson.d.mts +2 -0
  29. package/dist/dev/writeMetaJson.mjs +19 -0
  30. package/dist/dev/writeOneSegmentSchemaFile.d.mts +12 -0
  31. package/dist/dev/{writeOneSchemaFile.mjs → writeOneSegmentSchemaFile.mjs} +11 -8
  32. package/dist/generate/ensureClient.d.mts +2 -4
  33. package/dist/generate/ensureClient.mjs +26 -28
  34. package/dist/generate/generate.d.mts +13 -0
  35. package/dist/generate/generate.mjs +307 -0
  36. package/dist/generate/getClientTemplateFiles.d.mts +20 -0
  37. package/dist/generate/getClientTemplateFiles.mjs +85 -0
  38. package/dist/generate/getProjectFullSchema.d.mts +9 -0
  39. package/dist/generate/getProjectFullSchema.mjs +64 -0
  40. package/dist/generate/getTemplateClientImports.d.mts +18 -0
  41. package/dist/generate/getTemplateClientImports.mjs +36 -0
  42. package/dist/generate/index.d.mts +31 -11
  43. package/dist/generate/index.mjs +177 -85
  44. package/dist/generate/writeOneClientFile.d.mts +43 -0
  45. package/dist/generate/writeOneClientFile.mjs +150 -0
  46. package/dist/getProjectInfo/getConfig/getConfigAbsolutePaths.d.mts +5 -0
  47. package/dist/getProjectInfo/{getConfigAbsolutePaths.mjs → getConfig/getConfigAbsolutePaths.mjs} +4 -1
  48. package/dist/getProjectInfo/getConfig/getRelativeSrcRoot.d.mts +3 -0
  49. package/dist/getProjectInfo/{getRelativeSrcRoot.mjs → getConfig/getRelativeSrcRoot.mjs} +3 -3
  50. package/dist/getProjectInfo/getConfig/getTemplateDefs.d.mts +25 -0
  51. package/dist/getProjectInfo/getConfig/getTemplateDefs.mjs +168 -0
  52. package/dist/getProjectInfo/getConfig/getUserConfig.d.mts +9 -0
  53. package/dist/getProjectInfo/getConfig/getUserConfig.mjs +142 -0
  54. package/dist/getProjectInfo/getConfig/index.d.mts +15 -0
  55. package/dist/getProjectInfo/getConfig/index.mjs +92 -0
  56. package/dist/getProjectInfo/getMetaSchema.d.mts +4 -0
  57. package/dist/getProjectInfo/getMetaSchema.mjs +12 -0
  58. package/dist/getProjectInfo/index.d.mts +12 -16
  59. package/dist/getProjectInfo/index.mjs +23 -29
  60. package/dist/index.d.mts +3 -3
  61. package/dist/index.mjs +119 -40
  62. package/dist/init/checkTSConfigForExperimentalDecorators.d.mts +1 -1
  63. package/dist/init/checkTSConfigForExperimentalDecorators.mjs +2 -2
  64. package/dist/init/createConfig.d.mts +5 -3
  65. package/dist/init/createConfig.mjs +77 -27
  66. package/dist/init/index.d.mts +2 -2
  67. package/dist/init/index.mjs +118 -103
  68. package/dist/init/installDependencies.d.mts +8 -6
  69. package/dist/init/installDependencies.mjs +7 -5
  70. package/dist/init/logUpdateDependenciesError.d.mts +6 -6
  71. package/dist/init/logUpdateDependenciesError.mjs +8 -4
  72. package/dist/init/updateDependenciesWithoutInstalling.d.mts +3 -3
  73. package/dist/init/updateDependenciesWithoutInstalling.mjs +41 -11
  74. package/dist/init/updateNPMScripts.d.mts +7 -2
  75. package/dist/init/updateNPMScripts.mjs +9 -5
  76. package/dist/init/updateTypeScriptConfig.d.mts +4 -1
  77. package/dist/init/updateTypeScriptConfig.mjs +12 -8
  78. package/dist/new/addClassToSegmentCode.d.mts +1 -1
  79. package/dist/new/addClassToSegmentCode.mjs +3 -3
  80. package/dist/new/addCommonTerms.d.mts +1 -1
  81. package/dist/new/addCommonTerms.mjs +1 -1
  82. package/dist/new/index.d.mts +2 -1
  83. package/dist/new/index.mjs +6 -5
  84. package/dist/new/newModule.d.mts +5 -3
  85. package/dist/new/newModule.mjs +34 -27
  86. package/dist/new/newSegment.d.mts +5 -2
  87. package/dist/new/newSegment.mjs +23 -16
  88. package/dist/new/render.d.mts +6 -3
  89. package/dist/new/render.mjs +15 -14
  90. package/dist/types.d.mts +64 -61
  91. package/dist/utils/chalkHighlightThing.d.mts +1 -1
  92. package/dist/utils/chalkHighlightThing.mjs +1 -1
  93. package/dist/utils/compileJSONSchemaToTypeScriptType.d.mts +5 -0
  94. package/dist/utils/compileJSONSchemaToTypeScriptType.mjs +9 -0
  95. package/dist/utils/compileTs.d.mts +12 -0
  96. package/dist/utils/compileTs.mjs +263 -0
  97. package/dist/utils/debounceWithArgs.d.mts +3 -2
  98. package/dist/utils/debounceWithArgs.mjs +1 -1
  99. package/dist/utils/formatLoggedSegmentName.d.mts +3 -1
  100. package/dist/utils/formatLoggedSegmentName.mjs +4 -3
  101. package/dist/utils/generateFnName.d.mts +23 -0
  102. package/dist/utils/generateFnName.mjs +78 -0
  103. package/dist/utils/getAvailablePort.d.mts +1 -2
  104. package/dist/utils/getAvailablePort.mjs +1 -2
  105. package/dist/utils/getFileSystemEntryType.d.mts +1 -1
  106. package/dist/utils/getFileSystemEntryType.mjs +1 -1
  107. package/dist/utils/getLogger.d.mts +1 -1
  108. package/dist/utils/getLogger.mjs +1 -1
  109. package/dist/utils/getNPMPackageMetadata.d.mts +2 -3
  110. package/dist/utils/getNPMPackageMetadata.mjs +1 -1
  111. package/dist/utils/getPackageJson.d.mts +3 -0
  112. package/dist/utils/getPackageJson.mjs +23 -0
  113. package/dist/utils/getPublicModuleNameFromPath.d.mts +4 -0
  114. package/dist/utils/getPublicModuleNameFromPath.mjs +9 -0
  115. package/dist/utils/locateSegments.d.mts +12 -0
  116. package/dist/{locateSegments.mjs → utils/locateSegments.mjs} +14 -7
  117. package/dist/utils/normalizeOpenAPIMixin.d.mts +15 -0
  118. package/dist/utils/normalizeOpenAPIMixin.mjs +96 -0
  119. package/dist/utils/pickSegmentFullSchema.d.mts +3 -0
  120. package/dist/utils/pickSegmentFullSchema.mjs +15 -0
  121. package/dist/utils/prettify.d.mts +1 -1
  122. package/dist/utils/prettify.mjs +1 -1
  123. package/dist/utils/removeUnlistedDirectories.d.mts +9 -0
  124. package/dist/utils/removeUnlistedDirectories.mjs +60 -0
  125. package/dist/utils/resolveAbsoluteModulePath.d.mts +2 -0
  126. package/dist/utils/resolveAbsoluteModulePath.mjs +32 -0
  127. package/dist/utils/updateConfigProperty.d.mts +2 -0
  128. package/dist/utils/updateConfigProperty.mjs +132 -0
  129. package/module-templates/arktype/controller.ts.ejs +90 -0
  130. package/module-templates/type/controller.ts.ejs +80 -0
  131. package/module-templates/type/service.ts.ejs +43 -0
  132. package/module-templates/valibot/controller.ts.ejs +91 -0
  133. package/module-templates/zod/controller.ts.ejs +98 -0
  134. package/package.json +50 -25
  135. package/client-templates/main/main.cjs.ejs +0 -15
  136. package/client-templates/main/main.d.cts.ejs +0 -14
  137. package/client-templates/module/module.d.mts.ejs +0 -14
  138. package/client-templates/module/module.mjs.ejs +0 -24
  139. package/client-templates/python/__init__.py +0 -276
  140. package/client-templates/ts/index.ts.ejs +0 -25
  141. package/dist/dev/isSchemaEmpty.d.mts +0 -2
  142. package/dist/dev/isSchemaEmpty.mjs +0 -4
  143. package/dist/dev/writeOneSchemaFile.d.mts +0 -12
  144. package/dist/generate/getClientTemplates.d.mts +0 -16
  145. package/dist/generate/getClientTemplates.mjs +0 -42
  146. package/dist/getProjectInfo/getConfig.d.mts +0 -11
  147. package/dist/getProjectInfo/getConfig.mjs +0 -35
  148. package/dist/getProjectInfo/getConfigAbsolutePaths.d.mts +0 -4
  149. package/dist/getProjectInfo/getRelativeSrcRoot.d.mts +0 -3
  150. package/dist/getProjectInfo/getUserConfig.d.mts +0 -9
  151. package/dist/getProjectInfo/getUserConfig.mjs +0 -27
  152. package/dist/getProjectInfo/importUncachedModule.d.mts +0 -3
  153. package/dist/getProjectInfo/importUncachedModule.mjs +0 -40
  154. package/dist/getProjectInfo/importUncachedModuleWorker.d.mts +0 -1
  155. package/dist/getProjectInfo/importUncachedModuleWorker.mjs +0 -25
  156. package/dist/init/getTemplateFilesFromPackage.d.mts +0 -7
  157. package/dist/init/getTemplateFilesFromPackage.mjs +0 -59
  158. package/dist/initProgram.d.mts +0 -2
  159. package/dist/initProgram.mjs +0 -22
  160. package/dist/locateSegments.d.mts +0 -11
  161. package/dist/postinstall.d.mts +0 -1
  162. package/dist/postinstall.mjs +0 -21
  163. package/templates/controller.ejs +0 -50
  164. package/templates/service.ejs +0 -27
@@ -1,47 +1,52 @@
1
- import { confirm, select } from '@inquirer/prompts';
1
+ import { confirm, select, checkbox } from '@inquirer/prompts';
2
2
  import path from 'node:path';
3
3
  import fs from 'node:fs/promises';
4
- import getConfigPaths from '../getProjectInfo/getConfigAbsolutePaths.mjs';
5
4
  import chalk from 'chalk';
6
- import getFileSystemEntryType from '../utils/getFileSystemEntryType.mjs';
7
- import installDependencies, { getPackageManager } from './installDependencies.mjs';
8
- import getLogger from '../utils/getLogger.mjs';
9
- import createConfig from './createConfig.mjs';
10
- import updateNPMScripts, { getDevScript } from './updateNPMScripts.mjs';
11
- import checkTSConfigForExperimentalDecorators from './checkTSConfigForExperimentalDecorators.mjs';
12
- import updateTypeScriptConfig from './updateTypeScriptConfig.mjs';
13
- import updateDependenciesWithoutInstalling from './updateDependenciesWithoutInstalling.mjs';
14
- import logUpdateDependenciesError from './logUpdateDependenciesError.mjs';
15
- import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
16
5
  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';
17
17
  export class Init {
18
18
  root;
19
19
  log;
20
- async #init({ configPaths, pkgJson, }, { useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, validateOnClient, reactQuery, dryRun, channel, }) {
20
+ async #init({ configPaths, pkgJson, }, { useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, bundle, lang, dryRun, channel, }) {
21
21
  const { log, root } = this;
22
- const dependencies = ['vovk', 'vovk-client'];
23
- const devDependencies = ['vovk-cli', 'openapi3-ts'];
22
+ const dependencies = ['vovk', 'vovk-client', 'vovk-ajv', 'openapi3-ts'];
23
+ const devDependencies = ['vovk-cli'];
24
+ if (lang?.includes('py')) {
25
+ devDependencies.push('vovk-python');
26
+ }
27
+ if (lang?.includes('rs')) {
28
+ devDependencies.push('vovk-rust');
29
+ }
24
30
  // delete older config files
25
31
  if (configPaths.length) {
26
32
  await Promise.all(configPaths.map((configPath) => fs.rm(configPath)));
27
33
  log.debug(`Deleted existing config file${configPaths.length > 1 ? 's' : ''} at ${configPaths.join(', ')}`);
28
34
  }
29
35
  if (validationLibrary) {
30
- dependencies.push(validationLibrary);
31
36
  dependencies.push(...({
32
- 'vovk-zod': ['zod'],
33
- 'vovk-yup': ['yup'],
34
- 'vovk-dto': ['class-validator', 'class-transformer', 'vovk-mapped-types', 'reflect-metadata'],
37
+ zod: ['zod'],
38
+ valibot: ['valibot', '@valibot/to-json-schema'],
39
+ arktype: ['arktype'],
35
40
  }[validationLibrary] ?? []));
36
41
  }
37
- if (reactQuery) {
38
- dependencies.push('vovk-react-query');
39
- dependencies.push('@tanstack/react-query');
42
+ if (bundle) {
43
+ const TSDOWN_VERSION = '0.19.0';
44
+ devDependencies.push(`tsdown@${TSDOWN_VERSION}`);
40
45
  }
41
46
  if (updateScripts) {
42
47
  try {
43
- if (!dryRun)
44
- await updateNPMScripts(pkgJson, root, updateScripts);
48
+ if (!dryRun && pkgJson)
49
+ await updateNPMScripts({ pkgJson, root, bundle, updateScriptsMode: updateScripts });
45
50
  log.info('Updated scripts at package.json');
46
51
  }
47
52
  catch (error) {
@@ -53,16 +58,22 @@ export class Init {
53
58
  }
54
59
  if (updateTsConfig) {
55
60
  try {
61
+ const compilerOptions = {
62
+ experimentalDecorators: true,
63
+ };
56
64
  if (!dryRun)
57
- await updateTypeScriptConfig(root);
58
- log.info('Added "experimentalDecorators" to tsconfig.json');
65
+ await updateTypeScriptConfig(root, compilerOptions);
66
+ log.info(`Added ${Object.keys(compilerOptions)
67
+ .map((k) => `"${k}"`)
68
+ .join(' and ')} to tsconfig.json`);
59
69
  }
60
70
  catch (error) {
61
71
  log.error(`Failed to update tsconfig.json: ${error.message}`);
62
72
  }
63
73
  }
64
- if (!dryRun) {
74
+ if (!dryRun && pkgJson) {
65
75
  let depsUpdated = false;
76
+ const packageManager = getPackageManager({ useNpm, useYarn, usePnpm, useBun, pkgJson });
66
77
  try {
67
78
  await updateDependenciesWithoutInstalling({
68
79
  log,
@@ -75,29 +86,30 @@ export class Init {
75
86
  }
76
87
  catch (e) {
77
88
  const error = e;
78
- logUpdateDependenciesError({ log, error, useNpm, useYarn, usePnpm, useBun, dependencies, devDependencies });
89
+ logUpdateDependenciesError({
90
+ log,
91
+ error,
92
+ packageManager,
93
+ dependencies,
94
+ devDependencies,
95
+ channel,
96
+ });
79
97
  }
80
98
  if (depsUpdated) {
81
- const packageManager = getPackageManager({ useNpm, useYarn, usePnpm, useBun });
82
99
  if (skipInstall) {
83
- log.info(`Installation skipped. Please, install them manually with ${chalkHighlightThing(packageManager + ' install')}`);
100
+ log.info(`Installation skipped. Please, install them manually with ${chalkHighlightThing(`${packageManager} install`)}`);
84
101
  }
85
102
  else {
86
103
  try {
87
104
  await installDependencies({
88
105
  log,
89
106
  cwd: root,
90
- options: {
91
- useNpm,
92
- useYarn,
93
- usePnpm,
94
- useBun,
95
- },
107
+ packageManager,
96
108
  });
97
109
  log.info('Dependencies installed successfully');
98
110
  }
99
111
  catch (error) {
100
- log.warn(`Failed to install dependencies: ${error.message}. Please, install them manually with ${chalkHighlightThing(packageManager + ' install')}`);
112
+ log.warn(`Failed to install dependencies. ${error.message}. Please, install them manually with ${chalkHighlightThing(`${packageManager} install`)}`);
101
113
  }
102
114
  }
103
115
  }
@@ -106,43 +118,46 @@ export class Init {
106
118
  const { configAbsolutePath } = await createConfig({
107
119
  root,
108
120
  log,
109
- options: { validationLibrary, validateOnClient, reactQuery, channel, dryRun },
121
+ options: { validationLibrary, channel, bundle, lang, dryRun },
110
122
  });
111
- log.info('Config created successfully at ' + configAbsolutePath);
123
+ log.info(`Config created successfully at ${chalkHighlightThing(configAbsolutePath)}`);
124
+ log.info(`You can now create a root segment with ${chalkHighlightThing('npx vovk new segment')} command`);
112
125
  }
113
126
  catch (error) {
114
- log.error(`Failed to create config: ${error.message}`);
127
+ log.error(`Failed to create config: ${error.message}. Please, refer to the documentation at https://vovk.dev/config`);
115
128
  }
116
129
  }
117
- async main(prefix, { yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, validateOnClient, reactQuery, dryRun, channel, }) {
130
+ async main({ prefix, yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, bundle, lang, dryRun, channel, }) {
118
131
  const cwd = process.cwd();
119
- const root = path.resolve(cwd, prefix);
120
- const log = getLogger(logLevel);
121
- const pkgJson = await NPMCliPackageJson.load(root);
132
+ const root = path.resolve(cwd, prefix ?? '.');
133
+ const log = getLogger(logLevel ?? 'info');
134
+ const pkgJson = await NPMCliPackageJson.load(root).catch(() => null);
122
135
  this.root = root;
123
136
  this.log = log;
124
- const configPaths = await getConfigPaths({ cwd, relativePath: prefix });
137
+ const configPaths = await getConfigAbsolutePaths({ cwd, relativePath: prefix });
125
138
  if (yes) {
126
- return this.#init({ configPaths, pkgJson }, {
127
- useNpm: useNpm ?? (!useYarn && !usePnpm && !useBun),
139
+ return this.#init({ configPaths, pkgJson, cwd }, {
140
+ prefix: prefix ?? '.',
141
+ useNpm: useNpm ?? false,
128
142
  useYarn: useYarn ?? false,
129
143
  usePnpm: usePnpm ?? false,
130
144
  useBun: useBun ?? false,
131
145
  skipInstall: skipInstall ?? false,
132
146
  updateTsConfig: updateTsConfig ?? true,
133
147
  updateScripts: updateScripts ?? 'implicit',
134
- validationLibrary: validationLibrary?.toLocaleLowerCase() === 'none' ? null : (validationLibrary ?? 'vovk-zod'),
135
- validateOnClient: validateOnClient ?? true,
136
- reactQuery: reactQuery ?? true,
148
+ validationLibrary: validationLibrary?.toLocaleLowerCase() === 'none' ? null : (validationLibrary ?? 'zod'),
149
+ bundle: bundle ?? true,
137
150
  dryRun: dryRun ?? false,
138
151
  channel: channel ?? 'latest',
152
+ lang: lang ?? [],
139
153
  });
140
154
  }
141
155
  if (!(await getFileSystemEntryType(path.join(root, 'package.json')))) {
142
- throw new Error(`package.json not found at ${root}. Run "npx create-next-app" to create a new Next.js project.`);
156
+ log.warn(`${chalkHighlightThing('package.json')} not found at ${chalkHighlightThing(root)}. Run "npx create-next-app" to create a new Next.js project
157
+ .`);
143
158
  }
144
- if (!(await getFileSystemEntryType(path.join(root, 'tsconfig.json')))) {
145
- throw new Error(`tsconfig.json not found at ${root}. Run "npx tsc --init" to create a new tsconfig.json file.`);
159
+ else if (pkgJson && !(await getFileSystemEntryType(path.join(root, 'tsconfig.json')))) {
160
+ log.warn(`${chalkHighlightThing('tsconfig.json')} not found at ${chalkHighlightThing(root)}. Run "npx tsc --init" to create a new tsconfig.json file.`);
146
161
  }
147
162
  if (configPaths.length) {
148
163
  if (!(await confirm({
@@ -156,62 +171,27 @@ export class Init {
156
171
  : (validationLibrary ??
157
172
  (await select({
158
173
  message: 'Choose validation library',
159
- default: 'vovk-zod',
174
+ default: 'zod',
160
175
  choices: [
161
176
  {
162
- name: 'vovk-zod',
163
- value: 'vovk-zod',
177
+ name: 'Zod',
178
+ value: 'zod',
164
179
  description: 'Use Zod for data validation',
165
180
  },
166
181
  {
167
- name: 'vovk-yup',
168
- value: 'vovk-yup',
169
- description: 'Use Yup for data validation',
182
+ name: 'ArkType',
183
+ value: 'arktype',
184
+ description: 'Use ArkType for data validation.',
170
185
  },
171
186
  {
172
- name: 'vovk-dto',
173
- value: 'vovk-dto',
174
- description: 'Use class-validator for data validation. Also installs class-transformer, vovk-mapped-types and reflect-metadata',
187
+ name: 'Valibot',
188
+ value: 'valibot',
189
+ description: 'Use Valibot for data validation.',
175
190
  },
176
191
  { name: 'None', value: null, description: 'Install validation library later' },
177
192
  ],
178
193
  })));
179
- if (validationLibrary) {
180
- validateOnClient =
181
- validateOnClient ??
182
- (await confirm({
183
- message: 'Do you want to enable client validation?',
184
- }));
185
- }
186
- updateScripts =
187
- updateScripts ??
188
- (await select({
189
- message: 'Do you want to update package.json by adding "generate" and updating "dev" NPM scripts?',
190
- default: 'implicit',
191
- choices: [
192
- {
193
- name: 'Yes, use "concurrently" implicitly',
194
- value: 'implicit',
195
- 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')}"`)}`,
196
- },
197
- {
198
- name: 'Yes, use "concurrently" explicitly',
199
- value: 'explicit',
200
- 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')}"`)}`,
201
- },
202
- {
203
- name: 'No',
204
- value: undefined,
205
- description: 'Add the NPM scripts manually',
206
- },
207
- ],
208
- }));
209
- reactQuery =
210
- reactQuery ??
211
- (await confirm({
212
- message: 'Do you want to use @tanstack/react-query for data fetching at React components?',
213
- }));
214
- if (typeof updateTsConfig === 'undefined') {
194
+ if (typeof updateTsConfig === 'undefined' && pkgJson) {
215
195
  let shouldAsk = false;
216
196
  try {
217
197
  shouldAsk = !(await checkTSConfigForExperimentalDecorators(root));
@@ -220,13 +200,48 @@ export class Init {
220
200
  log.error(`Failed to check tsconfig.json for "experimentalDecorators": ${error.message}`);
221
201
  }
222
202
  if (shouldAsk) {
203
+ const keys = ['experimentalDecorators'];
223
204
  updateTsConfig = await confirm({
224
- message: 'Do you want to add "experimentalDecorators" option to tsconfig.json?',
205
+ message: `Do you want to add ${keys.map((k) => `"${k}"`).join(' and ')} to tsconfig.json? (recommended)`,
225
206
  });
226
207
  }
227
208
  }
228
- await this.#init({ configPaths, pkgJson }, {
229
- useNpm: useNpm ?? (!useYarn && !usePnpm && !useBun),
209
+ bundle ??= await confirm({
210
+ message: 'Do you want to set up "tsdown" to bundle TypeScript client?',
211
+ default: true,
212
+ });
213
+ updateScripts ??= !pkgJson
214
+ ? undefined
215
+ : await select({
216
+ message: `Do you want to update "dev" and add "prebuild"${bundle ? ' and "bundle"' : ''} NPM scripts at package.json (recommended)?`,
217
+ default: 'implicit',
218
+ choices: [
219
+ {
220
+ name: 'Yes, use "concurrently" implicitly',
221
+ value: 'implicit',
222
+ description: `The ${chalk.cyanBright.bold(`"dev"`)} script will use concurrently API to run "next dev" and "vovk dev" commands at the same time. It will automatically find an available port, running ${chalk.cyanBright.bold(`"${getDevScript(pkgJson, 'implicit')}"`)}. The ${chalk.cyanBright.bold(`"prebuild"`)} script will be set to ${chalk.cyanBright.bold(`"vovk generate"`)}`,
223
+ },
224
+ {
225
+ name: 'Yes, use "concurrently" explicitly',
226
+ value: 'explicit',
227
+ description: `The ${chalk.cyanBright.bold(`"dev"`)} script will use pre-defined PORT variable to run "next dev" and "vovk dev" as "concurrently" CLI arguments ${chalk.cyanBright.bold(`"${getDevScript(pkgJson, 'explicit')}"`)}. The ${chalk.cyanBright.bold(`"prebuild"`)} script will be set to ${chalk.cyanBright.bold(`"vovk generate"`)}`,
228
+ },
229
+ {
230
+ name: 'No',
231
+ value: undefined,
232
+ description: 'Add the NPM scripts manually',
233
+ },
234
+ ],
235
+ });
236
+ lang ??= await checkbox({
237
+ message: 'Do you want to generate RPC client for other languages besides TypeScript (experimental)?',
238
+ choices: [
239
+ { name: 'Python', value: 'py' },
240
+ { name: 'Rust', value: 'rs' },
241
+ ],
242
+ });
243
+ await this.#init({ configPaths, pkgJson, cwd }, {
244
+ useNpm: useNpm ?? false,
230
245
  useYarn: useYarn ?? false,
231
246
  usePnpm: usePnpm ?? false,
232
247
  useBun: useBun ?? false,
@@ -234,8 +249,8 @@ export class Init {
234
249
  updateTsConfig,
235
250
  updateScripts,
236
251
  validationLibrary,
237
- validateOnClient,
238
- reactQuery,
252
+ bundle,
253
+ lang,
239
254
  dryRun,
240
255
  channel,
241
256
  });
@@ -1,10 +1,12 @@
1
- import getLogger from '../utils/getLogger.mjs';
1
+ import type NPMCliPackageJson from '@npmcli/package-json';
2
+ import type { getLogger } from '../utils/getLogger.mjs';
2
3
  import type { InitOptions } from '../types.mjs';
3
- type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun';
4
- export declare function getPackageManager(options: Pick<InitOptions, 'useNpm' | 'useYarn' | 'usePnpm' | 'useBun'>): PackageManager;
5
- export default function installDependencies({ log, cwd, options, }: {
4
+ export type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun';
5
+ export declare function getPackageManager(options: Pick<InitOptions, 'useNpm' | 'useYarn' | 'usePnpm' | 'useBun'> & {
6
+ pkgJson: NPMCliPackageJson;
7
+ }): PackageManager;
8
+ export declare function installDependencies({ log, cwd, packageManager, }: {
6
9
  log: ReturnType<typeof getLogger>;
7
10
  cwd: string;
8
- options: Pick<InitOptions, 'useNpm' | 'useYarn' | 'usePnpm' | 'useBun'>;
11
+ packageManager: PackageManager;
9
12
  }): Promise<void>;
10
- export {};
@@ -1,4 +1,5 @@
1
1
  import { spawn } from 'node:child_process';
2
+ import { chalkHighlightThing } from '../utils/chalkHighlightThing.mjs';
2
3
  export function getPackageManager(options) {
3
4
  if (options.useNpm)
4
5
  return 'npm';
@@ -8,13 +9,14 @@ export function getPackageManager(options) {
8
9
  return 'pnpm';
9
10
  if (options.useBun)
10
11
  return 'bun';
11
- return 'npm'; // Default to npm if no options are true
12
+ const packageManager = options.pkgJson.content?.packageManager;
13
+ return packageManager ? packageManager.split('@')[0] : 'npm'; // Default to npm if no options are true
12
14
  }
13
- export default async function installDependencies({ log, cwd, options, }) {
14
- const packageManager = getPackageManager(options);
15
- log.info(`Installing dependencies at ${cwd} using ${packageManager}...`);
15
+ export async function installDependencies({ log, cwd, packageManager, }) {
16
+ log.info(`Installing dependencies at ${chalkHighlightThing(cwd)} using ${chalkHighlightThing(packageManager)}...`);
16
17
  await new Promise((resolve, reject) => {
17
- const child = spawn(packageManager, ['install'], { cwd, stdio: 'inherit' });
18
+ const args = ['install'];
19
+ const child = spawn(packageManager, args, { cwd, stdio: 'inherit' });
18
20
  child.on('close', (code) => {
19
21
  if (code === 0) {
20
22
  resolve();
@@ -1,11 +1,11 @@
1
- import type getLogger from '../utils/getLogger.mjs';
2
- export default function logUpdateDependenciesError({ useNpm, useYarn, usePnpm, useBun, log, dependencies, devDependencies, error, }: {
3
- useNpm?: boolean;
4
- useYarn?: boolean;
5
- usePnpm?: boolean;
6
- useBun?: boolean;
1
+ import type { InitOptions } from '../types.mjs';
2
+ import type { getLogger } from '../utils/getLogger.mjs';
3
+ import type { PackageManager } from './installDependencies.mjs';
4
+ export declare function logUpdateDependenciesError({ packageManager, log, dependencies, devDependencies, error, channel, }: {
5
+ packageManager: PackageManager;
7
6
  log: ReturnType<typeof getLogger>;
8
7
  dependencies: string[];
9
8
  devDependencies: string[];
10
9
  error: Error;
10
+ channel: InitOptions['channel'];
11
11
  }): void;
@@ -1,8 +1,12 @@
1
- import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
2
- import { getPackageManager } from './installDependencies.mjs';
3
- export default function logUpdateDependenciesError({ useNpm, useYarn, usePnpm, useBun, log, dependencies, devDependencies, error, }) {
4
- const packageManager = getPackageManager({ useNpm, useYarn, usePnpm, useBun });
1
+ import { chalkHighlightThing } from '../utils/chalkHighlightThing.mjs';
2
+ export function logUpdateDependenciesError({ packageManager, log, dependencies, devDependencies, error, channel, }) {
5
3
  const installCommands = [];
4
+ const addChannel = (packageName) => {
5
+ const isVovk = packageName.startsWith('vovk');
6
+ return isVovk ? (!channel || channel !== 'latest' ? `${packageName}@${channel}` : packageName) : packageName;
7
+ };
8
+ dependencies = dependencies.map(addChannel);
9
+ devDependencies = devDependencies.map(addChannel);
6
10
  if (dependencies.length > 0) {
7
11
  let depInstallCmd = '';
8
12
  switch (packageManager) {
@@ -1,6 +1,6 @@
1
- import type getLogger from '../utils/getLogger.mjs';
2
- import { InitOptions } from '../types.mjs';
3
- export default function updateDependenciesWithoutInstalling({ log, dir, dependencyNames, devDependencyNames, channel, }: {
1
+ import type { getLogger } from '../utils/getLogger.mjs';
2
+ import type { InitOptions } from '../types.mjs';
3
+ export declare function updateDependenciesWithoutInstalling({ log, dir, dependencyNames, devDependencyNames, channel, }: {
4
4
  log: ReturnType<typeof getLogger>;
5
5
  dir: string;
6
6
  dependencyNames: string[];
@@ -1,23 +1,53 @@
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';
5
- async function updateDeps({ packageJson, packageNames, channel, key, }) {
4
+ import { getNPMPackageMetadata } from '../utils/getNPMPackageMetadata.mjs';
5
+ async function updateDeps({ packageJson, packageNames, channel, key, log, }) {
6
6
  return Promise.all(packageNames.map(async (packageName) => {
7
- const metadata = await getNPMPackageMetadata(packageName);
8
- const isVovk = packageName.startsWith('vovk') && packageName !== 'vovk-mapped-types';
9
- const latestVersion = metadata['dist-tags'][isVovk ? (channel ?? 'latest') : 'latest'];
10
- if (!packageJson[key]) {
11
- packageJson[key] = {};
7
+ let name;
8
+ let version;
9
+ if (packageName.startsWith('@')) {
10
+ // Handle scoped packages (@org/name@version)
11
+ const lastAtIndex = packageName.lastIndexOf('@');
12
+ if (lastAtIndex > 0) {
13
+ name = packageName.substring(0, lastAtIndex);
14
+ version = packageName.substring(lastAtIndex + 1);
15
+ }
16
+ else {
17
+ name = packageName;
18
+ version = undefined;
19
+ }
20
+ }
21
+ else {
22
+ // Handle regular packages (name@version)
23
+ const parts = packageName.split('@');
24
+ name = parts[0];
25
+ version = parts[1];
26
+ }
27
+ if (version) {
28
+ packageJson[key] ??= {};
29
+ packageJson[key][name] = version;
30
+ return;
12
31
  }
13
- packageJson[key][packageName] = `^${latestVersion}`;
32
+ let metadata;
33
+ try {
34
+ metadata = await getNPMPackageMetadata(name);
35
+ }
36
+ catch (error) {
37
+ log.error(`Failed to fetch metadata for package ${name}@${channel ?? 'latest'}: ${error}`);
38
+ return;
39
+ }
40
+ const isVovk = name.startsWith('vovk');
41
+ const latestVersion = metadata['dist-tags'][isVovk ? (channel ?? 'latest') : 'latest'];
42
+ packageJson[key] ??= {};
43
+ packageJson[key][name] = `^${latestVersion}`;
14
44
  }));
15
45
  }
16
- export default async function updateDependenciesWithoutInstalling({ log, dir, dependencyNames, devDependencyNames, channel, }) {
46
+ export async function updateDependenciesWithoutInstalling({ log, dir, dependencyNames, devDependencyNames, channel, }) {
17
47
  const packageJsonPath = path.join(dir, 'package.json');
18
48
  const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
19
- await updateDeps({ packageJson, packageNames: dependencyNames, channel, key: 'dependencies' });
20
- await updateDeps({ packageJson, packageNames: devDependencyNames, channel, key: 'devDependencies' });
49
+ await updateDeps({ packageJson, packageNames: dependencyNames, channel, log, key: 'dependencies' });
50
+ await updateDeps({ packageJson, packageNames: devDependencyNames, channel, log, key: 'devDependencies' });
21
51
  await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
22
52
  log.info('Added dependencies to package.json:');
23
53
  for (const dependency of dependencyNames) {
@@ -1,3 +1,8 @@
1
- import NPMCliPackageJson from '@npmcli/package-json';
1
+ import type NPMCliPackageJson from '@npmcli/package-json';
2
2
  export declare function getDevScript(pkgJson: NPMCliPackageJson, updateScriptsMode: 'implicit' | 'explicit'): string;
3
- export default function updateNPMScripts(pkgJson: NPMCliPackageJson, root: string, updateScriptsMode: 'implicit' | 'explicit'): Promise<void>;
3
+ export declare function updateNPMScripts({ pkgJson, bundle, updateScriptsMode, }: {
4
+ pkgJson: NPMCliPackageJson;
5
+ root: string;
6
+ bundle?: boolean;
7
+ updateScriptsMode: 'implicit' | 'explicit';
8
+ }): Promise<void>;
@@ -1,16 +1,20 @@
1
1
  export function getDevScript(pkgJson, updateScriptsMode) {
2
- const nextDev = pkgJson.content.scripts?.dev ?? 'next dev';
3
- const nextDevFlags = nextDev.replace('next dev', '').trim();
2
+ const dev = pkgJson.content.scripts?.dev ?? 'next dev';
3
+ if (dev.includes('vovk dev')) {
4
+ return dev; // Already has vovk dev
5
+ }
6
+ const nextDevFlags = dev.replace('next dev', '').trim();
4
7
  return updateScriptsMode === 'explicit'
5
- ? `PORT=3000 concurrently '${nextDev}' 'vovk dev' --kill-others`
8
+ ? `PORT=3000 concurrently '${dev}' 'vovk dev' --kill-others`
6
9
  : `vovk dev --next-dev${nextDevFlags ? ` -- ${nextDevFlags}` : ''}`;
7
10
  }
8
- export default async function updateNPMScripts(pkgJson, root, updateScriptsMode) {
11
+ export async function updateNPMScripts({ pkgJson, bundle, updateScriptsMode, }) {
9
12
  pkgJson.update({
10
13
  scripts: {
11
14
  ...pkgJson.content.scripts,
12
- generate: 'vovk generate',
13
15
  dev: getDevScript(pkgJson, updateScriptsMode),
16
+ prebuild: 'vovk generate',
17
+ ...(bundle ? { bundle: 'vovk bundle' } : {}),
14
18
  },
15
19
  });
16
20
  await pkgJson.save();
@@ -1 +1,4 @@
1
- export default function updateTypeScriptConfig(root: string): Promise<void>;
1
+ export declare function updateTypeScriptConfig(root: string, compilerOptions: {
2
+ experimentalDecorators?: true;
3
+ emitDecoratorMetadata?: true;
4
+ }): Promise<void>;
@@ -1,15 +1,19 @@
1
1
  import path from 'node:path';
2
2
  import fs from 'node:fs/promises';
3
3
  import * as jsonc from 'jsonc-parser';
4
- import prettify from '../utils/prettify.mjs';
5
- export default async function updateTypeScriptConfig(root) {
4
+ import { prettify } from '../utils/prettify.mjs';
5
+ export async function updateTypeScriptConfig(root, compilerOptions) {
6
6
  const tsconfigPath = path.join(root, 'tsconfig.json');
7
7
  const tsconfigContent = await fs.readFile(tsconfigPath, 'utf8');
8
- // Use jsonc-parser to generate edits and modify the experimentalDecorators property
9
- const edits = jsonc.modify(tsconfigContent, ['compilerOptions', 'experimentalDecorators'], true, {
10
- formattingOptions: {},
11
- });
12
- // Apply the edits to the original content
13
- const updatedContent = await prettify(jsonc.applyEdits(tsconfigContent, edits), tsconfigPath);
8
+ let updatedContent = tsconfigContent;
9
+ // Apply each compiler option
10
+ for (const [key, value] of Object.entries(compilerOptions)) {
11
+ const edits = jsonc.modify(updatedContent, ['compilerOptions', key], value, {
12
+ formattingOptions: {},
13
+ });
14
+ updatedContent = jsonc.applyEdits(updatedContent, edits);
15
+ }
16
+ // Prettify the final content
17
+ updatedContent = await prettify(updatedContent, tsconfigPath);
14
18
  await fs.writeFile(tsconfigPath, updatedContent, 'utf8');
15
19
  }
@@ -1,4 +1,4 @@
1
- export default function addClassToSegmentCode(segmentSourceCode: string, { sourceName, compiledName, importPath, }: {
1
+ export declare function addClassToSegmentCode(segmentSourceCode: string, { sourceName, compiledName, importPath, }: {
2
2
  sourceName: string;
3
3
  compiledName: string;
4
4
  importPath: string;
@@ -1,5 +1,5 @@
1
1
  import { Project, QuoteKind, SyntaxKind } from 'ts-morph';
2
- export default function addClassToSegmentCode(segmentSourceCode, { sourceName, compiledName, importPath, }) {
2
+ export function addClassToSegmentCode(segmentSourceCode, { sourceName, compiledName, importPath, }) {
3
3
  const project = new Project({
4
4
  manipulationSettings: {
5
5
  quoteKind: QuoteKind.Single,
@@ -7,11 +7,11 @@ export default function addClassToSegmentCode(segmentSourceCode, { sourceName, c
7
7
  });
8
8
  const sourceFile = project.createSourceFile('route.ts', segmentSourceCode, { overwrite: true });
9
9
  // Add the import if it doesn't exist
10
- let importDeclaration = sourceFile.getImportDeclaration((imp) => {
10
+ const importDeclaration = sourceFile.getImportDeclaration((imp) => {
11
11
  return imp.getModuleSpecifierValue() === importPath;
12
12
  });
13
13
  if (!importDeclaration) {
14
- importDeclaration = sourceFile.addImportDeclaration({
14
+ sourceFile.addImportDeclaration({
15
15
  defaultImport: sourceName,
16
16
  moduleSpecifier: importPath,
17
17
  });
@@ -1 +1 @@
1
- export default function addCommonTerms(): void;
1
+ export declare function addCommonTerms(): void;
@@ -84,7 +84,7 @@ const terms = [
84
84
  ['half', 'halves'],
85
85
  ['scarf', 'scarves'],
86
86
  ];
87
- export default function addCommonTerms() {
87
+ export function addCommonTerms() {
88
88
  terms.forEach(([singular, plural]) => {
89
89
  const regex = new RegExp(`${singular}$`, 'i');
90
90
  pluralize.addPluralRule(regex, plural);
@@ -1,2 +1,3 @@
1
1
  import type { NewOptions } from '../types.mjs';
2
- export default function newComponents(components: string[], { dryRun, dir, templates, overwrite, noSegmentUpdate, empty }: NewOptions): Promise<void>;
2
+ import type { ProjectInfo } from '../getProjectInfo/index.mts';
3
+ export declare function newComponents(components: string[], projectInfo: ProjectInfo, { dryRun, outDir, templates, overwrite, noSegmentUpdate, empty, static: isStaticSegment }: NewOptions): Promise<void>;