vovk-cli 0.0.1-beta.26 → 0.0.1-beta.30

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 (56) hide show
  1. package/dist/getProjectInfo/getConfig.d.mts +3 -2
  2. package/dist/getProjectInfo/getConfig.mjs +5 -6
  3. package/dist/getProjectInfo/getConfigAbsolutePaths.d.mts +4 -0
  4. package/dist/getProjectInfo/{getConfigPaths.mjs → getConfigAbsolutePaths.mjs} +2 -2
  5. package/dist/getProjectInfo/getRelativeSrcRoot.d.mts +3 -1
  6. package/dist/getProjectInfo/getRelativeSrcRoot.mjs +1 -2
  7. package/dist/getProjectInfo/getUserConfig.d.mts +8 -0
  8. package/dist/getProjectInfo/getUserConfig.mjs +19 -0
  9. package/dist/getProjectInfo/index.d.mts +2 -1
  10. package/dist/getProjectInfo/index.mjs +4 -5
  11. package/dist/index.d.mts +10 -1
  12. package/dist/index.mjs +11 -2
  13. package/dist/init/checkTSConfigForExperimentalDecorators.d.mts +1 -0
  14. package/dist/init/checkTSConfigForExperimentalDecorators.mjs +15 -0
  15. package/dist/init/createConfig.d.mts +7 -0
  16. package/dist/init/createConfig.mjs +38 -0
  17. package/dist/init/getTemplateFilesFromPackage.d.mts +6 -0
  18. package/dist/init/getTemplateFilesFromPackage.mjs +76 -0
  19. package/dist/init/index.d.mts +3 -14
  20. package/dist/init/index.mjs +163 -157
  21. package/dist/init/installDependencies.d.mts +9 -1
  22. package/dist/init/installDependencies.mjs +82 -26
  23. package/dist/init/updateNPMScripts.d.mts +1 -0
  24. package/dist/init/updateNPMScripts.mjs +13 -0
  25. package/dist/init/updateTSConfig.d.mts +1 -0
  26. package/dist/init/updateTSConfig.mjs +14 -0
  27. package/dist/locateSegments.mjs +2 -2
  28. package/dist/new/newModule.mjs +2 -2
  29. package/dist/new/newSegment.mjs +2 -2
  30. package/dist/postinstall.mjs +2 -2
  31. package/dist/utils/getFileSystemEntryType.d.mts +5 -0
  32. package/dist/utils/getFileSystemEntryType.mjs +23 -0
  33. package/dist/watcher/index.mjs +3 -2
  34. package/package.json +6 -3
  35. package/templates/controller.ejs +1 -85
  36. package/templates/service.ejs +1 -9
  37. package/templates/worker.ejs +1 -9
  38. package/templates_old/controller.ejs +85 -0
  39. package/templates_old/service.ejs +9 -0
  40. package/templates_old/worker.ejs +9 -0
  41. package/tmp_test_dir/README.md +36 -0
  42. package/tmp_test_dir/next.config.mjs +4 -0
  43. package/tmp_test_dir/package-lock.json +2914 -0
  44. package/tmp_test_dir/package.json +24 -0
  45. package/tmp_test_dir/vovk.config.js +11 -0
  46. package/dist/getProjectInfo/getConfigPaths.d.mts +0 -1
  47. package/dist/getProjectInfo/readConfig.d.mts +0 -6
  48. package/dist/getProjectInfo/readConfig.mjs +0 -19
  49. package/dist/utils/fileExists.d.mts +0 -1
  50. package/dist/utils/fileExists.mjs +0 -10
  51. /package/{templates → templates_old}/MyThingController.c.only.template.ts +0 -0
  52. /package/{templates → templates_old}/MyThingController.c.template.ts +0 -0
  53. /package/{templates → templates_old}/MyThingService.s.template.ts +0 -0
  54. /package/{templates → templates_old}/zod/MyThingController.c.only.template.ts +0 -0
  55. /package/{templates → templates_old}/zod/MyThingController.c.template.ts +0 -0
  56. /package/{templates → templates_old}/zod/MyThingService.s.template.ts +0 -0
@@ -1,8 +1,9 @@
1
1
  import type { VovkConfig } from '../types.mjs';
