@amritk/generate-validators 0.16.0 → 0.17.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 +13 -6
- package/README.md +36 -16
- package/dist/generators/build-schema.d.ts +2 -2
- package/dist/generators/build-schema.js +23 -3
- package/dist/generators/emit-format-checks.d.ts +50 -0
- package/dist/generators/emit-format-checks.js +248 -0
- package/dist/generators/enforced-keywords.d.ts +16 -4
- package/dist/generators/enforced-keywords.js +13 -3
- package/dist/generators/folds-to-constant.d.ts +1 -1
- package/dist/generators/folds-to-constant.js +6 -2
- package/dist/generators/generate-files.d.ts +7 -0
- package/dist/generators/generate-files.js +10 -2
- package/dist/generators/generate-validator-function.d.ts +2 -2
- package/dist/generators/generate-validator-function.js +103 -75
- package/package.json +4 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isSchemaObject } from "@amritk/helpers/schema-guards";
|
|
2
|
+
import { enforcesFormat, NO_FORMATS } from "./enforced-keywords.js";
|
|
2
3
|
const ANNOTATION_KEYWORDS = /* @__PURE__ */ new Set([
|
|
3
4
|
"$anchor",
|
|
4
5
|
"$comment",
|
|
@@ -25,14 +26,17 @@ const ANNOTATION_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
25
26
|
"writeOnly",
|
|
26
27
|
"xml"
|
|
27
28
|
]);
|
|
28
|
-
const foldsToConstant = (schema) => {
|
|
29
|
+
const foldsToConstant = (schema, formats = NO_FORMATS) => {
|
|
29
30
|
if (schema === true)
|
|
30
31
|
return true;
|
|
31
32
|
if (schema === false)
|
|
32
33
|
return false;
|
|
33
34
|
if (!isSchemaObject(schema))
|
|
34
35
|
return void 0;
|
|
35
|
-
|
|
36
|
+
const record = schema;
|
|
37
|
+
if (enforcesFormat(record, formats))
|
|
38
|
+
return void 0;
|
|
39
|
+
return Object.keys(record).every((key) => ANNOTATION_KEYWORDS.has(key)) ? true : void 0;
|
|
36
40
|
};
|
|
37
41
|
export {
|
|
38
42
|
foldsToConstant
|
|
@@ -24,6 +24,13 @@ type GenerateValidatorFileOptions = {
|
|
|
24
24
|
* {@link UnknownKeysStrategy} for the trade-off between the two.
|
|
25
25
|
*/
|
|
26
26
|
readonly unknownKeys?: UnknownKeysStrategy;
|
|
27
|
+
/**
|
|
28
|
+
* The `format` names this build enforces. Empty (the default) leaves `format`
|
|
29
|
+
* an annotation, as 2020-12 reads it; a name here makes the generated
|
|
30
|
+
* `validateX` and `isX` both check it, against a `formats.ts` emitted
|
|
31
|
+
* alongside.
|
|
32
|
+
*/
|
|
33
|
+
readonly formats?: ReadonlySet<string>;
|
|
27
34
|
};
|
|
28
35
|
/**
|
|
29
36
|
* Generates a complete TypeScript validator file from a JSON Schema.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { generateTypeDefinition } from "@amritk/helpers/generate-type-definition";
|
|
2
2
|
import { DEFAULT_UNKNOWN_KEYS } from "@amritk/helpers/unknown-keys-strategy";
|
|
3
3
|
import { collectValidatorImports } from "./collect-validator-imports.js";
|
|
4
|
+
import { formatCheckName } from "./emit-format-checks.js";
|
|
5
|
+
import { NO_FORMATS } from "./enforced-keywords.js";
|
|
4
6
|
import { generateBooleanGuard, generateValidatorFunction } from "./generate-validator-function.js";
|
|
5
7
|
const escapeForWordMatch = (name) => name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6
8
|
const generateValidatorFile = (schema, typeName, options) => {
|
|
@@ -10,8 +12,9 @@ const generateValidatorFile = (schema, typeName, options) => {
|
|
|
10
12
|
...options?.rootSchema !== void 0 ? { rootSchema: options.rootSchema } : {}
|
|
11
13
|
});
|
|
12
14
|
const unknownKeys = options?.unknownKeys ?? DEFAULT_UNKNOWN_KEYS;
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
+
const formats = options?.formats ?? NO_FORMATS;
|
|
16
|
+
const validatorFunction = generateValidatorFunction(schema, typeName, typeSuffix, options?.rootSchema, unknownKeys, formats);
|
|
17
|
+
const booleanGuard = generateBooleanGuard(schema, typeName, typeSuffix, unknownKeys, formats);
|
|
15
18
|
const body = validatorFunction + booleanGuard;
|
|
16
19
|
const emitted = typeDefinition + body;
|
|
17
20
|
const mentions = (name) => new RegExp(`\\b${escapeForWordMatch(name)}\\b`).test(emitted);
|
|
@@ -30,6 +33,11 @@ const generateValidatorFile = (schema, typeName, options) => {
|
|
|
30
33
|
const runtimeHelpers = ["valuesEqual", "allUnique", "escapePointer", "everyItem"].filter((name) => body.includes(`${name}(`));
|
|
31
34
|
if (runtimeHelpers.length > 0) {
|
|
32
35
|
result += `import { ${runtimeHelpers.join(", ")} } from './validation-result.js'
|
|
36
|
+
`;
|
|
37
|
+
}
|
|
38
|
+
const formatChecks = [...formats].map(formatCheckName).filter((name) => body.includes(`${name}(`)).sort();
|
|
39
|
+
if (formatChecks.length > 0) {
|
|
40
|
+
result += `import { ${formatChecks.join(", ")} } from './formats.js'
|
|
33
41
|
`;
|
|
34
42
|
}
|
|
35
43
|
for (const imp of refImports) {
|
|
@@ -16,7 +16,7 @@ import type { JSONSchema } from 'json-schema-typed/draft-2020-12';
|
|
|
16
16
|
* `unknownKeys` picks how a closed object's no-extras test counts keys — see
|
|
17
17
|
* {@link UnknownKeysStrategy}.
|
|
18
18
|
*/
|
|
19
|
-
export declare const generateBooleanGuard: (schema: JSONSchema, typeName: string, _suffix?: string, unknownKeys?: UnknownKeysStrategy) => string;
|
|
19
|
+
export declare const generateBooleanGuard: (schema: JSONSchema, typeName: string, _suffix?: string, unknownKeys?: UnknownKeysStrategy, formats?: ReadonlySet<string>) => string;
|
|
20
20
|
/**
|
|
21
21
|
* Generates a TypeScript validator function from a JSON Schema.
|
|
22
22
|
*
|
|
@@ -39,4 +39,4 @@ export declare const generateBooleanGuard: (schema: JSONSchema, typeName: string
|
|
|
39
39
|
* // }
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
|
-
export declare const generateValidatorFunction: (schema: JSONSchema, typeName: string, suffix?: string, rootSchema?: Record<string, unknown>, unknownKeys?: UnknownKeysStrategy) => string;
|
|
42
|
+
export declare const generateValidatorFunction: (schema: JSONSchema, typeName: string, suffix?: string, rootSchema?: Record<string, unknown>, unknownKeys?: UnknownKeysStrategy, formats?: ReadonlySet<string>) => string;
|