vovk-cli 0.0.1-draft.37 → 0.0.1-draft.371

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 (142) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +29 -1
  3. package/client-templates/cjs/index.cjs.ejs +19 -0
  4. package/client-templates/cjs/index.d.cts.ejs +22 -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/mjs/index.d.mts.ejs +22 -0
  8. package/client-templates/mjs/index.mjs.ejs +18 -0
  9. package/client-templates/openapiCjs/openapi.cjs.ejs +4 -0
  10. package/client-templates/openapiCjs/openapi.d.cts.ejs +4 -0
  11. package/client-templates/openapiJson/openapi.json.ejs +1 -0
  12. package/client-templates/openapiTs/openapi.ts.ejs +4 -0
  13. package/client-templates/packageJson/package.json.ejs +1 -0
  14. package/client-templates/readme/README.md.ejs +39 -0
  15. package/client-templates/schemaCjs/schema.cjs.ejs +24 -0
  16. package/client-templates/schemaCjs/schema.d.cts.ejs +10 -0
  17. package/client-templates/schemaJson/schema.json.ejs +1 -0
  18. package/client-templates/schemaTs/schema.ts.ejs +28 -0
  19. package/client-templates/ts/index.ts.ejs +27 -0
  20. package/dist/bundle/index.d.mts +8 -0
  21. package/dist/bundle/index.mjs +103 -0
  22. package/dist/dev/diffSegmentSchema.d.mts +36 -0
  23. package/dist/dev/{diffSchema.mjs → diffSegmentSchema.mjs} +3 -11
  24. package/dist/dev/ensureSchemaFiles.d.mts +4 -1
  25. package/dist/dev/ensureSchemaFiles.mjs +15 -31
  26. package/dist/dev/index.d.mts +5 -1
  27. package/dist/dev/index.mjs +191 -80
  28. package/dist/dev/logDiffResult.d.mts +1 -1
  29. package/dist/dev/logDiffResult.mjs +6 -43
  30. package/dist/dev/writeMetaJson.d.mts +2 -0
  31. package/dist/dev/writeMetaJson.mjs +20 -0
  32. package/dist/dev/writeOneSegmentSchemaFile.d.mts +12 -0
  33. package/dist/dev/{writeOneSchemaFile.mjs → writeOneSegmentSchemaFile.mjs} +10 -6
  34. package/dist/generate/ensureClient.d.mts +3 -0
  35. package/dist/generate/ensureClient.mjs +28 -0
  36. package/dist/generate/generate.d.mts +13 -0
  37. package/dist/generate/generate.mjs +306 -0
  38. package/dist/generate/getClientTemplateFiles.d.mts +20 -0
  39. package/dist/generate/getClientTemplateFiles.mjs +85 -0
  40. package/dist/generate/getProjectFullSchema.d.mts +8 -0
  41. package/dist/generate/getProjectFullSchema.mjs +66 -0
  42. package/dist/generate/getTemplateClientImports.d.mts +19 -0
  43. package/dist/generate/getTemplateClientImports.mjs +49 -0
  44. package/dist/generate/index.d.mts +33 -0
  45. package/dist/generate/index.mjs +186 -0
  46. package/dist/generate/writeOneClientFile.d.mts +42 -0
  47. package/dist/generate/writeOneClientFile.mjs +139 -0
  48. package/dist/getProjectInfo/getConfig/getConfigAbsolutePaths.d.mts +5 -0
  49. package/dist/getProjectInfo/{getConfigAbsolutePaths.mjs → getConfig/getConfigAbsolutePaths.mjs} +4 -1
  50. package/dist/getProjectInfo/{getRelativeSrcRoot.d.mts → getConfig/getRelativeSrcRoot.d.mts} +1 -1
  51. package/dist/getProjectInfo/{getRelativeSrcRoot.mjs → getConfig/getRelativeSrcRoot.mjs} +2 -2
  52. package/dist/getProjectInfo/getConfig/getTemplateDefs.d.mts +24 -0
  53. package/dist/getProjectInfo/getConfig/getTemplateDefs.mjs +165 -0
  54. package/dist/getProjectInfo/{getUserConfig.d.mts → getConfig/getUserConfig.d.mts} +3 -2
  55. package/dist/getProjectInfo/{getUserConfig.mjs → getConfig/getUserConfig.mjs} +3 -3
  56. package/dist/getProjectInfo/{importUncachedModule.mjs → getConfig/importUncachedModule.mjs} +1 -4
  57. package/dist/getProjectInfo/getConfig/index.d.mts +78 -0
  58. package/dist/getProjectInfo/getConfig/index.mjs +91 -0
  59. package/dist/getProjectInfo/getMetaSchema.d.mts +8 -0
  60. package/dist/getProjectInfo/getMetaSchema.mjs +27 -0
  61. package/dist/getProjectInfo/index.d.mts +14 -9
  62. package/dist/getProjectInfo/index.mjs +24 -22
  63. package/dist/index.d.mts +2 -2
  64. package/dist/index.mjs +117 -35
  65. package/dist/init/createConfig.d.mts +2 -2
  66. package/dist/init/createConfig.mjs +40 -13
  67. package/dist/init/createStandardSchemaValidatorFile.d.mts +4 -0
  68. package/dist/init/createStandardSchemaValidatorFile.mjs +52 -0
  69. package/dist/init/getTemplateFilesFromPackage.mjs +10 -5
  70. package/dist/init/index.d.mts +2 -2
  71. package/dist/init/index.mjs +123 -72
  72. package/dist/init/installDependencies.mjs +4 -2
  73. package/dist/init/logUpdateDependenciesError.d.mts +3 -1
  74. package/dist/init/logUpdateDependenciesError.mjs +7 -1
  75. package/dist/init/updateDependenciesWithoutInstalling.mjs +39 -9
  76. package/dist/init/updateNPMScripts.d.mts +3 -1
  77. package/dist/init/updateNPMScripts.mjs +10 -7
  78. package/dist/init/updateTypeScriptConfig.d.mts +4 -1
  79. package/dist/init/updateTypeScriptConfig.mjs +11 -7
  80. package/dist/initProgram.d.mts +1 -1
  81. package/dist/initProgram.mjs +17 -17
  82. package/dist/locateSegments.d.mts +8 -1
  83. package/dist/locateSegments.mjs +13 -3
  84. package/dist/new/addClassToSegmentCode.d.mts +1 -2
  85. package/dist/new/addClassToSegmentCode.mjs +3 -3
  86. package/dist/new/index.d.mts +2 -1
  87. package/dist/new/index.mjs +5 -3
  88. package/dist/new/newModule.d.mts +5 -2
  89. package/dist/new/newModule.mjs +26 -24
  90. package/dist/new/newSegment.d.mts +4 -1
  91. package/dist/new/newSegment.mjs +20 -12
  92. package/dist/new/render.d.mts +7 -3
  93. package/dist/new/render.mjs +31 -10
  94. package/dist/types.d.mts +66 -44
  95. package/dist/utils/compileJSONSchemaToTypeScriptType.d.mts +5 -0
  96. package/dist/utils/compileJSONSchemaToTypeScriptType.mjs +9 -0
  97. package/dist/utils/compileTs.d.mts +12 -0
  98. package/dist/utils/compileTs.mjs +261 -0
  99. package/dist/utils/debounceWithArgs.d.mts +2 -2
  100. package/dist/utils/debounceWithArgs.mjs +24 -6
  101. package/dist/utils/deepExtend.d.mts +54 -0
  102. package/dist/utils/deepExtend.mjs +129 -0
  103. package/dist/utils/formatLoggedSegmentName.d.mts +3 -1
  104. package/dist/utils/formatLoggedSegmentName.mjs +3 -2
  105. package/dist/utils/generateFnName.d.mts +23 -0
  106. package/dist/utils/generateFnName.mjs +76 -0
  107. package/dist/utils/getPackageJson.d.mts +3 -0
  108. package/dist/utils/getPackageJson.mjs +22 -0
  109. package/dist/utils/getPublicModuleNameFromPath.d.mts +4 -0
  110. package/dist/utils/getPublicModuleNameFromPath.mjs +9 -0
  111. package/dist/utils/normalizeOpenAPIMixin.d.mts +14 -0
  112. package/dist/utils/normalizeOpenAPIMixin.mjs +114 -0
  113. package/dist/utils/pickSegmentFullSchema.d.mts +3 -0
  114. package/dist/utils/pickSegmentFullSchema.mjs +15 -0
  115. package/dist/utils/removeUnlistedDirectories.d.mts +10 -0
  116. package/dist/utils/removeUnlistedDirectories.mjs +61 -0
  117. package/dist/utils/resolveAbsoluteModulePath.d.mts +2 -0
  118. package/dist/utils/resolveAbsoluteModulePath.mjs +32 -0
  119. package/module-templates/arktype/controller.ts.ejs +68 -0
  120. package/module-templates/type/controller.ts.ejs +56 -0
  121. package/module-templates/type/service.ts.ejs +28 -0
  122. package/module-templates/valibot/controller.ts.ejs +68 -0
  123. package/package.json +40 -22
  124. package/dist/dev/diffSchema.d.mts +0 -43
  125. package/dist/dev/ensureClient.d.mts +0 -5
  126. package/dist/dev/ensureClient.mjs +0 -31
  127. package/dist/dev/isMetadataEmpty.d.mts +0 -2
  128. package/dist/dev/isMetadataEmpty.mjs +0 -4
  129. package/dist/dev/writeOneSchemaFile.d.mts +0 -11
  130. package/dist/generateClient.d.mts +0 -7
  131. package/dist/generateClient.mjs +0 -97
  132. package/dist/getProjectInfo/getConfig.d.mts +0 -11
  133. package/dist/getProjectInfo/getConfig.mjs +0 -29
  134. package/dist/getProjectInfo/getConfigAbsolutePaths.d.mts +0 -4
  135. package/dist/postinstall.d.mts +0 -1
  136. package/dist/postinstall.mjs +0 -24
  137. package/templates/controller.ejs +0 -52
  138. package/templates/service.ejs +0 -27
  139. package/templates/worker.ejs +0 -24
  140. /package/dist/getProjectInfo/{importUncachedModule.d.mts → getConfig/importUncachedModule.d.mts} +0 -0
  141. /package/dist/getProjectInfo/{importUncachedModuleWorker.d.mts → getConfig/importUncachedModuleWorker.d.mts} +0 -0
  142. /package/dist/getProjectInfo/{importUncachedModuleWorker.mjs → getConfig/importUncachedModuleWorker.mjs} +0 -0