2
- export default function getConfig({ clientOutDir }: {
2
+ export default function getConfig({ clientOutDir, cwd }: {
3
3
  clientOutDir?: string;
4
+ cwd: string;
4
5
  }): Promise<{
5
6
  config: Required<VovkConfig>;
6
7
  srcRoot: string;
7
- configPaths: string[];
8
+ configAbsolutePaths: string[];
8
9
  }>;
@@ -1,9 +1,9 @@
1
- import readConfig from './readConfig.mjs';
1
+ import getUserConfig from './getUserConfig.mjs';
2
2
  import getRelativeSrcRoot from './getRelativeSrcRoot.mjs';
3
- export default async function getConfig({ clientOutDir }) {
3
+ export default async function getConfig({ clientOutDir, cwd }) {
4
4
  const env = process.env;
5
- const { userConfig, configPaths } = await readConfig();
6
- const srcRoot = await getRelativeSrcRoot();
5
+ const { userConfig, configAbsolutePaths } = await getUserConfig({ cwd });
6
+ const srcRoot = await getRelativeSrcRoot({ cwd });
7
7
  const config = {
8
8
  modulesDir: env.VOVK_MODULES_DIR ?? userConfig.modulesDir ?? './' + [srcRoot, 'modules'].filter(Boolean).join('/'),
9
9
  validateOnClient: env.VOVK_VALIDATE_ON_CLIENT ?? userConfig.validateOnClient ?? null,
@@ -17,12 +17,11 @@ export default async function getConfig({ clientOutDir }) {
17
17
  logLevel: env.VOVK_LOG_LEVEL ?? userConfig.logLevel ?? 'debug', // TODO: change to 'warn' when v3 is ready
18
18
  prettifyClient: userConfig.prettifyClient ?? false,
19
19
  templates: {
20
- // TODO individual templates for each validation library
21
20
  service: 'vovk-cli/templates/service.ejs',
22
21
  controller: 'vovk-cli/templates/controller.ejs',
23
22
  worker: 'vovk-cli/templates/worker.ejs',
24
23
  ...userConfig.templates,
25
24
  },
26
25
  };
27
- return { config, srcRoot, configPaths };
26
+ return { config, srcRoot, configAbsolutePaths };
28
27
  }
@@ -0,0 +1,4 @@
1
+ export default function getConfigAbsolutePaths({ cwd, relativePath, }: {
2
+ cwd: string;
3
+ relativePath?: string;
4
+ }): Promise<string[]>;
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
- export default async function getConfigPaths(relativePath = '') {
4
- const rootDir = path.resolve(process.cwd(), relativePath || '');
3
+ export default async function getConfigAbsolutePaths({ cwd, relativePath, }) {
4
+ const rootDir = path.resolve(cwd, relativePath || '');
5
5
  const baseName = 'vovk.config';
6
6
  const extensions = ['cjs', 'mjs', 'js'];
7
7
  const dirs = [path.join(rootDir, '.config'), rootDir];
@@ -1 +1,3 @@
1
- export default function getRelativeSrcRoot(): Promise<"." | "./src">;
1
+ export default function getRelativeSrcRoot({ cwd }: {
2
+ cwd: string;
3
+ }): Promise<"." | "./src">;
@@ -1,7 +1,6 @@
1
1
  import path from 'path';
2
2
  import directoryExists from './directoryExists.mjs';
3
- export default async function getRelativeSrcRoot() {
4
- const cwd = process.cwd();
3
+ export default async function getRelativeSrcRoot({ cwd }) {
5
4
  // Next.js Docs: src/app or src/pages will be ignored if app or pages are present in the root directory.
6
5
  if (await directoryExists(path.join(cwd, 'app'))) {
7
6
  return '.';
@@ -0,0 +1,8 @@
1
+ import type { VovkConfig } from '../types.mjs';
2
+ declare function getUserConfig({ cwd, }: {
3
+ cwd: string;
4
+ }): Promise<{
5
+ userConfig: VovkConfig;
6
+ configAbsolutePaths: string[];
7
+ }>;
8
+ export default getUserConfig;
@@ -0,0 +1,19 @@
1
+ import getConfigAbsolutePaths from './getConfigAbsolutePaths.mjs';
2
+ async function getUserConfig({ cwd, }) {
3
+ const configAbsolutePaths = await getConfigAbsolutePaths({ cwd });
4
+ let userConfig = {};
5
+ if (!configAbsolutePaths.length) {
6
+ return { userConfig, configAbsolutePaths };
7
+ }
8
+ const configPath = configAbsolutePaths[0];
9
+ try {
10
+ const cacheBuster = Date.now();
11
+ ({ default: userConfig } = (await import(`${configPath}?cache=${cacheBuster}`)));
12
+ }
13
+ catch (e) {
14
+ // eslint-disable-next-line no-console
15
+ console.error('🐺 ❌ Error reading config file:', e.message);
16
+ }
17
+ return { userConfig, configAbsolutePaths };
18
+ }
19
+ export default getUserConfig;
@@ -1,7 +1,8 @@
1
1
  export type ProjectInfo = Awaited<ReturnType<typeof getProjectInfo>>;
2
- export default function getProjectInfo({ port: givenPort, clientOutDir, }?: {
2
+ export default function getProjectInfo({ port: givenPort, clientOutDir, cwd, }?: {
3
3
  port?: number;
4
4
  clientOutDir?: string;
5
+ cwd?: string;
5
6
  }): Promise<{
6
7
  cwd: string;
7
8
  port: string;
@@ -1,12 +1,11 @@
1
1
  import path from 'path';
2
2
  import getConfig from './getConfig.mjs';
3
3
  import getLogger from '../utils/getLogger.mjs';
4
- export default async function getProjectInfo({ port: givenPort, clientOutDir, } = {}) {
4
+ export default async function getProjectInfo({ port: givenPort, clientOutDir, cwd = process.cwd(), } = {}) {
5
5
  const port = givenPort?.toString() ?? process.env.PORT ?? '3000';
6
6
  // Make PORT available to the config file at getConfig
7
7
  process.env.PORT = port;
8
- const cwd = process.cwd();
9
- const { config, srcRoot, configPaths } = await getConfig({ clientOutDir });
8
+ const { config, srcRoot, configAbsolutePaths } = await getConfig({ clientOutDir, cwd });
10
9
  const apiEntryPoint = `${config.origin ?? ''}/${config.rootEntry}`;
11
10
  const apiDir = path.join(srcRoot, 'app', config.rootEntry);
12
11
  const schemaOutImportPath = path.relative(config.clientOutDir, config.schemaOutDir);
@@ -17,8 +16,8 @@ export default async function getProjectInfo({ port: givenPort, clientOutDir, }
17
16
  ? path.relative(config.clientOutDir, config.validateOnClient)
18
17
  : config.validateOnClient;
19
18
  const log = getLogger(config.logLevel);
20
- if (configPaths.length > 1) {
21
- log.warn(`Multiple config files found. Using the first one: ${configPaths[0]}`);
19
+ if (configAbsolutePaths.length > 1) {
20
+ log.warn(`Multiple config files found. Using the first one: ${configAbsolutePaths[0]}`);
22
21
  }
23
22
  return {
24
23
  cwd,
package/dist/index.d.mts CHANGED
@@ -3,8 +3,17 @@ import type { LogLevelNames } from 'loglevel';
3
3
  import type { VovkConfig, VovkEnv } from './types.mjs';
4
4
  export type { VovkConfig, VovkEnv };
5
5
  export interface InitOptions {
6
- yes: boolean;
6
+ yes?: boolean;
7
7
  logLevel: LogLevelNames;
8
+ useNpm?: boolean;
9
+ useYarn?: boolean;
10
+ usePnpm?: boolean;
11
+ useBun?: boolean;
12
+ skipInstall?: boolean;
13
+ updateTsConfig?: boolean;
14
+ updateScripts?: 'implicit' | 'explicit';
15
+ validationLibrary?: string;
16
+ validateOnClient?: boolean;
8
17
  }
9
18
  export interface NewOptions {
10
19
  dryRun: boolean;
package/dist/index.mjs CHANGED
@@ -75,8 +75,17 @@ program
75
75
  .command('init [prefix]')
76
76
  .description('Initialize Vovk project')
77
77
  .option('-Y, --yes', 'Skip all prompts and use default values')
78
- .option('--log-level <level>', 'Set log level', 'info')
79
- .action((prefix = '.', options) => Init.main(prefix, options));
78
+ .option('--log-level <level>', 'Set log level', 'debug') // TODO change to 'info'
79
+ .option('--use-npm', 'Use npm as package manager')
80
+ .option('--use-yarn', 'Use yarn as package manager')
81
+ .option('--use-pnpm', 'Use pnpm as package manager')
82
+ .option('--use-bun', 'Use bun as package manager')
83
+ .option('--skip-install', 'Skip installing dependencies')
84
+ .option('--update-ts-config', 'Update tsconfig.json')
85
+ .option('--update-scripts <mode>', 'Update package.json scripts (implicit or explicit)')
86
+ .option('--validation-library <library>', 'Validation library to use')
87
+ .option('--validate-on-client', 'Validate on client')
88
+ .action((prefix = '.', options) => new Init().main(prefix, options));
80
89
  program
81
90
  .command('new [components...]')
82
91
  .alias('n')
@@ -0,0 +1 @@
1
+ export default function checkTSConfigForExperimentalDecorators(root: string): Promise<boolean>;
@@ -0,0 +1,15 @@
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import * as jsonc from 'jsonc-parser';
4
+ export default async function checkTSConfigForExperimentalDecorators(root) {
5
+ const tsconfigPath = path.resolve(root, 'tsconfig.json');
6
+ let tsconfigContent;
7
+ try {
8
+ tsconfigContent = await fs.readFile(tsconfigPath, 'utf8');
9
+ }
10
+ catch (error) {
11
+ throw new Error(`Failed to read tsconfig.json at ${tsconfigPath}. You can run "npx tsc --init" to create it. ${String(error)}`);
12
+ }
13
+ const tsconfig = jsonc.parse(tsconfigContent);
14
+ return !!tsconfig?.compilerOptions?.experimentalDecorators;
15
+ }
@@ -0,0 +1,7 @@
1
+ import type getLogger from '../utils/getLogger.mjs';
2
+ import type { InitOptions } from '../index.mjs';
3
+ export default function createConfig({ root, log, options: { validationLibrary, validateOnClient }, }: {
4
+ root: string;
5
+ log: ReturnType<typeof getLogger>;
6
+ options: Pick<InitOptions, 'validationLibrary' | 'validateOnClient'>;
7
+ }): Promise<void>;
@@ -0,0 +1,38 @@
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+ import getFileSystemEntryType, { FileSystemEntryType } from '../utils/getFileSystemEntryType.mjs';
4
+ import getTemplateFilesFromPackage from './getTemplateFilesFromPackage.mjs';
5
+ import prettify from '../utils/prettify.mjs';
6
+ export default async function createConfig({ root, log, options: { validationLibrary, validateOnClient }, }) {
7
+ const config = {};
8
+ const dotConfigPath = path.join(root, '.config');
9
+ const dir = (await getFileSystemEntryType(dotConfigPath)) === FileSystemEntryType.DIRECTORY ? dotConfigPath : root;
10
+ const isModule = await fs
11
+ .readFile(path.join(root, 'package.json'), 'utf-8')
12
+ .then((content) => JSON.parse(content).type === 'module');
13
+ const configAbsolutePath = path.join(dir, isModule ? 'vovk.config.mjs' : 'vovk.config.js');
14
+ config.validationLibrary = validationLibrary;
15
+ if (validateOnClient) {
16
+ config.validateOnClient = `${validationLibrary}/validateOnClient`;
17
+ }
18
+ const templates = {
19
+ controller: 'vovk-cli/templates/controller.ejs',
20
+ service: 'vovk-cli/templates/service.ejs',
21
+ worker: 'vovk-cli/templates/worker.ejs',
22
+ };
23
+ if (validationLibrary) {
24
+ try {
25
+ const validationTemplates = await getTemplateFilesFromPackage(validationLibrary);
26
+ Object.assign(templates, validationTemplates);
27
+ }
28
+ catch (error) {
29
+ log.error(`Failed to fetch validation library templates: ${error.message}`);
30
+ }
31
+ }
32
+ config.templates = templates;
33
+ const configStr = await prettify(`/** @type {import('vovk-cli').VovkConfig} */
34
+ const config = ${JSON.stringify(config, null, 2)};
35
+ ${isModule ? '\nexport default config;' : 'module.exports = config;'}`, configAbsolutePath);
36
+ await fs.writeFile(configAbsolutePath, configStr, 'utf-8');
37
+ log.info(`Config created at ${configAbsolutePath}`);
38
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Retrieves a list of files in the 'templates' folder of an NPM package.
3
+ * @param packageName - The name of the NPM package.
4
+ * @returns A promise that resolves to an array of file paths.
5
+ */
6
+ export default function getTemplatesFiles(packageName: string): Promise<Record<string, string>>;
@@ -0,0 +1,76 @@
1
+ import { createGunzip } from 'zlib';
2
+ import tar from 'tar-stream';
3
+ import { Readable } from 'stream';
4
+ /**
5
+ * Retrieves a list of files in the 'templates' folder of an NPM package.
6
+ * @param packageName - The name of the NPM package.
7
+ * @returns A promise that resolves to an array of file paths.
8
+ */
9
+ export default async function getTemplatesFiles(packageName) {
10
+ try {
11
+ // Fetch package metadata from the npm registry
12
+ const metadataResponse = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}`);
13
+ if (!metadataResponse.ok) {
14
+ throw new Error(`Failed to fetch package metadata: ${metadataResponse.statusText}`);
15
+ }
16
+ const metadata = (await metadataResponse.json());
17
+ const latestVersion = metadata['dist-tags'].latest;
18
+ const tarballUrl = metadata.versions[latestVersion].dist.tarball;
19
+ // Fetch the tarball
20
+ const tarballResponse = await fetch(tarballUrl);
21
+ if (!tarballResponse.ok) {
22
+ throw new Error(`Failed to fetch tarball: ${tarballResponse.statusText}`);
23
+ }
24
+ const tarballArrayBuffer = await tarballResponse.arrayBuffer();
25
+ const tarballBuffer = Buffer.from(tarballArrayBuffer);
26
+ // Extract the tarball in memory and collect template files
27
+ const templateFiles = await extractTemplatesFromTarball(tarballBuffer);
28
+ const entries = templateFiles
29
+ .filter((fileName) => fileName.startsWith('/templates/') && !fileName.endsWith('/') && fileName.endsWith('.ejs'))
30
+ .map((fileName) => [fileName.substring('/templates/'.length), `${packageName}${fileName}`]);
31
+ return Object.fromEntries(entries);
32
+ }
33
+ catch (error) {
34
+ console.error('Error fetching templates files:', error);
35
+ throw error;
36
+ }
37
+ }
38
+ /**
39
+ * Extracts the templates from the tarball buffer.
40
+ * @param tarballBuffer - The tarball data as a Buffer.
41
+ * @returns A promise that resolves to an array of template file paths.
42
+ */
43
+ function extractTemplatesFromTarball(tarballBuffer) {
44
+ return new Promise((resolve, reject) => {
45
+ const extract = tar.extract();
46
+ const files = [];
47
+ extract.on('entry', (header, stream, next) => {
48
+ const filePath = header.name;
49
+ // Check if the file is in the 'templates' folder
50
+ if (filePath.startsWith('package/templates/')) {
51
+ files.push(filePath.replace('package/', ''));
52
+ }
53
+ stream.on('end', () => next());
54
+ stream.resume();
55
+ });
56
+ extract.on('finish', () => {
57
+ resolve(files);
58
+ });
59
+ extract.on('error', (err) => {
60
+ reject(err);
61
+ });
62
+ // Decompress and extract the tarball buffer
63
+ const gunzip = createGunzip();
64
+ gunzip.on('error', reject);
65
+ const tarballStream = Readable.from(tarballBuffer);
66
+ tarballStream.pipe(gunzip).pipe(extract);
67
+ });
68
+ }
69
+ // Example usage
70
+ getTemplatesFiles('your-package-name')
71
+ .then((files) => {
72
+ console.log('Files in templates folder:', files);
73
+ })
74
+ .catch((err) => {
75
+ console.error('Error:', err);
76
+ });
@@ -1,20 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import type { VovkConfig } from '../types.mjs';
3
2
  import type { InitOptions } from '../index.mjs';
4
3
  import getLogger from '../utils/getLogger.mjs';
5
- declare abstract class Action<T> {
6
- context: Context;
7
- data: T;
8
- action: () => void;
9
- constructor(context: Context);
10
- toJSON: () => T;
11
- }
12
- declare class Context {
13
- actions: Action<unknown>[];
14
- vovkConfig: VovkConfig;
4
+ export declare class Init {
5
+ #private;
15
6
  root: string;
16
7
  log: ReturnType<typeof getLogger>;
17
- static main(prefix: string, { yes, logLevel }: InitOptions): Promise<void>;
8
+ main(prefix: string, { yes, logLevel, useNpm, useYarn, usePnpm, useBun, skipInstall, updateTsConfig, updateScripts, validationLibrary, validateOnClient, }: InitOptions): Promise<void>;
18
9
  }
19
- export declare const Init: typeof Context;
20
- export {};