@amritk/generate-examples 0.6.3 → 0.7.0
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/AI.md +19 -0
- package/README.md +56 -1
- package/dist/generators/assert-generator-depth.d.ts +28 -0
- package/dist/generators/assert-generator-depth.js +10 -0
- package/dist/generators/closed-value-set.d.ts +14 -0
- package/dist/generators/closed-value-set.js +20 -0
- package/dist/generators/collect-example-imports.js +9 -3
- package/dist/generators/derive-example.js +154 -89
- package/dist/generators/generate-arbitrary.js +187 -96
- package/dist/generators/generate-files.js +3 -2
- package/dist/generators/is-object-like.d.ts +47 -0
- package/dist/generators/is-object-like.js +23 -0
- package/dist/generators/satisfies-scalar-constraints.d.ts +17 -0
- package/dist/generators/satisfies-scalar-constraints.js +34 -0
- package/dist/generators/schema-validation.d.ts +12 -0
- package/dist/generators/schema-validation.js +70 -9
- package/package.json +3 -3
|
@@ -16,23 +16,47 @@ const FILTER_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
16
16
|
"maxProperties",
|
|
17
17
|
"contains"
|
|
18
18
|
]);
|
|
19
|
-
const
|
|
19
|
+
const SCHEMA_MAPS = /* @__PURE__ */ new Set([
|
|
20
|
+
"properties",
|
|
21
|
+
"patternProperties",
|
|
22
|
+
"$defs",
|
|
23
|
+
"definitions",
|
|
24
|
+
"dependentSchemas",
|
|
25
|
+
"dependencies"
|
|
26
|
+
]);
|
|
27
|
+
const SKIP_RECURSE = /* @__PURE__ */ new Set([
|
|
28
|
+
// The data keywords, matching `@amritk/helpers`' `DATA_KEYWORDS` —
|
|
29
|
+
// `example` is OpenAPI 3.0's singular spelling and belongs with `examples`.
|
|
30
|
+
"enum",
|
|
31
|
+
"const",
|
|
32
|
+
"examples",
|
|
33
|
+
"example",
|
|
34
|
+
"default",
|
|
35
|
+
// Plus this walker's own additions, which are not data but are equally not
|
|
36
|
+
// applied here.
|
|
37
|
+
"$ref",
|
|
38
|
+
"required",
|
|
39
|
+
"$defs",
|
|
40
|
+
"definitions"
|
|
41
|
+
]);
|
|
20
42
|
const filterAnswers = /* @__PURE__ */ new WeakMap();
|
|
21
43
|
const needsValidationFilter = (schema) => {
|
|
22
|
-
const walk = (node) => {
|
|
44
|
+
const walk = (node, inSchemaMap = false) => {
|
|
23
45
|
if (Array.isArray(node))
|
|
24
|
-
return node.some(walk);
|
|
46
|
+
return node.some((item) => walk(item, inSchemaMap));
|
|
25
47
|
if (node === null || typeof node !== "object")
|
|
26
48
|
return false;
|
|
27
49
|
const obj = node;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
50
|
+
if (!inSchemaMap) {
|
|
51
|
+
for (const key of Object.keys(obj)) {
|
|
52
|
+
if (FILTER_KEYWORDS.has(key))
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
31
55
|
}
|
|
32
|
-
for (const
|
|
33
|
-
if (SKIP_RECURSE.has(key))
|
|
56
|
+
for (const key of Object.keys(obj)) {
|
|
57
|
+
if (!inSchemaMap && SKIP_RECURSE.has(key))
|
|
34
58
|
continue;
|
|
35
|
-
if (walk(
|
|
59
|
+
if (walk(obj[key], !inSchemaMap && SCHEMA_MAPS.has(key)))
|
|
36
60
|
return true;
|
|
37
61
|
}
|
|
38
62
|
return false;
|
|
@@ -138,6 +162,7 @@ const spliceDefs = (schema, rootSchema) => {
|
|
|
138
162
|
};
|
|
139
163
|
const WARNING_SCHEMA_LIMIT = 240;
|
|
140
164
|
const reportedGuardFailures = /* @__PURE__ */ new Set();
|
|
165
|
+
const MAX_REPORTED_GUARD_FAILURES = 1e3;
|
|
141
166
|
const describeSchema = (schema) => {
|
|
142
167
|
const serialized = (() => {
|
|
143
168
|
try {
|
|
@@ -155,6 +180,8 @@ const warnUndecidableSchema = (schema, reason) => {
|
|
|
155
180
|
${described}`;
|
|
156
181
|
if (reportedGuardFailures.has(key))
|
|
157
182
|
return;
|
|
183
|
+
if (reportedGuardFailures.size >= MAX_REPORTED_GUARD_FAILURES)
|
|
184
|
+
reportedGuardFailures.clear();
|
|
158
185
|
reportedGuardFailures.add(key);
|
|
159
186
|
console.warn(`Warning: cannot validate generated values against ${described} \u2014 ${message}. Every candidate value is accepted for this subschema, so constraints only the validator enforces (\`oneOf\`, \`not\`, \`pattern\`, \`if\`/\`then\`, \u2026) go unchecked there and the emitted example may not satisfy its own schema. Generation continues regardless; the usual causes are a \`$ref\` pointing outside this fragment and a \`pattern\` the ReDoS screen rejects.`);
|
|
160
187
|
};
|
|
@@ -166,6 +193,39 @@ const tryGuard = (schema, checkFormats) => {
|
|
|
166
193
|
return void 0;
|
|
167
194
|
}
|
|
168
195
|
};
|
|
196
|
+
const everyPatternCompiles = (node) => {
|
|
197
|
+
if (node === null || typeof node !== "object")
|
|
198
|
+
return true;
|
|
199
|
+
if (Array.isArray(node))
|
|
200
|
+
return node.every(everyPatternCompiles);
|
|
201
|
+
const compiles = (source) => {
|
|
202
|
+
try {
|
|
203
|
+
new RegExp(source);
|
|
204
|
+
return true;
|
|
205
|
+
} catch {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
for (const [key, value] of Object.entries(node)) {
|
|
210
|
+
if (key === "pattern" && typeof value === "string" && !compiles(value))
|
|
211
|
+
return false;
|
|
212
|
+
if (key === "patternProperties" && value !== null && typeof value === "object") {
|
|
213
|
+
if (!Object.keys(value).every(compiles))
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
if (!everyPatternCompiles(value))
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
220
|
+
};
|
|
221
|
+
const canBuildGuard = (schema, rootSchema) => {
|
|
222
|
+
const resolved = withResolvableDefs(schema, rootSchema);
|
|
223
|
+
if (!everyPatternCompiles(resolved)) {
|
|
224
|
+
warnUndecidableSchema(resolved, "the schema carries a `pattern` that is not a valid regular expression");
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
return tryGuard(resolved, false) !== void 0;
|
|
228
|
+
};
|
|
169
229
|
const makeInstanceCheck = (schema, rootSchema, options) => {
|
|
170
230
|
const resolved = withResolvableDefs(schema, rootSchema);
|
|
171
231
|
const guard = tryGuard(resolved, options?.checkFormats === true);
|
|
@@ -181,6 +241,7 @@ const makeInstanceCheck = (schema, rootSchema, options) => {
|
|
|
181
241
|
};
|
|
182
242
|
};
|
|
183
243
|
export {
|
|
244
|
+
canBuildGuard,
|
|
184
245
|
makeInstanceCheck,
|
|
185
246
|
needsValidationFilter,
|
|
186
247
|
withResolvableDefs
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amritk/generate-examples",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Generate fast-check arbitraries and example values from JSON Schemas.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"json-schema-typed": "^8.0.1",
|
|
58
|
-
"@amritk/helpers": "^0.
|
|
59
|
-
"@amritk/runtime-validators": "^0.
|
|
58
|
+
"@amritk/helpers": "^0.16.0",
|
|
59
|
+
"@amritk/runtime-validators": "^0.12.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"ajv": "^8.17.1"
|