@amritk/generate-examples 0.5.2 → 0.5.4

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,46 +1,29 @@
1
- import { generateTypeDefinition } from '@amritk/helpers/generate-type-definition';
2
- import { collectExampleImports } from './collect-example-imports.js';
3
- import { generateExampleConst } from './derive-example.js';
4
- import { generateArbitrary, VALIDATE_IMPORT_NAME, VALIDATE_IMPORT_STATEMENT } from './generate-arbitrary.js';
5
- /**
6
- * Generates a complete TypeScript example file from a JSON Schema.
7
- *
8
- * The file contains:
9
- * - An import of `fast-check` and imports for any `$ref` types and arbitraries
10
- * - The exported TypeScript type definition
11
- * - An exported `fast-check` arbitrary (`FooArbitrary`)
12
- * - An exported concrete example value (`fooExample`)
13
- *
14
- * @example
15
- * ```typescript
16
- * const schema = { type: 'object', properties: { title: { type: 'string' } }, required: ['title'] }
17
- * generateExampleFile(schema, 'Info')
18
- * // import * as fc from 'fast-check'
19
- * // export type Info = { title: string }
20
- * // export const InfoArbitrary: fc.Arbitrary<Info> = fc.record({ "title": fc.string() })
21
- * // export const infoExample: Info = { "title": "string" }
22
- * ```
23
- */
24
- export const generateExampleFile = (schema, typeName, options) => {
25
- const typeSuffix = options?.typeSuffix ?? '';
26
- const refImports = collectExampleImports(schema, {
27
- selfRef: options?.selfRef,
28
- rootSchema: options?.rootSchema,
29
- typeSuffix,
30
- });
31
- const typeDefinition = generateTypeDefinition(schema, typeName, { typeSuffix });
32
- const arbitrary = generateArbitrary(schema, typeName, typeSuffix, options?.lazyRefFilenames, options?.rootSchema);
33
- const example = generateExampleConst(schema, typeName, options?.rootSchema);
34
- let result = `import * as fc from 'fast-check'\n`;
35
- // The arbitrary embeds a runtime validator only for schemas whose keywords no
36
- // `fc.*` combinator captures; import it just for those files.
37
- if (arbitrary.includes(`${VALIDATE_IMPORT_NAME}(`)) {
38
- result += VALIDATE_IMPORT_STATEMENT + '\n';
39
- }
40
- for (const imp of refImports) {
41
- result += imp + '\n';
42
- }
43
- result += '\n';
44
- result += typeDefinition + '\n\n' + arbitrary + '\n\n' + example + '\n';
45
- return result;
1
+ import { generateTypeDefinition } from "@amritk/helpers/generate-type-definition";
2
+ import { collectExampleImports } from "./collect-example-imports.js";
3
+ import { generateExampleConst } from "./derive-example.js";
4
+ import { generateArbitrary, VALIDATE_IMPORT_NAME, VALIDATE_IMPORT_STATEMENT } from "./generate-arbitrary.js";
5
+ const generateExampleFile = (schema, typeName, options) => {
6
+ const typeSuffix = options?.typeSuffix ?? "";
7
+ const refImports = collectExampleImports(schema, {
8
+ selfRef: options?.selfRef,
9
+ rootSchema: options?.rootSchema,
10
+ typeSuffix
11
+ });
12
+ const typeDefinition = generateTypeDefinition(schema, typeName, { typeSuffix });
13
+ const arbitrary = generateArbitrary(schema, typeName, typeSuffix, options?.lazyRefFilenames, options?.rootSchema);
14
+ const example = generateExampleConst(schema, typeName, options?.rootSchema);
15
+ let result = `import * as fc from 'fast-check'
16
+ `;
17
+ if (arbitrary.includes(`${VALIDATE_IMPORT_NAME}(`)) {
18
+ result += VALIDATE_IMPORT_STATEMENT + "\n";
19
+ }
20
+ for (const imp of refImports) {
21
+ result += imp + "\n";
22
+ }
23
+ result += "\n";
24
+ result += typeDefinition + "\n\n" + arbitrary + "\n\n" + example + "\n";
25
+ return result;
26
+ };
27
+ export {
28
+ generateExampleFile
46
29
  };
@@ -1,83 +1,60 @@
1
- import { isSchemaObject } from '@amritk/helpers/schema-guards';
2
- import { validateGuard } from '@amritk/runtime-validators';
3
- /**
4
- * Keywords the direct generators can't fully honour on their own, so a value they
5
- * produce must be re-checked against a real validator. `oneOf` is included because
6
- * neither path enforces its *exactly-one* exclusivity; `anyOf`/`allOf` are not,
7
- * since a single satisfied branch (already how they are generated) is enough.
8
- */
9
- const FILTER_KEYWORDS = new Set([
10
- 'if',
11
- 'then',
12
- 'else',
13
- 'not',
14
- 'oneOf',
15
- 'patternProperties',
16
- 'propertyNames',
17
- 'dependentRequired',
18
- 'dependentSchemas',
19
- 'dependencies',
20
- 'minProperties',
21
- 'maxProperties',
22
- 'contains',
1
+ import { isSchemaObject } from "@amritk/helpers/schema-guards";
2
+ import { validateGuard } from "@amritk/runtime-validators";
3
+ const FILTER_KEYWORDS = /* @__PURE__ */ new Set([
4
+ "if",
5
+ "then",
6
+ "else",
7
+ "not",
8
+ "oneOf",
9
+ "patternProperties",
10
+ "propertyNames",
11
+ "dependentRequired",
12
+ "dependentSchemas",
13
+ "dependencies",
14
+ "minProperties",
15
+ "maxProperties",
16
+ "contains"
23
17
  ]);
24
- /**
25
- * Keys whose values are *data* (or reference targets), not applied subschemas, so
26
- * a `not`/`if`/… appearing inside them must not be mistaken for an applicator.
27
- * `$defs`/`definitions` hold *unapplied* definitions — a hard keyword there only
28
- * matters once referenced, and each referenced def gets its own generated file.
29
- */
30
- const SKIP_RECURSE = new Set(['enum', 'const', 'examples', 'default', '$ref', 'required', '$defs', 'definitions']);
31
- /**
32
- * True when `schema` (anywhere in its applied subschema tree) uses a keyword the
33
- * direct generators can't guarantee, so the generated value must be run through a
34
- * validating filter. `$ref`s are not followed — a referenced definition is emitted
35
- * as its own self-validating file.
36
- */
37
- export const needsValidationFilter = (schema) => {
38
- const walk = (node) => {
39
- if (Array.isArray(node))
40
- return node.some(walk);
41
- if (node === null || typeof node !== 'object')
42
- return false;
43
- const obj = node;
44
- for (const key of Object.keys(obj)) {
45
- if (FILTER_KEYWORDS.has(key))
46
- return true;
47
- }
48
- for (const [key, value] of Object.entries(obj)) {
49
- if (SKIP_RECURSE.has(key))
50
- continue;
51
- if (walk(value))
52
- return true;
53
- }
54
- return false;
55
- };
56
- return walk(schema);
57
- };
58
- /**
59
- * Returns `schema` augmented with the root document's `$defs`/`definitions` so its
60
- * local `$ref`s (`#/$defs/…`) resolve when it is validated in isolation. The
61
- * schema's own definitions win on collision.
62
- */
63
- export const withResolvableDefs = (schema, rootSchema) => {
64
- const base = isSchemaObject(schema) ? { ...schema } : { const: schema };
65
- if (!rootSchema)
66
- return base;
67
- for (const key of ['$defs', 'definitions']) {
68
- const rootDefs = rootSchema[key];
69
- if (rootDefs && typeof rootDefs === 'object') {
70
- base[key] = { ...rootDefs, ...(base[key] ?? {}) };
71
- }
18
+ const SKIP_RECURSE = /* @__PURE__ */ new Set(["enum", "const", "examples", "default", "$ref", "required", "$defs", "definitions"]);
19
+ const needsValidationFilter = (schema) => {
20
+ const walk = (node) => {
21
+ if (Array.isArray(node))
22
+ return node.some(walk);
23
+ if (node === null || typeof node !== "object")
24
+ return false;
25
+ const obj = node;
26
+ for (const key of Object.keys(obj)) {
27
+ if (FILTER_KEYWORDS.has(key))
28
+ return true;
29
+ }
30
+ for (const [key, value] of Object.entries(obj)) {
31
+ if (SKIP_RECURSE.has(key))
32
+ continue;
33
+ if (walk(value))
34
+ return true;
72
35
  }
36
+ return false;
37
+ };
38
+ return walk(schema);
39
+ };
40
+ const withResolvableDefs = (schema, rootSchema) => {
41
+ const base = isSchemaObject(schema) ? { ...schema } : { const: schema };
42
+ if (!rootSchema)
73
43
  return base;
44
+ for (const key of ["$defs", "definitions"]) {
45
+ const rootDefs = rootSchema[key];
46
+ if (rootDefs && typeof rootDefs === "object") {
47
+ base[key] = { ...rootDefs, ...base[key] ?? {} };
48
+ }
49
+ }
50
+ return base;
51
+ };
52
+ const makeInstanceCheck = (schema, rootSchema) => {
53
+ const guard = validateGuard(withResolvableDefs(schema, rootSchema));
54
+ return (value) => guard(value) === true;
74
55
  };
75
- /**
76
- * Compiles a boolean validator for `schema` (with the root document's definitions
77
- * spliced in so local `$ref`s resolve). Used at generation time to accept/reject
78
- * candidate example values for keywords the deriver can't satisfy structurally.
79
- */
80
- export const makeInstanceCheck = (schema, rootSchema) => {
81
- const guard = validateGuard(withResolvableDefs(schema, rootSchema));
82
- return (value) => guard(value) === true;
56
+ export {
57
+ makeInstanceCheck,
58
+ needsValidationFilter,
59
+ withResolvableDefs
83
60
  };
package/dist/index.js CHANGED
@@ -1,3 +1,10 @@
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';
1
+ import { buildExampleSchema } from "./generators/build-schema.js";
2
+ import { deriveExample, generateExampleConst, serializeValue } from "./generators/derive-example.js";
3
+ import { generateArbitrary } from "./generators/generate-arbitrary.js";
4
+ export {
5
+ buildExampleSchema,
6
+ deriveExample,
7
+ generateArbitrary,
8
+ generateExampleConst,
9
+ serializeValue
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amritk/generate-examples",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "Generate fast-check arbitraries and example values from JSON Schemas.",
5
5
  "module": "./dist/index.js",
6
6
  "type": "module",
@@ -26,13 +26,14 @@
26
26
  "url": "https://github.com/amritk/mjst/issues"
27
27
  },
28
28
  "files": [
29
- "dist"
29
+ "dist",
30
+ "AI.md"
30
31
  ],
31
32
  "publishConfig": {
32
33
  "access": "public"
33
34
  },
34
35
  "scripts": {
35
- "build": "tsgo -p tsconfig.build.json && tsc-alias -p tsconfig.build.json -f",
36
+ "build": "tsgo -p tsconfig.build.json && tsc-alias -p tsconfig.build.json -f && node ../../scripts/strip-comments.mjs",
36
37
  "types:check": "tsgo -p . --noEmit",
37
38
  "test": "NODE_ENV=production vitest run --root ../.. generate-examples"
38
39
  },
@@ -47,8 +48,8 @@
47
48
  },
48
49
  "dependencies": {
49
50
  "json-schema-typed": "^8.0.1",
50
- "@amritk/helpers": "0.13.2",
51
- "@amritk/runtime-validators": "0.7.2"
51
+ "@amritk/helpers": "0.13.4",
52
+ "@amritk/runtime-validators": "0.8.0"
52
53
  },
53
54
  "devDependencies": {
54
55
  "ajv": "^8.17.1"