@@ -0,0 +1,261 @@
1
+ import upperFirst from 'lodash/upperFirst.js';
2
+ import camelCase from 'lodash/camelCase.js';
3
+ export function compileTs(options) {
4
+ const context = {
5
+ refs: options.refs || new Map(),
6
+ compiledRefs: new Map(),
7
+ refsInProgress: new Set(),
8
+ };
9
+ // Collect all definitions from the schema
10
+ collectDefinitions(options.schema, context.refs);
11
+ // Ensure the main type name is valid
12
+ const mainTypeName = sanitizeTypeName(options.name);
13
+ const mainType = compileSchema(options.schema, mainTypeName, context);
14
+ // Compile all referenced types, unless dontCreateRefTypes is set
15
+ const compiledRefs = options.dontCreateRefTypes
16
+ ? ''
17
+ : Array.from(context.compiledRefs.entries())
18
+ .map(([, typeDecl]) => typeDecl)
19
+ .join('\n\n');
20
+ return compiledRefs
21
+ ? `${compiledRefs}\n\n${options.schema.description ? `/** ${escapeJSDocComment(options.schema.description)} */\n` : ''}export type ${mainTypeName} = ${mainType};`
22
+ : `${options.schema.description ? `/** ${escapeJSDocComment(options.schema.description)} */\n` : ''}export type ${mainTypeName} = ${mainType};`;
23
+ }
24
+ function collectDefinitions(schema, refs) {
25
+ // Collect from $defs
26
+ if (schema.$defs) {
27
+ Object.entries(schema.$defs).forEach(([key, def]) => {
28
+ if (typeof def === 'object') {
29
+ refs.set(`#/$defs/${key}`, def);
30
+ }
31
+ });
32
+ }
33
+ // Collect from definitions (older spec)
34
+ if (schema.definitions) {
35
+ Object.entries(schema.definitions).forEach(([key, def]) => {
36
+ if (typeof def === 'object') {
37
+ refs.set(`#/definitions/${key}`, def);
38
+ }
39
+ });
40
+ }
41
+ // Collect from components/schemas (OpenAPI spec)
42
+ if (schema?.components?.schemas) {
43
+ Object.entries(schema?.components?.schemas ?? {}).forEach(([key, def]) => {
44
+ if (typeof def === 'object') {
45
+ refs.set(`#/components/schemas/${key}`, def);
46
+ }
47
+ });
48
+ }
49
+ // Recursively collect from nested schemas
50
+ const schemasToProcess = [];
51
+ if (schema.properties) {
52
+ schemasToProcess.push(...Object.values(schema.properties).filter(isSchema));
53
+ }
54
+ if (schema.items) {
55
+ if (Array.isArray(schema.items)) {
56
+ schemasToProcess.push(...schema.items.filter(isSchema));
57
+ }
58
+ else if (isSchema(schema.items)) {
59
+ schemasToProcess.push(schema.items);
60
+ }
61
+ }
62
+ if (schema.additionalProperties && isSchema(schema.additionalProperties)) {
63
+ schemasToProcess.push(schema.additionalProperties);
64
+ }
65
+ if (schema.allOf)
66
+ schemasToProcess.push(...schema.allOf.filter(isSchema));
67
+ if (schema.anyOf)
68
+ schemasToProcess.push(...schema.anyOf.filter(isSchema));
69
+ if (schema.oneOf)
70
+ schemasToProcess.push(...schema.oneOf.filter(isSchema));
71
+ schemasToProcess.forEach((s) => collectDefinitions(s, refs));
72
+ }
73
+ function isSchema(value) {
74
+ return typeof value === 'object' && !Array.isArray(value);
75
+ }
76
+ function compileSchema(schema, name, context) {
77
+ if (typeof schema === 'boolean') {
78
+ return schema ? 'any' : 'never';
79
+ }
80
+ // Handle x-tsType extension
81
+ if ('x-tsType' in schema && typeof schema['x-tsType'] === 'string') {
82
+ return schema['x-tsType'];
83
+ }
84
+ // Handle $ref
85
+ if (schema.$ref) {
86
+ return handleRef(schema.$ref, context);
87
+ }
88
+ // Handle combinators
89
+ if (schema.allOf) {
90
+ return handleAllOf(schema.allOf, name, context);
91
+ }
92
+ if (schema.anyOf) {
93
+ return handleAnyOf(schema.anyOf, name, context);
94
+ }
95
+ if (schema.oneOf) {
96
+ return handleOneOf(schema.oneOf, name, context);
97
+ }
98
+ // Handle type-specific compilation
99
+ if (schema.enum) {
100
+ return handleEnum(schema.enum);
101
+ }
102
+ if (schema.const !== undefined) {
103
+ return handleConst(schema.const);
104
+ }
105
+ if (!schema.type) {
106
+ // No type specified, could be object
107
+ if (schema.properties || schema.additionalProperties) {
108
+ return handleObject(schema, name, context);
109
+ }
110
+ return 'any';
111
+ }
112
+ if (Array.isArray(schema.type)) {
113
+ return schema.type.map((t) => compileSchemaWithType({ ...schema, type: t }, name, context)).join(' | ');
114
+ }
115
+ return compileSchemaWithType(schema, name, context);
116
+ }
117
+ function compileSchemaWithType(schema, name, context) {
118
+ switch (schema.type) {
119
+ case 'null':
120
+ return 'null';
121
+ case 'boolean':
122
+ return 'boolean';
123
+ case 'string':
124
+ return 'string';
125
+ case 'number':
126
+ return 'number';
127
+ case 'integer':
128
+ return 'number';
129
+ case 'array':
130
+ return handleArray(schema, name, context);
131
+ case 'object':
132
+ return handleObject(schema, name, context);
133
+ default:
134
+ return 'any';
135
+ }
136
+ }
137
+ function handleRef(ref, context) {
138
+ const typeName = refToTypeName(ref);
139
+ // Check if we're already compiling this ref (circular reference)
140
+ if (context.refsInProgress.has(ref)) {
141
+ return typeName;
142
+ }
143
+ // Check if already compiled
144
+ if (context.compiledRefs.has(ref)) {
145
+ return typeName;
146
+ }
147
+ // Find the referenced schema
148
+ const referencedSchema = context.refs.get(ref);
149
+ if (!referencedSchema) {
150
+ return 'any'; // Reference not found
151
+ }
152
+ // Mark as in progress
153
+ context.refsInProgress.add(ref);
154
+ // Compile the referenced schema
155
+ const compiledType = compileSchema(referencedSchema, typeName, context);
156
+ const description = referencedSchema.description
157
+ ? `/** ${escapeJSDocComment(referencedSchema.description)} */\n`
158
+ : '';
159
+ context.compiledRefs.set(ref, `${description}export type ${typeName} = ${compiledType};`);
160
+ // Mark as completed
161
+ context.refsInProgress.delete(ref);
162
+ return typeName;
163
+ }
164
+ function handleAllOf(schemas, name, context) {
165
+ const types = schemas.map((s, i) => compileSchema(s, sanitizeTypeName(`${name}-all-of-${i}`), context));
166
+ // For allOf, we need to intersect types
167
+ // If they're all objects, we can merge them properly
168
+ const objectTypes = types.filter((t) => t.startsWith('{') && t.endsWith('}'));
169
+ if (objectTypes.length === types.length) {
170
+ // Merge object types
171
+ const merged = objectTypes.map((t) => t.slice(1, -1).trim()).filter((t) => t.length > 0);
172
+ return merged.length > 0 ? `{ ${merged.join('; ')} }` : '{}';
173
+ }
174
+ return types.join(' & ');
175
+ }
176
+ function handleAnyOf(schemas, name, context) {
177
+ const types = schemas.map((s, i) => compileSchema(s, sanitizeTypeName(`${name}-any-of-${i}`), context));
178
+ return types.join(' | ');
179
+ }
180
+ function handleOneOf(schemas, name, context) {
181
+ // For TypeScript, oneOf behaves like anyOf
182
+ const types = schemas.map((s, i) => compileSchema(s, sanitizeTypeName(`${name}-one-of-${i}`), context));
183
+ return types.join(' | ');
184
+ }
185
+ function handleEnum(enumValues) {
186
+ return enumValues.map((v) => JSON.stringify(v)).join(' | ');
187
+ }
188
+ function handleConst(value) {
189
+ return JSON.stringify(value);
190
+ }
191
+ function handleArray(schema, name, context) {
192
+ if (!schema.items) {
193
+ return 'any[]';
194
+ }
195
+ if (Array.isArray(schema.items)) {
196
+ // Tuple (ignoring min/max as requested)
197
+ const types = schema.items.map((item, i) => compileSchema(item, `${name}Item${i}`, context));
198
+ return `[${types.join(', ')}]`;
199
+ }
200
+ const itemType = compileSchema(schema.items, `${name}Item`, context);
201
+ return `${wrapUnionType(itemType)}[]`;
202
+ }
203
+ function handleObject(schema, name, context) {
204
+ const props = [];
205
+ // Handle known properties
206
+ if (schema.properties) {
207
+ const required = new Set(schema.required || []);
208
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
209
+ if (!isSchema(propSchema))
210
+ continue;
211
+ const isRequired = required.has(propName);
212
+ // Ensure the generated type name for nested properties is valid
213
+ const nestedTypeName = sanitizeTypeName(`${name}-${propName}`);
214
+ const propType = compileSchema(propSchema, nestedTypeName, context);
215
+ const safePropName = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(propName) ? propName : `"${propName}"`;
216
+ // Add JSDoc comment if description is present
217
+ const comment = propSchema.description ? `\n/** ${escapeJSDocComment(propSchema.description)} */\n` : '';
218
+ props.push(`${comment}${safePropName}${isRequired ? '' : '?'}: ${propType}`);
219
+ }
220
+ }
221
+ // Handle additional properties
222
+ if (schema.additionalProperties === true) {
223
+ props.push('[key: string]: any');
224
+ }
225
+ else if (schema.additionalProperties && isSchema(schema.additionalProperties)) {
226
+ const additionalTypeName = sanitizeTypeName(`${name}-additional`);
227
+ const additionalType = compileSchema(schema.additionalProperties, additionalTypeName, context);
228
+ props.push(`[key: string]: ${additionalType}`);
229
+ }
230
+ // Handle pattern properties
231
+ if (schema.patternProperties) {
232
+ // For simplicity, treat pattern properties as string index signature
233
+ const patternTypes = Object.values(schema.patternProperties)
234
+ .filter(isSchema)
235
+ .map((s, i) => compileSchema(s, sanitizeTypeName(`${name}-pattern-${i}`), context));
236
+ if (patternTypes.length > 0) {
237
+ props.push(`[key: string]: ${patternTypes.join(' | ')}`);
238
+ }
239
+ }
240
+ return props.length > 0 ? `{ ${props.join('; ')} }` : '{}';
241
+ }
242
+ function refToTypeName(ref) {
243
+ // Extract the last part of the reference as the type name
244
+ const parts = ref.split('/');
245
+ const name = parts[parts.length - 1];
246
+ // Convert kebab-case to PascalCase
247
+ return upperFirst(camelCase(name));
248
+ }
249
+ function wrapUnionType(type) {
250
+ // Wrap union types in parentheses for array types
251
+ return type.includes('|') ? `(${type})` : type;
252
+ }
253
+ function sanitizeTypeName(name) {
254
+ return upperFirst(camelCase(name));
255
+ }
256
+ // Utility function to escape JSDoc comment terminators in descriptions
257
+ function escapeJSDocComment(description) {
258
+ if (!description)
259
+ return '';
260
+ return description.replace(/\*\//g, '*\\/');
261
+ }
@@ -1,2 +1,2 @@
1
- import { KnownAny } from '../types.mjs';
2
- export default function debounceWithArgs<T extends (...args: KnownAny[]) => KnownAny>(fn: T, wait: number): (...args: Parameters<T>) => void | Promise<void>;
1
+ import type { KnownAny } from 'vovk';
2
+ export default function debounceWithArgs<Callback extends (...args: KnownAny[]) => KnownAny>(callback: Callback, wait: number): (...args: Parameters<Callback>) => Promise<Awaited<ReturnType<Callback>>>;
@@ -1,11 +1,29 @@
1
- import debounce from 'lodash/debounce.js';
2
- export default function debounceWithArgs(fn, wait) {
3
- const debouncedFunctions = new Map();
1
+ export default function debounceWithArgs(callback, wait) {
2
+ // Stores timeouts keyed by the stringified arguments
3
+ const timeouts = new Map();
4
4
  return (...args) => {
5
+ // Convert arguments to a JSON string (or any other stable key generation)
5
6
  const key = JSON.stringify(args);
6
- if (!debouncedFunctions.has(key)) {
7
- debouncedFunctions.set(key, debounce(fn, wait));
7
+ // Clear any existing timer for this specific key
8
+ if (timeouts.has(key)) {
9
+ clearTimeout(timeouts.get(key));
8
10
  }
9
- return debouncedFunctions.get(key)(...args);
11
+ // Return a promise that resolves/rejects after the debounce delay
12
+ return new Promise((resolve, reject) => {
13
+ const timeoutId = setTimeout(async () => {
14
+ try {
15
+ const result = await callback(...args);
16
+ resolve(result);
17
+ }
18
+ catch (error) {
19
+ reject(error);
20
+ }
21
+ finally {
22
+ // Remove the entry once the callback is invoked
23
+ timeouts.delete(key);
24
+ }
25
+ }, wait);
26
+ timeouts.set(key, timeoutId);
27
+ });
10
28
  };
11
29
  }
@@ -0,0 +1,54 @@
1
+ /*!
2
+ * @description Recursive object extending
3
+ * @author Viacheslav Lotsmanov <lotsmanov89@gmail.com>
4
+ * @license MIT
5
+ *
6
+ * The MIT License (MIT)
7
+ *
8
+ * Copyright (c) 2013-2018 Viacheslav Lotsmanov
9
+ *
10
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
11
+ * this software and associated documentation files (the "Software"), to deal in
12
+ * the Software without restriction, including without limitation the rights to
13
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
14
+ * the Software, and to permit persons to whom the Software is furnished to do so,
15
+ * subject to the following conditions:
16
+ *
17
+ * The above copyright notice and this permission notice shall be included in all
18
+ * copies or substantial portions of the Software.
19
+ *
20
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
22
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
23
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ */
27
+ type DeepPartial<T> = {
28
+ [P in keyof T]?: T[P] extends (infer U)[] ? DeepPartial<U>[] : T[P] extends object ? DeepPartial<T[P]> : T[P];
29
+ };
30
+ type SpecificValue = Buffer | Date | RegExp;
31
+ declare function isSpecificValue(val: any): val is SpecificValue;
32
+ declare function cloneSpecificValue(val: SpecificValue): SpecificValue;
33
+ /**
34
+ * Recursive cloning array.
35
+ */
36
+ declare function deepCloneArray<T = any>(arr: T[]): T[];
37
+ declare function safeGetProperty<T extends object>(object: T, property: PropertyKey): any;
38
+ /**
39
+ * Extending object that entered in first argument.
40
+ *
41
+ * Returns extended object or false if have no target object or incorrect type.
42
+ *
43
+ * If you wish to clone source object (without modify it), just use empty new
44
+ * object as first argument, like this:
45
+ * deepExtend({}, yourObj_1, [yourObj_N]);
46
+ */
47
+ declare function deepExtend<T extends object>(...args: [T, ...Partial<T>[]]): T;
48
+ declare function deepExtend<T extends object, U extends object>(target: T, source: U): T & U;
49
+ declare function deepExtend<T extends object, U extends object, V extends object>(target: T, source1: U, source2: V): T & U & V;
50
+ declare function deepExtend<T extends object, U extends object, V extends object, W extends object>(target: T, source1: U, source2: V, source3: W): T & U & V & W;
51
+ declare function deepExtend<T extends object>(target: T, ...sources: any[]): T;
52
+ export default deepExtend;
53
+ export { deepExtend, deepCloneArray, isSpecificValue, cloneSpecificValue, safeGetProperty };
54
+ export type { DeepPartial, SpecificValue };
@@ -0,0 +1,129 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /*!
3
+ * @description Recursive object extending
4
+ * @author Viacheslav Lotsmanov <lotsmanov89@gmail.com>
5
+ * @license MIT
6
+ *
7
+ * The MIT License (MIT)
8
+ *
9
+ * Copyright (c) 2013-2018 Viacheslav Lotsmanov
10
+ *
11
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
12
+ * this software and associated documentation files (the "Software"), to deal in
13
+ * the Software without restriction, including without limitation the rights to
14
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
15
+ * the Software, and to permit persons to whom the Software is furnished to do so,
16
+ * subject to the following conditions:
17
+ *
18
+ * The above copyright notice and this permission notice shall be included in all
19
+ * copies or substantial portions of the Software.
20
+ *
21
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
23
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
24
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+ */
28
+ 'use strict';
29
+ function isSpecificValue(val) {
30
+ return val instanceof Buffer || val instanceof Date || val instanceof RegExp;
31
+ }
32
+ function cloneSpecificValue(val) {
33
+ if (val instanceof Buffer) {
34
+ const x = Buffer.alloc ? Buffer.alloc(val.length) : Buffer.from(val);
35
+ val.copy(x);
36
+ return x;
37
+ }
38
+ else if (val instanceof Date) {
39
+ return new Date(val.getTime());
40
+ }
41
+ else if (val instanceof RegExp) {
42
+ return new RegExp(val);
43
+ }
44
+ else {
45
+ throw new Error('Unexpected situation');
46
+ }
47
+ }
48
+ /**
49
+ * Recursive cloning array.
50
+ */
51
+ function deepCloneArray(arr) {
52
+ const clone = [];
53
+ arr.forEach((item, index) => {
54
+ if (typeof item === 'object' && item !== null) {
55
+ if (Array.isArray(item)) {
56
+ clone[index] = deepCloneArray(item);
57
+ }
58
+ else if (isSpecificValue(item)) {
59
+ clone[index] = cloneSpecificValue(item);
60
+ }
61
+ else {
62
+ clone[index] = deepExtend({}, item);
63
+ }
64
+ }
65
+ else {
66
+ clone[index] = item;
67
+ }
68
+ });
69
+ return clone;
70
+ }
71
+ function safeGetProperty(object, property) {
72
+ return property === '__proto__' ? undefined : object[property];
73
+ }
74
+ function deepExtend(...args) {
75
+ if (args.length < 1 || typeof args[0] !== 'object') {
76
+ return false;
77
+ }
78
+ if (args.length < 2) {
79
+ return args[0];
80
+ }
81
+ const target = args[0];
82
+ // convert arguments to array and cut off target object
83
+ const sources = args.slice(1);
84
+ sources.forEach((obj) => {
85
+ // skip argument if isn't an object, is null, or is an array
86
+ if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
87
+ return;
88
+ }
89
+ Object.keys(obj).forEach((key) => {
90
+ const src = safeGetProperty(target, key); // source value
91
+ const val = safeGetProperty(obj, key); // new value
92
+ // recursion prevention
93
+ if (val === target) {
94
+ return;
95
+ }
96
+ else if (typeof val !== 'object' || val === null) {
97
+ /**
98
+ * if new value isn't object then just overwrite by new value
99
+ * instead of extending.
100
+ */
101
+ target[key] = val;
102
+ return;
103
+ }
104
+ // just clone arrays (and recursive clone objects inside)
105
+ else if (Array.isArray(val)) {
106
+ target[key] = deepCloneArray(val);
107
+ return;
108
+ }
109
+ // custom cloning and overwrite for specific objects
110
+ else if (isSpecificValue(val)) {
111
+ target[key] = cloneSpecificValue(val);
112
+ return;
113
+ }
114
+ // overwrite by new value if source isn't object or array
115
+ else if (typeof src !== 'object' || src === null || Array.isArray(src)) {
116
+ target[key] = deepExtend({}, val);
117
+ return;
118
+ }
119
+ // source value and new value is objects both, extending...
120
+ else {
121
+ target[key] = deepExtend(src, val);
122
+ return;
123
+ }
124
+ });
125
+ });
126
+ return target;
127
+ }
128
+ export default deepExtend;
129
+ export { deepExtend, deepCloneArray, isSpecificValue, cloneSpecificValue, safeGetProperty };
@@ -1,4 +1,6 @@
1
- export default function formatLoggedSegmentName(segmentName: string, { withChalk, upperFirst }?: {
1
+ export default function formatLoggedSegmentName(segmentName: string, { withChalk, upperFirst, isStatic, segmentType, }?: {
2
2
  withChalk?: boolean;
3
3
  upperFirst?: boolean;
4
+ isStatic?: boolean;
5
+ segmentType?: 'segment' | 'mixin';
4
6
  }): string;
@@ -1,7 +1,8 @@
1
1
  import upperFirstLodash from 'lodash/upperFirst.js';
2
2
  import chalkHighlightThing from './chalkHighlightThing.mjs';
3
- export default function formatLoggedSegmentName(segmentName, { withChalk = true, upperFirst = false } = {}) {
4
- let text = segmentName ? `segment "${segmentName}"` : 'the root segment';
3
+ export default function formatLoggedSegmentName(segmentName, { withChalk = true, upperFirst = false, isStatic = false, segmentType = 'segment', // TODO: Apply to all formatLoggedSegmentName invocations
4
+ } = {}) {
5
+ let text = segmentName ? `${isStatic ? 'static ' : ''}${segmentType} "${segmentName}"` : 'the root segment';
5
6
  text = upperFirst ? upperFirstLodash(text) : text;
6
7
  return withChalk ? chalkHighlightThing(text) : text;
7
8
  }
@@ -0,0 +1,23 @@
1
+ import { HttpMethod } from 'vovk';
2
+ export interface VerbMapEntry {
3
+ noParams?: string;
4
+ withParams?: string;
5
+ default?: string;
6
+ }
7
+ export declare const VERB_MAP: Record<HttpMethod, VerbMapEntry>;
8
+ export declare function capitalize(str: string): string;
9
+ interface GenerateFnNameOptions {
10
+ /** Segments to strip out (e.g. ['api','v1']) */
11
+ ignoreSegments?: string[];
12
+ }
13
+ /**
14
+ * Turn an HTTP method + OpenAPI path into a camelCased function name.
15
+ *
16
+ * Examples:
17
+ * generateFnName('GET', '/users') // "listUsers"
18
+ * generateFnName('GET', '/users/{id}') // "getUsersById"
19
+ * generateFnName('POST', '/v1/api/orders') // "createOrders"
20
+ * generateFnName('PATCH', '/users/{userId}/profile') // "patchUsersProfileByUserId"
21
+ */
22
+ export declare function generateFnName(method: HttpMethod, rawPath: string, opts?: GenerateFnNameOptions): string;
23
+ export {};
@@ -0,0 +1,76 @@
1
+ export const VERB_MAP = {
2
+ GET: { noParams: 'list', withParams: 'get' },
3
+ POST: { default: 'create' },
4
+ PUT: { default: 'update' },
5
+ PATCH: { default: 'patch' },
6
+ DELETE: { default: 'delete' },
7
+ HEAD: { default: 'head' },
8
+ OPTIONS: { default: 'options' },
9
+ };
10
+ export function capitalize(str) {
11
+ if (str.length === 0)
12
+ return '';
13
+ return str[0].toUpperCase() + str.slice(1);
14
+ }
15
+ const DEFAULT_OPTIONS = {
16
+ ignoreSegments: ['api'],
17
+ };
18
+ /**
19
+ * Turn an HTTP method + OpenAPI path into a camelCased function name.
20
+ *
21
+ * Examples:
22
+ * generateFnName('GET', '/users') // "listUsers"
23
+ * generateFnName('GET', '/users/{id}') // "getUsersById"
24
+ * generateFnName('POST', '/v1/api/orders') // "createOrders"
25
+ * generateFnName('PATCH', '/users/{userId}/profile') // "patchUsersProfileByUserId"
26
+ */
27
+ export function generateFnName(method, rawPath, opts = {}) {
28
+ const { ignoreSegments } = {
29
+ ...DEFAULT_OPTIONS,
30
+ ...opts,
31
+ };
32
+ // 1. Clean & split path
33
+ const parts = rawPath
34
+ .replace(/^\/|\/$/g, '') // strip leading/trailing slash
35
+ .split('/')
36
+ .filter((seg) => !ignoreSegments?.includes(seg.toLowerCase()))
37
+ .filter(Boolean);
38
+ // 2. Separate resource tokens from path-params
39
+ const resources = [];
40
+ const params = [];
41
+ parts.forEach((seg) => {
42
+ const match = seg.match(/^{?([^}]+)}?$/);
43
+ if (match) {
44
+ params.push(match[1]);
45
+ }
46
+ else {
47
+ resources.push(seg);
48
+ }
49
+ });
50
+ // 3. Pick base verb from VERB_MAP
51
+ let baseVerb;
52
+ if (method === 'GET') {
53
+ baseVerb = params.length ? VERB_MAP.GET.withParams : VERB_MAP.GET.noParams;
54
+ }
55
+ else {
56
+ baseVerb = VERB_MAP[method].default;
57
+ }
58
+ // 4. Build the “resource” part
59
+ const resourcePart = resources.map(capitalize).join('');
60
+ // 5. Build the “ByParam” suffix
61
+ const byParams = params.length ? 'By' + params.map(capitalize).join('') : '';
62
+ // 6. Combine and ensure camelCase
63
+ const rawName = `${baseVerb}${resourcePart}${byParams}`;
64
+ return rawName[0].toLowerCase() + rawName.slice(1);
65
+ }
66
+ /*
67
+ // --- Example usage ---
68
+ console.log(generateFnName('GET', '/users')); // listUsers
69
+ console.log(generateFnName('GET', '/users/{id}')); // getUsersById
70
+ console.log(generateFnName('POST', '/users')); // createUsers
71
+ console.log(generateFnName('PATCH', '/users/{userId}/profile')); // patchUsersProfileByUserId
72
+ console.log(generateFnName('DELETE', '/v1/api/orders/{orderId}')); // deleteOrdersByOrderId
73
+
74
+ // You can also enable singularization:
75
+ console.log(generateFnName('GET', '/users/{userId}/orders', { singularizeResources: true })); // getUserOrderByUserId
76
+ */
@@ -0,0 +1,3 @@
1
+ import { PackageJson } from 'type-fest';
2
+ import type { ProjectInfo } from '../getProjectInfo/index.mjs';
3
+ export declare function getPackageJson(cwd: string, log: ProjectInfo['log']): Promise<PackageJson>;
@@ -0,0 +1,22 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ let cachedPromise;
4
+ export function getPackageJson(cwd, log) {
5
+ const pkgPath = path.join(cwd, 'package.json');
6
+ // If we have a cached promise, return it
7
+ if (cachedPromise) {
8
+ return cachedPromise;
9
+ }
10
+ const promise = fs
11
+ .readFile(pkgPath, 'utf8')
12
+ .then((content) => JSON.parse(content))
13
+ .catch(() => {
14
+ cachedPromise = undefined;
15
+ log.warn(`Failed to read package.json at ${pkgPath}. Using a fallback.`);
16
+ return {
17
+ name: 'unknown',
18
+ };
19
+ });
20
+ cachedPromise = promise;
21
+ return promise;
22
+ }
@@ -0,0 +1,4 @@
1
+ export default function getPublicModuleNameFromPath(modulePath: string): {
2
+ moduleName: string | null;
3
+ restPath: string;
4
+ };
@@ -0,0 +1,9 @@
1
+ export default function getPublicModuleNameFromPath(modulePath) {
2
+ if (modulePath && !modulePath.startsWith('.') && !modulePath.startsWith('/')) {
3
+ const pathParts = modulePath.split('/');
4
+ const moduleName = pathParts[0].startsWith('@') ? `${pathParts[0]}/${pathParts[1]}` : pathParts[0];
5
+ const restPath = pathParts.slice(pathParts[0].startsWith('@') ? 2 : 1).join('/');
6
+ return { moduleName, restPath };
7
+ }
8
+ return { moduleName: null, restPath: modulePath };
9
+ }
@@ -0,0 +1,14 @@
1
+ import { HttpMethod, VovkOperationObject, VovkStrictConfig, type VovkConfig } from 'vovk';
2
+ import { OpenAPIObject } from 'openapi3-ts/oas31';
3
+ import type { ProjectInfo } from '../getProjectInfo/index.mjs';
4
+ export type GetOpenAPINameFn = (config: {
5
+ operationObject: VovkOperationObject;
6
+ method: HttpMethod;
7
+ path: string;
8
+ openAPIObject: OpenAPIObject;
9
+ }) => string;
10
+ export declare function normalizeOpenAPIMixin({ mixinModule, log, cwd, }: {
11
+ mixinModule: NonNullable<NonNullable<NonNullable<NonNullable<VovkConfig['generatorConfig']>['segments']>[string]>['openAPIMixin']>;
12
+ log: ProjectInfo['log'];
13
+ cwd?: string;
14
+ }): Promise<NonNullable<NonNullable<NonNullable<NonNullable<VovkStrictConfig['generatorConfig']>['segments']>[string]>['openAPIMixin']>>;