vovk-cli 0.0.1-draft.98 → 0.0.1

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 +1 -1
  23. package/dist/dev/ensureSchemaFiles.mjs +15 -46
  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 +306 -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 +32 -12
  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 +143 -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 +117 -102
  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 +2 -2
  73. package/dist/init/updateDependenciesWithoutInstalling.mjs +41 -11
  74. package/dist/init/updateNPMScripts.d.mts +6 -1
  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 +31 -25
  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 +261 -0
  97. package/dist/utils/debounceWithArgs.d.mts +1 -2
  98. package/dist/utils/debounceWithArgs.mjs +2 -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 +76 -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 +1 -1
  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
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023-present Andrii Gubanov
3
+ Copyright (c) 2023-present Andrey Gubanov
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,29 +1,37 @@
1
- <p align="center">
2
- <picture>
3
- <source width="300" media="(prefers-color-scheme: dark)" srcset="https://vovk.dev/vovk-logo-white.svg">
4
- <source width="300" media="(prefers-color-scheme: light)" srcset="https://vovk.dev/vovk-logo.svg">
5
- <img width="300" alt="vovk" src="https://vovk.dev/vovk-logo.svg">
6
- </picture><br>
7
- <strong>REST + RPC = ♥️</strong>
8
- </p>
9
-
10
1
  <p align="center">
11
- Back-end meta-framework for <a href="https://nextjs.org/docs/app">Next.js</a>
2
+ <a href="https://vovk.dev">
3
+ <picture>
4
+ <source width="300" media="(prefers-color-scheme: dark)" srcset="https://vovk.dev/vovk-logo-white.svg">
5
+ <source width="300" media="(prefers-color-scheme: light)" srcset="https://vovk.dev/vovk-logo.svg">
6
+ <img width="300" alt="vovk" src="https://vovk.dev/vovk-logo.svg">
7
+ </picture>
8
+ </a>
9
+ <br>
10
+ <strong>Back-end Framework for Next.js App Router</strong>
11
+ <br />
12
+ <a href="https://vovk.dev/">Documentation</a>
13
+ &nbsp;&nbsp;
14
+ <a href="https://vovk.dev/quick-install">Quick Start</a>
15
+ &nbsp;&nbsp;
16
+ <a href="https://vovk.dev/performance">Performance</a>
12
17
  </p>
13
18
 
14
19
  ---
15
20
 
16
21
  ## vovk-cli [![npm version](https://badge.fury.io/js/vovk-cli.svg)](https://www.npmjs.com/package/vovk-cli)
17
22
 
18
- The Vovk.ts CLI that generates schema and client but also provides some useful utilities for the development process.
23
+ Vovk.ts CLI that will be used as a devDependency in a Vovk.ts app.
19
24
 
20
25
  ```sh
21
26
  npm install -D vovk-cli
22
27
  ```
23
28
 
