vovk-cli 0.0.1-draft.96 → 0.0.1-draft.98

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,7 +1,7 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import debounce from 'lodash/debounce.js';
4
- import writeOneSchemaFile, { ROOT_SEGMENT_SCHEMA_NAME } from './writeOneSchemaFile.mjs';
4
+ import writeOneSchemaFile, { JSON_DIR_NAME, ROOT_SEGMENT_SCHEMA_NAME } from './writeOneSchemaFile.mjs';
5
5
  import formatLoggedSegmentName from '../utils/formatLoggedSegmentName.mjs';
6
6
  /**
7
7
  * Ensure that the schema files are created to avoid any import errors.
@@ -9,10 +9,11 @@ import formatLoggedSegmentName from '../utils/formatLoggedSegmentName.mjs';
9
9
  export default async function ensureSchemaFiles(projectInfo, schemaOutAbsolutePath, segmentNames) {
10
10
  const now = Date.now();
11
11
  let hasChanged = false;
12
+ const schemaJsonOutAbsolutePath = path.join(schemaOutAbsolutePath, JSON_DIR_NAME);
12
13
  const jsContent = `// auto-generated ${new Date().toISOString()}
13
14
  ${segmentNames
14
15
  .map((segmentName) => {
15
- return `module.exports['${segmentName}'] = require('./${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json');`;
16
+ return `module.exports['${segmentName}'] = require('./${JSON_DIR_NAME}/${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json');`;
16
17
  })
17
18
  .join('\n')}`;
18
19
  const dTsContent = `// auto-generated ${new Date().toISOString()}
@@ -23,7 +24,7 @@ ${segmentNames.map((segmentName) => ` '${segmentName}': VovkSchema;`).join('\n'
23
24
  export default fullSchema;`;
24
25
  const tsContent = `// auto-generated ${new Date().toISOString()}
25
26
  import type { VovkSchema } from 'vovk';
26
- ${segmentNames.map((segmentName, i) => `import segment${i} from './${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json';`).join('\n')}
27
+ ${segmentNames.map((segmentName, i) => `import segment${i} from './${JSON_DIR_NAME}/${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json';`).join('\n')}
27
28
  const fullSchema = {
28
29
  ${segmentNames.map((segmentName, i) => ` '${segmentName}': segment${i} as VovkSchema,`).join('\n')}
29
30
  };
@@ -48,7 +49,7 @@ export default fullSchema;`;
48
49
  // Create JSON files (if not exist) with name [segmentName].json (where segmentName can include /, which means the folder structure can be nested)
49
50
  await Promise.all(segmentNames.map(async (segmentName) => {
50
51
  const { isCreated } = await writeOneSchemaFile({
51
- schemaOutAbsolutePath,
52
+ schemaJsonOutAbsolutePath,
52
53
  schema: {
53
54
  emitSchema: false,
54
55
  segmentName,
@@ -90,7 +91,7 @@ export default fullSchema;`;
90
91
  }));
91
92
  }
92
93
  // Start the recursive deletion from the root directory
93
- await deleteUnnecessaryJsonFiles(schemaOutAbsolutePath);
94
+ await deleteUnnecessaryJsonFiles(schemaJsonOutAbsolutePath);
94
95
  if (hasChanged)
95
96
  projectInfo?.log.info(`Created empty schema files in ${Date.now() - now}ms`);
96
97
  }
@@ -7,7 +7,7 @@ import capitalize from 'lodash/capitalize.js';
7
7
  import debounce from 'lodash/debounce.js';
8
8
  import once from 'lodash/once.js';
9
9
  import { debouncedEnsureSchemaFiles } from './ensureSchemaFiles.mjs';
10
- import writeOneSchemaFile from './writeOneSchemaFile.mjs';
10
+ import writeOneSchemaFile, { JSON_DIR_NAME } from './writeOneSchemaFile.mjs';
11
11
  import logDiffResult from './logDiffResult.mjs';
12
12
  import ensureClient from '../generate/ensureClient.mjs';
13
13
  import getProjectInfo from '../getProjectInfo/index.mjs';
@@ -260,7 +260,7 @@ export class VovkDev {
260
260
  return;
261
261
  }
262
262
  log.debug(`Handling received schema from ${formatLoggedSegmentName(schema.segmentName)}`);
263
- const schemaOutAbsolutePath = path.join(cwd, config.schemaOutDir);
263
+ const schemaJsonOutAbsolutePath = path.join(cwd, config.schemaOutDir, JSON_DIR_NAME);
264
264
  const segment = this.#segments.find((s) => s.segmentName === schema.segmentName);
265
265
  if (!segment) {
266
266
  log.warn(`Segment "${schema.segmentName}" not found`);
@@ -270,7 +270,7 @@ export class VovkDev {
270
270
  if (schema.emitSchema) {
271
271
  const now = Date.now();
272
272
  const { diffResult } = await writeOneSchemaFile({
273
- schemaOutAbsolutePath,
273
+ schemaJsonOutAbsolutePath,
274
274
  schema,
275
275
  skipIfExists: false,
276
276
  });
@@ -1,8 +1,9 @@
1
1
  import type { VovkSchema } from 'vovk';
2
2
  import { type DiffResult } from './diffSchema.mjs';
3
3
  export declare const ROOT_SEGMENT_SCHEMA_NAME = "_root";
4
- export default function writeOneSchemaFile({ schemaOutAbsolutePath, schema, skipIfExists, }: {
5
- schemaOutAbsolutePath: string;
4
+ export declare const JSON_DIR_NAME = "json";
5
+ export default function writeOneSchemaFile({ schemaJsonOutAbsolutePath, schema, skipIfExists, }: {
6
+ schemaJsonOutAbsolutePath: string;
6
7
  schema: VovkSchema;
7
8
  skipIfExists?: boolean;
8
9
  }): Promise<{
@@ -3,8 +3,9 @@ import fs from 'node:fs/promises';
3
3
  import diffSchema from './diffSchema.mjs';
4
4
  import getFileSystemEntryType from '../utils/getFileSystemEntryType.mjs';
5
5
  export const ROOT_SEGMENT_SCHEMA_NAME = '_root';
6
- export default async function writeOneSchemaFile({ schemaOutAbsolutePath, schema, skipIfExists = false, }) {
7
- const segmentPath = path.join(schemaOutAbsolutePath, `${schema.segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json`);
6
+ export const JSON_DIR_NAME = 'json';
7
+ export default async function writeOneSchemaFile({ schemaJsonOutAbsolutePath, schema, skipIfExists = false, }) {
8
+ const segmentPath = path.join(schemaJsonOutAbsolutePath, `${schema.segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json`);
8
9
  if (skipIfExists && (await getFileSystemEntryType(segmentPath))) {
9
10
  try {
10
11
  await fs.stat(segmentPath);
@@ -7,18 +7,18 @@ export default async function ensureClient({ config, cwd, log }) {
7
7
  const { clientOutDirAbsolutePath, templateFiles } = getClientTemplates({
8
8
  config,
9
9
  cwd,
10
- templateNames: config.experimental_clientGenerateTemplateNames,
10
+ generateFrom: config.generateFrom,
11
11
  });
12
12
  let usedTemplateNames = [];
13
13
  const text = `// auto-generated ${new Date().toISOString()}
14
- // This is a temporary placeholder to avoid errors if client is imported before it's generated.
14
+ // This is a temporary placeholder to avoid compilation errors if client is imported before it's generated.
15
15
  // If you still see this text, the client is not generated yet because of an unknown problem.
16
16
  // Feel free to report an issue at https://github.com/finom/vovk/issues`;
17
17
  for (const { outPath, templateName } of templateFiles) {
18
18
  const existing = await fs.readFile(outPath, 'utf-8').catch(() => null);
19
19
  if (!existing) {
20
20
  await fs.mkdir(clientOutDirAbsolutePath, { recursive: true });
21
- await fs.writeFile(outPath, text);
21
+ await fs.writeFile(outPath, outPath.endsWith('.py') ? text.replace(/\/\//g, '#') : text);
22
22
  usedTemplateNames.push(templateName);
23
23
  }
24
24
  }
@@ -1,13 +1,14 @@
1
- import { VovkConfig } from '../types.mjs';
1
+ import type { VovkStrictConfig } from '../types.mjs';
2
2
  interface ClientTemplate {
3
3
  templateName: string;
4
4
  templatePath: string;
5
5
  outPath: string;
6
+ fullSchema?: string | boolean;
6
7
  }
7
- export default function getClientTemplates({ config, cwd, templateNames, }: {
8
- config: Required<VovkConfig>;
8
+ export default function getClientTemplates({ config, cwd, generateFrom, }: {
9
+ config: VovkStrictConfig;
9
10
  cwd: string;
10
- templateNames?: string[];
11
+ generateFrom?: VovkStrictConfig['generateFrom'];
11
12
  }): {
12
13
  clientOutDirAbsolutePath: string;
13
14
  templateFiles: ClientTemplate[];
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path';
2
- export default function getClientTemplates({ config, cwd, templateNames = [], }) {
2
+ export default function getClientTemplates({ config, cwd, generateFrom = [], }) {
3
3
  const templatesDir = path.join(import.meta.dirname, '../..', 'client-templates');
4
4
  const clientOutDirAbsolutePath = path.resolve(cwd, config.clientOutDir);
5
5
  const mapper = (dir) => (name) => ({
@@ -13,16 +13,28 @@ export default function getClientTemplates({ config, cwd, templateNames = [], })
13
13
  module: ['module.mjs.ejs', 'module.d.mts.ejs'].map(mapper('module')),
14
14
  python: ['__init__.py'].map(mapper('python')),
15
15
  };
16
- const templateFiles = (templateNames ?? config.experimental_clientGenerateTemplateNames).reduce((acc, template) => {
17
- if (template in builtInTemplatesMap) {
18
- return [...acc, ...builtInTemplatesMap[template]];
16
+ const templateFiles = (generateFrom ?? config.generateFrom).reduce((acc, template) => {
17
+ if (typeof template === 'string') {
18
+ if (template in builtInTemplatesMap) {
19
+ return [...acc, ...builtInTemplatesMap[template]];
20
+ }
21
+ return [
22
+ ...acc,
23
+ {
24
+ templateName: template,
25
+ templatePath: path.resolve(cwd, template),
26
+ outPath: path.join(clientOutDirAbsolutePath, path.basename(template).replace('.ejs', '')),
27
+ },
28
+ ];
19
29
  }
30
+ const outDirAbsolutePath = template.outDir ? path.resolve(cwd, template.outDir) : clientOutDirAbsolutePath;
20
31
  return [
21
32
  ...acc,
22
33
  {
23
- templateName: template,
24
- templatePath: path.resolve(cwd, template),
25
- outPath: path.join(clientOutDirAbsolutePath, path.basename(template).replace('.ejs', '')),
34
+ templateName: template.templateName ?? template.templatePath,
35
+ templatePath: path.resolve(cwd, template.templatePath),
36
+ outPath: path.join(outDirAbsolutePath, path.basename(template.templatePath).replace('.ejs', '')),
37
+ fullSchema: template.fullSchema,
26
38
  },
27
39
  ];
28
40
  }, []);
@@ -7,10 +7,10 @@ import getClientTemplates from './getClientTemplates.mjs';
7
7
  import chalkHighlightThing from '../utils/chalkHighlightThing.mjs';
8
8
  import uniq from 'lodash/uniq.js';
9
9
  export default async function generate({ projectInfo, segments, segmentsSchema, forceNothingWrittenLog, templates, prettify: prettifyClient, fullSchema, }) {
10
- templates = templates ?? projectInfo.config.experimental_clientGenerateTemplateNames;
10
+ const generateFrom = templates ?? projectInfo.config.generateFrom;
11
11
  const noClient = templates?.[0] === 'none';
12
12
  const { config, cwd, log, clientImports, apiRoot } = projectInfo;
13
- const { clientOutDirAbsolutePath, templateFiles } = getClientTemplates({ config, cwd, templateNames: templates });
13
+ const { clientOutDirAbsolutePath, templateFiles } = getClientTemplates({ config, cwd, generateFrom });
14
14
  // Ensure that each segment has a matching schema if it needs to be emitted:
15
15
  for (let i = 0; i < segments.length; i++) {
16
16
  const { segmentName } = segments[i];
@@ -57,14 +57,25 @@ export default async function generate({ projectInfo, segments, segmentsSchema,
57
57
  };
58
58
  }));
59
59
  const usedTemplateNames = uniq(processedTemplates.filter(({ needsWriting }) => needsWriting).map(({ templateName }) => templateName));
60
- if (fullSchema || usedTemplateNames.length > 0) {
60
+ let fullSchemaNames = [];
61
+ const DEFAULT_NAME = 'full-schema.json';
62
+ if (fullSchema) {
63
+ fullSchemaNames.push(typeof fullSchema === 'string' ? fullSchema : DEFAULT_NAME);
64
+ fullSchemaNames.push(...templateFiles
65
+ .filter(({ fullSchema }) => fullSchema)
66
+ .map(({ fullSchema }) => (typeof fullSchema === 'string' ? fullSchema : DEFAULT_NAME)));
67
+ }
68
+ fullSchemaNames = uniq(fullSchemaNames);
69
+ if (fullSchemaNames.length || usedTemplateNames.length > 0) {
61
70
  // Make sure the output directory exists
62
71
  await fs.mkdir(clientOutDirAbsolutePath, { recursive: true });
63
72
  }
64
- if (fullSchema) {
65
- const fullSchemaOutAbsolutePath = path.resolve(clientOutDirAbsolutePath, typeof fullSchema === 'string' ? fullSchema : 'full-schema.json');
66
- await fs.writeFile(fullSchemaOutAbsolutePath, JSON.stringify(segmentsSchema, null, 2));
67
- log.info(`Full schema has ben written to ${fullSchemaOutAbsolutePath}`);
73
+ if (fullSchemaNames.length) {
74
+ await Promise.all(fullSchemaNames.map(async (name) => {
75
+ const fullSchemaOutAbsolutePath = path.resolve(clientOutDirAbsolutePath, name);
76
+ await fs.writeFile(fullSchemaOutAbsolutePath, JSON.stringify(segmentsSchema, null, 2));
77
+ log.info(`Full schema has ben written to ${fullSchemaOutAbsolutePath}`);
78
+ }));
68
79
  }
69
80
  if (usedTemplateNames.length === 0) {
70
81
  const logOrDebug = forceNothingWrittenLog ? log.info : log.debug;
@@ -8,6 +8,7 @@ export default async function getConfig({ clientOutDir, cwd }) {
8
8
  const validateOnClientImport = env.VOVK_VALIDATE_ON_CLIENT_PATH ?? conf.validateOnClientImport ?? null;
9
9
  const fetcherImport = env.VOVK_FETCHER_PATH ?? conf.fetcherImport ?? 'vovk/dist/client/defaultFetcher.js';
10
10
  const createRPCImport = env.VOVK_CREATE_RPC_PATH ?? conf.createRPCImport ?? 'vovk/dist/client/createRPC.js';
11
+ const defaultClientTemplates = ['ts', 'module', 'main'];
11
12
  const config = {
12
13
  modulesDir: env.VOVK_MODULES_DIR ?? conf.modulesDir ?? './' + [srcRoot, 'modules'].filter(Boolean).join('/'),
13
14
  validateOnClientImport: typeof validateOnClientImport === 'string' ? [validateOnClientImport] : validateOnClientImport,
@@ -21,7 +22,9 @@ export default async function getConfig({ clientOutDir, cwd }) {
21
22
  logLevel: env.VOVK_LOG_LEVEL ?? conf.logLevel ?? 'info',
22
23
  prettifyClient: (env.VOVK_PRETTIFY_CLIENT ? !!env.VOVK_PRETTIFY_CLIENT : null) ?? conf.prettifyClient ?? false,
23
24
  devHttps: (env.VOVK_DEV_HTTPS ? !!env.VOVK_DEV_HTTPS : null) ?? conf.devHttps ?? false,
24
- experimental_clientGenerateTemplateNames: conf.experimental_clientGenerateTemplateNames ?? ['ts', 'module', 'main'],
25
+ generateFrom: typeof conf.generateFrom === 'function'
26
+ ? conf.generateFrom(defaultClientTemplates)
27
+ : (conf.generateFrom ?? ['ts', 'module', 'main']),
25
28
  templates: {
26
29
  service: 'vovk-cli/templates/service.ejs',
27
30
  controller: 'vovk-cli/templates/controller.ejs',
package/dist/types.d.mts CHANGED
@@ -18,6 +18,12 @@ export type VovkEnv = {
18
18
  __VOVK_START_WATCHER_IN_STANDALONE_MODE__?: 'true';
19
19
  __VOVK_EXIT__?: 'true' | 'false';
20
20
  };
21
+ type GenerateFrom = (string | {
22
+ templatePath: string;
23
+ outDir?: string;
24
+ templateName?: string;
25
+ fullSchema?: string | boolean;
26
+ })[];
21
27
  export type VovkConfig = {
22
28
  clientOutDir?: string;
23
29
  schemaOutDir?: string;
@@ -31,17 +37,18 @@ export type VovkConfig = {
31
37
  logLevel?: LogLevelNames;
32
38
  prettifyClient?: boolean;
33
39
  devHttps?: boolean;
34
- experimental_clientGenerateTemplateNames?: string[];
40
+ generateFrom?: GenerateFrom | ((value: GenerateFrom) => GenerateFrom);
35
41
  templates?: {
36
42
  service?: string;
37
43
  controller?: string;
38
44
  [key: string]: string | undefined;
39
45
  };
40
46
  };
41
- export type VovkStrictConfig = Required<Omit<VovkConfig, 'validateOnClientImport' | 'fetcherImport' | 'createRPCImport'>> & {
47
+ export type VovkStrictConfig = Required<Omit<VovkConfig, 'validateOnClientImport' | 'fetcherImport' | 'createRPCImport' | 'generateFrom'>> & {
42
48
  validateOnClientImport: string[] | null;
43
49
  fetcherImport: string[];
44
50
  createRPCImport: string[];
51
+ generateFrom: GenerateFrom;
45
52
  };
46
53
  export type VovkModuleRenderResult = {
47
54
  fileName: string;
@@ -84,3 +91,4 @@ export interface NewOptions {
84
91
  noSegmentUpdate?: boolean;
85
92
  empty?: boolean;
86
93
  }
94
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vovk-cli",
3
- "version": "0.0.1-draft.96",
3
+ "version": "0.0.1-draft.98",
4
4
  "bin": {
5
5
  "vovk": "./dist/index.mjs"
6
6
  },
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "homepage": "https://vovk.dev",
38
38
  "peerDependencies": {
39
- "vovk": "^3.0.0-draft.83"
39
+ "vovk": "^3.0.0-draft.87"
40
40
  },
41
41
  "dependencies": {
42
42
  "@inquirer/prompts": "^7.3.1",