@amritk/generate-examples 0.1.1 → 0.2.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.
- package/dist/generators/build-schema.d.ts +3 -1
- package/dist/generators/build-schema.d.ts.map +1 -0
- package/dist/generators/build-schema.js +44 -0
- package/dist/generators/collect-example-imports.d.ts +1 -0
- package/dist/generators/collect-example-imports.d.ts.map +1 -0
- package/dist/generators/collect-example-imports.js +88 -0
- package/dist/generators/derive-example.d.ts +1 -0
- package/dist/generators/derive-example.d.ts.map +1 -0
- package/dist/generators/derive-example.js +137 -0
- package/dist/generators/generate-arbitrary.d.ts +1 -0
- package/dist/generators/generate-arbitrary.d.ts.map +1 -0
- package/dist/generators/generate-arbitrary.js +165 -0
- package/dist/generators/generate-files.d.ts +1 -0
- package/dist/generators/generate-files.d.ts.map +1 -0
- package/dist/generators/generate-files.js +41 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -1353
- package/package.json +6 -6
- package/src/generators/build-schema.ts +14 -79
package/dist/index.js
CHANGED
|
@@ -1,1353 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
var buildDynamicRefMap = (rootSchema) => {
|
|
6
|
-
const map = {};
|
|
7
|
-
if (!isSchemaObject(rootSchema) || !("$defs" in rootSchema)) {
|
|
8
|
-
return map;
|
|
9
|
-
}
|
|
10
|
-
const defs = rootSchema.$defs;
|
|
11
|
-
for (const [key, value] of Object.entries(defs)) {
|
|
12
|
-
if (typeof value === "object" && value !== null && "$dynamicAnchor" in value && typeof value["$dynamicAnchor"] === "string") {
|
|
13
|
-
const anchor = value["$dynamicAnchor"];
|
|
14
|
-
map[`#${anchor}`] = `#/$defs/${key}`;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return map;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
// ../helpers/dist/extract-refs.js
|
|
21
|
-
var isResolvableRef = (ref) => {
|
|
22
|
-
if (ref === "#")
|
|
23
|
-
return false;
|
|
24
|
-
if (ref.startsWith("#"))
|
|
25
|
-
return true;
|
|
26
|
-
if (ref.startsWith("http://") || ref.startsWith("https://"))
|
|
27
|
-
return true;
|
|
28
|
-
return false;
|
|
29
|
-
};
|
|
30
|
-
var extractRefs = (schema) => {
|
|
31
|
-
const refs = new Set;
|
|
32
|
-
const traverse = (obj) => {
|
|
33
|
-
if (typeof obj !== "object" || obj === null) {
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (Array.isArray(obj)) {
|
|
37
|
-
for (const item of obj) {
|
|
38
|
-
traverse(item);
|
|
39
|
-
}
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const record = obj;
|
|
43
|
-
if ("$ref" in record && typeof record["$ref"] === "string" && isResolvableRef(record["$ref"])) {
|
|
44
|
-
refs.add(record["$ref"]);
|
|
45
|
-
}
|
|
46
|
-
for (const key in record) {
|
|
47
|
-
traverse(record[key]);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
traverse(schema);
|
|
51
|
-
return refs;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// ../helpers/dist/ref-to-filename.js
|
|
55
|
-
var toKebabCase = (value) => value.replace(/OAuth/g, "Oauth").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
|
|
56
|
-
var uriRefToFilename = (uri) => {
|
|
57
|
-
const hashIndex = uri.indexOf("#");
|
|
58
|
-
const baseUri = hashIndex === -1 ? uri : uri.slice(0, hashIndex);
|
|
59
|
-
const fragment = hashIndex === -1 ? "" : uri.slice(hashIndex + 1);
|
|
60
|
-
const withoutProtocol = baseUri.replace(/^https?:\/\/[^/]+\//, "");
|
|
61
|
-
const withoutExt = withoutProtocol.replace(/\.json$/, "");
|
|
62
|
-
const rawSegments = withoutExt.split("/");
|
|
63
|
-
const SKIP_KEYS = new Set(["definitions", "$defs"]);
|
|
64
|
-
const segments = [];
|
|
65
|
-
for (let i = 0;i < rawSegments.length; i++) {
|
|
66
|
-
const s = rawSegments[i];
|
|
67
|
-
if (SKIP_KEYS.has(s))
|
|
68
|
-
continue;
|
|
69
|
-
const prevRaw = rawSegments[i - 1];
|
|
70
|
-
if (/^\d+\.\d+/.test(s) && prevRaw !== undefined && SKIP_KEYS.has(prevRaw))
|
|
71
|
-
continue;
|
|
72
|
-
segments.push(s);
|
|
73
|
-
}
|
|
74
|
-
const baseName = segments.map((s) => toKebabCase(s).replace(/\./g, "-")).join("-");
|
|
75
|
-
if (!fragment)
|
|
76
|
-
return baseName;
|
|
77
|
-
const fragSegments = fragment.split("/").filter((s) => s && !SKIP_KEYS.has(s) && s !== "properties");
|
|
78
|
-
const fragLast = fragSegments[fragSegments.length - 1];
|
|
79
|
-
if (!fragLast)
|
|
80
|
-
return baseName;
|
|
81
|
-
return `${baseName}-${toKebabCase(fragLast)}`;
|
|
82
|
-
};
|
|
83
|
-
var refToFilename = (ref) => {
|
|
84
|
-
if (ref.startsWith("http://") || ref.startsWith("https://")) {
|
|
85
|
-
return uriRefToFilename(ref);
|
|
86
|
-
}
|
|
87
|
-
const segments = ref.split("/");
|
|
88
|
-
let filename = segments[segments.length - 1];
|
|
89
|
-
if (/[A-Z]/.test(filename)) {
|
|
90
|
-
filename = toKebabCase(filename);
|
|
91
|
-
}
|
|
92
|
-
return filename;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
// ../helpers/dist/ref-to-name.js
|
|
96
|
-
var toKebabCase2 = (value) => value.replace(/OAuth/g, "Oauth").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
|
|
97
|
-
var uriRefToFilename2 = (uri) => {
|
|
98
|
-
const hashIndex = uri.indexOf("#");
|
|
99
|
-
const baseUri = hashIndex === -1 ? uri : uri.slice(0, hashIndex);
|
|
100
|
-
const fragment = hashIndex === -1 ? "" : uri.slice(hashIndex + 1);
|
|
101
|
-
const withoutProtocol = baseUri.replace(/^https?:\/\/[^/]+\//, "");
|
|
102
|
-
const withoutExt = withoutProtocol.replace(/\.json$/, "");
|
|
103
|
-
const rawSegments = withoutExt.split("/");
|
|
104
|
-
const SKIP_KEYS = new Set(["definitions", "$defs"]);
|
|
105
|
-
const segments = [];
|
|
106
|
-
for (let i = 0;i < rawSegments.length; i++) {
|
|
107
|
-
const s = rawSegments[i];
|
|
108
|
-
if (SKIP_KEYS.has(s))
|
|
109
|
-
continue;
|
|
110
|
-
const prevRaw = rawSegments[i - 1];
|
|
111
|
-
if (/^\d+\.\d+/.test(s) && prevRaw !== undefined && SKIP_KEYS.has(prevRaw))
|
|
112
|
-
continue;
|
|
113
|
-
segments.push(s);
|
|
114
|
-
}
|
|
115
|
-
const baseName = segments.map((s) => toKebabCase2(s).replace(/\./g, "-")).join("-");
|
|
116
|
-
if (!fragment)
|
|
117
|
-
return baseName;
|
|
118
|
-
const fragSegments = fragment.split("/").filter((s) => s && !SKIP_KEYS.has(s) && s !== "properties");
|
|
119
|
-
const fragLast = fragSegments[fragSegments.length - 1];
|
|
120
|
-
if (!fragLast)
|
|
121
|
-
return baseName;
|
|
122
|
-
return `${baseName}-${toKebabCase2(fragLast)}`;
|
|
123
|
-
};
|
|
124
|
-
var refToFilename2 = (ref) => {
|
|
125
|
-
if (ref.startsWith("http://") || ref.startsWith("https://")) {
|
|
126
|
-
return uriRefToFilename2(ref);
|
|
127
|
-
}
|
|
128
|
-
const segments = ref.split("/");
|
|
129
|
-
let filename = segments[segments.length - 1];
|
|
130
|
-
if (/[A-Z]/.test(filename)) {
|
|
131
|
-
filename = toKebabCase2(filename);
|
|
132
|
-
}
|
|
133
|
-
return filename;
|
|
134
|
-
};
|
|
135
|
-
var kebabToPascal = (kebab, suffix) => {
|
|
136
|
-
const words = kebab.split("-");
|
|
137
|
-
let pascalCase = "";
|
|
138
|
-
for (const word of words) {
|
|
139
|
-
pascalCase += word.charAt(0).toUpperCase() + word.slice(1);
|
|
140
|
-
}
|
|
141
|
-
return pascalCase + suffix;
|
|
142
|
-
};
|
|
143
|
-
var refToName = (ref, suffix = "") => kebabToPascal(refToFilename2(ref), suffix);
|
|
144
|
-
|
|
145
|
-
// ../helpers/dist/resolve-dynamic-refs.js
|
|
146
|
-
var resolveDynamicRefs = (schema, dynamicRefMap) => {
|
|
147
|
-
if (typeof schema !== "object" || schema === null) {
|
|
148
|
-
return schema;
|
|
149
|
-
}
|
|
150
|
-
if (Object.keys(dynamicRefMap).length === 0) {
|
|
151
|
-
return schema;
|
|
152
|
-
}
|
|
153
|
-
const clone = JSON.parse(JSON.stringify(schema));
|
|
154
|
-
const walk = (obj) => {
|
|
155
|
-
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const record = obj;
|
|
159
|
-
if ("$dynamicRef" in record && typeof record["$dynamicRef"] === "string") {
|
|
160
|
-
const resolved = dynamicRefMap[record["$dynamicRef"]];
|
|
161
|
-
if (resolved) {
|
|
162
|
-
record["$ref"] = resolved;
|
|
163
|
-
delete record["$dynamicRef"];
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
for (const key in record) {
|
|
167
|
-
walk(record[key]);
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
walk(clone);
|
|
171
|
-
return clone;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
// ../helpers/dist/resolve-ref.js
|
|
175
|
-
var navigatePointer = (pointer, schema) => {
|
|
176
|
-
const parts = pointer.split("/").filter(Boolean);
|
|
177
|
-
let current = schema;
|
|
178
|
-
for (const part of parts) {
|
|
179
|
-
const decodedPart = part.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
180
|
-
if (current && typeof current === "object" && decodedPart in current) {
|
|
181
|
-
const next = current[decodedPart];
|
|
182
|
-
if (typeof next === "object" && next !== null) {
|
|
183
|
-
current = next;
|
|
184
|
-
} else {
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
} else {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return current;
|
|
192
|
-
};
|
|
193
|
-
var resolveRef = (ref, rootSchema) => {
|
|
194
|
-
if (ref.startsWith("#")) {
|
|
195
|
-
return navigatePointer(ref.slice(1), rootSchema);
|
|
196
|
-
}
|
|
197
|
-
const hashIndex = ref.indexOf("#");
|
|
198
|
-
const baseUri = hashIndex === -1 ? ref : ref.slice(0, hashIndex);
|
|
199
|
-
const rawFragment = hashIndex === -1 ? "" : ref.slice(hashIndex + 1);
|
|
200
|
-
const fragment = rawFragment === "" || rawFragment === "/" ? "" : rawFragment;
|
|
201
|
-
const defs = rootSchema["$defs"];
|
|
202
|
-
if (typeof defs !== "object" || defs === null)
|
|
203
|
-
return;
|
|
204
|
-
const defsRecord = defs;
|
|
205
|
-
const base = defsRecord[baseUri];
|
|
206
|
-
if (typeof base !== "object" || base === null)
|
|
207
|
-
return;
|
|
208
|
-
if (!fragment)
|
|
209
|
-
return base;
|
|
210
|
-
const normalizedFragment = fragment.replace(/^\/definitions\//, "/$defs/");
|
|
211
|
-
return navigatePointer(normalizedFragment, base);
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
// ../helpers/dist/upgrade-draft07-schema.js
|
|
215
|
-
var toKebabCase3 = (value) => value.replace(/OAuth/g, "Oauth").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
|
|
216
|
-
var uriRefToFilename3 = (uri) => {
|
|
217
|
-
const hashIndex = uri.indexOf("#");
|
|
218
|
-
const baseUri = hashIndex === -1 ? uri : uri.slice(0, hashIndex);
|
|
219
|
-
const fragment = hashIndex === -1 ? "" : uri.slice(hashIndex + 1);
|
|
220
|
-
const withoutProtocol = baseUri.replace(/^https?:\/\/[^/]+\//, "");
|
|
221
|
-
const withoutExt = withoutProtocol.replace(/\.json$/, "");
|
|
222
|
-
const rawSegments = withoutExt.split("/");
|
|
223
|
-
const SKIP_KEYS = new Set(["definitions", "$defs"]);
|
|
224
|
-
const segments = [];
|
|
225
|
-
for (let i = 0;i < rawSegments.length; i++) {
|
|
226
|
-
const s = rawSegments[i];
|
|
227
|
-
if (SKIP_KEYS.has(s))
|
|
228
|
-
continue;
|
|
229
|
-
const prevRaw = rawSegments[i - 1];
|
|
230
|
-
if (/^\d+\.\d+/.test(s) && prevRaw !== undefined && SKIP_KEYS.has(prevRaw))
|
|
231
|
-
continue;
|
|
232
|
-
segments.push(s);
|
|
233
|
-
}
|
|
234
|
-
const baseName = segments.map((s) => toKebabCase3(s).replace(/\./g, "-")).join("-");
|
|
235
|
-
if (!fragment)
|
|
236
|
-
return baseName;
|
|
237
|
-
const fragSegments = fragment.split("/").filter((s) => s && !SKIP_KEYS.has(s) && s !== "properties");
|
|
238
|
-
const fragLast = fragSegments[fragSegments.length - 1];
|
|
239
|
-
if (!fragLast)
|
|
240
|
-
return baseName;
|
|
241
|
-
return `${baseName}-${toKebabCase3(fragLast)}`;
|
|
242
|
-
};
|
|
243
|
-
var refToFilename3 = (ref) => {
|
|
244
|
-
if (ref.startsWith("http://") || ref.startsWith("https://")) {
|
|
245
|
-
return uriRefToFilename3(ref);
|
|
246
|
-
}
|
|
247
|
-
const segments = ref.split("/");
|
|
248
|
-
let filename = segments[segments.length - 1];
|
|
249
|
-
if (/[A-Z]/.test(filename)) {
|
|
250
|
-
filename = toKebabCase3(filename);
|
|
251
|
-
}
|
|
252
|
-
return filename;
|
|
253
|
-
};
|
|
254
|
-
var isDraft07Schema = (schema) => typeof schema["$schema"] === "string" && schema["$schema"].includes("draft-07");
|
|
255
|
-
var rewriteRefs = (obj, refMap, selfRef) => {
|
|
256
|
-
if (typeof obj !== "object" || obj === null)
|
|
257
|
-
return obj;
|
|
258
|
-
if (Array.isArray(obj))
|
|
259
|
-
return obj.map((item) => rewriteRefs(item, refMap, selfRef));
|
|
260
|
-
const record = obj;
|
|
261
|
-
const result = {};
|
|
262
|
-
for (const [key, value] of Object.entries(record)) {
|
|
263
|
-
if (key === "$ref" && typeof value === "string") {
|
|
264
|
-
if (refMap.has(value)) {
|
|
265
|
-
result[key] = refMap.get(value);
|
|
266
|
-
} else if (value === "#" && selfRef) {
|
|
267
|
-
result[key] = selfRef;
|
|
268
|
-
} else {
|
|
269
|
-
result[key] = value;
|
|
270
|
-
}
|
|
271
|
-
} else {
|
|
272
|
-
result[key] = rewriteRefs(value, refMap, selfRef);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return result;
|
|
276
|
-
};
|
|
277
|
-
var hoistNestedDefs = (defs) => {
|
|
278
|
-
const hoisted = {};
|
|
279
|
-
for (const [parentName, parentSchema] of Object.entries(defs)) {
|
|
280
|
-
if (typeof parentSchema !== "object" || parentSchema === null) {
|
|
281
|
-
hoisted[parentName] = parentSchema;
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
const parentObj = parentSchema;
|
|
285
|
-
const nestedDefs = parentObj["$defs"];
|
|
286
|
-
if (!nestedDefs || typeof nestedDefs !== "object") {
|
|
287
|
-
hoisted[parentName] = parentSchema;
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
const parentPrefix = parentName.startsWith("http://") || parentName.startsWith("https://") ? refToFilename3(parentName) : parentName;
|
|
291
|
-
const localToHoisted = new Map;
|
|
292
|
-
for (const localName of Object.keys(nestedDefs)) {
|
|
293
|
-
const hoistedName = `${parentPrefix}-${toKebabCase3(localName)}`;
|
|
294
|
-
localToHoisted.set(`#/$defs/${localName}`, `#/$defs/${hoistedName}`);
|
|
295
|
-
}
|
|
296
|
-
const selfRef = `#/$defs/${parentPrefix}`;
|
|
297
|
-
const rewrittenParent = rewriteRefs(parentObj, localToHoisted, selfRef);
|
|
298
|
-
hoisted[parentName] = rewrittenParent;
|
|
299
|
-
for (const [localName, localSchema] of Object.entries(nestedDefs)) {
|
|
300
|
-
const hoistedName = `${parentPrefix}-${toKebabCase3(localName)}`;
|
|
301
|
-
hoisted[hoistedName] = rewriteRefs(localSchema, localToHoisted, selfRef);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
return hoisted;
|
|
305
|
-
};
|
|
306
|
-
var upgradeDraft07Schema = (schema) => {
|
|
307
|
-
if (!isDraft07Schema(schema))
|
|
308
|
-
return schema;
|
|
309
|
-
const { definitions, $schema: _, ...rest } = schema;
|
|
310
|
-
const rawDefs = definitions ?? {};
|
|
311
|
-
const renamedDefs = {};
|
|
312
|
-
for (const [key, value] of Object.entries(rawDefs)) {
|
|
313
|
-
renamedDefs[key] = renameNestedDefs(value);
|
|
314
|
-
}
|
|
315
|
-
const hoistedDefs = hoistNestedDefs(renamedDefs);
|
|
316
|
-
for (const key of Object.keys(hoistedDefs)) {
|
|
317
|
-
if (key.startsWith("http://") || key.startsWith("https://")) {
|
|
318
|
-
const shortName = refToFilename3(key);
|
|
319
|
-
if (shortName && !(shortName in hoistedDefs)) {
|
|
320
|
-
hoistedDefs[shortName] = hoistedDefs[key];
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
return {
|
|
325
|
-
...rest,
|
|
326
|
-
$defs: hoistedDefs
|
|
327
|
-
};
|
|
328
|
-
};
|
|
329
|
-
var renameNestedDefs = (obj) => {
|
|
330
|
-
if (typeof obj !== "object" || obj === null)
|
|
331
|
-
return obj;
|
|
332
|
-
if (Array.isArray(obj))
|
|
333
|
-
return obj.map(renameNestedDefs);
|
|
334
|
-
const record = obj;
|
|
335
|
-
const result = {};
|
|
336
|
-
for (const [key, value] of Object.entries(record)) {
|
|
337
|
-
if (key === "$ref" && typeof value === "string" && value.startsWith("#/definitions/")) {
|
|
338
|
-
result[key] = value.replace("#/definitions/", "#/$defs/");
|
|
339
|
-
} else {
|
|
340
|
-
const outKey = key === "definitions" ? "$defs" : key;
|
|
341
|
-
result[outKey] = renameNestedDefs(value);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
return result;
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
// ../helpers/dist/generate-type-definition.js
|
|
348
|
-
var isSchemaObject2 = (schema) => {
|
|
349
|
-
return typeof schema === "object" && schema !== null && typeof schema !== "boolean";
|
|
350
|
-
};
|
|
351
|
-
var isObjectSchema = (schema) => {
|
|
352
|
-
return isSchemaObject2(schema) && (("type" in schema) && schema.type === "object" || ("properties" in schema));
|
|
353
|
-
};
|
|
354
|
-
var MJST_EXTENSION_KEY = "x-mjst";
|
|
355
|
-
var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
356
|
-
var SUPPORTED_PRIMITIVES = new Set(["bigint"]);
|
|
357
|
-
var SAFE_BRAND = /^[\w$ -]+$/;
|
|
358
|
-
var readExtensionString = (schema, field) => {
|
|
359
|
-
if (!isSchemaObject2(schema))
|
|
360
|
-
return;
|
|
361
|
-
const extension = schema[MJST_EXTENSION_KEY];
|
|
362
|
-
if (typeof extension !== "object" || extension === null)
|
|
363
|
-
return;
|
|
364
|
-
const value = extension[field];
|
|
365
|
-
return typeof value === "string" ? value : undefined;
|
|
366
|
-
};
|
|
367
|
-
var getMjstInstanceOf = (schema) => {
|
|
368
|
-
const instanceOf = readExtensionString(schema, "instanceOf");
|
|
369
|
-
return instanceOf !== undefined && IDENTIFIER.test(instanceOf) ? instanceOf : undefined;
|
|
370
|
-
};
|
|
371
|
-
var getMjstPrimitive = (schema) => {
|
|
372
|
-
const primitive = readExtensionString(schema, "primitive");
|
|
373
|
-
return primitive !== undefined && SUPPORTED_PRIMITIVES.has(primitive) ? primitive : undefined;
|
|
374
|
-
};
|
|
375
|
-
var getMjstBrand = (schema) => {
|
|
376
|
-
const brand = readExtensionString(schema, "brand");
|
|
377
|
-
return brand !== undefined && SAFE_BRAND.test(brand) ? brand : undefined;
|
|
378
|
-
};
|
|
379
|
-
var toKebabCase4 = (value) => value.replace(/OAuth/g, "Oauth").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
|
|
380
|
-
var uriRefToFilename4 = (uri) => {
|
|
381
|
-
const hashIndex = uri.indexOf("#");
|
|
382
|
-
const baseUri = hashIndex === -1 ? uri : uri.slice(0, hashIndex);
|
|
383
|
-
const fragment = hashIndex === -1 ? "" : uri.slice(hashIndex + 1);
|
|
384
|
-
const withoutProtocol = baseUri.replace(/^https?:\/\/[^/]+\//, "");
|
|
385
|
-
const withoutExt = withoutProtocol.replace(/\.json$/, "");
|
|
386
|
-
const rawSegments = withoutExt.split("/");
|
|
387
|
-
const SKIP_KEYS = new Set(["definitions", "$defs"]);
|
|
388
|
-
const segments = [];
|
|
389
|
-
for (let i = 0;i < rawSegments.length; i++) {
|
|
390
|
-
const s = rawSegments[i];
|
|
391
|
-
if (SKIP_KEYS.has(s))
|
|
392
|
-
continue;
|
|
393
|
-
const prevRaw = rawSegments[i - 1];
|
|
394
|
-
if (/^\d+\.\d+/.test(s) && prevRaw !== undefined && SKIP_KEYS.has(prevRaw))
|
|
395
|
-
continue;
|
|
396
|
-
segments.push(s);
|
|
397
|
-
}
|
|
398
|
-
const baseName = segments.map((s) => toKebabCase4(s).replace(/\./g, "-")).join("-");
|
|
399
|
-
if (!fragment)
|
|
400
|
-
return baseName;
|
|
401
|
-
const fragSegments = fragment.split("/").filter((s) => s && !SKIP_KEYS.has(s) && s !== "properties");
|
|
402
|
-
const fragLast = fragSegments[fragSegments.length - 1];
|
|
403
|
-
if (!fragLast)
|
|
404
|
-
return baseName;
|
|
405
|
-
return `${baseName}-${toKebabCase4(fragLast)}`;
|
|
406
|
-
};
|
|
407
|
-
var refToFilename4 = (ref) => {
|
|
408
|
-
if (ref.startsWith("http://") || ref.startsWith("https://")) {
|
|
409
|
-
return uriRefToFilename4(ref);
|
|
410
|
-
}
|
|
411
|
-
const segments = ref.split("/");
|
|
412
|
-
let filename = segments[segments.length - 1];
|
|
413
|
-
if (/[A-Z]/.test(filename)) {
|
|
414
|
-
filename = toKebabCase4(filename);
|
|
415
|
-
}
|
|
416
|
-
return filename;
|
|
417
|
-
};
|
|
418
|
-
var kebabToPascal2 = (kebab, suffix) => {
|
|
419
|
-
const words = kebab.split("-");
|
|
420
|
-
let pascalCase = "";
|
|
421
|
-
for (const word of words) {
|
|
422
|
-
pascalCase += word.charAt(0).toUpperCase() + word.slice(1);
|
|
423
|
-
}
|
|
424
|
-
return pascalCase + suffix;
|
|
425
|
-
};
|
|
426
|
-
var refToName2 = (ref, suffix = "") => kebabToPascal2(refToFilename4(ref), suffix);
|
|
427
|
-
var JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
428
|
-
var safeKey = (key) => {
|
|
429
|
-
if (JS_IDENTIFIER.test(key)) {
|
|
430
|
-
return key;
|
|
431
|
-
}
|
|
432
|
-
return `'${key}'`;
|
|
433
|
-
};
|
|
434
|
-
var getConditionalObjectSchema = (schema) => {
|
|
435
|
-
if (!isSchemaObject2(schema)) {
|
|
436
|
-
return null;
|
|
437
|
-
}
|
|
438
|
-
if (!("if" in schema) || !("then" in schema)) {
|
|
439
|
-
return null;
|
|
440
|
-
}
|
|
441
|
-
const ifSchema = schema.if;
|
|
442
|
-
const thenSchema = schema.then;
|
|
443
|
-
if (!isSchemaObject2(ifSchema) || !isSchemaObject2(thenSchema)) {
|
|
444
|
-
return null;
|
|
445
|
-
}
|
|
446
|
-
const ifProperties = ifSchema.properties;
|
|
447
|
-
const thenProperties = thenSchema.properties;
|
|
448
|
-
const hasIfProperties = ifProperties && typeof ifProperties === "object";
|
|
449
|
-
const hasThenProperties = thenProperties && typeof thenProperties === "object";
|
|
450
|
-
if (!hasIfProperties && !hasThenProperties) {
|
|
451
|
-
return null;
|
|
452
|
-
}
|
|
453
|
-
const properties = {
|
|
454
|
-
...hasIfProperties ? ifProperties : {},
|
|
455
|
-
...hasThenProperties ? thenProperties : {}
|
|
456
|
-
};
|
|
457
|
-
const required = new Set;
|
|
458
|
-
if (Array.isArray(ifSchema.required)) {
|
|
459
|
-
for (const key of ifSchema.required) {
|
|
460
|
-
required.add(key);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
if (hasIfProperties) {
|
|
464
|
-
for (const key in ifProperties) {
|
|
465
|
-
required.add(key);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
if (Array.isArray(thenSchema.required)) {
|
|
469
|
-
for (const key of thenSchema.required) {
|
|
470
|
-
required.add(key);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
if (hasThenProperties) {
|
|
474
|
-
for (const key in thenProperties) {
|
|
475
|
-
required.add(key);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
const thenRef = typeof thenSchema.$ref === "string" ? thenSchema.$ref : null;
|
|
479
|
-
return {
|
|
480
|
-
schema: {
|
|
481
|
-
type: "object",
|
|
482
|
-
properties,
|
|
483
|
-
...required.size > 0 ? { required: Array.from(required) } : {}
|
|
484
|
-
},
|
|
485
|
-
thenRef
|
|
486
|
-
};
|
|
487
|
-
};
|
|
488
|
-
var isObjectLikeSchema = (schema) => {
|
|
489
|
-
if (!isSchemaObject2(schema)) {
|
|
490
|
-
return false;
|
|
491
|
-
}
|
|
492
|
-
if (isObjectSchema(schema)) {
|
|
493
|
-
return true;
|
|
494
|
-
}
|
|
495
|
-
return "patternProperties" in schema || "additionalProperties" in schema || "if" in schema && "then" in schema;
|
|
496
|
-
};
|
|
497
|
-
var getBooleanSubSchemaType = (schema) => {
|
|
498
|
-
return schema ? "unknown" : "never";
|
|
499
|
-
};
|
|
500
|
-
var buildJsDocBlock = (title, description, commentUrl) => {
|
|
501
|
-
let block = `/**
|
|
502
|
-
`;
|
|
503
|
-
block += `* ${title}
|
|
504
|
-
`;
|
|
505
|
-
block += `*
|
|
506
|
-
`;
|
|
507
|
-
block += `* ${description}
|
|
508
|
-
`;
|
|
509
|
-
if (commentUrl?.startsWith("http")) {
|
|
510
|
-
block += `*
|
|
511
|
-
`;
|
|
512
|
-
block += `* @see {@link ${commentUrl}}
|
|
513
|
-
`;
|
|
514
|
-
}
|
|
515
|
-
block += `*/
|
|
516
|
-
`;
|
|
517
|
-
return block;
|
|
518
|
-
};
|
|
519
|
-
var getTypeScriptType = (schema, options = {}) => {
|
|
520
|
-
const base = getUnbrandedType(schema, options);
|
|
521
|
-
const brand = getMjstBrand(schema);
|
|
522
|
-
return brand ? `(${base} & { readonly __brand: '${brand}' })` : base;
|
|
523
|
-
};
|
|
524
|
-
var recordType = (keyType, valueType, options) => options.readonly ? `Readonly<Record<${keyType}, ${valueType}>>` : `Record<${keyType}, ${valueType}>`;
|
|
525
|
-
var getUnbrandedType = (schema, options = {}) => {
|
|
526
|
-
if (typeof schema === "boolean") {
|
|
527
|
-
return getBooleanSubSchemaType(schema);
|
|
528
|
-
}
|
|
529
|
-
if (typeof schema !== "object" || schema === null) {
|
|
530
|
-
return "unknown";
|
|
531
|
-
}
|
|
532
|
-
const instanceOf = getMjstInstanceOf(schema);
|
|
533
|
-
if (instanceOf) {
|
|
534
|
-
return instanceOf;
|
|
535
|
-
}
|
|
536
|
-
const primitive = getMjstPrimitive(schema);
|
|
537
|
-
if (primitive) {
|
|
538
|
-
return primitive;
|
|
539
|
-
}
|
|
540
|
-
if (schema.$ref) {
|
|
541
|
-
if (!schema.$ref.startsWith("#")) {
|
|
542
|
-
return "unknown";
|
|
543
|
-
}
|
|
544
|
-
return refToName2(schema.$ref, options.typeSuffix);
|
|
545
|
-
}
|
|
546
|
-
if (schema.$dynamicRef) {
|
|
547
|
-
if (schema.$dynamicRef === "#meta") {
|
|
548
|
-
return `Schema${options.typeSuffix ?? ""}`;
|
|
549
|
-
}
|
|
550
|
-
return refToName2(schema.$dynamicRef, options.typeSuffix);
|
|
551
|
-
}
|
|
552
|
-
if (schema.const !== undefined) {
|
|
553
|
-
return JSON.stringify(schema.const);
|
|
554
|
-
}
|
|
555
|
-
if (schema.enum && schema.enum.length > 0) {
|
|
556
|
-
if (schema.enum.length === 1) {
|
|
557
|
-
return JSON.stringify(schema.enum[0]);
|
|
558
|
-
}
|
|
559
|
-
let enumUnion = JSON.stringify(schema.enum[0]);
|
|
560
|
-
for (let i = 1;i < schema.enum.length; i++) {
|
|
561
|
-
enumUnion += " | " + JSON.stringify(schema.enum[i]);
|
|
562
|
-
}
|
|
563
|
-
return enumUnion;
|
|
564
|
-
}
|
|
565
|
-
if (schema.enum && schema.enum.length > 1) {
|
|
566
|
-
let multiEnumUnion = JSON.stringify(schema.enum[0]);
|
|
567
|
-
for (let i = 1;i < schema.enum.length; i++) {
|
|
568
|
-
multiEnumUnion += " | " + JSON.stringify(schema.enum[i]);
|
|
569
|
-
}
|
|
570
|
-
return multiEnumUnion;
|
|
571
|
-
}
|
|
572
|
-
if (schema.oneOf && Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
|
|
573
|
-
let oneOfUnion = getTypeScriptType(schema.oneOf[0], options);
|
|
574
|
-
for (let i = 1;i < schema.oneOf.length; i++) {
|
|
575
|
-
oneOfUnion += " | " + getTypeScriptType(schema.oneOf[i], options);
|
|
576
|
-
}
|
|
577
|
-
return oneOfUnion;
|
|
578
|
-
}
|
|
579
|
-
if (schema.anyOf && Array.isArray(schema.anyOf) && schema.anyOf.length > 0) {
|
|
580
|
-
let anyOfUnion = getTypeScriptType(schema.anyOf[0], options);
|
|
581
|
-
for (let i = 1;i < schema.anyOf.length; i++) {
|
|
582
|
-
anyOfUnion += " | " + getTypeScriptType(schema.anyOf[i], options);
|
|
583
|
-
}
|
|
584
|
-
return anyOfUnion;
|
|
585
|
-
}
|
|
586
|
-
if (schema.allOf && Array.isArray(schema.allOf) && schema.allOf.length > 0) {
|
|
587
|
-
let intersectionTypes = getTypeScriptType(schema.allOf[0], options);
|
|
588
|
-
for (let i = 1;i < schema.allOf.length; i++) {
|
|
589
|
-
intersectionTypes += " & " + getTypeScriptType(schema.allOf[i], options);
|
|
590
|
-
}
|
|
591
|
-
return intersectionTypes;
|
|
592
|
-
}
|
|
593
|
-
const conditionalResult = getConditionalObjectSchema(schema);
|
|
594
|
-
if (conditionalResult) {
|
|
595
|
-
const baseType = getTypeScriptType(conditionalResult.schema, options);
|
|
596
|
-
if (conditionalResult.thenRef) {
|
|
597
|
-
return `(${baseType}) & ${refToName2(conditionalResult.thenRef, options.typeSuffix)}`;
|
|
598
|
-
}
|
|
599
|
-
return baseType;
|
|
600
|
-
}
|
|
601
|
-
if (!schema.type) {
|
|
602
|
-
if (schema.additionalProperties !== undefined) {
|
|
603
|
-
if (typeof schema.additionalProperties === "boolean") {
|
|
604
|
-
return recordType("string", getBooleanSubSchemaType(schema.additionalProperties), options);
|
|
605
|
-
}
|
|
606
|
-
return recordType("string", getTypeScriptType(schema.additionalProperties, options), options);
|
|
607
|
-
}
|
|
608
|
-
if (schema.patternProperties && typeof schema.patternProperties === "object") {
|
|
609
|
-
const firstEntry = Object.entries(schema.patternProperties)[0];
|
|
610
|
-
if (firstEntry) {
|
|
611
|
-
const [pattern, value] = firstEntry;
|
|
612
|
-
if (value !== undefined) {
|
|
613
|
-
const valueType = typeof value === "boolean" ? getBooleanSubSchemaType(value) : getTypeScriptType(value, options);
|
|
614
|
-
if (pattern === "^x-") {
|
|
615
|
-
return recordType("`x-${string}`", valueType, options);
|
|
616
|
-
}
|
|
617
|
-
return recordType("string", valueType, options);
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
if (schema.default !== undefined) {
|
|
622
|
-
if (typeof schema.default === "string") {
|
|
623
|
-
return "string";
|
|
624
|
-
}
|
|
625
|
-
if (typeof schema.default === "number") {
|
|
626
|
-
return "number";
|
|
627
|
-
}
|
|
628
|
-
if (typeof schema.default === "boolean") {
|
|
629
|
-
return "boolean";
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
return "unknown";
|
|
633
|
-
}
|
|
634
|
-
if (Array.isArray(schema.type)) {
|
|
635
|
-
const mapType = (t) => {
|
|
636
|
-
switch (t) {
|
|
637
|
-
case "string":
|
|
638
|
-
return "string";
|
|
639
|
-
case "number":
|
|
640
|
-
case "integer":
|
|
641
|
-
return "number";
|
|
642
|
-
case "boolean":
|
|
643
|
-
return "boolean";
|
|
644
|
-
case "null":
|
|
645
|
-
return "null";
|
|
646
|
-
case "array":
|
|
647
|
-
return "unknown[]";
|
|
648
|
-
case "object":
|
|
649
|
-
return "Record<string, unknown>";
|
|
650
|
-
default:
|
|
651
|
-
return "unknown";
|
|
652
|
-
}
|
|
653
|
-
};
|
|
654
|
-
let typeUnion = mapType(schema.type[0]);
|
|
655
|
-
for (let i = 1;i < schema.type.length; i++) {
|
|
656
|
-
typeUnion += " | " + mapType(schema.type[i]);
|
|
657
|
-
}
|
|
658
|
-
return typeUnion;
|
|
659
|
-
}
|
|
660
|
-
switch (schema.type) {
|
|
661
|
-
case "string":
|
|
662
|
-
return "string";
|
|
663
|
-
case "number":
|
|
664
|
-
case "integer":
|
|
665
|
-
return "number";
|
|
666
|
-
case "boolean":
|
|
667
|
-
return "boolean";
|
|
668
|
-
case "array":
|
|
669
|
-
if (schema.items) {
|
|
670
|
-
const itemType = getTypeScriptType(schema.items, options);
|
|
671
|
-
const wrappedItemType = itemType.includes(" | ") ? `(${itemType})` : itemType;
|
|
672
|
-
return options.readonly ? `readonly ${wrappedItemType}[]` : `${wrappedItemType}[]`;
|
|
673
|
-
}
|
|
674
|
-
return options.readonly ? "readonly unknown[]" : "unknown[]";
|
|
675
|
-
case "object":
|
|
676
|
-
if (schema.properties) {
|
|
677
|
-
const readonlyPrefix = options.readonly ? "readonly " : "";
|
|
678
|
-
const hasDescriptions = Object.values(schema.properties).some((p) => isSchemaObject2(p) && (typeof p.description === "string" || typeof p.$comment === "string"));
|
|
679
|
-
if (hasDescriptions) {
|
|
680
|
-
let properties2 = "";
|
|
681
|
-
let first2 = true;
|
|
682
|
-
for (const key in schema.properties) {
|
|
683
|
-
const propSchema = schema.properties[key];
|
|
684
|
-
const isRequired = schema.required?.includes(key) ?? false;
|
|
685
|
-
const optional = isRequired ? "" : "?";
|
|
686
|
-
const propType = getTypeScriptType(propSchema, options);
|
|
687
|
-
const inlineDescription = isSchemaObject2(propSchema) && typeof propSchema.description === "string" ? propSchema.description : isSchemaObject2(propSchema) && typeof propSchema.$comment === "string" ? propSchema.$comment : undefined;
|
|
688
|
-
if (!first2)
|
|
689
|
-
properties2 += `
|
|
690
|
-
`;
|
|
691
|
-
first2 = false;
|
|
692
|
-
if (inlineDescription) {
|
|
693
|
-
properties2 += " /** " + inlineDescription + ` */
|
|
694
|
-
` + readonlyPrefix + safeKey(key) + optional + ": " + propType + ";";
|
|
695
|
-
} else {
|
|
696
|
-
properties2 += " " + readonlyPrefix + safeKey(key) + optional + ": " + propType + ";";
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
return `{
|
|
700
|
-
` + properties2 + `
|
|
701
|
-
}`;
|
|
702
|
-
}
|
|
703
|
-
let properties = "";
|
|
704
|
-
let first = true;
|
|
705
|
-
for (const key in schema.properties) {
|
|
706
|
-
const propSchema = schema.properties[key];
|
|
707
|
-
const isRequired = schema.required?.includes(key) ?? false;
|
|
708
|
-
const optional = isRequired ? "" : "?";
|
|
709
|
-
const propType = getTypeScriptType(propSchema, options);
|
|
710
|
-
if (!first)
|
|
711
|
-
properties += "; ";
|
|
712
|
-
properties += readonlyPrefix + safeKey(key) + optional + ": " + propType;
|
|
713
|
-
first = false;
|
|
714
|
-
}
|
|
715
|
-
return "{ " + properties + " }";
|
|
716
|
-
}
|
|
717
|
-
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
718
|
-
const additionalPropType = getTypeScriptType(schema.additionalProperties, options);
|
|
719
|
-
return recordType("string", additionalPropType, options);
|
|
720
|
-
}
|
|
721
|
-
if (schema.patternProperties && typeof schema.patternProperties === "object") {
|
|
722
|
-
const firstEntry = Object.entries(schema.patternProperties)[0];
|
|
723
|
-
if (firstEntry) {
|
|
724
|
-
const [pattern, patternVal] = firstEntry;
|
|
725
|
-
if (patternVal) {
|
|
726
|
-
const valueType = getTypeScriptType(patternVal, options);
|
|
727
|
-
if (pattern === "^x-") {
|
|
728
|
-
return recordType("`x-${string}`", valueType, options);
|
|
729
|
-
}
|
|
730
|
-
return recordType("string", valueType, options);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
return "object";
|
|
735
|
-
default:
|
|
736
|
-
return "unknown";
|
|
737
|
-
}
|
|
738
|
-
};
|
|
739
|
-
var generateTypeDefinition = (schema, typeName, options = {}) => {
|
|
740
|
-
const readonlyPrefix = options.readonly ? "readonly " : "";
|
|
741
|
-
if (!isObjectLikeSchema(schema)) {
|
|
742
|
-
const tsType = getTypeScriptType(schema, options);
|
|
743
|
-
let result = "";
|
|
744
|
-
const topLevelComment = isSchemaObject2(schema) && typeof schema.description === "string" && schema.description || isSchemaObject2(schema) && typeof schema.$comment === "string" && schema.$comment || undefined;
|
|
745
|
-
if (topLevelComment) {
|
|
746
|
-
result += buildJsDocBlock(typeName, topLevelComment);
|
|
747
|
-
}
|
|
748
|
-
result += `export type ${typeName} = ${tsType};`;
|
|
749
|
-
return result;
|
|
750
|
-
}
|
|
751
|
-
if (isObjectLikeSchema(schema)) {
|
|
752
|
-
const conditionalResult = getConditionalObjectSchema(schema);
|
|
753
|
-
const normalizedSchema = conditionalResult?.schema ?? schema;
|
|
754
|
-
const conditionalThenRef = conditionalResult?.thenRef ?? null;
|
|
755
|
-
let jsDocTitle;
|
|
756
|
-
let jsDocDescription;
|
|
757
|
-
const topLevelComment = isSchemaObject2(schema) && typeof schema.description === "string" && schema.description || isSchemaObject2(schema) && typeof schema.$comment === "string" && schema.$comment || undefined;
|
|
758
|
-
if (topLevelComment) {
|
|
759
|
-
jsDocTitle = typeName;
|
|
760
|
-
jsDocDescription = topLevelComment;
|
|
761
|
-
}
|
|
762
|
-
const hasProperties2 = normalizedSchema.properties && Object.keys(normalizedSchema.properties).length > 0;
|
|
763
|
-
const hasAdditionalProperties2 = normalizedSchema.additionalProperties && typeof normalizedSchema.additionalProperties === "object";
|
|
764
|
-
const hasPatternProperties = normalizedSchema.patternProperties && typeof normalizedSchema.patternProperties === "object" && Object.keys(normalizedSchema.patternProperties).length > 0;
|
|
765
|
-
if (!hasProperties2 && hasPatternProperties && normalizedSchema.patternProperties) {
|
|
766
|
-
const firstEntry = Object.entries(normalizedSchema.patternProperties)[0];
|
|
767
|
-
const firstPattern = firstEntry?.[0];
|
|
768
|
-
const firstPatternProperty = firstEntry?.[1];
|
|
769
|
-
if (firstPatternProperty === undefined) {
|
|
770
|
-
return `export type ${typeName} = Record<string, unknown>;`;
|
|
771
|
-
}
|
|
772
|
-
const patternPropType = typeof firstPatternProperty === "boolean" ? getBooleanSubSchemaType(firstPatternProperty) : getTypeScriptType(firstPatternProperty, options);
|
|
773
|
-
const keyType = firstPattern === "^x-" ? "`x-${string}`" : "string";
|
|
774
|
-
let result2 = "";
|
|
775
|
-
if (jsDocTitle && jsDocDescription) {
|
|
776
|
-
result2 += buildJsDocBlock(jsDocTitle, jsDocDescription);
|
|
777
|
-
}
|
|
778
|
-
result2 += `export type ${typeName} = ${recordType(keyType, patternPropType, options)};`;
|
|
779
|
-
return result2;
|
|
780
|
-
}
|
|
781
|
-
if (!hasProperties2 && hasAdditionalProperties2 && normalizedSchema.additionalProperties) {
|
|
782
|
-
const additionalPropType = getTypeScriptType(normalizedSchema.additionalProperties, options);
|
|
783
|
-
let result2 = "";
|
|
784
|
-
if (jsDocTitle && jsDocDescription) {
|
|
785
|
-
result2 += buildJsDocBlock(jsDocTitle, jsDocDescription);
|
|
786
|
-
}
|
|
787
|
-
result2 += `export type ${typeName} = {
|
|
788
|
-
${readonlyPrefix}[key: string]: ${additionalPropType};
|
|
789
|
-
};`;
|
|
790
|
-
return result2;
|
|
791
|
-
}
|
|
792
|
-
const schemaProps = normalizedSchema.properties ?? {};
|
|
793
|
-
let properties = "";
|
|
794
|
-
let isFirstProp = true;
|
|
795
|
-
for (const key in schemaProps) {
|
|
796
|
-
const propSchema = schemaProps[key];
|
|
797
|
-
const isRequired = normalizedSchema.required?.includes(key) ?? false;
|
|
798
|
-
const optional = isRequired ? "" : "?";
|
|
799
|
-
const propType = getTypeScriptType(propSchema, options);
|
|
800
|
-
const quotedKey = readonlyPrefix + safeKey(key);
|
|
801
|
-
if (!isFirstProp)
|
|
802
|
-
properties += `
|
|
803
|
-
`;
|
|
804
|
-
isFirstProp = false;
|
|
805
|
-
const inlineDescription = isSchemaObject2(propSchema) && typeof propSchema.description === "string" ? propSchema.description : isSchemaObject2(propSchema) && typeof propSchema.$comment === "string" ? propSchema.$comment : undefined;
|
|
806
|
-
if (inlineDescription) {
|
|
807
|
-
properties += " /** " + inlineDescription + ` */
|
|
808
|
-
` + quotedKey + optional + ": " + propType + ";";
|
|
809
|
-
} else {
|
|
810
|
-
properties += " " + quotedKey + optional + ": " + propType + ";";
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
const allOfIntersections = [];
|
|
814
|
-
if (isSchemaObject2(schema) && Array.isArray(schema.allOf)) {
|
|
815
|
-
for (const entry of schema.allOf) {
|
|
816
|
-
if (isSchemaObject2(entry) && entry.$ref) {
|
|
817
|
-
allOfIntersections.push(refToName2(entry.$ref, options.typeSuffix));
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
if (isSchemaObject2(schema) && typeof schema.$ref === "string" && schema.$ref.startsWith("#")) {
|
|
822
|
-
allOfIntersections.push(refToName2(schema.$ref, options.typeSuffix));
|
|
823
|
-
}
|
|
824
|
-
let result = "";
|
|
825
|
-
if (jsDocTitle && jsDocDescription) {
|
|
826
|
-
result += buildJsDocBlock(jsDocTitle, jsDocDescription);
|
|
827
|
-
}
|
|
828
|
-
let typeBody = `{
|
|
829
|
-
` + properties + `
|
|
830
|
-
}`;
|
|
831
|
-
if (conditionalThenRef) {
|
|
832
|
-
typeBody += " & " + refToName2(conditionalThenRef, options.typeSuffix);
|
|
833
|
-
}
|
|
834
|
-
for (const intersectionType of allOfIntersections) {
|
|
835
|
-
typeBody += " & " + intersectionType;
|
|
836
|
-
}
|
|
837
|
-
result += "export type " + typeName + " = " + typeBody + ";";
|
|
838
|
-
return result;
|
|
839
|
-
}
|
|
840
|
-
return "export type " + typeName + " = unknown;";
|
|
841
|
-
};
|
|
842
|
-
|
|
843
|
-
// ../helpers/dist/schema-guards.js
|
|
844
|
-
var hasRef = (value) => {
|
|
845
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && "$ref" in value && typeof value.$ref === "string";
|
|
846
|
-
};
|
|
847
|
-
var isSchemaObject3 = (schema) => {
|
|
848
|
-
return typeof schema === "object" && schema !== null && typeof schema !== "boolean";
|
|
849
|
-
};
|
|
850
|
-
var hasType = (schema) => {
|
|
851
|
-
return isSchemaObject3(schema) && "type" in schema && typeof schema.type === "string";
|
|
852
|
-
};
|
|
853
|
-
var hasProperties = (schema) => {
|
|
854
|
-
return isSchemaObject3(schema) && "properties" in schema && typeof schema.properties === "object" && schema.properties !== null;
|
|
855
|
-
};
|
|
856
|
-
var hasEnum = (schema) => {
|
|
857
|
-
return isSchemaObject3(schema) && "enum" in schema && Array.isArray(schema.enum);
|
|
858
|
-
};
|
|
859
|
-
var hasConst = (schema) => {
|
|
860
|
-
return isSchemaObject3(schema) && "const" in schema;
|
|
861
|
-
};
|
|
862
|
-
var hasPattern = (schema) => {
|
|
863
|
-
return isSchemaObject3(schema) && "pattern" in schema && typeof schema.pattern === "string";
|
|
864
|
-
};
|
|
865
|
-
var hasFormat = (schema) => {
|
|
866
|
-
return isSchemaObject3(schema) && "format" in schema && typeof schema.format === "string";
|
|
867
|
-
};
|
|
868
|
-
var hasDefault = (schema) => {
|
|
869
|
-
return isSchemaObject3(schema) && "default" in schema;
|
|
870
|
-
};
|
|
871
|
-
var hasExamples = (schema) => {
|
|
872
|
-
return isSchemaObject3(schema) && "examples" in schema && Array.isArray(schema.examples);
|
|
873
|
-
};
|
|
874
|
-
var hasOneOf = (schema) => {
|
|
875
|
-
return isSchemaObject3(schema) && "oneOf" in schema && Array.isArray(schema.oneOf);
|
|
876
|
-
};
|
|
877
|
-
var hasAnyOf = (schema) => {
|
|
878
|
-
return isSchemaObject3(schema) && "anyOf" in schema && Array.isArray(schema.anyOf);
|
|
879
|
-
};
|
|
880
|
-
var hasAllOf = (schema) => {
|
|
881
|
-
return isSchemaObject3(schema) && "allOf" in schema && Array.isArray(schema.allOf);
|
|
882
|
-
};
|
|
883
|
-
var hasRequired = (schema) => {
|
|
884
|
-
return isSchemaObject3(schema) && "required" in schema && Array.isArray(schema.required);
|
|
885
|
-
};
|
|
886
|
-
var hasItems = (schema) => {
|
|
887
|
-
return isSchemaObject3(schema) && "items" in schema && typeof schema.items === "object" && schema.items !== null && typeof schema.items !== "boolean";
|
|
888
|
-
};
|
|
889
|
-
var hasAdditionalProperties = (schema) => {
|
|
890
|
-
return isSchemaObject3(schema) && "additionalProperties" in schema;
|
|
891
|
-
};
|
|
892
|
-
var hasMinLength = (schema) => {
|
|
893
|
-
return isSchemaObject3(schema) && "minLength" in schema && typeof schema.minLength === "number";
|
|
894
|
-
};
|
|
895
|
-
var hasMaxLength = (schema) => {
|
|
896
|
-
return isSchemaObject3(schema) && "maxLength" in schema && typeof schema.maxLength === "number";
|
|
897
|
-
};
|
|
898
|
-
var hasMinimum = (schema) => {
|
|
899
|
-
return isSchemaObject3(schema) && "minimum" in schema && typeof schema.minimum === "number";
|
|
900
|
-
};
|
|
901
|
-
var hasMaximum = (schema) => {
|
|
902
|
-
return isSchemaObject3(schema) && "maximum" in schema && typeof schema.maximum === "number";
|
|
903
|
-
};
|
|
904
|
-
var hasExclusiveMinimum = (schema) => {
|
|
905
|
-
return isSchemaObject3(schema) && "exclusiveMinimum" in schema && typeof schema.exclusiveMinimum === "number";
|
|
906
|
-
};
|
|
907
|
-
var hasExclusiveMaximum = (schema) => {
|
|
908
|
-
return isSchemaObject3(schema) && "exclusiveMaximum" in schema && typeof schema.exclusiveMaximum === "number";
|
|
909
|
-
};
|
|
910
|
-
var hasMultipleOf = (schema) => {
|
|
911
|
-
return isSchemaObject3(schema) && "multipleOf" in schema && typeof schema.multipleOf === "number";
|
|
912
|
-
};
|
|
913
|
-
var hasMinItems = (schema) => {
|
|
914
|
-
return isSchemaObject3(schema) && "minItems" in schema && typeof schema.minItems === "number";
|
|
915
|
-
};
|
|
916
|
-
var hasMaxItems = (schema) => {
|
|
917
|
-
return isSchemaObject3(schema) && "maxItems" in schema && typeof schema.maxItems === "number";
|
|
918
|
-
};
|
|
919
|
-
var hasUniqueItems = (schema) => {
|
|
920
|
-
return isSchemaObject3(schema) && "uniqueItems" in schema && typeof schema.uniqueItems === "boolean";
|
|
921
|
-
};
|
|
922
|
-
|
|
923
|
-
// src/generators/collect-example-imports.ts
|
|
924
|
-
var buildImport = (ref, suffix) => {
|
|
925
|
-
const filename = refToFilename(ref);
|
|
926
|
-
const typeName = refToName(ref, suffix);
|
|
927
|
-
return `import { type ${typeName}, ${typeName}Arbitrary } from './${filename}'`;
|
|
928
|
-
};
|
|
929
|
-
var collectDirectRefs = (schema) => {
|
|
930
|
-
if (typeof schema === "boolean" || schema === null)
|
|
931
|
-
return [];
|
|
932
|
-
const refs = [];
|
|
933
|
-
if (hasRef(schema)) {
|
|
934
|
-
refs.push(schema.$ref);
|
|
935
|
-
return refs;
|
|
936
|
-
}
|
|
937
|
-
const propSchemas = "properties" in schema && typeof schema.properties === "object" && schema.properties !== null ? Object.values(schema.properties) : [];
|
|
938
|
-
for (const prop of propSchemas) {
|
|
939
|
-
if (hasRef(prop))
|
|
940
|
-
refs.push(prop.$ref);
|
|
941
|
-
if (hasItems(prop) && hasRef(prop.items))
|
|
942
|
-
refs.push(prop.items.$ref);
|
|
943
|
-
if (hasAdditionalProperties(prop) && hasRef(prop.additionalProperties)) {
|
|
944
|
-
refs.push(prop.additionalProperties.$ref);
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
if (hasItems(schema) && hasRef(schema.items)) {
|
|
948
|
-
refs.push(schema.items.$ref);
|
|
949
|
-
}
|
|
950
|
-
if (hasAdditionalProperties(schema) && hasRef(schema.additionalProperties)) {
|
|
951
|
-
refs.push(schema.additionalProperties.$ref);
|
|
952
|
-
}
|
|
953
|
-
for (const branch of [
|
|
954
|
-
...hasOneOf(schema) ? schema.oneOf : [],
|
|
955
|
-
...hasAnyOf(schema) ? schema.anyOf : [],
|
|
956
|
-
...hasAllOf(schema) ? schema.allOf : []
|
|
957
|
-
]) {
|
|
958
|
-
if (hasRef(branch))
|
|
959
|
-
refs.push(branch.$ref);
|
|
960
|
-
}
|
|
961
|
-
return refs;
|
|
962
|
-
};
|
|
963
|
-
var collectExampleImports = (schema, options) => {
|
|
964
|
-
const selfFilename = options?.selfRef ? refToFilename(options.selfRef) : null;
|
|
965
|
-
const rootSchema = options?.rootSchema;
|
|
966
|
-
const typeSuffix = options?.typeSuffix ?? "";
|
|
967
|
-
const refs = collectDirectRefs(schema);
|
|
968
|
-
const seen = new Set;
|
|
969
|
-
const imports = [];
|
|
970
|
-
for (const ref of refs) {
|
|
971
|
-
const filename = refToFilename(ref);
|
|
972
|
-
if (seen.has(filename))
|
|
973
|
-
continue;
|
|
974
|
-
if (selfFilename && filename === selfFilename)
|
|
975
|
-
continue;
|
|
976
|
-
if (rootSchema) {
|
|
977
|
-
const resolved = resolveRef(ref, rootSchema);
|
|
978
|
-
if (!resolved)
|
|
979
|
-
continue;
|
|
980
|
-
}
|
|
981
|
-
seen.add(filename);
|
|
982
|
-
imports.push(buildImport(ref, typeSuffix));
|
|
983
|
-
}
|
|
984
|
-
return imports;
|
|
985
|
-
};
|
|
986
|
-
|
|
987
|
-
// ../helpers/dist/mjst-extension.js
|
|
988
|
-
var isSchemaObject4 = (schema) => {
|
|
989
|
-
return typeof schema === "object" && schema !== null && typeof schema !== "boolean";
|
|
990
|
-
};
|
|
991
|
-
var MJST_EXTENSION_KEY2 = "x-mjst";
|
|
992
|
-
var IDENTIFIER2 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
993
|
-
var SUPPORTED_PRIMITIVES2 = new Set(["bigint"]);
|
|
994
|
-
var readExtensionString2 = (schema, field) => {
|
|
995
|
-
if (!isSchemaObject4(schema))
|
|
996
|
-
return;
|
|
997
|
-
const extension = schema[MJST_EXTENSION_KEY2];
|
|
998
|
-
if (typeof extension !== "object" || extension === null)
|
|
999
|
-
return;
|
|
1000
|
-
const value = extension[field];
|
|
1001
|
-
return typeof value === "string" ? value : undefined;
|
|
1002
|
-
};
|
|
1003
|
-
var getMjstInstanceOf2 = (schema) => {
|
|
1004
|
-
const instanceOf = readExtensionString2(schema, "instanceOf");
|
|
1005
|
-
return instanceOf !== undefined && IDENTIFIER2.test(instanceOf) ? instanceOf : undefined;
|
|
1006
|
-
};
|
|
1007
|
-
var getMjstPrimitive2 = (schema) => {
|
|
1008
|
-
const primitive = readExtensionString2(schema, "primitive");
|
|
1009
|
-
return primitive !== undefined && SUPPORTED_PRIMITIVES2.has(primitive) ? primitive : undefined;
|
|
1010
|
-
};
|
|
1011
|
-
|
|
1012
|
-
// src/generators/derive-example.ts
|
|
1013
|
-
var lowerFirst = (name) => name.charAt(0).toLowerCase() + name.slice(1);
|
|
1014
|
-
var exampleName = (typeName) => `${lowerFirst(typeName)}Example`;
|
|
1015
|
-
var exampleString = (schema) => {
|
|
1016
|
-
if (hasFormat(schema)) {
|
|
1017
|
-
switch (schema.format) {
|
|
1018
|
-
case "email":
|
|
1019
|
-
return "user@example.com";
|
|
1020
|
-
case "uuid":
|
|
1021
|
-
return "00000000-0000-0000-0000-000000000000";
|
|
1022
|
-
case "uri":
|
|
1023
|
-
case "url":
|
|
1024
|
-
return "https://example.com";
|
|
1025
|
-
case "date-time":
|
|
1026
|
-
return "1970-01-01T00:00:00.000Z";
|
|
1027
|
-
case "date":
|
|
1028
|
-
return "1970-01-01";
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
let value = "string";
|
|
1032
|
-
if (hasMinLength(schema) && value.length < schema.minLength)
|
|
1033
|
-
value = value.padEnd(schema.minLength, "x");
|
|
1034
|
-
if (hasMaxLength(schema) && value.length > schema.maxLength)
|
|
1035
|
-
value = value.slice(0, schema.maxLength);
|
|
1036
|
-
return value;
|
|
1037
|
-
};
|
|
1038
|
-
var deriveExample = (schema, rootSchema, seen = new Set) => {
|
|
1039
|
-
if (!isSchemaObject3(schema))
|
|
1040
|
-
return null;
|
|
1041
|
-
if (hasConst(schema))
|
|
1042
|
-
return schema.const;
|
|
1043
|
-
if (hasExamples(schema) && Array.isArray(schema.examples) && schema.examples.length > 0)
|
|
1044
|
-
return schema.examples[0];
|
|
1045
|
-
if (hasDefault(schema))
|
|
1046
|
-
return schema.default;
|
|
1047
|
-
if (hasEnum(schema) && schema.enum.length > 0)
|
|
1048
|
-
return schema.enum[0];
|
|
1049
|
-
if (hasRef(schema)) {
|
|
1050
|
-
const ref = schema.$ref;
|
|
1051
|
-
if (seen.has(ref) || !rootSchema)
|
|
1052
|
-
return null;
|
|
1053
|
-
const resolved = resolveRef(ref, rootSchema);
|
|
1054
|
-
if (!resolved)
|
|
1055
|
-
return null;
|
|
1056
|
-
return deriveExample(resolved, rootSchema, new Set([...seen, ref]));
|
|
1057
|
-
}
|
|
1058
|
-
const instanceOf = getMjstInstanceOf2(schema);
|
|
1059
|
-
if (instanceOf === "Date")
|
|
1060
|
-
return new Date(0);
|
|
1061
|
-
const primitive = getMjstPrimitive2(schema);
|
|
1062
|
-
if (primitive === "bigint")
|
|
1063
|
-
return 0n;
|
|
1064
|
-
if (hasOneOf(schema) && schema.oneOf[0] !== undefined)
|
|
1065
|
-
return deriveExample(schema.oneOf[0], rootSchema, seen);
|
|
1066
|
-
if (hasAnyOf(schema) && schema.anyOf[0] !== undefined)
|
|
1067
|
-
return deriveExample(schema.anyOf[0], rootSchema, seen);
|
|
1068
|
-
if (!hasType(schema))
|
|
1069
|
-
return null;
|
|
1070
|
-
switch (schema.type) {
|
|
1071
|
-
case "string":
|
|
1072
|
-
return exampleString(schema);
|
|
1073
|
-
case "number":
|
|
1074
|
-
case "integer":
|
|
1075
|
-
return hasMinimum(schema) ? schema.minimum : 0;
|
|
1076
|
-
case "boolean":
|
|
1077
|
-
return true;
|
|
1078
|
-
case "null":
|
|
1079
|
-
return null;
|
|
1080
|
-
case "array": {
|
|
1081
|
-
const item = hasItems(schema) ? deriveExample(schema.items, rootSchema, seen) : null;
|
|
1082
|
-
const count = hasMinItems(schema) ? Math.max(schema.minItems, 1) : 1;
|
|
1083
|
-
return Array.from({ length: count }, () => item);
|
|
1084
|
-
}
|
|
1085
|
-
case "object": {
|
|
1086
|
-
const out = {};
|
|
1087
|
-
if (hasProperties(schema)) {
|
|
1088
|
-
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
1089
|
-
out[key] = deriveExample(propSchema, rootSchema, seen);
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
return out;
|
|
1093
|
-
}
|
|
1094
|
-
default:
|
|
1095
|
-
return null;
|
|
1096
|
-
}
|
|
1097
|
-
};
|
|
1098
|
-
var serializeValue = (value) => {
|
|
1099
|
-
if (typeof value === "bigint")
|
|
1100
|
-
return `${value}n`;
|
|
1101
|
-
if (value instanceof Date)
|
|
1102
|
-
return `new Date(${JSON.stringify(value.toISOString())})`;
|
|
1103
|
-
if (Array.isArray(value))
|
|
1104
|
-
return `[${value.map(serializeValue).join(", ")}]`;
|
|
1105
|
-
if (value !== null && typeof value === "object") {
|
|
1106
|
-
const entries = Object.entries(value).filter(([, v]) => v !== undefined).map(([key, v]) => `${JSON.stringify(key)}: ${serializeValue(v)}`);
|
|
1107
|
-
return `{ ${entries.join(", ")} }`;
|
|
1108
|
-
}
|
|
1109
|
-
return JSON.stringify(value);
|
|
1110
|
-
};
|
|
1111
|
-
var generateExampleConst = (schema, typeName, rootSchema) => {
|
|
1112
|
-
const value = deriveExample(schema, rootSchema);
|
|
1113
|
-
return `export const ${exampleName(typeName)}: ${typeName} = ${serializeValue(value)}`;
|
|
1114
|
-
};
|
|
1115
|
-
|
|
1116
|
-
// src/generators/generate-arbitrary.ts
|
|
1117
|
-
var arbitraryName = (typeName) => `${typeName}Arbitrary`;
|
|
1118
|
-
var stringExpr = (schema) => {
|
|
1119
|
-
if (hasFormat(schema)) {
|
|
1120
|
-
switch (schema.format) {
|
|
1121
|
-
case "email":
|
|
1122
|
-
return "fc.emailAddress()";
|
|
1123
|
-
case "uuid":
|
|
1124
|
-
return "fc.uuid()";
|
|
1125
|
-
case "uri":
|
|
1126
|
-
case "url":
|
|
1127
|
-
return "fc.webUrl()";
|
|
1128
|
-
case "date-time":
|
|
1129
|
-
return "fc.date({ noInvalidDate: true }).map((d) => d.toISOString())";
|
|
1130
|
-
case "date":
|
|
1131
|
-
return "fc.date({ noInvalidDate: true }).map((d) => d.toISOString().slice(0, 10))";
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
if (hasPattern(schema))
|
|
1135
|
-
return `fc.stringMatching(/${schema.pattern}/)`;
|
|
1136
|
-
const opts = [];
|
|
1137
|
-
if (hasMinLength(schema))
|
|
1138
|
-
opts.push(`minLength: ${schema.minLength}`);
|
|
1139
|
-
if (hasMaxLength(schema))
|
|
1140
|
-
opts.push(`maxLength: ${schema.maxLength}`);
|
|
1141
|
-
return opts.length > 0 ? `fc.string({ ${opts.join(", ")} })` : "fc.string()";
|
|
1142
|
-
};
|
|
1143
|
-
var integerExpr = (schema) => {
|
|
1144
|
-
const opts = [];
|
|
1145
|
-
if (hasMinimum(schema))
|
|
1146
|
-
opts.push(`min: ${schema.minimum}`);
|
|
1147
|
-
else if (hasExclusiveMinimum(schema))
|
|
1148
|
-
opts.push(`min: ${Number(schema.exclusiveMinimum) + 1}`);
|
|
1149
|
-
if (hasMaximum(schema))
|
|
1150
|
-
opts.push(`max: ${schema.maximum}`);
|
|
1151
|
-
else if (hasExclusiveMaximum(schema))
|
|
1152
|
-
opts.push(`max: ${Number(schema.exclusiveMaximum) - 1}`);
|
|
1153
|
-
const base = opts.length > 0 ? `fc.integer({ ${opts.join(", ")} })` : "fc.integer()";
|
|
1154
|
-
return hasMultipleOf(schema) ? `${base}.filter((n) => n % ${schema.multipleOf} === 0)` : base;
|
|
1155
|
-
};
|
|
1156
|
-
var numberExpr = (schema) => {
|
|
1157
|
-
const opts = ["noNaN: true", "noDefaultInfinity: true"];
|
|
1158
|
-
if (hasMinimum(schema))
|
|
1159
|
-
opts.push(`min: ${schema.minimum}`);
|
|
1160
|
-
else if (hasExclusiveMinimum(schema))
|
|
1161
|
-
opts.push(`min: ${schema.exclusiveMinimum}`, "minExcluded: true");
|
|
1162
|
-
if (hasMaximum(schema))
|
|
1163
|
-
opts.push(`max: ${schema.maximum}`);
|
|
1164
|
-
else if (hasExclusiveMaximum(schema))
|
|
1165
|
-
opts.push(`max: ${schema.exclusiveMaximum}`, "maxExcluded: true");
|
|
1166
|
-
const base = `fc.double({ ${opts.join(", ")} })`;
|
|
1167
|
-
return hasMultipleOf(schema) ? `${base}.filter((n) => n % ${schema.multipleOf} === 0)` : base;
|
|
1168
|
-
};
|
|
1169
|
-
var arrayExpr = (schema, suffix) => {
|
|
1170
|
-
const items = hasItems(schema) && isSchemaObject3(schema.items) ? arbitraryExpr(schema.items, suffix) : "fc.anything()";
|
|
1171
|
-
const opts = [];
|
|
1172
|
-
if (hasMinItems(schema))
|
|
1173
|
-
opts.push(`minLength: ${schema.minItems}`);
|
|
1174
|
-
if (hasMaxItems(schema))
|
|
1175
|
-
opts.push(`maxLength: ${schema.maxItems}`);
|
|
1176
|
-
const fn = hasUniqueItems(schema) && schema.uniqueItems === true ? "fc.uniqueArray" : "fc.array";
|
|
1177
|
-
return opts.length > 0 ? `${fn}(${items}, { ${opts.join(", ")} })` : `${fn}(${items})`;
|
|
1178
|
-
};
|
|
1179
|
-
var objectExpr = (schema, suffix) => {
|
|
1180
|
-
if (!hasProperties(schema))
|
|
1181
|
-
return "fc.object()";
|
|
1182
|
-
const required = new Set(hasRequired(schema) ? schema.required : []);
|
|
1183
|
-
const keys = Object.keys(schema.properties);
|
|
1184
|
-
const entries = Object.entries(schema.properties).map(([key, propSchema]) => `${JSON.stringify(key)}: ${arbitraryExpr(propSchema, suffix)}`);
|
|
1185
|
-
if (entries.length === 0)
|
|
1186
|
-
return "fc.record({})";
|
|
1187
|
-
const model = `{ ${entries.join(", ")} }`;
|
|
1188
|
-
if (keys.every((key) => required.has(key)))
|
|
1189
|
-
return `fc.record(${model})`;
|
|
1190
|
-
const requiredKeys = [...required].map((key) => JSON.stringify(key)).join(", ");
|
|
1191
|
-
return `fc.record(${model}, { requiredKeys: [${requiredKeys}] })`;
|
|
1192
|
-
};
|
|
1193
|
-
var oneofExpr = (branches, suffix) => {
|
|
1194
|
-
const exprs = branches.map((branch) => arbitraryExpr(branch, suffix));
|
|
1195
|
-
return `fc.oneof(${exprs.join(", ")})`;
|
|
1196
|
-
};
|
|
1197
|
-
var scalarExpr = (type, schema, suffix) => {
|
|
1198
|
-
switch (type) {
|
|
1199
|
-
case "string":
|
|
1200
|
-
return stringExpr(schema);
|
|
1201
|
-
case "integer":
|
|
1202
|
-
return integerExpr(schema);
|
|
1203
|
-
case "number":
|
|
1204
|
-
return numberExpr(schema);
|
|
1205
|
-
case "boolean":
|
|
1206
|
-
return "fc.boolean()";
|
|
1207
|
-
case "null":
|
|
1208
|
-
return "fc.constant(null)";
|
|
1209
|
-
case "array":
|
|
1210
|
-
return arrayExpr(schema, suffix);
|
|
1211
|
-
case "object":
|
|
1212
|
-
return objectExpr(schema, suffix);
|
|
1213
|
-
default:
|
|
1214
|
-
return "fc.anything()";
|
|
1215
|
-
}
|
|
1216
|
-
};
|
|
1217
|
-
var arbitraryExpr = (schema, suffix) => {
|
|
1218
|
-
if (!isSchemaObject3(schema))
|
|
1219
|
-
return "fc.anything()";
|
|
1220
|
-
if (hasRef(schema))
|
|
1221
|
-
return arbitraryName(refToName(schema.$ref, suffix));
|
|
1222
|
-
if (hasConst(schema))
|
|
1223
|
-
return `fc.constant(${JSON.stringify(schema.const)})`;
|
|
1224
|
-
if (hasEnum(schema)) {
|
|
1225
|
-
const values = schema.enum.map((value) => JSON.stringify(value)).join(", ");
|
|
1226
|
-
return `fc.constantFrom(${values})`;
|
|
1227
|
-
}
|
|
1228
|
-
const instanceOf = getMjstInstanceOf2(schema);
|
|
1229
|
-
if (instanceOf === "Date")
|
|
1230
|
-
return "fc.date({ noInvalidDate: true })";
|
|
1231
|
-
if (instanceOf)
|
|
1232
|
-
return "fc.anything()";
|
|
1233
|
-
const primitive = getMjstPrimitive2(schema);
|
|
1234
|
-
if (primitive === "bigint")
|
|
1235
|
-
return "fc.bigInt()";
|
|
1236
|
-
if (primitive)
|
|
1237
|
-
return "fc.anything()";
|
|
1238
|
-
if (hasOneOf(schema))
|
|
1239
|
-
return oneofExpr(schema.oneOf, suffix);
|
|
1240
|
-
if (hasAnyOf(schema))
|
|
1241
|
-
return oneofExpr(schema.anyOf, suffix);
|
|
1242
|
-
if (hasType(schema))
|
|
1243
|
-
return scalarExpr(schema.type, schema, suffix);
|
|
1244
|
-
return "fc.anything()";
|
|
1245
|
-
};
|
|
1246
|
-
var generateArbitrary = (schema, typeName, suffix = "") => {
|
|
1247
|
-
const expr = arbitraryExpr(schema, suffix);
|
|
1248
|
-
return `export const ${arbitraryName(typeName)}: fc.Arbitrary<${typeName}> = ${expr}`;
|
|
1249
|
-
};
|
|
1250
|
-
|
|
1251
|
-
// src/generators/generate-files.ts
|
|
1252
|
-
var generateExampleFile = (schema, typeName, options) => {
|
|
1253
|
-
const typeSuffix = options?.typeSuffix ?? "";
|
|
1254
|
-
const refImports = collectExampleImports(schema, {
|
|
1255
|
-
selfRef: options?.selfRef,
|
|
1256
|
-
rootSchema: options?.rootSchema,
|
|
1257
|
-
typeSuffix
|
|
1258
|
-
});
|
|
1259
|
-
const typeDefinition = generateTypeDefinition(schema, typeName, { typeSuffix });
|
|
1260
|
-
const arbitrary = generateArbitrary(schema, typeName, typeSuffix);
|
|
1261
|
-
const example = generateExampleConst(schema, typeName, options?.rootSchema);
|
|
1262
|
-
let result = `import * as fc from 'fast-check'
|
|
1263
|
-
`;
|
|
1264
|
-
for (const imp of refImports) {
|
|
1265
|
-
result += imp + `
|
|
1266
|
-
`;
|
|
1267
|
-
}
|
|
1268
|
-
result += `
|
|
1269
|
-
`;
|
|
1270
|
-
result += typeDefinition + `
|
|
1271
|
-
|
|
1272
|
-
` + arbitrary + `
|
|
1273
|
-
|
|
1274
|
-
` + example + `
|
|
1275
|
-
`;
|
|
1276
|
-
return result;
|
|
1277
|
-
};
|
|
1278
|
-
|
|
1279
|
-
// src/generators/build-schema.ts
|
|
1280
|
-
var buildExampleSchema = async (rootSchema, rootTypeName, typeSuffix = "") => {
|
|
1281
|
-
rootSchema = upgradeDraft07Schema(rootSchema);
|
|
1282
|
-
const files = [];
|
|
1283
|
-
const processedRefs = new Set;
|
|
1284
|
-
const processedFilenames = new Set;
|
|
1285
|
-
const refsToProcess = [];
|
|
1286
|
-
const dynamicRefMap = buildDynamicRefMap(rootSchema);
|
|
1287
|
-
const processedRootSchema = resolveDynamicRefs(rootSchema, dynamicRefMap);
|
|
1288
|
-
const rootContent = generateExampleFile(processedRootSchema, rootTypeName, {
|
|
1289
|
-
rootSchema,
|
|
1290
|
-
typeSuffix
|
|
1291
|
-
});
|
|
1292
|
-
const rootFilename = rootTypeName.toLowerCase();
|
|
1293
|
-
if (rootFilename !== "index") {
|
|
1294
|
-
processedFilenames.add(rootFilename);
|
|
1295
|
-
files.push({ filename: `${rootFilename}.ts`, content: rootContent });
|
|
1296
|
-
}
|
|
1297
|
-
const rootRefs = extractRefs(rootSchema);
|
|
1298
|
-
refsToProcess.push(...rootRefs);
|
|
1299
|
-
while (refsToProcess.length > 0) {
|
|
1300
|
-
const ref = refsToProcess.shift();
|
|
1301
|
-
if (!ref || processedRefs.has(ref))
|
|
1302
|
-
continue;
|
|
1303
|
-
processedRefs.add(ref);
|
|
1304
|
-
const resolvedSchema = resolveRef(ref, rootSchema);
|
|
1305
|
-
if (!resolvedSchema) {
|
|
1306
|
-
console.warn(`Warning: Could not resolve ref: ${ref}`);
|
|
1307
|
-
continue;
|
|
1308
|
-
}
|
|
1309
|
-
const typeName = refToName(ref, typeSuffix);
|
|
1310
|
-
const filename = refToFilename(ref);
|
|
1311
|
-
const processedSchema = resolveDynamicRefs(resolvedSchema, dynamicRefMap);
|
|
1312
|
-
const content = generateExampleFile(processedSchema, typeName, {
|
|
1313
|
-
selfRef: ref,
|
|
1314
|
-
rootSchema,
|
|
1315
|
-
typeSuffix
|
|
1316
|
-
});
|
|
1317
|
-
if (filename !== "index" && !processedFilenames.has(filename)) {
|
|
1318
|
-
processedFilenames.add(filename);
|
|
1319
|
-
files.push({ filename: `${filename}.ts`, content });
|
|
1320
|
-
}
|
|
1321
|
-
for (const nestedRef of extractRefs(resolvedSchema)) {
|
|
1322
|
-
if (!processedRefs.has(nestedRef))
|
|
1323
|
-
refsToProcess.push(nestedRef);
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
const TYPE_EXPORT_RE = /^export type (\w+)/gm;
|
|
1327
|
-
const CONST_EXPORT_RE = /^export const (\w+)/gm;
|
|
1328
|
-
const sortedFiles = [...files].sort((a, b) => a.filename.localeCompare(b.filename));
|
|
1329
|
-
let indexContent = "";
|
|
1330
|
-
for (const file of sortedFiles) {
|
|
1331
|
-
const moduleName = file.filename.replace(/\.ts$/, "");
|
|
1332
|
-
const typeNames = [];
|
|
1333
|
-
const constNames = [];
|
|
1334
|
-
for (const match of file.content.matchAll(TYPE_EXPORT_RE))
|
|
1335
|
-
typeNames.push(match[1]);
|
|
1336
|
-
for (const match of file.content.matchAll(CONST_EXPORT_RE))
|
|
1337
|
-
constNames.push(match[1]);
|
|
1338
|
-
if (typeNames.length === 0 && constNames.length === 0)
|
|
1339
|
-
continue;
|
|
1340
|
-
const typeExports = typeNames.map((n) => `type ${n}`);
|
|
1341
|
-
indexContent += `export { ${[...typeExports, ...constNames].join(", ")} } from './${moduleName}';
|
|
1342
|
-
`;
|
|
1343
|
-
}
|
|
1344
|
-
files.push({ filename: "index.ts", content: indexContent });
|
|
1345
|
-
return files;
|
|
1346
|
-
};
|
|
1347
|
-
export {
|
|
1348
|
-
serializeValue,
|
|
1349
|
-
generateExampleConst,
|
|
1350
|
-
generateArbitrary,
|
|
1351
|
-
deriveExample,
|
|
1352
|
-
buildExampleSchema
|
|
1353
|
-
};
|
|
1
|
+
export { buildExampleSchema } from './generators/build-schema.js';
|
|
2
|
+
export { deriveExample, generateExampleConst, serializeValue } from './generators/derive-example.js';
|
|
3
|
+
export { generateArbitrary } from './generators/generate-arbitrary.js';
|