24
- - [vovk dev](https://vovk.dev/cli/vovk-dev) - starts the development script that watches the changes in controllers and regenerates the schema and client.
25
- - [vovk generate](https://vovk.dev/cli/vovk-generate) - generates the client based on the schema.
26
- - [vovk init](https://vovk.dev/cli/vovk-init) - initializes the Vovk.ts project.
27
- - [vovk new](https://vovk.dev/cli/vovk-new) - generates a new controller, service or a custom module.
29
+ - [vovk dev](https://vovk.dev/dev) - starts the development script that watches the changes in [controllers](https://vovk.dev/controller) and regenerates the [schema](https://vovk.dev/schema) and [client](https://vovk.dev/typescript)
30
+ - [vovk generate](https://vovk.dev/generate) - generates the client based on the schema
31
+ - [vovk bundle](https://vovk.dev/bundle) - bundles the client with [tsdown](https://tsdown.dev/)
32
+ - [vovk init](https://vovk.dev/init) - initializes a new Vovk.ts project
33
+ - [vovk new](https://vovk.dev/new) - generates a new controller, service or a custom module
28
34
 
29
- For more information, please visit the [CLI documentation](https://vovk.dev/cli) or use `npx vovk-cli --help` to get the list of available commands and options.
35
+ ```sh
36
+ npx vovk-cli --help
37
+ ```
@@ -0,0 +1,21 @@
1
+ <%- t.getFirstLineBanner() %>
2
+ import type { VovkFetcher } from 'vovk/fetcher';
3
+ import type { createRPC } from '<%= t.commonImports.createRPC %>';
4
+ <% Object.values(t.schema.segments).filter((segment) => segment.emitSchema).forEach((segment, i) => { if(segment.segmentType !== 'mixin') { %>
5
+ import type { Controllers as Controllers<%= i %> } from "<%= t.segmentMeta[segment.segmentName].segmentImportPath %>";
6
+ <% }}) %>
7
+ <% if (t.hasMixins) { %>
8
+ import type { Controllers as MixinControllers, Mixins } from "./mixins";
9
+ <% } %>
10
+ <% Object.entries(t.reExports).forEach(([reExportWhat, reExportFrom]) => { %>
11
+ export { <%= reExportWhat %> } from '<%= reExportFrom %>';
12
+ <% }) %>
13
+ <% Object.values(t.schema.segments).filter((segment) => segment.emitSchema).forEach((segment, i) => { %>
14
+ <% Object.keys(segment.controllers).forEach((rpcModuleName) => { %>
15
+ export const <%= rpcModuleName %>: ReturnType<typeof createRPC<<%= segment.segmentType === 'mixin' ? `MixinControllers` : `Controllers${i}` %>["<%= rpcModuleName %>"], typeof import('<%- t.segmentImports[segment.segmentName].fetcher %>').fetcher extends VovkFetcher<infer U> ? U : never>>;
16
+ <% })
17
+ }) %>
18
+ export { schema } from './schema.js';
19
+ <% if (t.hasMixins) { %>
20
+ export { Mixins };
21
+ <% } %>
@@ -0,0 +1,18 @@
1
+ <%- t.getFirstLineBanner() %>
2
+ import { createRPC } from '<%= t.commonImports.createRPC %>';
3
+ import { schema } from './schema.js';
4
+ <% Object.entries(t.reExports).forEach(([reExportWhat, reExportFrom]) => { %>
5
+ export { <%= reExportWhat %> } from '<%= reExportFrom %>';
6
+ <% }) %>
7
+ <% Object.values(t.schema.segments).filter((segment) => segment.emitSchema).forEach((segment, i) => { %>
8
+ <% Object.keys(segment.controllers).forEach((rpcModuleName) => {
9
+ const apiRoot = t.segmentMeta[segment.segmentName].forceApiRoot ?? t.apiRoot; %>
10
+ export const <%= rpcModuleName %> = createRPC(
11
+ schema, '<%= segment.segmentName %>', '<%= rpcModuleName %>', import('<%- t.segmentImports[segment.segmentName].fetcher %>'),
12
+ { validateOnClient: <%- t.segmentImports[segment.segmentName].validateOnClient ? `import('${t.segmentImports[segment.segmentName].validateOnClient}')` : 'undefined' %>, <%- typeof t.segmentMeta[segment.segmentName].segmentNameOverride === 'string' ? `segmentNameOverride: '${t.segmentMeta[segment.segmentName].segmentNameOverride}', ` : '' %><%- segment.segmentType === 'mixin' ? '' : apiRoot ? `apiRoot: '${apiRoot}'` : '' %> }
13
+ );
14
+ <%
15
+ });
16
+ });
17
+ %>
18
+ export { schema };
@@ -0,0 +1,64 @@
1
+ <%- t.getFirstLineBanner() %>
2
+ import type { VovkRequest, VovkStreamAsyncIterable, KnownAny } from 'vovk';
3
+
4
+ <% const mixins = Object.values(t.schema.segments).filter((segment) => segment.emitSchema && segment.segmentType === 'mixin'); %>
5
+
6
+ export namespace Mixins {
7
+ <% for (const segment of mixins) { %>
8
+ <% if(segment.meta?.openAPIObject?.components?.schemas) { %>
9
+ export namespace <%= t._.upperFirst(t._.camelCase(segment.segmentName)) %> {
10
+ <% for (const [componentName, componentSchema] of Object.entries(segment.meta.openAPIObject.components.schemas)) { %>
11
+ <%- t.compileJSONSchemaToTypeScriptType(componentSchema, componentName, segment.meta.openAPIObject.components, { dontCreateRefTypes: true }) %>
12
+ <% } %>
13
+ }
14
+ <% } %>
15
+ <% } %>
16
+ }
17
+
18
+ export namespace Types {
19
+ <% for (const segment of mixins) { %>
20
+ export namespace <%= t._.upperFirst(t._.camelCase(segment.segmentName)) %> {
21
+ <% for (const [controllerName, controllerSchema] of Object.entries(segment.controllers)) { %>
22
+ export namespace <%= controllerSchema.rpcModuleName %> {
23
+ <% for (const [handlerName, handlerSchema] of Object.entries(controllerSchema.handlers)) { %>
24
+ export namespace <%= t._.upperFirst(handlerName) %> {
25
+ <%- t.compileJSONSchemaToTypeScriptType(handlerSchema.validation?.body, 'Body') %>
26
+ <%- t.compileJSONSchemaToTypeScriptType(handlerSchema.validation?.query, 'Query') %>
27
+ <%- t.compileJSONSchemaToTypeScriptType(handlerSchema.validation?.params, 'Params') %>
28
+ <%- t.compileJSONSchemaToTypeScriptType(handlerSchema.validation?.output, 'Output') %>
29
+ <%- t.compileJSONSchemaToTypeScriptType(handlerSchema.validation?.iteration, 'Iteration') %>
30
+ }
31
+ <% } %>
32
+ }
33
+ <% } %>
34
+ }
35
+ <% } %>
36
+ }
37
+
38
+ <% const getType = (segment, controllerSchema, handlerName, validationType) => {
39
+ const segmentNs = t._.upperFirst(t._.camelCase(segment.segmentName));
40
+ const controllerNs = controllerSchema.rpcModuleName;
41
+ const handlerNs = t._.upperFirst(handlerName);
42
+ const typeName = t._.upperFirst(validationType);
43
+ const handlerSchema = controllerSchema.handlers[handlerName];
44
+ if(handlerSchema.validation?.[validationType] ) {
45
+ return 'Types.' + segmentNs + '.' + controllerNs + '.' + handlerNs + '.' + typeName;
46
+ }
47
+ return 'null';
48
+ } %>
49
+
50
+ export type Controllers = {
51
+ <% for (const segment of Object.values(t.schema.segments).filter((segment) => segment.emitSchema && segment.segmentType === 'mixin')) { %>
52
+ <% for (const controllerSchema of Object.values(segment.controllers)) { %>
53
+ <%= controllerSchema.rpcModuleName %>: {
54
+ <% for (const [handlerName, handlerSchema] of Object.entries(controllerSchema.handlers)) { %>
55
+ <%= handlerName %>: (req: VovkRequest<
56
+ <%- getType(segment, controllerSchema, handlerName, 'body') %>,
57
+ <%- getType(segment, controllerSchema, handlerName, 'query') %>,
58
+ <%- getType(segment, controllerSchema, handlerName, 'params') %>
59
+ >) => <%- handlerSchema.validation?.output ? `Promise<${getType(segment, controllerSchema, handlerName, 'output')}>` : handlerSchema.validation?.iteration ? `Promise<VovkStreamAsyncIterable<${getType(segment, controllerSchema, handlerName, 'iteration')}>>` : 'Promise<KnownAny>' %>,
60
+ <% } %>
61
+ };
62
+ <% } %>
63
+ <% } %>
64
+ };
@@ -0,0 +1 @@
1
+ <%- JSON.stringify(t._.pickBy(t.schema.segments, (segment) => segment.segmentType === 'mixin'), null, 2) %>
@@ -0,0 +1,4 @@
1
+ <%- t.getFirstLineBanner() %>
2
+ import type { OpenAPIObject } from 'openapi3-ts/oas31';
3
+
4
+ export const openapi: OpenAPIObject;
@@ -0,0 +1,4 @@
1
+ <%- t.getFirstLineBanner() %>
2
+ import openapi from './openapi.json' with { type: 'json' };
3
+
4
+ export { openapi };
@@ -0,0 +1 @@
1
+ <%- JSON.stringify(t.openapi, null, 2) %>
@@ -0,0 +1,4 @@
1
+ <%- t.getFirstLineBanner() %>
2
+ import openapi from './openapi.json' with { type: "json" };
3
+
4
+ export { openapi };
@@ -0,0 +1 @@
1
+ <%- JSON.stringify(t.package, null, 2) %>
@@ -0,0 +1,39 @@
1
+ <%- t.getFirstLineBanner('html') %>
2
+ <%- t.readme.banner %>
3
+
4
+ # <%= t.package.name %> v<%= t.package.version %> [![TypeScript](https://badgen.net/badge/-/TypeScript?icon=typescript&label&labelColor=blue&color=555555)](https://www.typescriptlang.org/) [![Vovk.ts](https://badgen.net/badge/Built%20with/Vovk.ts/333333?icon=https://vovk.dev/icon-white.svg)](https://vovk.dev)
5
+
6
+ <%- t.readme.description ?? (`${t.package.description ? `> ${t.package.description}` : ''}`) %>
7
+
8
+ <%- t.package.license ? `License: **${t.package.license}**` : '' %>
9
+
10
+ ```bash
11
+ # Install the package
12
+ <%= t.readme.installCommand ?? `npm install ${t.package.name}` %>
13
+ ```
14
+
15
+ <% Object.entries(t.schema.segments).forEach(([segmentName, segment]) => {
16
+ Object.values(segment.controllers).forEach((controllerSchema) => { %>
17
+
18
+ ## <%= controllerSchema.rpcModuleName %>
19
+ <% Object.entries(controllerSchema.handlers).forEach(([handlerName, handlerSchema]) => { %>
20
+ ### <%= controllerSchema.rpcModuleName %>.<%= handlerName %>
21
+ <%- handlerSchema.operationObject?.summary ? `> ${handlerSchema.operationObject.summary}` : '' %>
22
+
23
+ <%- handlerSchema.operationObject?.description ? `${handlerSchema.operationObject.description}` : '' %>
24
+
25
+ <% const forceApiRoot = t.segmentMeta[segment.segmentName].forceApiRoot ?? controllerSchema.forceApiRoot; %>
26
+ `<%= handlerSchema.httpMethod %> <%= [...(forceApiRoot ? [forceApiRoot] : [t.apiRoot, segmentName]), controllerSchema.prefix, handlerSchema.path].map((part, i) => i > 0 ? t._.trim(part, '/') : part).filter(Boolean).join('/') %>`
27
+
28
+ ```ts
29
+ <%- t.createCodeSamples({
30
+ handlerSchema,
31
+ handlerName,
32
+ controllerSchema,
33
+ package: t.package,
34
+ config: t.samples,
35
+ }).ts %>
36
+ ```
37
+ <% }) %>
38
+ <% }) %>
39
+ <% }) %>
@@ -0,0 +1,10 @@
1
+ <%- t.getFirstLineBanner() %>
2
+ import type { VovkMetaSchema, VovkSegmentSchema } from 'vovk';
3
+
4
+ export const schema: {
5
+ $schema: '<%- t.VovkSchemaIdEnum.SCHEMA %>';
6
+ meta: VovkMetaSchema;
7
+ segments: {<% Object.values(t.schema.segments).filter((segment) => segment.emitSchema).forEach((segment) => { %>
8
+ '<%= segment.segmentName %>': VovkSegmentSchema;<% }) %>
9
+ };
10
+ };
@@ -0,0 +1,29 @@
1
+ <%- t.getFirstLineBanner() %>
2
+ <% if(t.isVovkProject) { %>
3
+ import meta from './<%= t.schemaOutDir %>/_meta.json' with { type: 'json' };
4
+ <% } else { %>
5
+ const meta = <%- JSON.stringify(t.schema.meta, null, 2) %>;
6
+ <% } %>
7
+
8
+ <% if(t.hasMixins) { %>
9
+ import mixins from './mixins.json' with { type: 'json' };
10
+ <% } %>
11
+ <% Object.values(t.schema.segments).filter((segment) => segment.emitSchema && segment.segmentType !== 'mixin').forEach((segment, i) => { %>
12
+ import schema<%= i %> from './<%= t.schemaOutDir %>/<%= segment.segmentName || t.ROOT_SEGMENT_FILE_NAME %>.json' with { type: 'json' };
13
+ <% }) %>
14
+
15
+ const segments = {<% Object.values(t.schema.segments).filter((segment) => segment.emitSchema && segment.segmentType !== 'mixin').forEach((segment, i) => { %>
16
+ '<%= segment.segmentName %>': schema<%= i %>,
17
+ <% }) %>
18
+ <% if(t.hasMixins) { %>
19
+ ...mixins,
20
+ <% } %>
21
+ };
22
+
23
+ const schema = {
24
+ $schema: '<%- t.VovkSchemaIdEnum.SCHEMA %>',
25
+ segments,
26
+ meta,
27
+ };
28
+
29
+ export { schema };
@@ -0,0 +1 @@
1
+ <%- JSON.stringify(t.schema, null, 2) %>
@@ -0,0 +1,28 @@
1
+ <%- t.getFirstLineBanner() %>
2
+ <% if(t.hasMixins) { %>
3
+ import mixins from './mixins.json' with { type: "json" };
4
+ import type { Mixins } from './mixins.d.ts';
5
+ <% } %>
6
+ <% Object.values(t.schema.segments).filter((segment) => segment.emitSchema && segment.segmentType !== 'mixin').forEach((segment, i) => { %>
7
+ import segment<%= i %> from './<%= t.schemaOutDir %>/<%= segment.segmentName || t.ROOT_SEGMENT_FILE_NAME %>.json' with { type: "json" };
8
+ <% }); %>
9
+ <% if(t.isVovkProject) { %>
10
+ import meta from './<%= t.schemaOutDir %>/_meta.json' with { type: "json" };
11
+ <% } else { %>
12
+ const meta = <%- JSON.stringify(t.schema.meta, null, 2) %>;
13
+ <% } %>
14
+ const segments = {<% Object.values(t.schema.segments).filter((segment) => segment.emitSchema && segment.segmentType !== 'mixin').forEach((segment, i) => { %>
15
+ '<%= segment.segmentName %>': segment<%= i %>,<% }) %>
16
+ <% if(t.hasMixins) { %>
17
+ ...mixins,
18
+ <% } %>
19
+ };
20
+
21
+ export const schema = {
22
+ $schema: '<%- t.VovkSchemaIdEnum.SCHEMA %>',
23
+ segments,
24
+ meta,
25
+ };
26
+ <% if (t.hasMixins) { %>
27
+ export { Mixins };
28
+ <% } %>
@@ -0,0 +1,27 @@
1
+ <%- t.getFirstLineBanner() %>
2
+ import type { VovkFetcher } from 'vovk/fetcher';
3
+ import { createRPC } from '<%= t.commonImports.createRPC %>';
4
+ import { schema } from './schema<%= t.nodeNextResolutionExt.ts %>';
5
+ <% Object.values(t.schema.segments).filter((segment) => segment.emitSchema).forEach((segment, i) => { if(segment.segmentType !== 'mixin') { %>
6
+ import type { Controllers as Controllers<%= i %> } from "<%= t.segmentMeta[segment.segmentName].segmentImportPath %>";
7
+ <% }
8
+ });
9
+ if (t.hasMixins) { %>
10
+ import type { Controllers as MixinControllers, Mixins } from "./mixins.d.ts";
11
+ <% } %>
12
+ <% Object.entries(t.reExports).forEach(([reExportWhat, reExportFrom]) => { %>
13
+ export { <%= reExportWhat %> } from '<%= reExportFrom %>';
14
+ <% }) %>
15
+ <% Object.values(t.schema.segments).filter((segment) => segment.emitSchema).forEach((segment, i) => {
16
+ Object.keys(segment.controllers).forEach((rpcModuleName) => {
17
+ const apiRoot = t.segmentMeta[segment.segmentName].forceApiRoot ?? t.apiRoot; %>
18
+ export const <%= rpcModuleName %> = createRPC<<%= segment.segmentType === 'mixin' ? `MixinControllers` : `Controllers${i}` %>["<%= rpcModuleName %>"], typeof import('<%- t.segmentImports[segment.segmentName].fetcher %>').fetcher extends VovkFetcher<infer U> ? U : never>(
19
+ schema, '<%= segment.segmentName %>', '<%= rpcModuleName %>', import('<%- t.segmentImports[segment.segmentName].fetcher %>'),
20
+ { validateOnClient: <%- t.segmentImports[segment.segmentName].validateOnClient ? `import('${t.segmentImports[segment.segmentName].validateOnClient}')` : 'undefined' %>, <%- typeof t.segmentMeta[segment.segmentName].segmentNameOverride === 'string' ? `segmentNameOverride: '${t.segmentMeta[segment.segmentName].segmentNameOverride}', ` : '' %><%- segment.segmentType === 'mixin' ? '' : apiRoot ? `apiRoot: '${apiRoot}'` : '' %> }
21
+ );
22
+ <% })
23
+ }) %>
24
+ export { schema };
25
+ <% if (t.hasMixins) { %>
26
+ export { Mixins };
27
+ <% } %>
@@ -0,0 +1,8 @@
1
+ import type { VovkSchema } from 'vovk';
2
+ import type { ProjectInfo } from '../getProjectInfo/index.mjs';
3
+ import type { BundleOptions } from '../types.mjs';
4
+ export declare function bundle({ projectInfo, fullSchema, cliBundleOptions, }: {
5
+ projectInfo: ProjectInfo;
6
+ fullSchema: VovkSchema;
7
+ cliBundleOptions: BundleOptions;
8
+ }): Promise<void>;
@@ -0,0 +1,76 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ import groupBy from 'lodash/groupBy.js';
4
+ import { generate } from '../generate/generate.mjs';
5
+ import { BuiltInTemplateName } from '../getProjectInfo/getConfig/getTemplateDefs.mjs';
6
+ import { chalkHighlightThing } from '../utils/chalkHighlightThing.mjs';
7
+ import { locateSegments } from '../utils/locateSegments.mjs';
8
+ export async function bundle({ projectInfo, fullSchema, cliBundleOptions, }) {
9
+ const { config, log, cwd, apiDirAbsolutePath } = projectInfo;
10
+ const locatedSegments = await locateSegments({ dir: apiDirAbsolutePath, config, log });
11
+ const { bundle: bundleConfig } = config;
12
+ const keepPrebundleDir = cliBundleOptions?.keepPrebundleDir ?? bundleConfig?.keepPrebundleDir ?? false;
13
+ const prebundleOutDirAbsolute = path.resolve(cwd, cliBundleOptions?.prebundleOutDir ?? bundleConfig.prebundleOutDir);
14
+ const entry = path.join(prebundleOutDirAbsolute, 'index.ts');
15
+ const outDir = cliBundleOptions?.outDir ?? bundleConfig.outDir;
16
+ if (!outDir) {
17
+ throw new Error('No output directory specified for bundling');
18
+ }
19
+ const outDirAbsolute = path.resolve(cwd, outDir);
20
+ await generate({
21
+ isEnsuringClient: false,
22
+ isBundle: true,
23
+ projectInfo,
24
+ forceNothingWrittenLog: true,
25
+ fullSchema,
26
+ locatedSegments,
27
+ cliGenerateOptions: {
28
+ schemaPath: cliBundleOptions?.schemaPath,
29
+ origin: cliBundleOptions?.origin,
30
+ openapiSpec: cliBundleOptions?.openapiSpec,
31
+ openapiGetModuleName: cliBundleOptions?.openapiGetModuleName,
32
+ openapiGetMethodName: cliBundleOptions?.openapiGetMethodName,
33
+ openapiRootUrl: cliBundleOptions?.openapiRootUrl,
34
+ openapiMixinName: cliBundleOptions?.openapiMixinName,
35
+ openapiFallback: cliBundleOptions?.openapiFallback,
36
+ composedFrom: [BuiltInTemplateName.tsBase],
37
+ composedOut: prebundleOutDirAbsolute,
38
+ composedOnly: true,
39
+ composedIncludeSegments: cliBundleOptions.includeSegments ?? bundleConfig.includeSegments,
40
+ composedExcludeSegments: cliBundleOptions.excludeSegments ?? bundleConfig.excludeSegments,
41
+ },
42
+ });
43
+ log.debug(`Bundling ${chalkHighlightThing(entry)} to ${chalkHighlightThing(outDirAbsolute)}`);
44
+ await bundleConfig.build({
45
+ outDir: outDirAbsolute,
46
+ prebundleDir: prebundleOutDirAbsolute,
47
+ entry,
48
+ });
49
+ log.debug(`Bundled index.ts to ${chalkHighlightThing(outDirAbsolute)}`);
50
+ const requiresGroup = groupBy(Object.entries(bundleConfig.requires), ([, relativePath]) => relativePath);
51
+ for (const [relativePath, group] of Object.entries(requiresGroup)) {
52
+ await generate({
53
+ isEnsuringClient: false,
54
+ isBundle: true,
55
+ projectInfo,
56
+ forceNothingWrittenLog: true,
57
+ fullSchema,
58
+ locatedSegments,
59
+ cliGenerateOptions: {
60
+ schemaPath: cliBundleOptions?.schemaPath,
61
+ origin: cliBundleOptions?.origin,
62
+ composedFrom: group.map(([templateName]) => templateName),
63
+ composedOut: path.resolve(outDirAbsolute, relativePath),
64
+ composedOnly: true,
65
+ },
66
+ });
67
+ }
68
+ if (!keepPrebundleDir) {
69
+ await fs.rm(prebundleOutDirAbsolute, { recursive: true, force: true });
70
+ log.debug(`Deleted temporary TypeScript client output directory: ${chalkHighlightThing(prebundleOutDirAbsolute)}`);
71
+ }
72
+ else {
73
+ log.debug(`Temporary TypeScript client output directory not deleted because it is marked to keep: ${chalkHighlightThing(prebundleOutDirAbsolute)}`);
74
+ }
75
+ log.info(`Bundled TypeScript client to ${chalkHighlightThing(outDirAbsolute)}`);
76
+ }
@@ -1,4 +1,4 @@
1
- import type { VovkControllerSchema, VovkSchema } from 'vovk';
1
+ import type { VovkControllerSchema, VovkSegmentSchema } from 'vovk/internal';
2
2
  interface HandlersDiff {
3
3
  nameOfClass: string;
4
4
  added: string[];
@@ -14,7 +14,7 @@ export interface DiffResult {
14
14
  controllers: ControllersDiff;
15
15
  }
16
16
  export declare function diffHandlers<T extends VovkControllerSchema['handlers']>(oldHandlers: T, newHandlers: T, nameOfClass: string): HandlersDiff;
17
- export declare function diffControllers<T extends VovkSchema['controllers']>(oldItems: T, newItems: T): ControllersDiff;
17
+ export declare function diffControllers<T extends VovkSegmentSchema['controllers']>(oldItems: T, newItems: T): ControllersDiff;
18
18
  /**
19
19
  example output:
20
20
  {
@@ -32,5 +32,5 @@ example output:
32
32
  }
33
33
  }
34
34
  */
35
- export default function diffSchema(oldJson: VovkSchema, newJson: VovkSchema): DiffResult;
35
+ export declare function diffSegmentSchema(oldJson: VovkSegmentSchema, newJson: VovkSegmentSchema): DiffResult;
36
36
  export {};
@@ -57,7 +57,7 @@ example output:
57
57
  }
58
58
  }
59
59
  */
60
- export default function diffSchema(oldJson, newJson) {
60
+ export function diffSegmentSchema(oldJson, newJson) {
61
61
  return {
62
62
  controllers: diffControllers(oldJson.controllers ?? {}, newJson.controllers ?? {}),
63
63
  };
@@ -2,5 +2,5 @@ import { ProjectInfo } from '../getProjectInfo/index.mjs';
2
2
  /**
3
3
  * Ensure that the schema files are created to avoid any import errors.
4
4
  */
5
- export default function ensureSchemaFiles(projectInfo: ProjectInfo | null, schemaOutAbsolutePath: string, segmentNames: string[]): Promise<void>;
5
+ export declare function ensureSchemaFiles(projectInfo: ProjectInfo, schemaOutAbsolutePath: string, segmentNames: string[]): Promise<void>;
6
6
  export declare const debouncedEnsureSchemaFiles: import("lodash").DebouncedFunc<typeof ensureSchemaFiles>;
@@ -1,58 +1,27 @@
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, { JSON_DIR_NAME, ROOT_SEGMENT_SCHEMA_NAME } from './writeOneSchemaFile.mjs';
5
- import formatLoggedSegmentName from '../utils/formatLoggedSegmentName.mjs';
4
+ import { VovkSchemaIdEnum } from 'vovk/internal';
5
+ import { writeOneSegmentSchemaFile, META_FILE_NAME, ROOT_SEGMENT_FILE_NAME } from './writeOneSegmentSchemaFile.mjs';
6
+ import { formatLoggedSegmentName } from '../utils/formatLoggedSegmentName.mjs';
7
+ import { writeMetaJson } from './writeMetaJson.mjs';
6
8
  /**
7
9
  * Ensure that the schema files are created to avoid any import errors.
8
10
  */
9
- export default async function ensureSchemaFiles(projectInfo, schemaOutAbsolutePath, segmentNames) {
11
+ export async function ensureSchemaFiles(projectInfo, schemaOutAbsolutePath, segmentNames) {
10
12
  const now = Date.now();
11
13
  let hasChanged = false;
12
- const schemaJsonOutAbsolutePath = path.join(schemaOutAbsolutePath, JSON_DIR_NAME);
13
- const jsContent = `// auto-generated ${new Date().toISOString()}
14
- ${segmentNames
15
- .map((segmentName) => {
16
- return `module.exports['${segmentName}'] = require('./${JSON_DIR_NAME}/${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json');`;
17
- })
18
- .join('\n')}`;
19
- const dTsContent = `// auto-generated ${new Date().toISOString()}
20
- import type { VovkSchema } from 'vovk';
21
- declare const fullSchema: {
22
- ${segmentNames.map((segmentName) => ` '${segmentName}': VovkSchema;`).join('\n')}
23
- };
24
- export default fullSchema;`;
25
- const tsContent = `// auto-generated ${new Date().toISOString()}
26
- import type { VovkSchema } from 'vovk';
27
- ${segmentNames.map((segmentName, i) => `import segment${i} from './${JSON_DIR_NAME}/${segmentName || ROOT_SEGMENT_SCHEMA_NAME}.json';`).join('\n')}
28
- const fullSchema = {
29
- ${segmentNames.map((segmentName, i) => ` '${segmentName}': segment${i} as VovkSchema,`).join('\n')}
30
- };
31
- export default fullSchema;`;
32
- const jsAbsolutePath = path.join(schemaOutAbsolutePath, 'main.cjs');
33
- const dTsAbsolutePath = path.join(schemaOutAbsolutePath, 'main.d.cts');
34
- const tsAbsolutePath = path.join(schemaOutAbsolutePath, 'index.ts');
35
- const existingJs = await fs.readFile(jsAbsolutePath, 'utf-8').catch(() => null);
36
- const existingDTs = await fs.readFile(dTsAbsolutePath, 'utf-8').catch(() => null);
37
- const existingTs = await fs.readFile(tsAbsolutePath, 'utf-8').catch(() => null);
38
14
  await fs.mkdir(schemaOutAbsolutePath, { recursive: true });
39
- // ignore 1st lines at the files
40
- if (existingJs?.split('\n').slice(1).join('\n') !== jsContent.split('\n').slice(1).join('\n')) {
41
- await fs.writeFile(jsAbsolutePath, jsContent);
42
- }
43
- if (existingDTs?.split('\n').slice(1).join('\n') !== dTsContent.split('\n').slice(1).join('\n')) {
44
- await fs.writeFile(dTsAbsolutePath, dTsContent);
45
- }
46
- if (existingTs?.split('\n').slice(1).join('\n') !== tsContent.split('\n').slice(1).join('\n')) {
47
- await fs.writeFile(tsAbsolutePath, tsContent);
48
- }
15
+ await writeMetaJson(schemaOutAbsolutePath, projectInfo);
49
16
  // Create JSON files (if not exist) with name [segmentName].json (where segmentName can include /, which means the folder structure can be nested)
50
17
  await Promise.all(segmentNames.map(async (segmentName) => {
51
- const { isCreated } = await writeOneSchemaFile({
52
- schemaJsonOutAbsolutePath,
53
- schema: {
18
+ const { isCreated } = await writeOneSegmentSchemaFile({
19
+ schemaOutAbsolutePath,
20
+ segmentSchema: {
21
+ $schema: VovkSchemaIdEnum.SEGMENT,
54
22
  emitSchema: false,
55
23
  segmentName,
24
+ segmentType: 'segment',
56
25
  controllers: {},
57
26
  },
58
27
  skipIfExists: true,
@@ -63,7 +32,7 @@ export default fullSchema;`;
63
32
  }
64
33
  }));
65
34
  // Recursive function to delete unnecessary JSON files and folders
66
- async function deleteUnnecessaryJsonFiles(dirPath) {
35
+ async function deleteUnnecessaryJsonFiles(dirPath, allow = [`${META_FILE_NAME}.json`]) {
67
36
  const entries = await fs.readdir(dirPath, { withFileTypes: true });
68
37
  await Promise.all(entries.map(async (entry) => {
69
38
  const absolutePath = path.join(dirPath, entry.name);
@@ -82,7 +51,8 @@ export default fullSchema;`;
82
51
  const relativePath = path.relative(schemaOutAbsolutePath, absolutePath);
83
52
  const segmentName = relativePath.replace(/\\/g, '/').slice(0, -5); // Remove '.json' extension
84
53
  if (!segmentNames.includes(segmentName) &&
85
- !segmentNames.includes(segmentName.replace(ROOT_SEGMENT_SCHEMA_NAME, ''))) {
54
+ !segmentNames.includes(segmentName.replace(ROOT_SEGMENT_FILE_NAME, '')) &&
55
+ !allow.includes(entry.name)) {
86
56
  await fs.unlink(absolutePath);
87
57
  projectInfo?.log.debug(`Deleted unnecessary schema file for ${formatLoggedSegmentName(segmentName)}`);
88
58
  hasChanged = true;
@@ -90,8 +60,7 @@ export default fullSchema;`;
90
60
  }
91
61
  }));
92
62
  }
93
- // Start the recursive deletion from the root directory
94
- await deleteUnnecessaryJsonFiles(schemaJsonOutAbsolutePath);
63
+ await deleteUnnecessaryJsonFiles(schemaOutAbsolutePath);
95
64
  if (hasChanged)
96
65
  projectInfo?.log.info(`Created empty schema files in ${Date.now() - now}ms`);
97
66
  }
@@ -1,5 +1,7 @@
1
+ import type { DevOptions } from '../types.mjs';
1
2
  export declare class VovkDev {
2
3
  #private;
4
+ constructor({ schemaOut, devHttps, logLevel }: Pick<DevOptions, 'schemaOut' | 'devHttps' | 'logLevel'>);
3
5
  start({ exit }: {
4
6
  exit: boolean;
5
7
  }): Promise<void>;