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.
- package/dist/getProjectInfo/getConfig.mjs +6 -9
- package/dist/getProjectInfo/getRelativeSrcRoot.d.mts +1 -0
- package/dist/getProjectInfo/{getSrcRoot.mjs → getRelativeSrcRoot.mjs} +3 -3
- package/dist/getProjectInfo/index.d.mts +0 -2
- package/dist/getProjectInfo/index.mjs +1 -5
- package/dist/getProjectInfo/readConfig.mjs +2 -4
- package/dist/index.mjs +4 -2
- package/dist/server/generateClient.mjs +10 -10
- package/dist/server/index.mjs +23 -17
- package/package.json +2 -2
- package/dist/getProjectInfo/getCwdPath.d.mts +0 -1
- package/dist/getProjectInfo/getCwdPath.mjs +0 -13
- package/dist/getProjectInfo/getSrcRoot.d.mts +0 -1
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import readConfig from './readConfig.mjs';
|
|
2
|
-
import
|
|
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
|
|
9
|
-
const cwd = process.cwd();
|
|
6
|
+
const srcRoot = await getRelativeSrcRoot();
|
|
10
7
|
const config = {
|
|
11
|
-
modulesDir:
|
|
12
|
-
validateOnClient:
|
|
13
|
-
validationLibrary:
|
|
14
|
-
fetcher:
|
|
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
|
|
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
|
|
7
|
+
return '.';
|
|
8
8
|
}
|
|
9
9
|
else if (await directoryExists(path.join(cwd, 'src/app'))) {
|
|
10
|
-
return
|
|
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
|
|
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
|
-
|
|
27
|
-
|
|
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
|
|
69
|
-
const
|
|
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
|
|
6
|
-
const
|
|
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
|
-
${
|
|
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 } = ${
|
|
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(
|
|
77
|
-
const localDtsPath = path.join(
|
|
78
|
-
const localTsPath = path.join(
|
|
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:
|
|
84
|
+
return { written: false, path: clientoOutDirFullPath };
|
|
85
85
|
}
|
|
86
|
-
await fs.mkdir(
|
|
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:
|
|
91
|
+
return { written: true, path: clientoOutDirFullPath };
|
|
92
92
|
}
|
package/dist/server/index.mjs
CHANGED
|
@@ -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 {
|
|
25
|
-
const
|
|
26
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
|
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 {
|
|
157
|
-
log.
|
|
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 {
|
|
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.
|
|
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
|
-
|
|
234
|
-
const
|
|
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.
|
|
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.
|
|
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>;
|