vovk 3.0.0-draft.323 → 3.0.0-draft.324

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,4 +1,4 @@
1
1
  import { type VovkSchema, VovkStrictConfig } from '../../types';
2
- export declare function openAPIToVovkSchema({ apiRoot, source: { object: openAPIObject }, getModuleName, getMethodName, errorMessageKey, mixinName, }: VovkStrictConfig['openApiMixins'][string] & {
2
+ export declare function openAPIToVovkSchema({ apiRoot, source: { object: openAPIObject }, getModuleName, getMethodName, errorMessageKey, package: packageJson, mixinName, }: VovkStrictConfig['openApiMixins'][string] & {
3
3
  mixinName: string;
4
4
  }): VovkSchema;
@@ -57,7 +57,7 @@ const normalizeGetMethodName = (getMethodName) => {
57
57
  }
58
58
  return getMethodName;
59
59
  };
60
- function openAPIToVovkSchema({ apiRoot, source: { object: openAPIObject }, getModuleName = 'api', getMethodName = 'auto', errorMessageKey, mixinName, }) {
60
+ function openAPIToVovkSchema({ apiRoot, source: { object: openAPIObject }, getModuleName = 'api', getMethodName = 'auto', errorMessageKey, package: packageJson, mixinName, }) {
61
61
  const forceApiRoot = apiRoot ??
62
62
  openAPIObject.servers?.[0]?.url ??
63
63
  ('host' in openAPIObject
@@ -77,6 +77,7 @@ function openAPIToVovkSchema({ apiRoot, source: { object: openAPIObject }, getMo
77
77
  controllers: {},
78
78
  meta: {
79
79
  components: openAPIObject.components,
80
+ package: packageJson,
80
81
  },
81
82
  },
82
83
  },
@@ -1,10 +1,9 @@
1
1
  import type { OpenAPIObject } from 'openapi3-ts/oas31';
2
2
  import { type CodeSamplePackageJson } from '../utils/createCodeExamples';
3
- import { type VovkSchema, KnownAny } from '../types';
4
- export declare function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject, package: packageJson, sampler, }: {
3
+ import { type VovkSchema } from '../types';
4
+ export declare function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject, package: packageJson, }: {
5
5
  rootEntry: string;
6
6
  schema: VovkSchema;
7
7
  openAPIObject?: Partial<OpenAPIObject>;
8
8
  package?: CodeSamplePackageJson;
9
- sampler?: (schema: KnownAny) => KnownAny;
10
9
  }): OpenAPIObject;
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.vovkSchemaToOpenAPI = vovkSchemaToOpenAPI;
4
4
  const createCodeExamples_1 = require("../utils/createCodeExamples");
5
- const jsonSchemaSampler_1 = require("../utils/jsonSchemaSampler");
6
5
  const types_1 = require("../types");
6
+ const getJSONSchemaSample_1 = require("../utils/getJSONSchemaSample");
7
7
  function extractComponents(schema) {
8
8
  if (!schema)
9
9
  return [undefined, {}];
@@ -43,7 +43,7 @@ function extractComponents(schema) {
43
43
  const processedSchema = process(schema);
44
44
  return [processedSchema, components];
45
45
  }
46
- function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject = {}, package: packageJson = { name: 'my-rpc-client' }, sampler = jsonSchemaSampler_1.jsonSchemaSampler, }) {
46
+ function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject = {}, package: packageJson = { name: 'my-rpc-client' }, }) {
47
47
  const paths = {};
48
48
  const components = {};
49
49
  for (const [segmentName, segmentSchema] of Object.entries(fullSchema.segments ?? {})) {
@@ -141,9 +141,9 @@ function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject = {}
141
141
  ...iterationValidation,
142
142
  examples: iterationValidation.examples ?? [
143
143
  [
144
- JSON.stringify(sampler(iterationValidation)),
145
- JSON.stringify(sampler(iterationValidation)),
146
- JSON.stringify(sampler(iterationValidation)),
144
+ JSON.stringify((0, getJSONSchemaSample_1.getJSONSchemaSample)(iterationValidation)),
145
+ JSON.stringify((0, getJSONSchemaSample_1.getJSONSchemaSample)(iterationValidation)),
146
+ JSON.stringify((0, getJSONSchemaSample_1.getJSONSchemaSample)(iterationValidation)),
147
147
  ].join('\n'),
148
148
  ],
149
149
  },
package/cjs/types.d.ts CHANGED
@@ -34,6 +34,7 @@ export type VovkSegmentSchema<T = KnownAny> = {
34
34
  controllers: Record<string, VovkControllerSchema<T>>;
35
35
  meta?: {
36
36
  components?: OpenAPIObject['components'];
37
+ package?: PackageJson;
37
38
  [key: string]: KnownAny;
38
39
  };
39
40
  };
@@ -241,6 +242,7 @@ export interface VovkLLMTool {
241
242
  export type SimpleJSONSchema = {
242
243
  type: 'object';
243
244
  $ref?: string;
245
+ items?: SimpleJSONSchema;
244
246
  description?: string;
245
247
  properties: Record<string, SimpleJSONSchema>;
246
248
  required?: string[];
@@ -7,12 +7,11 @@ export type CodeSamplePackageJson = {
7
7
  py_name?: string;
8
8
  [key: string]: KnownAny;
9
9
  };
10
- export declare function createCodeExamples({ handlerName, handlerSchema, controllerSchema, package: packageJson, sampler, }: {
10
+ export declare function createCodeExamples({ handlerName, handlerSchema, controllerSchema, package: packageJson, }: {
11
11
  handlerName: string;
12
12
  handlerSchema: VovkHandlerSchema;
13
13
  controllerSchema: VovkControllerSchema;
14
14
  package?: CodeSamplePackageJson;
15
- sampler?: (schema: KnownAny) => KnownAny;
16
15
  }): {
17
16
  ts: string;
18
17
  py: string;
@@ -1,34 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createCodeExamples = createCodeExamples;
4
- const jsonSchemaSampler_1 = require("./jsonSchemaSampler");
5
- const stringifyTsSample = (data, pad = 4) => JSON.stringify(data, null, 2)
6
- .replace(/"([A-Za-z_$][0-9A-Za-z_$]*)":/g, '$1:')
7
- .split('\n')
8
- .map((line, i, a) => (i === 0 ? line : i === a.length - 1 ? ' '.repeat(pad) + line : ' '.repeat(pad + 2) + line))
9
- .join('\n');
10
- const stringifyPySample = (data, pad = 4) => JSON.stringify(data, null, 2)
11
- .split('\n')
12
- .map((line, i, a) => (i === 0 ? line : i === a.length - 1 ? ' '.repeat(pad) + line : ' '.repeat(pad + 2) + line))
13
- .join('\n');
4
+ const getJSONSchemaExample_1 = require("./getJSONSchemaExample");
14
5
  const toSnakeCase = (str) => str
15
6
  .replace(/-/g, '_') // Replace hyphens with underscores
16
7
  .replace(/([a-z0-9])([A-Z])/g, '$1_$2') // Add underscore between lowercase/digit and uppercase
17
8
  .replace(/([A-Z])([A-Z])(?=[a-z])/g, '$1_$2') // Add underscore between uppercase letters if the second one is followed by a lowercase
18
9
  .toLowerCase()
19
10
  .replace(/^_/, ''); // Remove leading underscore
20
- function createCodeExamples({ handlerName, handlerSchema, controllerSchema, package: packageJson, sampler = jsonSchemaSampler_1.jsonSchemaSampler, }) {
11
+ function createCodeExamples({ handlerName, handlerSchema, controllerSchema, package: packageJson, }) {
21
12
  const queryValidation = handlerSchema?.validation?.query;
22
13
  const bodyValidation = handlerSchema?.validation?.body;
23
14
  const paramsValidation = handlerSchema?.validation?.params;
24
15
  const outputValidation = handlerSchema?.validation?.output;
25
16
  const iterationValidation = handlerSchema?.validation?.iteration;
26
- const queryFake = queryValidation && sampler(queryValidation);
27
- const bodyFake = bodyValidation && sampler(bodyValidation);
28
- const paramsFake = paramsValidation && sampler(paramsValidation);
29
- const outputFake = outputValidation && sampler(outputValidation);
30
- const iterationFake = iterationValidation && sampler(iterationValidation);
31
- const hasArg = !!queryFake || !!bodyFake || !!paramsFake;
17
+ const getTsSample = (schema, indent) => (0, getJSONSchemaExample_1.getJSONSchemaExample)(schema, { stripQuotes: true, indent: indent ?? 4 });
18
+ const getPySample = (schema, indent) => (0, getJSONSchemaExample_1.getJSONSchemaExample)(schema, { stripQuotes: false, indent: indent ?? 4, comment: '#' });
19
+ const getRsSample = (schema, indent) => (0, getJSONSchemaExample_1.getJSONSchemaExample)(schema, { stripQuotes: false, indent: indent ?? 4 });
20
+ const hasArg = !!queryValidation || !!bodyValidation || !!paramsValidation;
32
21
  const rpcName = controllerSchema.rpcModuleName;
33
22
  const handlerNameSnake = toSnakeCase(handlerName);
34
23
  const rpcNameSnake = toSnakeCase(rpcName);
@@ -36,43 +25,50 @@ function createCodeExamples({ handlerName, handlerSchema, controllerSchema, pack
36
25
  const packageNameSnake = toSnakeCase(packageName);
37
26
  const tsArgs = hasArg
38
27
  ? `{
39
- ${paramsFake ? ` params: ${stringifyTsSample(paramsFake)},\n` : ''}${bodyFake ? ` body: ${stringifyTsSample(bodyFake)},\n` : ''}${queryFake ? ` query: ${stringifyTsSample(queryFake)},\n` : ''}}`
28
+ ${[
29
+ bodyValidation ? ` body: ${getTsSample(bodyValidation)},` : null,
30
+ queryValidation ? ` query: ${getTsSample(queryValidation)},` : null,
31
+ paramsValidation ? ` params: ${getTsSample(paramsValidation)},` : null,
32
+ ]
33
+ .filter(Boolean)
34
+ .join('\n')}
35
+ }`
40
36
  : '';
41
37
  const TS_CODE = `import { ${rpcName} } from '${packageName}';
42
38
 
43
- ${iterationFake ? 'using' : 'const'} response = await ${rpcName}.${handlerName}(${tsArgs});
44
- ${outputFake
39
+ ${iterationValidation ? 'using' : 'const'} response = await ${rpcName}.${handlerName}(${tsArgs});
40
+ ${outputValidation
45
41
  ? `
46
42
  console.log(response);
47
43
  /*
48
- ${stringifyTsSample(outputFake, 0)}
44
+ ${getTsSample(outputValidation, 0)}
49
45
  */`
50
- : ''}${iterationFake
46
+ : ''}${iterationValidation
51
47
  ? `
52
48
  for await (const item of response) {
53
49
  console.log(item);
54
50
  /*
55
- ${stringifyTsSample(iterationFake, 4)}
51
+ ${getTsSample(iterationValidation, 2)}
56
52
  */
57
53
  }`
58
54
  : ''}`;
59
55
  const PY_CODE = `from ${packageJson?.py_name ?? packageNameSnake} import ${rpcName}
60
56
 
61
- response = ${rpcName}.${handlerNameSnake}(${hasArg ? `\n params=${paramsFake ? stringifyPySample(paramsFake) : 'None'},\n` : ''}${bodyFake ? ` body=${stringifyPySample(bodyFake)},\n` : ''}${queryFake ? ` query=${stringifyPySample(queryFake)},\n` : ''})
57
+ response = ${rpcName}.${handlerNameSnake}(${hasArg
58
+ ? [
59
+ bodyValidation ? ` body=${getPySample(bodyValidation)},` : null,
60
+ queryValidation ? ` query=${getPySample(queryValidation)},` : null,
61
+ paramsValidation ? ` params=${getPySample(paramsValidation)},` : null,
62
+ ]
63
+ .filter(Boolean)
64
+ .join('\n')
65
+ : ''})
62
66
 
63
- ${outputFake
64
- ? `print(response)\n${JSON.stringify(outputFake, null, 2)
65
- .split('\n')
66
- .map((s) => `# ${s}`)
67
- .join('\n')}`
68
- : ''}${iterationFake
67
+ ${outputValidation ? `print(response)\n${getPySample(outputValidation, 0)}` : ''}${iterationValidation
69
68
  ? `for i, item in enumerate(response):
70
- print(f"iteration #{i}:\\n {item}")
71
- # iteration #0:
72
- ${JSON.stringify(iterationFake, null, 2)
73
- .split('\n')
74
- .map((s) => ` # ${s}`)
75
- .join('\n')}`
69
+ print(f"iteration #{i}:\\n {item}")
70
+ # iteration #0:
71
+ ${getPySample(iterationValidation, 2)}`
76
72
  : ''}`;
77
73
  const serdeUnwrap = (fake) => `from_value(json!(${fake})).unwrap()`;
78
74
  const RS_CODE = `use ${packageJson?.rs_name ?? packageNameSnake}::${rpcNameSnake};
@@ -80,29 +76,29 @@ use serde_json::{ from_value, json };
80
76
 
81
77
  pub fn main() {
82
78
  let response = ${rpcNameSnake}::${handlerNameSnake}(
83
- ${bodyFake ? serdeUnwrap(stringifyPySample(bodyFake)) : '()'}, /* body */
84
- ${queryFake ? serdeUnwrap(stringifyPySample(queryFake)) : '()'}, /* query */
85
- ${paramsFake ? serdeUnwrap(stringifyPySample(paramsFake)) : '()'}, /* params */
79
+ ${bodyValidation ? serdeUnwrap(getRsSample(bodyValidation)) : '()'}, /* body */
80
+ ${queryValidation ? serdeUnwrap(getRsSample(queryValidation)) : '()'}, /* query */
81
+ ${paramsValidation ? serdeUnwrap(getRsSample(paramsValidation)) : '()'}, /* params */
86
82
  None, /* headers (HashMap) */
87
83
  None, /* api_root */
88
84
  false, /* disable_client_validation */
89
85
  );
90
86
 
91
- ${outputFake
87
+ ${outputValidation
92
88
  ? `match response {
93
89
  Ok(output) => println!("{:?}", output),
94
90
  /*
95
- output ${stringifyPySample(outputFake, 4)}
91
+ output ${getTsSample(outputValidation, 2)}
96
92
  */
97
93
  Err(e) => println!("error: {:?}", e),
98
94
  }`
99
- : ''}${iterationFake
95
+ : ''}${iterationValidation
100
96
  ? `match response {
101
97
  Ok(stream) => {
102
98
  for (i, item) in stream.enumerate() {
103
99
  println!("#{}: {:?}", i, item);
104
100
  /*
105
- #0: iteration ${stringifyTsSample(iterationFake, 10)}
101
+ #0: iteration ${getTsSample(iterationValidation, 6)}
106
102
  */
107
103
  }
108
104
  },
@@ -0,0 +1,8 @@
1
+ import { KnownAny } from '../types';
2
+ interface SamplerOptions {
3
+ comment?: '//' | '#';
4
+ stripQuotes?: boolean;
5
+ indent?: number;
6
+ }
7
+ export declare function getJSONSchemaExample(schema: KnownAny, options: SamplerOptions, rootSchema?: KnownAny): string;
8
+ export {};
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getJSONSchemaExample = getJSONSchemaExample;
4
+ function getJSONSchemaExample(schema, options, rootSchema) {
5
+ const { comment = '//', stripQuotes = false, indent = 0 } = options;
6
+ if (!schema || typeof schema !== 'object')
7
+ return 'null';
8
+ // Use the input schema as the root if not provided
9
+ rootSchema = rootSchema || schema;
10
+ // Get the sample value
11
+ const sampleValue = getSampleValue(schema, rootSchema);
12
+ // Format the output with descriptions
13
+ return formatWithDescriptions(sampleValue, schema, rootSchema, comment, stripQuotes, indent);
14
+ }
15
+ function getSampleValue(schema, rootSchema) {
16
+ if (!schema || typeof schema !== 'object')
17
+ return null;
18
+ // If there's an example, use it
19
+ if (schema.example !== undefined) {
20
+ return schema.example;
21
+ }
22
+ // If there are examples, use one of them
23
+ if (schema.examples && schema.examples.length > 0) {
24
+ return schema.examples[0];
25
+ }
26
+ // Handle const if present
27
+ if (schema.const !== undefined) {
28
+ return schema.const;
29
+ }
30
+ // Handle $ref if present
31
+ if (schema.$ref) {
32
+ return handleRef(schema.$ref, rootSchema);
33
+ }
34
+ // Handle enum if present
35
+ if (schema.enum && schema.enum.length > 0) {
36
+ return schema.enum[0];
37
+ }
38
+ // Handle oneOf, anyOf, allOf
39
+ if (schema.oneOf && schema.oneOf.length > 0) {
40
+ return getSampleValue(schema.oneOf[0], rootSchema);
41
+ }
42
+ if (schema.anyOf && schema.anyOf.length > 0) {
43
+ return getSampleValue(schema.anyOf[0], rootSchema);
44
+ }
45
+ if (schema.allOf && schema.allOf.length > 0) {
46
+ // Merge all schemas in allOf
47
+ const mergedSchema = schema.allOf.reduce((acc, s) => ({ ...acc, ...s }), {});
48
+ return getSampleValue(mergedSchema, rootSchema);
49
+ }
50
+ // Handle different types
51
+ if (schema.type) {
52
+ switch (schema.type) {
53
+ case 'string':
54
+ return handleString(schema);
55
+ case 'number':
56
+ case 'integer':
57
+ return handleNumber(schema);
58
+ case 'boolean':
59
+ return handleBoolean();
60
+ case 'object':
61
+ return handleObject(schema, rootSchema);
62
+ case 'array':
63
+ return handleArray(schema, rootSchema);
64
+ case 'null':
65
+ return null;
66
+ default:
67
+ return null;
68
+ }
69
+ }
70
+ // If type is not specified but properties are, treat it as an object
71
+ if (schema.properties) {
72
+ return handleObject(schema, rootSchema);
73
+ }
74
+ // Default fallback
75
+ return null;
76
+ }
77
+ function formatWithDescriptions(value, schema, rootSchema, comment, stripQuotes, indent) {
78
+ const indentStr = ' '.repeat(indent);
79
+ // Handle null
80
+ if (value === null) {
81
+ return 'null';
82
+ }
83
+ // Handle primitives
84
+ if (typeof value !== 'object' || value instanceof Date) {
85
+ return JSON.stringify(value);
86
+ }
87
+ // Handle arrays
88
+ if (Array.isArray(value)) {
89
+ if (value.length === 0)
90
+ return '[]';
91
+ const items = value.map((item) => {
92
+ const itemSchema = schema.items || {};
93
+ const formattedItem = formatWithDescriptions(item, itemSchema, rootSchema, comment, stripQuotes, indent + 1);
94
+ return `${indentStr} ${formattedItem}`;
95
+ });
96
+ return `[\n${items.join(',\n')}\n${indentStr}]`;
97
+ }
98
+ // Handle objects
99
+ if (typeof value === 'object') {
100
+ const entries = Object.entries(value);
101
+ if (entries.length === 0)
102
+ return '{}';
103
+ const formattedEntries = [];
104
+ const isTopLevel = indent === 0;
105
+ // Add top-level description for objects
106
+ if (isTopLevel && schema.type === 'object' && schema.description) {
107
+ const descLines = schema.description.split('\n');
108
+ formattedEntries.push(`${indentStr}${comment} -----`);
109
+ descLines.forEach((line) => {
110
+ formattedEntries.push(`${indentStr}${comment} ${line.trim()}`);
111
+ });
112
+ formattedEntries.push(`${indentStr}${comment} -----`);
113
+ }
114
+ entries.forEach(([key, val], index) => {
115
+ const propSchema = schema.properties?.[key] || {};
116
+ // Handle $ref in property schema
117
+ let resolvedPropSchema = propSchema;
118
+ if (propSchema.$ref) {
119
+ resolvedPropSchema = resolveRef(propSchema.$ref, rootSchema);
120
+ }
121
+ // Add property description if it exists
122
+ if (resolvedPropSchema.description) {
123
+ const descLines = resolvedPropSchema.description.split('\n');
124
+ descLines.forEach((line) => {
125
+ formattedEntries.push(`${indentStr} ${comment} ${line.trim()}`);
126
+ });
127
+ }
128
+ // Format the key
129
+ const formattedKey = stripQuotes && /^[A-Za-z_$][0-9A-Za-z_$]*$/.test(key) ? key : JSON.stringify(key);
130
+ // Format the value
131
+ const formattedValue = formatWithDescriptions(val, resolvedPropSchema, rootSchema, comment, stripQuotes, indent + 1);
132
+ formattedEntries.push(`${indentStr} ${formattedKey}: ${formattedValue}${index < entries.length - 1 ? ',' : ''}`);
133
+ });
134
+ return `{\n${formattedEntries.join('\n')}\n${indentStr}}`;
135
+ }
136
+ return JSON.stringify(value);
137
+ }
138
+ function resolveRef(ref, rootSchema) {
139
+ const path = ref.split('/').slice(1);
140
+ let current = rootSchema;
141
+ for (const segment of path) {
142
+ current = current[segment];
143
+ if (current === undefined) {
144
+ return {};
145
+ }
146
+ }
147
+ return current;
148
+ }
149
+ function handleRef(ref, rootSchema) {
150
+ const resolved = resolveRef(ref, rootSchema);
151
+ return getSampleValue(resolved, rootSchema);
152
+ }
153
+ function handleString(schema) {
154
+ if (schema.format) {
155
+ switch (schema.format) {
156
+ case 'email':
157
+ case 'idn-email':
158
+ return 'user@example.com';
159
+ case 'uri':
160
+ case 'url':
161
+ case 'iri':
162
+ return 'https://example.com';
163
+ case 'date':
164
+ return '2023-01-01';
165
+ case 'date-time':
166
+ return '2023-01-01T00:00:00Z';
167
+ case 'time':
168
+ return '12:00:00Z';
169
+ case 'duration':
170
+ return 'PT1H';
171
+ case 'uuid':
172
+ return '00000000-0000-0000-0000-000000000000';
173
+ case 'regex':
174
+ return '^[a-zA-Z0-9]+$';
175
+ case 'relative-json-pointer':
176
+ return '/some/relative/path';
177
+ case 'color':
178
+ return '#000000';
179
+ case 'hostname':
180
+ return 'example.com';
181
+ case 'zipcode':
182
+ return '12345';
183
+ case 'phone':
184
+ return '+123-456-7890';
185
+ case 'password':
186
+ return '******';
187
+ default:
188
+ return 'string';
189
+ }
190
+ }
191
+ if (schema.pattern) {
192
+ return 'pattern-string';
193
+ }
194
+ return 'string';
195
+ }
196
+ function handleNumber(schema) {
197
+ if (schema.minimum !== undefined && schema.maximum !== undefined) {
198
+ return schema.minimum;
199
+ }
200
+ else if (schema.minimum !== undefined) {
201
+ return schema.minimum;
202
+ }
203
+ else if (schema.maximum !== undefined) {
204
+ return schema.maximum;
205
+ }
206
+ return 0;
207
+ }
208
+ function handleBoolean() {
209
+ return true;
210
+ }
211
+ function handleObject(schema, rootSchema) {
212
+ const result = {};
213
+ if (schema.properties) {
214
+ const required = schema.required || [];
215
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
216
+ if (required.includes(key) || required.length === 0) {
217
+ result[key] = getSampleValue(propSchema, rootSchema);
218
+ }
219
+ }
220
+ }
221
+ if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
222
+ result['additionalProp'] = getSampleValue(schema.additionalProperties, rootSchema);
223
+ }
224
+ return result;
225
+ }
226
+ function handleArray(schema, rootSchema) {
227
+ if (schema.items) {
228
+ const itemSchema = schema.items;
229
+ const minItems = schema.minItems || 1;
230
+ const numItems = Math.min(minItems, 3);
231
+ return Array.from({ length: numItems }, () => getSampleValue(itemSchema, rootSchema));
232
+ }
233
+ return [];
234
+ }
@@ -0,0 +1,2 @@
1
+ import { KnownAny } from '../types';
2
+ export declare function getJSONSchemaSample(schema: KnownAny, rootSchema?: KnownAny): KnownAny;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.jsonSchemaSampler = jsonSchemaSampler;
4
- function jsonSchemaSampler(schema, rootSchema) {
3
+ exports.getJSONSchemaSample = getJSONSchemaSample;
4
+ function getJSONSchemaSample(schema, rootSchema) {
5
5
  if (!schema || typeof schema !== 'object')
6
6
  return null;
7
7
  // Use the input schema as the root if not provided
@@ -28,15 +28,15 @@ function jsonSchemaSampler(schema, rootSchema) {
28
28
  }
29
29
  // Handle oneOf, anyOf, allOf
30
30
  if (schema.oneOf && schema.oneOf.length > 0) {
31
- return jsonSchemaSampler(schema.oneOf[0], rootSchema);
31
+ return getJSONSchemaSample(schema.oneOf[0], rootSchema);
32
32
  }
33
33
  if (schema.anyOf && schema.anyOf.length > 0) {
34
- return jsonSchemaSampler(schema.anyOf[0], rootSchema);
34
+ return getJSONSchemaSample(schema.anyOf[0], rootSchema);
35
35
  }
36
36
  if (schema.allOf && schema.allOf.length > 0) {
37
37
  // Merge all schemas in allOf
38
38
  const mergedSchema = schema.allOf.reduce((acc, s) => ({ ...acc, ...s }), {});
39
- return jsonSchemaSampler(mergedSchema, rootSchema);
39
+ return getJSONSchemaSample(mergedSchema, rootSchema);
40
40
  }
41
41
  // Handle different types
42
42
  if (schema.type) {
@@ -77,7 +77,7 @@ function handleRef(ref, rootSchema) {
77
77
  }
78
78
  }
79
79
  // Process the referenced schema
80
- return jsonSchemaSampler(current, rootSchema);
80
+ return getJSONSchemaSample(current, rootSchema);
81
81
  }
82
82
  function handleString(schema) {
83
83
  if (schema.format) {
@@ -145,13 +145,13 @@ function handleObject(schema, rootSchema) {
145
145
  for (const [key, propSchema] of Object.entries(schema.properties)) {
146
146
  // Only include required properties or as a basic example
147
147
  if (required.includes(key) || required.length === 0) {
148
- result[key] = jsonSchemaSampler(propSchema, rootSchema);
148
+ result[key] = getJSONSchemaSample(propSchema, rootSchema);
149
149
  }
150
150
  }
151
151
  }
152
152
  // Handle additionalProperties
153
153
  if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
154
- result['additionalProp'] = jsonSchemaSampler(schema.additionalProperties, rootSchema);
154
+ result['additionalProp'] = getJSONSchemaSample(schema.additionalProperties, rootSchema);
155
155
  }
156
156
  return result;
157
157
  }
@@ -161,7 +161,7 @@ function handleArray(schema, rootSchema) {
161
161
  const minItems = schema.minItems || 1;
162
162
  // Create minimum number of items (capped at a reasonable max for examples)
163
163
  const numItems = Math.min(minItems, 3);
164
- return Array.from({ length: numItems }, () => jsonSchemaSampler(itemSchema, rootSchema));
164
+ return Array.from({ length: numItems }, () => getJSONSchemaSample(itemSchema, rootSchema));
165
165
  }
166
166
  return [];
167
167
  }
@@ -1,4 +1,4 @@
1
1
  import { type VovkSchema, VovkStrictConfig } from '../../types';
2
- export declare function openAPIToVovkSchema({ apiRoot, source: { object: openAPIObject }, getModuleName, getMethodName, errorMessageKey, mixinName, }: VovkStrictConfig['openApiMixins'][string] & {
2
+ export declare function openAPIToVovkSchema({ apiRoot, source: { object: openAPIObject }, getModuleName, getMethodName, errorMessageKey, package: packageJson, mixinName, }: VovkStrictConfig['openApiMixins'][string] & {
3
3
  mixinName: string;
4
4
  }): VovkSchema;
@@ -57,7 +57,7 @@ const normalizeGetMethodName = (getMethodName) => {
57
57
  }
58
58
  return getMethodName;
59
59
  };
60
- function openAPIToVovkSchema({ apiRoot, source: { object: openAPIObject }, getModuleName = 'api', getMethodName = 'auto', errorMessageKey, mixinName, }) {
60
+ function openAPIToVovkSchema({ apiRoot, source: { object: openAPIObject }, getModuleName = 'api', getMethodName = 'auto', errorMessageKey, package: packageJson, mixinName, }) {
61
61
  const forceApiRoot = apiRoot ??
62
62
  openAPIObject.servers?.[0]?.url ??
63
63
  ('host' in openAPIObject
@@ -77,6 +77,7 @@ function openAPIToVovkSchema({ apiRoot, source: { object: openAPIObject }, getMo
77
77
  controllers: {},
78
78
  meta: {
79
79
  components: openAPIObject.components,
80
+ package: packageJson,
80
81
  },
81
82
  },
82
83
  },
@@ -1,10 +1,9 @@
1
1
  import type { OpenAPIObject } from 'openapi3-ts/oas31';
2
2
  import { type CodeSamplePackageJson } from '../utils/createCodeExamples';
3
- import { type VovkSchema, KnownAny } from '../types';
4
- export declare function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject, package: packageJson, sampler, }: {
3
+ import { type VovkSchema } from '../types';
4
+ export declare function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject, package: packageJson, }: {
5
5
  rootEntry: string;
6
6
  schema: VovkSchema;
7
7
  openAPIObject?: Partial<OpenAPIObject>;
8
8
  package?: CodeSamplePackageJson;
9
- sampler?: (schema: KnownAny) => KnownAny;
10
9
  }): OpenAPIObject;
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.vovkSchemaToOpenAPI = vovkSchemaToOpenAPI;
4
4
  const createCodeExamples_1 = require("../utils/createCodeExamples");
5
- const jsonSchemaSampler_1 = require("../utils/jsonSchemaSampler");
6
5
  const types_1 = require("../types");
6
+ const getJSONSchemaSample_1 = require("../utils/getJSONSchemaSample");
7
7
  function extractComponents(schema) {
8
8
  if (!schema)
9
9
  return [undefined, {}];
@@ -43,7 +43,7 @@ function extractComponents(schema) {
43
43
  const processedSchema = process(schema);
44
44
  return [processedSchema, components];
45
45
  }
46
- function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject = {}, package: packageJson = { name: 'my-rpc-client' }, sampler = jsonSchemaSampler_1.jsonSchemaSampler, }) {
46
+ function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject = {}, package: packageJson = { name: 'my-rpc-client' }, }) {
47
47
  const paths = {};
48
48
  const components = {};
49
49
  for (const [segmentName, segmentSchema] of Object.entries(fullSchema.segments ?? {})) {
@@ -141,9 +141,9 @@ function vovkSchemaToOpenAPI({ rootEntry, schema: fullSchema, openAPIObject = {}
141
141
  ...iterationValidation,
142
142
  examples: iterationValidation.examples ?? [
143
143
  [
144
- JSON.stringify(sampler(iterationValidation)),
145
- JSON.stringify(sampler(iterationValidation)),
146
- JSON.stringify(sampler(iterationValidation)),
144
+ JSON.stringify((0, getJSONSchemaSample_1.getJSONSchemaSample)(iterationValidation)),
145
+ JSON.stringify((0, getJSONSchemaSample_1.getJSONSchemaSample)(iterationValidation)),
146
+ JSON.stringify((0, getJSONSchemaSample_1.getJSONSchemaSample)(iterationValidation)),
147
147
  ].join('\n'),
148
148
  ],
149
149
  },
package/mjs/types.d.ts CHANGED
@@ -34,6 +34,7 @@ export type VovkSegmentSchema<T = KnownAny> = {
34
34
  controllers: Record<string, VovkControllerSchema<T>>;
35
35
  meta?: {
36
36
  components?: OpenAPIObject['components'];
37
+ package?: PackageJson;
37
38
  [key: string]: KnownAny;
38
39
  };
39
40
  };
@@ -241,6 +242,7 @@ export interface VovkLLMTool {
241
242
  export type SimpleJSONSchema = {
242
243
  type: 'object';
243
244
  $ref?: string;
245
+ items?: SimpleJSONSchema;
244
246
  description?: string;
245
247
  properties: Record<string, SimpleJSONSchema>;
246
248
  required?: string[];
@@ -7,12 +7,11 @@ export type CodeSamplePackageJson = {
7
7
  py_name?: string;
8
8
  [key: string]: KnownAny;
9
9
  };
10
- export declare function createCodeExamples({ handlerName, handlerSchema, controllerSchema, package: packageJson, sampler, }: {
10
+ export declare function createCodeExamples({ handlerName, handlerSchema, controllerSchema, package: packageJson, }: {
11
11
  handlerName: string;
12
12
  handlerSchema: VovkHandlerSchema;
13
13
  controllerSchema: VovkControllerSchema;
14
14
  package?: CodeSamplePackageJson;
15
- sampler?: (schema: KnownAny) => KnownAny;
16
15
  }): {
17
16
  ts: string;
18
17
  py: string;
@@ -1,34 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createCodeExamples = createCodeExamples;
4
- const jsonSchemaSampler_1 = require("./jsonSchemaSampler");
5
- const stringifyTsSample = (data, pad = 4) => JSON.stringify(data, null, 2)
6
- .replace(/"([A-Za-z_$][0-9A-Za-z_$]*)":/g, '$1:')
7
- .split('\n')
8
- .map((line, i, a) => (i === 0 ? line : i === a.length - 1 ? ' '.repeat(pad) + line : ' '.repeat(pad + 2) + line))
9
- .join('\n');
10
- const stringifyPySample = (data, pad = 4) => JSON.stringify(data, null, 2)
11
- .split('\n')
12
- .map((line, i, a) => (i === 0 ? line : i === a.length - 1 ? ' '.repeat(pad) + line : ' '.repeat(pad + 2) + line))
13
- .join('\n');
4
+ const getJSONSchemaExample_1 = require("./getJSONSchemaExample");
14
5
  const toSnakeCase = (str) => str
15
6
  .replace(/-/g, '_') // Replace hyphens with underscores
16
7
  .replace(/([a-z0-9])([A-Z])/g, '$1_$2') // Add underscore between lowercase/digit and uppercase
17
8
  .replace(/([A-Z])([A-Z])(?=[a-z])/g, '$1_$2') // Add underscore between uppercase letters if the second one is followed by a lowercase
18
9
  .toLowerCase()
19
10
  .replace(/^_/, ''); // Remove leading underscore
20
- function createCodeExamples({ handlerName, handlerSchema, controllerSchema, package: packageJson, sampler = jsonSchemaSampler_1.jsonSchemaSampler, }) {
11
+ function createCodeExamples({ handlerName, handlerSchema, controllerSchema, package: packageJson, }) {
21
12
  const queryValidation = handlerSchema?.validation?.query;
22
13
  const bodyValidation = handlerSchema?.validation?.body;
23
14
  const paramsValidation = handlerSchema?.validation?.params;
24
15
  const outputValidation = handlerSchema?.validation?.output;
25
16
  const iterationValidation = handlerSchema?.validation?.iteration;
26
- const queryFake = queryValidation && sampler(queryValidation);
27
- const bodyFake = bodyValidation && sampler(bodyValidation);
28
- const paramsFake = paramsValidation && sampler(paramsValidation);
29
- const outputFake = outputValidation && sampler(outputValidation);
30
- const iterationFake = iterationValidation && sampler(iterationValidation);
31
- const hasArg = !!queryFake || !!bodyFake || !!paramsFake;
17
+ const getTsSample = (schema, indent) => (0, getJSONSchemaExample_1.getJSONSchemaExample)(schema, { stripQuotes: true, indent: indent ?? 4 });
18
+ const getPySample = (schema, indent) => (0, getJSONSchemaExample_1.getJSONSchemaExample)(schema, { stripQuotes: false, indent: indent ?? 4, comment: '#' });
19
+ const getRsSample = (schema, indent) => (0, getJSONSchemaExample_1.getJSONSchemaExample)(schema, { stripQuotes: false, indent: indent ?? 4 });
20
+ const hasArg = !!queryValidation || !!bodyValidation || !!paramsValidation;
32
21
  const rpcName = controllerSchema.rpcModuleName;
33
22
  const handlerNameSnake = toSnakeCase(handlerName);
34
23
  const rpcNameSnake = toSnakeCase(rpcName);
@@ -36,43 +25,50 @@ function createCodeExamples({ handlerName, handlerSchema, controllerSchema, pack
36
25
  const packageNameSnake = toSnakeCase(packageName);
37
26
  const tsArgs = hasArg
38
27
  ? `{
39
- ${paramsFake ? ` params: ${stringifyTsSample(paramsFake)},\n` : ''}${bodyFake ? ` body: ${stringifyTsSample(bodyFake)},\n` : ''}${queryFake ? ` query: ${stringifyTsSample(queryFake)},\n` : ''}}`
28
+ ${[
29
+ bodyValidation ? ` body: ${getTsSample(bodyValidation)},` : null,
30
+ queryValidation ? ` query: ${getTsSample(queryValidation)},` : null,
31
+ paramsValidation ? ` params: ${getTsSample(paramsValidation)},` : null,
32
+ ]
33
+ .filter(Boolean)
34
+ .join('\n')}
35
+ }`
40
36
  : '';
41
37
  const TS_CODE = `import { ${rpcName} } from '${packageName}';
42
38
 
43
- ${iterationFake ? 'using' : 'const'} response = await ${rpcName}.${handlerName}(${tsArgs});
44
- ${outputFake
39
+ ${iterationValidation ? 'using' : 'const'} response = await ${rpcName}.${handlerName}(${tsArgs});
40
+ ${outputValidation
45
41
  ? `
46
42
  console.log(response);
47
43
  /*
48
- ${stringifyTsSample(outputFake, 0)}
44
+ ${getTsSample(outputValidation, 0)}
49
45
  */`
50
- : ''}${iterationFake
46
+ : ''}${iterationValidation
51
47
  ? `
52
48
  for await (const item of response) {
53
49
  console.log(item);
54
50
  /*
55
- ${stringifyTsSample(iterationFake, 4)}
51
+ ${getTsSample(iterationValidation, 2)}
56
52
  */
57
53
  }`
58
54
  : ''}`;
59
55
  const PY_CODE = `from ${packageJson?.py_name ?? packageNameSnake} import ${rpcName}
60
56
 
61
- response = ${rpcName}.${handlerNameSnake}(${hasArg ? `\n params=${paramsFake ? stringifyPySample(paramsFake) : 'None'},\n` : ''}${bodyFake ? ` body=${stringifyPySample(bodyFake)},\n` : ''}${queryFake ? ` query=${stringifyPySample(queryFake)},\n` : ''})
57
+ response = ${rpcName}.${handlerNameSnake}(${hasArg
58
+ ? [
59
+ bodyValidation ? ` body=${getPySample(bodyValidation)},` : null,
60
+ queryValidation ? ` query=${getPySample(queryValidation)},` : null,
61
+ paramsValidation ? ` params=${getPySample(paramsValidation)},` : null,
62
+ ]
63
+ .filter(Boolean)
64
+ .join('\n')
65
+ : ''})
62
66
 
63
- ${outputFake
64
- ? `print(response)\n${JSON.stringify(outputFake, null, 2)
65
- .split('\n')
66
- .map((s) => `# ${s}`)
67
- .join('\n')}`
68
- : ''}${iterationFake
67
+ ${outputValidation ? `print(response)\n${getPySample(outputValidation, 0)}` : ''}${iterationValidation
69
68
  ? `for i, item in enumerate(response):
70
- print(f"iteration #{i}:\\n {item}")
71
- # iteration #0:
72
- ${JSON.stringify(iterationFake, null, 2)
73
- .split('\n')
74
- .map((s) => ` # ${s}`)
75
- .join('\n')}`
69
+ print(f"iteration #{i}:\\n {item}")
70
+ # iteration #0:
71
+ ${getPySample(iterationValidation, 2)}`
76
72
  : ''}`;
77
73
  const serdeUnwrap = (fake) => `from_value(json!(${fake})).unwrap()`;
78
74
  const RS_CODE = `use ${packageJson?.rs_name ?? packageNameSnake}::${rpcNameSnake};
@@ -80,29 +76,29 @@ use serde_json::{ from_value, json };
80
76
 
81
77
  pub fn main() {
82
78
  let response = ${rpcNameSnake}::${handlerNameSnake}(
83
- ${bodyFake ? serdeUnwrap(stringifyPySample(bodyFake)) : '()'}, /* body */
84
- ${queryFake ? serdeUnwrap(stringifyPySample(queryFake)) : '()'}, /* query */
85
- ${paramsFake ? serdeUnwrap(stringifyPySample(paramsFake)) : '()'}, /* params */
79
+ ${bodyValidation ? serdeUnwrap(getRsSample(bodyValidation)) : '()'}, /* body */
80
+ ${queryValidation ? serdeUnwrap(getRsSample(queryValidation)) : '()'}, /* query */
81
+ ${paramsValidation ? serdeUnwrap(getRsSample(paramsValidation)) : '()'}, /* params */
86
82
  None, /* headers (HashMap) */
87
83
  None, /* api_root */
88
84
  false, /* disable_client_validation */
89
85
  );
90
86
 
91
- ${outputFake
87
+ ${outputValidation
92
88
  ? `match response {
93
89
  Ok(output) => println!("{:?}", output),
94
90
  /*
95
- output ${stringifyPySample(outputFake, 4)}
91
+ output ${getTsSample(outputValidation, 2)}
96
92
  */
97
93
  Err(e) => println!("error: {:?}", e),
98
94
  }`
99
- : ''}${iterationFake
95
+ : ''}${iterationValidation
100
96
  ? `match response {
101
97
  Ok(stream) => {
102
98
  for (i, item) in stream.enumerate() {
103
99
  println!("#{}: {:?}", i, item);
104
100
  /*
105
- #0: iteration ${stringifyTsSample(iterationFake, 10)}
101
+ #0: iteration ${getTsSample(iterationValidation, 6)}
106
102
  */
107
103
  }
108
104
  },
@@ -0,0 +1,8 @@
1
+ import { KnownAny } from '../types';
2
+ interface SamplerOptions {
3
+ comment?: '//' | '#';
4
+ stripQuotes?: boolean;
5
+ indent?: number;
6
+ }
7
+ export declare function getJSONSchemaExample(schema: KnownAny, options: SamplerOptions, rootSchema?: KnownAny): string;
8
+ export {};
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getJSONSchemaExample = getJSONSchemaExample;
4
+ function getJSONSchemaExample(schema, options, rootSchema) {
5
+ const { comment = '//', stripQuotes = false, indent = 0 } = options;
6
+ if (!schema || typeof schema !== 'object')
7
+ return 'null';
8
+ // Use the input schema as the root if not provided
9
+ rootSchema = rootSchema || schema;
10
+ // Get the sample value
11
+ const sampleValue = getSampleValue(schema, rootSchema);
12
+ // Format the output with descriptions
13
+ return formatWithDescriptions(sampleValue, schema, rootSchema, comment, stripQuotes, indent);
14
+ }
15
+ function getSampleValue(schema, rootSchema) {
16
+ if (!schema || typeof schema !== 'object')
17
+ return null;
18
+ // If there's an example, use it
19
+ if (schema.example !== undefined) {
20
+ return schema.example;
21
+ }
22
+ // If there are examples, use one of them
23
+ if (schema.examples && schema.examples.length > 0) {
24
+ return schema.examples[0];
25
+ }
26
+ // Handle const if present
27
+ if (schema.const !== undefined) {
28
+ return schema.const;
29
+ }
30
+ // Handle $ref if present
31
+ if (schema.$ref) {
32
+ return handleRef(schema.$ref, rootSchema);
33
+ }
34
+ // Handle enum if present
35
+ if (schema.enum && schema.enum.length > 0) {
36
+ return schema.enum[0];
37
+ }
38
+ // Handle oneOf, anyOf, allOf
39
+ if (schema.oneOf && schema.oneOf.length > 0) {
40
+ return getSampleValue(schema.oneOf[0], rootSchema);
41
+ }
42
+ if (schema.anyOf && schema.anyOf.length > 0) {
43
+ return getSampleValue(schema.anyOf[0], rootSchema);
44
+ }
45
+ if (schema.allOf && schema.allOf.length > 0) {
46
+ // Merge all schemas in allOf
47
+ const mergedSchema = schema.allOf.reduce((acc, s) => ({ ...acc, ...s }), {});
48
+ return getSampleValue(mergedSchema, rootSchema);
49
+ }
50
+ // Handle different types
51
+ if (schema.type) {
52
+ switch (schema.type) {
53
+ case 'string':
54
+ return handleString(schema);
55
+ case 'number':
56
+ case 'integer':
57
+ return handleNumber(schema);
58
+ case 'boolean':
59
+ return handleBoolean();
60
+ case 'object':
61
+ return handleObject(schema, rootSchema);
62
+ case 'array':
63
+ return handleArray(schema, rootSchema);
64
+ case 'null':
65
+ return null;
66
+ default:
67
+ return null;
68
+ }
69
+ }
70
+ // If type is not specified but properties are, treat it as an object
71
+ if (schema.properties) {
72
+ return handleObject(schema, rootSchema);
73
+ }
74
+ // Default fallback
75
+ return null;
76
+ }
77
+ function formatWithDescriptions(value, schema, rootSchema, comment, stripQuotes, indent) {
78
+ const indentStr = ' '.repeat(indent);
79
+ // Handle null
80
+ if (value === null) {
81
+ return 'null';
82
+ }
83
+ // Handle primitives
84
+ if (typeof value !== 'object' || value instanceof Date) {
85
+ return JSON.stringify(value);
86
+ }
87
+ // Handle arrays
88
+ if (Array.isArray(value)) {
89
+ if (value.length === 0)
90
+ return '[]';
91
+ const items = value.map((item) => {
92
+ const itemSchema = schema.items || {};
93
+ const formattedItem = formatWithDescriptions(item, itemSchema, rootSchema, comment, stripQuotes, indent + 1);
94
+ return `${indentStr} ${formattedItem}`;
95
+ });
96
+ return `[\n${items.join(',\n')}\n${indentStr}]`;
97
+ }
98
+ // Handle objects
99
+ if (typeof value === 'object') {
100
+ const entries = Object.entries(value);
101
+ if (entries.length === 0)
102
+ return '{}';
103
+ const formattedEntries = [];
104
+ const isTopLevel = indent === 0;
105
+ // Add top-level description for objects
106
+ if (isTopLevel && schema.type === 'object' && schema.description) {
107
+ const descLines = schema.description.split('\n');
108
+ formattedEntries.push(`${indentStr}${comment} -----`);
109
+ descLines.forEach((line) => {
110
+ formattedEntries.push(`${indentStr}${comment} ${line.trim()}`);
111
+ });
112
+ formattedEntries.push(`${indentStr}${comment} -----`);
113
+ }
114
+ entries.forEach(([key, val], index) => {
115
+ const propSchema = schema.properties?.[key] || {};
116
+ // Handle $ref in property schema
117
+ let resolvedPropSchema = propSchema;
118
+ if (propSchema.$ref) {
119
+ resolvedPropSchema = resolveRef(propSchema.$ref, rootSchema);
120
+ }
121
+ // Add property description if it exists
122
+ if (resolvedPropSchema.description) {
123
+ const descLines = resolvedPropSchema.description.split('\n');
124
+ descLines.forEach((line) => {
125
+ formattedEntries.push(`${indentStr} ${comment} ${line.trim()}`);
126
+ });
127
+ }
128
+ // Format the key
129
+ const formattedKey = stripQuotes && /^[A-Za-z_$][0-9A-Za-z_$]*$/.test(key) ? key : JSON.stringify(key);
130
+ // Format the value
131
+ const formattedValue = formatWithDescriptions(val, resolvedPropSchema, rootSchema, comment, stripQuotes, indent + 1);
132
+ formattedEntries.push(`${indentStr} ${formattedKey}: ${formattedValue}${index < entries.length - 1 ? ',' : ''}`);
133
+ });
134
+ return `{\n${formattedEntries.join('\n')}\n${indentStr}}`;
135
+ }
136
+ return JSON.stringify(value);
137
+ }
138
+ function resolveRef(ref, rootSchema) {
139
+ const path = ref.split('/').slice(1);
140
+ let current = rootSchema;
141
+ for (const segment of path) {
142
+ current = current[segment];
143
+ if (current === undefined) {
144
+ return {};
145
+ }
146
+ }
147
+ return current;
148
+ }
149
+ function handleRef(ref, rootSchema) {
150
+ const resolved = resolveRef(ref, rootSchema);
151
+ return getSampleValue(resolved, rootSchema);
152
+ }
153
+ function handleString(schema) {
154
+ if (schema.format) {
155
+ switch (schema.format) {
156
+ case 'email':
157
+ case 'idn-email':
158
+ return 'user@example.com';
159
+ case 'uri':
160
+ case 'url':
161
+ case 'iri':
162
+ return 'https://example.com';
163
+ case 'date':
164
+ return '2023-01-01';
165
+ case 'date-time':
166
+ return '2023-01-01T00:00:00Z';
167
+ case 'time':
168
+ return '12:00:00Z';
169
+ case 'duration':
170
+ return 'PT1H';
171
+ case 'uuid':
172
+ return '00000000-0000-0000-0000-000000000000';
173
+ case 'regex':
174
+ return '^[a-zA-Z0-9]+$';
175
+ case 'relative-json-pointer':
176
+ return '/some/relative/path';
177
+ case 'color':
178
+ return '#000000';
179
+ case 'hostname':
180
+ return 'example.com';
181
+ case 'zipcode':
182
+ return '12345';
183
+ case 'phone':
184
+ return '+123-456-7890';
185
+ case 'password':
186
+ return '******';
187
+ default:
188
+ return 'string';
189
+ }
190
+ }
191
+ if (schema.pattern) {
192
+ return 'pattern-string';
193
+ }
194
+ return 'string';
195
+ }
196
+ function handleNumber(schema) {
197
+ if (schema.minimum !== undefined && schema.maximum !== undefined) {
198
+ return schema.minimum;
199
+ }
200
+ else if (schema.minimum !== undefined) {
201
+ return schema.minimum;
202
+ }
203
+ else if (schema.maximum !== undefined) {
204
+ return schema.maximum;
205
+ }
206
+ return 0;
207
+ }
208
+ function handleBoolean() {
209
+ return true;
210
+ }
211
+ function handleObject(schema, rootSchema) {
212
+ const result = {};
213
+ if (schema.properties) {
214
+ const required = schema.required || [];
215
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
216
+ if (required.includes(key) || required.length === 0) {
217
+ result[key] = getSampleValue(propSchema, rootSchema);
218
+ }
219
+ }
220
+ }
221
+ if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
222
+ result['additionalProp'] = getSampleValue(schema.additionalProperties, rootSchema);
223
+ }
224
+ return result;
225
+ }
226
+ function handleArray(schema, rootSchema) {
227
+ if (schema.items) {
228
+ const itemSchema = schema.items;
229
+ const minItems = schema.minItems || 1;
230
+ const numItems = Math.min(minItems, 3);
231
+ return Array.from({ length: numItems }, () => getSampleValue(itemSchema, rootSchema));
232
+ }
233
+ return [];
234
+ }
@@ -0,0 +1,2 @@
1
+ import { KnownAny } from '../types';
2
+ export declare function getJSONSchemaSample(schema: KnownAny, rootSchema?: KnownAny): KnownAny;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.jsonSchemaSampler = jsonSchemaSampler;
4
- function jsonSchemaSampler(schema, rootSchema) {
3
+ exports.getJSONSchemaSample = getJSONSchemaSample;
4
+ function getJSONSchemaSample(schema, rootSchema) {
5
5
  if (!schema || typeof schema !== 'object')
6
6
  return null;
7
7
  // Use the input schema as the root if not provided
@@ -28,15 +28,15 @@ function jsonSchemaSampler(schema, rootSchema) {
28
28
  }
29
29
  // Handle oneOf, anyOf, allOf
30
30
  if (schema.oneOf && schema.oneOf.length > 0) {
31
- return jsonSchemaSampler(schema.oneOf[0], rootSchema);
31
+ return getJSONSchemaSample(schema.oneOf[0], rootSchema);
32
32
  }
33
33
  if (schema.anyOf && schema.anyOf.length > 0) {
34
- return jsonSchemaSampler(schema.anyOf[0], rootSchema);
34
+ return getJSONSchemaSample(schema.anyOf[0], rootSchema);
35
35
  }
36
36
  if (schema.allOf && schema.allOf.length > 0) {
37
37
  // Merge all schemas in allOf
38
38
  const mergedSchema = schema.allOf.reduce((acc, s) => ({ ...acc, ...s }), {});
39
- return jsonSchemaSampler(mergedSchema, rootSchema);
39
+ return getJSONSchemaSample(mergedSchema, rootSchema);
40
40
  }
41
41
  // Handle different types
42
42
  if (schema.type) {
@@ -77,7 +77,7 @@ function handleRef(ref, rootSchema) {
77
77
  }
78
78
  }
79
79
  // Process the referenced schema
80
- return jsonSchemaSampler(current, rootSchema);
80
+ return getJSONSchemaSample(current, rootSchema);
81
81
  }
82
82
  function handleString(schema) {
83
83
  if (schema.format) {
@@ -145,13 +145,13 @@ function handleObject(schema, rootSchema) {
145
145
  for (const [key, propSchema] of Object.entries(schema.properties)) {
146
146
  // Only include required properties or as a basic example
147
147
  if (required.includes(key) || required.length === 0) {
148
- result[key] = jsonSchemaSampler(propSchema, rootSchema);
148
+ result[key] = getJSONSchemaSample(propSchema, rootSchema);
149
149
  }
150
150
  }
151
151
  }
152
152
  // Handle additionalProperties
153
153
  if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
154
- result['additionalProp'] = jsonSchemaSampler(schema.additionalProperties, rootSchema);
154
+ result['additionalProp'] = getJSONSchemaSample(schema.additionalProperties, rootSchema);
155
155
  }
156
156
  return result;
157
157
  }
@@ -161,7 +161,7 @@ function handleArray(schema, rootSchema) {
161
161
  const minItems = schema.minItems || 1;
162
162
  // Create minimum number of items (capped at a reasonable max for examples)
163
163
  const numItems = Math.min(minItems, 3);
164
- return Array.from({ length: numItems }, () => jsonSchemaSampler(itemSchema, rootSchema));
164
+ return Array.from({ length: numItems }, () => getJSONSchemaSample(itemSchema, rootSchema));
165
165
  }
166
166
  return [];
167
167
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vovk",
3
- "version": "3.0.0-draft.323",
3
+ "version": "3.0.0-draft.324",
4
4
  "main": "./cjs/index.js",
5
5
  "module": "./mjs/index.js",
6
6
  "types": "./mjs/index.d.ts",
@@ -1,2 +0,0 @@
1
- import { KnownAny } from '../types';
2
- export declare function jsonSchemaSampler(schema: KnownAny, rootSchema?: KnownAny): KnownAny;
@@ -1,2 +0,0 @@
1
- import { KnownAny } from '../types';
2
- export declare function jsonSchemaSampler(schema: KnownAny, rootSchema?: KnownAny): KnownAny;