vovk-cli 0.0.1-beta.6 → 0.0.1-beta.8

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.
@@ -1,17 +1,14 @@
1
1
  import readConfig from './readConfig.mjs';
2
- import getCwdPath from './getCwdPath.mjs';
3
- import getSrcRoot from './getSrcRoot.mjs';
4
- import path from 'path';
2
+ import getRelativeSrcRoot from './getRelativeSrcRoot.mjs';
5
3
  export default async function getConfig({ clientOutDir }) {
6
4
  const env = process.env;
7
5
  const userConfig = await readConfig();
8
- const srcRoot = await getSrcRoot();
9
- const cwd = process.cwd();
6
+ const srcRoot = await getRelativeSrcRoot();
10
7
  const config = {
11
- modulesDir: path.join(cwd, env.VOVK_MODULES_DIR ?? userConfig.modulesDir ?? './' + [srcRoot, 'modules'].filter(Boolean).join('/')),
12
- validateOnClient: getCwdPath(env.VOVK_VALIDATE_ON_CLIENT ?? userConfig.validateOnClient ?? null),
13
- validationLibrary: getCwdPath(env.VOVK_VALIDATION_LIBRARY ?? userConfig.validationLibrary ?? null),
14
- fetcher: getCwdPath(env.VOVK_FETCHER ?? userConfig.fetcher ?? 'vovk/client/defaultFetcher'),
8
+ modulesDir: env.VOVK_MODULES_DIR ?? userConfig.modulesDir ?? './' + [srcRoot, 'modules'].filter(Boolean).join('/'),
9
+ validateOnClient: env.VOVK_VALIDATE_ON_CLIENT ?? userConfig.validateOnClient ?? null,
10
+ validationLibrary: env.VOVK_VALIDATION_LIBRARY ?? userConfig.validationLibrary ?? null,
11
+ fetcher: env.VOVK_FETCHER ?? userConfig.fetcher ?? 'vovk/client/defaultFetcher',
15
12
  metadataOutDir: env.VOVK_METADATA_OUT_DIR ?? userConfig.metadataOutDir ?? './.vovk-schema',
16
13
  clientOutDir: clientOutDir ?? env.VOVK_CLIENT_OUT_DIR ?? userConfig.clientOutDir ?? './node_modules/.vovk',
17
14
  origin: (env.VOVK_ORIGIN ?? userConfig.origin ?? '').replace(/\/$/, ''), // Remove trailing slash
@@ -0,0 +1 @@
1
+ export default function getRelativeSrcRoot(): Promise<"." | "./src">;
@@ -1,13 +1,13 @@
1
1
  import path from 'path';
2
2
  import directoryExists from './directoryExists.mjs';
3
- export default async function getSrcRoot() {
3
+ export default async function getRelativeSrcRoot() {
4
4
  const cwd = process.cwd();
5
5
  // Next.js Docs: src/app or src/pages will be ignored if app or pages are present in the root directory.
6
6
  if (await directoryExists(path.join(cwd, 'app'))) {
7
- return cwd;
7
+ return '.';
8
8
  }
9
9
  else if (await directoryExists(path.join(cwd, 'src/app'))) {
10
- return path.join(cwd, 'src');
10
+ return './src';
11
11
  }
12
12
  throw new Error(`Could not find app router directory. Check Next.js docs for more info.`);
13
13
  }
@@ -10,9 +10,7 @@ export default function getProjectInfo({ port: givenPort, clientOutDir, }?: {
10
10
  apiEntryPoint: string;
11
11
  apiDir: string;
12
12
  srcRoot: string;
13
- metadataOutFullPath: string;
14
13
  metadataOutImportPath: string;
15
- clientOutFullPath: string;
16
14
  fetcherClientImportPath: string;
17
15
  config: Required<import("../types.mjs").VovkConfig>;
18
16
  log: {
@@ -12,12 +12,10 @@ export default async function getProjectInfo({ port: givenPort, clientOutDir, }
12
12
  const vovkPort = env.VOVK_PORT || (parseInt(port) + 6969).toString();
13
13
  const apiEntryPoint = `${config.origin ?? ''}/${config.rootEntry}`;
14
14
  const apiDir = path.join(srcRoot, 'app', config.rootEntry);
15
- const metadataOutFullPath = path.join(cwd, config.metadataOutDir);
16
- const metadataOutImportPath = path.relative(config.clientOutDir, metadataOutFullPath);
15
+ const metadataOutImportPath = path.relative(config.clientOutDir, config.metadataOutDir);
17
16
  const fetcherClientImportPath = config.fetcher.startsWith('.')
18
17
  ? path.relative(config.clientOutDir, config.fetcher)
19
18
  : config.fetcher;
20
- const clientOutFullPath = path.join(cwd, config.clientOutDir);
21
19
  const log = {
22
20
  info: (msg) => loglevel.info(chalk.blueBright(`🐺 ${msg}`)),
23
21
  warn: (msg) => loglevel.warn(chalk.yellowBright(`🐺 ${msg}`)),
@@ -33,9 +31,7 @@ export default async function getProjectInfo({ port: givenPort, clientOutDir, }
33
31
  apiEntryPoint,
34
32
  apiDir,
35
33
  srcRoot,
36
- metadataOutFullPath,
37
34
  metadataOutImportPath,
38
- clientOutFullPath,
39
35
  fetcherClientImportPath,
40
36
  config,
41
37
  log,
@@ -23,10 +23,8 @@ async function readConfig() {
23
23
  return config;
24
24
  }
25
25
  try {
26
- if (configPath.endsWith('.cjs') || configPath.endsWith('.js')) {
27
- const cacheBuster = Date.now();
28
- ({ default: config } = (await import(`${configPath}?cache=${cacheBuster}`)));
29
- }
26
+ const cacheBuster = Date.now();
27
+ ({ default: config } = (await import(`${configPath}?cache=${cacheBuster}`)));
30
28
  }
31
29
  catch (e) {
32
30
  // eslint-disable-next-line no-console
package/dist/index.mjs CHANGED
@@ -65,8 +65,10 @@ program
65
65
  .option('--client-out <path>', 'Path to output directory')
66
66
  .action(async (options) => {
67
67
  const projectInfo = await getProjectInfo({ clientOutDir: options.clientOut });
68
- const segments = await locateSegments(projectInfo.apiDir);
69
- const metadata = (await import(path.join(projectInfo.metadataOutFullPath, 'index.js')));
68
+ const { cwd, config, apiDir } = projectInfo;
69
+ const segments = await locateSegments(apiDir);
70
+ const metadataOutFullPath = path.join(cwd, config.metadataOutDir);
71
+ const metadata = (await import(path.join(metadataOutFullPath, 'index.js')));
70
72
  await generateClient(projectInfo, segments, metadata.default);
71
73
  });
72
74
  program
@@ -2,8 +2,8 @@ import path from 'path';
2
2
  import fs from 'fs/promises';
3
3
  export default async function generateClient(projectInfo, segments, segmentsMetadata) {
4
4
  const now = Date.now();
5
- const outDir = projectInfo.clientOutFullPath;
6
- const validatePath = projectInfo.config.validateOnClient?.startsWith('.')
5
+ const clientoOutDirFullPath = path.join(projectInfo.cwd, projectInfo.config.clientOutDir);
6
+ const validateFullPath = projectInfo.config.validateOnClient?.startsWith('.')
7
7
  ? path.join(projectInfo.cwd, projectInfo.config.validateOnClient)
8
8
  : projectInfo.config.validateOnClient;
9
9
  let dts = `// auto-generated
@@ -46,12 +46,12 @@ import metadata from '${projectInfo.metadataOutImportPath}';
46
46
  type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
47
47
  `;
48
48
  ts += `
49
- ${validatePath ? `import validateOnClient from '${validatePath}';\n` : '\nconst validateOnClient = undefined;'}
49
+ ${validateFullPath ? `import validateOnClient from '${validateFullPath}';\n` : '\nconst validateOnClient = undefined;'}
50
50
  type Options = typeof fetcher extends VovkClientFetcher<infer U> ? U : never;
51
51
  const prefix = '${projectInfo.apiEntryPoint}';
52
52
  `;
53
53
  js += `
54
- const { default: validateOnClient = null } = ${validatePath ? `require('${validatePath}')` : '{}'};
54
+ const { default: validateOnClient = null } = ${validateFullPath ? `require('${validateFullPath}')` : '{}'};
55
55
  const prefix = '${projectInfo.apiEntryPoint}';
56
56
  `;
57
57
  for (let i = 0; i < segments.length; i++) {
@@ -73,20 +73,20 @@ const prefix = '${projectInfo.apiEntryPoint}';
73
73
  ts += `export const ${key} = promisifyWorker<Workers${i}["${key}"]>(null, metadata['${segmentName}'].workers.${key});\n`;
74
74
  }
75
75
  }
76
- const localJsPath = path.join(outDir, 'client.js');
77
- const localDtsPath = path.join(outDir, 'client.d.ts');
78
- const localTsPath = path.join(outDir, 'index.ts');
76
+ const localJsPath = path.join(clientoOutDirFullPath, 'client.js');
77
+ const localDtsPath = path.join(clientoOutDirFullPath, 'client.d.ts');
78
+ const localTsPath = path.join(clientoOutDirFullPath, 'index.ts');
79
79
  const existingJs = await fs.readFile(localJsPath, 'utf-8').catch(() => '');
80
80
  const existingDts = await fs.readFile(localDtsPath, 'utf-8').catch(() => '');
81
81
  const existingTs = await fs.readFile(localTsPath, 'utf-8').catch(() => '');
82
82
  if (existingJs === js && existingDts === dts && existingTs === ts) {
83
83
  projectInfo.log.info(`Client is up to date and doesn't need to be regenerated (${Date.now() - now}ms).`);
84
- return { written: false, path: outDir };
84
+ return { written: false, path: clientoOutDirFullPath };
85
85
  }
86
- await fs.mkdir(outDir, { recursive: true });
86
+ await fs.mkdir(clientoOutDirFullPath, { recursive: true });
87
87
  await fs.writeFile(localJsPath, js);
88
88
  await fs.writeFile(localDtsPath, dts);
89
89
  await fs.writeFile(localTsPath, ts);
90
90
  projectInfo.log.info(`Client generated in ${Date.now() - now}ms`);
91
- return { written: true, path: outDir };
91
+ return { written: true, path: clientoOutDirFullPath };
92
92
  }
@@ -21,11 +21,13 @@ export class VovkCLIServer {
21
21
  #segmentWatcher = null;
22
22
  #watchSegments = () => {
23
23
  const segmentReg = /\/?\[\[\.\.\.[a-zA-Z-_]+\]\]\/route.ts$/;
24
- const { apiDir, log, metadataOutFullPath } = this.#projectInfo;
25
- const getSegmentName = (filePath) => path.relative(apiDir, filePath).replace(segmentReg, '');
26
- log.debug(`Watching segments in ${apiDir}`);
24
+ const { cwd, log, config, apiDir } = this.#projectInfo;
25
+ const metadataOutFullPath = path.join(cwd, config.metadataOutDir);
26
+ const apiDirFullPath = path.join(cwd, apiDir);
27
+ const getSegmentName = (filePath) => path.relative(apiDirFullPath, filePath).replace(segmentReg, '');
28
+ log.debug(`Watching segments in ${apiDirFullPath}`);
27
29
  this.#segmentWatcher = chokidar
28
- .watch(apiDir, {
30
+ .watch(apiDirFullPath, {
29
31
  persistent: true,
30
32
  ignoreInitial: true,
31
33
  })
@@ -51,7 +53,7 @@ export class VovkCLIServer {
51
53
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
52
54
  .on('addDir', async (dirPath) => {
53
55
  log.debug(`Directory ${dirPath} has been added to segments folder`);
54
- this.#segments = await locateSegments(this.#projectInfo.apiDir);
56
+ this.#segments = await locateSegments(apiDirFullPath);
55
57
  for (const { segmentName } of this.#segments) {
56
58
  void this.#ping(segmentName);
57
59
  }
@@ -59,7 +61,7 @@ export class VovkCLIServer {
59
61
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
60
62
  .on('unlinkDir', async (dirPath) => {
61
63
  log.debug(`Directory ${dirPath} has been removed from segments folder`);
62
- this.#segments = await locateSegments(this.#projectInfo.apiDir);
64
+ this.#segments = await locateSegments(apiDirFullPath);
63
65
  for (const { segmentName } of this.#segments) {
64
66
  void this.#ping(segmentName);
65
67
  }
@@ -83,10 +85,11 @@ export class VovkCLIServer {
83
85
  });
84
86
  };
85
87
  #watchModules = () => {
86
- const { config, log } = this.#projectInfo;
87
- log.debug(`Watching modules in ${config.modulesDir}`);
88
+ const { config, cwd, log } = this.#projectInfo;
89
+ const modulesDirFullPath = path.join(cwd, config.modulesDir);
90
+ log.debug(`Watching modules in ${modulesDirFullPath}`);
88
91
  this.#modulesWatcher = chokidar
89
- .watch(config.modulesDir, {
92
+ .watch(modulesDirFullPath, {
90
93
  persistent: true,
91
94
  ignoreInitial: true,
92
95
  })
@@ -119,7 +122,7 @@ export class VovkCLIServer {
119
122
  });
120
123
  };
121
124
  #watchConfig = () => {
122
- const { log } = this.#projectInfo;
125
+ const { log, cwd } = this.#projectInfo;
123
126
  log.debug(`Watching config files`);
124
127
  let isInitial = true;
125
128
  const handle = debounce(async () => {
@@ -136,7 +139,7 @@ export class VovkCLIServer {
136
139
  chokidar
137
140
  .watch('vovk.config.{js,mjs,cjs}', {
138
141
  persistent: true,
139
- cwd: process.cwd(),
142
+ cwd,
140
143
  ignoreInitial: false,
141
144
  depth: 0,
142
145
  })
@@ -153,8 +156,8 @@ export class VovkCLIServer {
153
156
  #watch() {
154
157
  if (this.#isWatching)
155
158
  throw new Error('Already watching');
156
- const { apiDir, log, config } = this.#projectInfo;
157
- log.info(`Watching segments in ${apiDir} and modules in ${config.modulesDir}. Detected initial segments: ${JSON.stringify(this.#segments.map((s) => s.segmentName))}.`);
159
+ const { log } = this.#projectInfo;
160
+ log.debug(`Starting segments and modules watcher. Detected initial segments: ${JSON.stringify(this.#segments.map((s) => s.segmentName))}.`);
158
161
  this.#watchSegments();
159
162
  this.#watchModules();
160
163
  this.#watchConfig();
@@ -196,11 +199,12 @@ export class VovkCLIServer {
196
199
  });
197
200
  }, 500);
198
201
  #createMetadataServer() {
199
- const { metadataOutFullPath, log } = this.#projectInfo;
202
+ const { log, config, cwd } = this.#projectInfo;
203
+ const metadataOutFullPath = path.join(cwd, config.metadataOutDir);
200
204
  return createMetadataServer(async ({ metadata }) => {
201
205
  const segment = this.#segments.find((s) => s.segmentName === metadata.segmentName);
202
206
  if (!segment) {
203
- log.debug(`Segment "${metadata.segmentName}" not found`);
207
+ log.warn(`Segment "${metadata.segmentName}" not found`);
204
208
  return;
205
209
  }
206
210
  this.#metadata[metadata.segmentName] = metadata;
@@ -230,8 +234,10 @@ export class VovkCLIServer {
230
234
  }
231
235
  async startServer({ clientOutDir } = {}) {
232
236
  this.#projectInfo = await getProjectInfo({ clientOutDir });
233
- this.#segments = await locateSegments(this.#projectInfo.apiDir);
234
- const { vovkPort, log, metadataOutFullPath } = this.#projectInfo;
237
+ const { vovkPort, log, config, cwd, apiDir } = this.#projectInfo;
238
+ const apiDirFullPath = path.join(cwd, apiDir);
239
+ const metadataOutFullPath = path.join(cwd, config.metadataOutDir);
240
+ this.#segments = await locateSegments(apiDirFullPath);
235
241
  const server = this.#createMetadataServer();
236
242
  if (!vovkPort) {
237
243
  log.error('No port provided for Vovk Server. Exiting...');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vovk-cli",
3
- "version": "0.0.1-beta.6",
3
+ "version": "0.0.1-beta.8",
4
4
  "bin": {
5
5
  "vovk": "./dist/index.mjs"
6
6
  },
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "homepage": "https://vovk.dev",
32
32
  "peerDependencies": {
33
- "vovk": "^3.0.0-beta.10"
33
+ "vovk": "^3.0.0-beta.18"
34
34
  },
35
35
  "dependencies": {
36
36
  "@inquirer/prompts": "^5.3.8",
@@ -1 +0,0 @@
1
- export default function getCwdPath<T extends string | null>(inputPath: T, baseDir?: string): T;
@@ -1,13 +0,0 @@
1
- import path from 'path';
2
- // TODO Rename
3
- export default function getCwdPath(inputPath, baseDir = process.cwd()) {
4
- if (inputPath === null) {
5
- return null;
6
- }
7
- // Check if the path is absolute
8
- if (path.isAbsolute(inputPath) || inputPath.startsWith('./') || inputPath.startsWith('../')) {
9
- return path.resolve(baseDir, inputPath);
10
- }
11
- // If it's a module or absolute path, keep it as is
12
- return inputPath;
13
- }
@@ -1 +0,0 @@
1
- export default function getSrcRoot(): Promise<string>;