@quonfig/cli 0.1.0 → 0.2.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/README.md +50 -50
- package/dist/codegen/json-schema-to-zod.js +127 -22
- package/dist/codegen/language-mappers/zod-base-mapper.d.ts +11 -1
- package/dist/codegen/language-mappers/zod-base-mapper.js +14 -2
- package/dist/codegen/language-mappers/zod-to-string-mapper.d.ts +2 -1
- package/dist/codegen/language-mappers/zod-to-string-mapper.js +6 -2
- package/dist/codegen/language-mappers/zod-to-typescript-mapper.d.ts +6 -2
- package/dist/codegen/language-mappers/zod-to-typescript-mapper.js +34 -5
- package/dist/codegen/language-mappers/zod-to-typescript-return-value-mapper.d.ts +6 -3
- package/dist/codegen/language-mappers/zod-to-typescript-return-value-mapper.js +22 -11
- package/dist/codegen/zod-introspection.d.ts +12 -0
- package/dist/codegen/zod-introspection.js +15 -0
- package/dist/commands/push.js +1 -1
- package/dist/commands/verify.js +1 -1
- package/dist/commands/workspace/bootstrap.js +1 -1
- package/dist/migrate/push-to-cloud.js +1 -1
- package/dist/util/git-ops.js +1 -1
- package/dist/verify/schema-error-reshape.d.ts +69 -0
- package/dist/verify/schema-error-reshape.js +257 -0
- package/dist/verify/schema-validator.d.ts +29 -0
- package/dist/verify/schema-validator.js +108 -0
- package/dist/verify/validate.d.ts +14 -2
- package/dist/verify/validate.js +92 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +3 -1
|
@@ -9,6 +9,7 @@ export declare class ZodToStringMapper extends ZodBaseMapper {
|
|
|
9
9
|
function(input: string, output: string): string;
|
|
10
10
|
functionArguments(value?: $ZodFunctionArgs): string;
|
|
11
11
|
functionReturns(value: $ZodFunctionOut): string;
|
|
12
|
+
intersection(left: string, right: string): string;
|
|
12
13
|
literal(value: string | number | boolean | null): string;
|
|
13
14
|
never(): string;
|
|
14
15
|
null(): string;
|
|
@@ -18,7 +19,7 @@ export declare class ZodToStringMapper extends ZodBaseMapper {
|
|
|
18
19
|
record(keyType: string, valueType: string): string;
|
|
19
20
|
renderField(type: z.ZodTypeAny, key?: string): string;
|
|
20
21
|
string(): string;
|
|
21
|
-
tuple(wrappedTypes: string[]): string;
|
|
22
|
+
tuple(wrappedTypes: string[], rest?: string): string;
|
|
22
23
|
undefined(): string;
|
|
23
24
|
union(wrappedTypes: string[]): string;
|
|
24
25
|
unknown(): string;
|
|
@@ -31,6 +31,9 @@ export class ZodToStringMapper extends ZodBaseMapper {
|
|
|
31
31
|
const mapper = new ZodToStringMapper();
|
|
32
32
|
return mapper.resolveType(value);
|
|
33
33
|
}
|
|
34
|
+
intersection(left, right) {
|
|
35
|
+
return `z.intersection(${left}, ${right})`;
|
|
36
|
+
}
|
|
34
37
|
literal(value) {
|
|
35
38
|
return `z.literal(${JSON.stringify(value)})`;
|
|
36
39
|
}
|
|
@@ -72,8 +75,9 @@ export class ZodToStringMapper extends ZodBaseMapper {
|
|
|
72
75
|
string() {
|
|
73
76
|
return 'z.string()';
|
|
74
77
|
}
|
|
75
|
-
tuple(wrappedTypes) {
|
|
76
|
-
|
|
78
|
+
tuple(wrappedTypes, rest) {
|
|
79
|
+
const base = `z.tuple([${wrappedTypes.join(', ')}])`;
|
|
80
|
+
return rest === undefined ? base : `${base}.rest(${rest})`;
|
|
77
81
|
}
|
|
78
82
|
undefined() {
|
|
79
83
|
return 'z.undefined()';
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { $ZodType } from 'zod/v4/core';
|
|
2
3
|
import { ZodTypeSupported } from '../types.js';
|
|
3
4
|
import { ZodBaseMapper } from './zod-base-mapper.js';
|
|
4
5
|
export type ZodToTypescriptMapperTarget = 'accessor' | 'raw';
|
|
5
6
|
export declare class ZodToTypescriptMapper extends ZodBaseMapper {
|
|
6
7
|
private fieldName;
|
|
8
|
+
private metaCaptureOpen;
|
|
7
9
|
private metaDescription;
|
|
8
10
|
private optionalProperty;
|
|
9
11
|
private target;
|
|
@@ -18,6 +20,7 @@ export declare class ZodToTypescriptMapper extends ZodBaseMapper {
|
|
|
18
20
|
function(args: string, returns: string): string;
|
|
19
21
|
functionArguments(value?: z.ZodTuple): string;
|
|
20
22
|
functionReturns(value: z.ZodTypeAny): string;
|
|
23
|
+
intersection(left: string, right: string): string;
|
|
21
24
|
literal(value: string | number | boolean | null): string;
|
|
22
25
|
never(): string;
|
|
23
26
|
null(): string;
|
|
@@ -26,10 +29,11 @@ export declare class ZodToTypescriptMapper extends ZodBaseMapper {
|
|
|
26
29
|
optional(wrappedType: string): string;
|
|
27
30
|
record(keyType: string, valueType: string): string;
|
|
28
31
|
renderField(type: ZodTypeSupported): string;
|
|
32
|
+
resolveType(type: $ZodType): string;
|
|
29
33
|
string(): string;
|
|
30
|
-
tuple(wrappedTypes: string[]): string;
|
|
34
|
+
tuple(wrappedTypes: string[], rest?: string): string;
|
|
31
35
|
undefined(): string;
|
|
32
36
|
union(wrappedTypes: string[]): string;
|
|
33
37
|
unknown(): string;
|
|
34
|
-
protected withMeta(
|
|
38
|
+
protected withMeta(_description: string, resolveType: () => string): string;
|
|
35
39
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import * as introspect from '../zod-introspection.js';
|
|
1
2
|
import { ZodBaseMapper } from './zod-base-mapper.js';
|
|
2
3
|
export class ZodToTypescriptMapper extends ZodBaseMapper {
|
|
3
4
|
fieldName;
|
|
5
|
+
// A field's comment comes from its own meta, looking through optional/nullable/default wrappers only.
|
|
6
|
+
// Meta deeper inside (a union branch title, an array item description) must not become the field's comment.
|
|
7
|
+
metaCaptureOpen = true;
|
|
4
8
|
metaDescription = undefined;
|
|
5
9
|
optionalProperty;
|
|
6
10
|
target;
|
|
@@ -41,6 +45,9 @@ export class ZodToTypescriptMapper extends ZodBaseMapper {
|
|
|
41
45
|
const mapper = new ZodToTypescriptMapper();
|
|
42
46
|
return mapper.resolveType(value);
|
|
43
47
|
}
|
|
48
|
+
intersection(left, right) {
|
|
49
|
+
return [left, right].map((t) => (t.includes(' | ') || t.includes('=>') ? `(${t})` : t)).join(' & ');
|
|
50
|
+
}
|
|
44
51
|
literal(value) {
|
|
45
52
|
return JSON.stringify(value);
|
|
46
53
|
}
|
|
@@ -102,11 +109,34 @@ export class ZodToTypescriptMapper extends ZodBaseMapper {
|
|
|
102
109
|
result += `"${this.fieldName}"${this.optionalProperty ? '?' : ''}: ${resolved}`;
|
|
103
110
|
return result;
|
|
104
111
|
}
|
|
112
|
+
resolveType(type) {
|
|
113
|
+
const wasOpen = this.metaCaptureOpen;
|
|
114
|
+
if (wasOpen) {
|
|
115
|
+
const description = introspect.getMetaDescription(type);
|
|
116
|
+
if (description) {
|
|
117
|
+
this.metaDescription = description;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
this.metaCaptureOpen =
|
|
121
|
+
wasOpen && (introspect.isOptional(type) || introspect.isNullable(type) || introspect.isDefault(type));
|
|
122
|
+
try {
|
|
123
|
+
return super.resolveType(type);
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
this.metaCaptureOpen = wasOpen;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
105
129
|
string() {
|
|
106
130
|
return 'string';
|
|
107
131
|
}
|
|
108
|
-
tuple(wrappedTypes) {
|
|
109
|
-
|
|
132
|
+
tuple(wrappedTypes, rest) {
|
|
133
|
+
const items = [...wrappedTypes];
|
|
134
|
+
if (rest !== undefined) {
|
|
135
|
+
// `...A | B[]` would parse as `...(A | (B[]))`, so wrap anything that isn't a simple type
|
|
136
|
+
const restType = /^[\w ,<>]+$/.test(rest) ? rest : `(${rest})`;
|
|
137
|
+
items.push(`...${restType}[]`);
|
|
138
|
+
}
|
|
139
|
+
return `[${items.join(', ')}]`;
|
|
110
140
|
}
|
|
111
141
|
undefined() {
|
|
112
142
|
return 'undefined';
|
|
@@ -125,9 +155,8 @@ export class ZodToTypescriptMapper extends ZodBaseMapper {
|
|
|
125
155
|
unknown() {
|
|
126
156
|
return 'unknown';
|
|
127
157
|
}
|
|
128
|
-
withMeta(
|
|
129
|
-
//
|
|
130
|
-
this.metaDescription = description;
|
|
158
|
+
withMeta(_description, resolveType) {
|
|
159
|
+
// The description is captured in resolveType, which knows whether it belongs to this field
|
|
131
160
|
return resolveType();
|
|
132
161
|
}
|
|
133
162
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { $ZodType } from 'zod/v4/core';
|
|
2
3
|
import { ZodTypeSupported } from '../types.js';
|
|
3
4
|
import { ZodBaseMapper } from './zod-base-mapper.js';
|
|
4
5
|
export declare class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
|
|
@@ -6,9 +7,9 @@ export declare class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
|
|
|
6
7
|
private FUNCTION_ARGUMENTS_NAME;
|
|
7
8
|
private metaDescription;
|
|
8
9
|
private returnTypePropertyPath;
|
|
9
|
-
constructor({ fieldName, returnTypePropertyPath }?: {
|
|
10
|
+
constructor({ fieldName, returnTypePropertyPath, }?: {
|
|
10
11
|
fieldName?: string;
|
|
11
|
-
returnTypePropertyPath?: string[];
|
|
12
|
+
returnTypePropertyPath?: (number | string)[];
|
|
12
13
|
});
|
|
13
14
|
any(): string;
|
|
14
15
|
array(): string;
|
|
@@ -17,6 +18,7 @@ export declare class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
|
|
|
17
18
|
function(args: string, returns: string): string;
|
|
18
19
|
functionArguments(value?: z.ZodTuple): string;
|
|
19
20
|
functionReturns(): string;
|
|
21
|
+
intersection(): string;
|
|
20
22
|
literal(): string;
|
|
21
23
|
never(): string;
|
|
22
24
|
null(): string;
|
|
@@ -25,8 +27,9 @@ export declare class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
|
|
|
25
27
|
optional(wrappedType: string): string;
|
|
26
28
|
record(): string;
|
|
27
29
|
renderField(type: ZodTypeSupported): string;
|
|
30
|
+
protected resolveTupleItem(item: $ZodType, index: number): string;
|
|
28
31
|
string(): string;
|
|
29
|
-
tuple(wrappedTypes: string[]): string;
|
|
32
|
+
tuple(wrappedTypes: string[], rest?: string): string;
|
|
30
33
|
undefined(): string;
|
|
31
34
|
union(wrappedTypes: string[]): string;
|
|
32
35
|
unknown(): string;
|
|
@@ -3,8 +3,9 @@ export class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
|
|
|
3
3
|
fieldName;
|
|
4
4
|
FUNCTION_ARGUMENTS_NAME = 'params';
|
|
5
5
|
metaDescription = undefined;
|
|
6
|
+
// Strings are property names, numbers are tuple indexes
|
|
6
7
|
returnTypePropertyPath;
|
|
7
|
-
constructor({ fieldName, returnTypePropertyPath } = {}) {
|
|
8
|
+
constructor({ fieldName, returnTypePropertyPath, } = {}) {
|
|
8
9
|
super();
|
|
9
10
|
this.fieldName = fieldName;
|
|
10
11
|
this.returnTypePropertyPath = returnTypePropertyPath ?? [];
|
|
@@ -36,6 +37,10 @@ export class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
|
|
|
36
37
|
functionReturns() {
|
|
37
38
|
return `Mustache.render(raw${this.printPropertyPath()} ?? "", ${this.FUNCTION_ARGUMENTS_NAME})`;
|
|
38
39
|
}
|
|
40
|
+
intersection() {
|
|
41
|
+
// Explicitly not supporting navigation into intersections, pass the raw value through
|
|
42
|
+
return `raw${this.printPropertyPath()}`;
|
|
43
|
+
}
|
|
39
44
|
literal() {
|
|
40
45
|
return `raw${this.printPropertyPath()}`;
|
|
41
46
|
}
|
|
@@ -102,18 +107,24 @@ export class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
|
|
|
102
107
|
this.metaDescription = undefined;
|
|
103
108
|
return result;
|
|
104
109
|
}
|
|
110
|
+
resolveTupleItem(item, index) {
|
|
111
|
+
const mapper = new ZodToTypescriptReturnValueMapper({
|
|
112
|
+
returnTypePropertyPath: [...this.returnTypePropertyPath, index],
|
|
113
|
+
});
|
|
114
|
+
return mapper.resolveType(item);
|
|
115
|
+
}
|
|
105
116
|
string() {
|
|
106
117
|
return `raw${this.printPropertyPath()}`;
|
|
107
118
|
}
|
|
108
|
-
tuple(wrappedTypes) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
119
|
+
tuple(wrappedTypes, rest) {
|
|
120
|
+
// Each fixed item was already resolved at its own index by resolveTupleItem
|
|
121
|
+
const tupleNavigation = [...wrappedTypes];
|
|
122
|
+
if (rest !== undefined) {
|
|
123
|
+
// Pass the remaining items through untouched; truncating to the fixed items would drop data at runtime.
|
|
124
|
+
// Mustache is never extracted inside arrays, so the rest needs no per-item mapping.
|
|
125
|
+
const path = this.printPropertyPath().replace(/!$/, '');
|
|
126
|
+
tupleNavigation.push(`...(raw${path}?.slice(${wrappedTypes.length}) ?? [])`);
|
|
127
|
+
}
|
|
117
128
|
return `[${tupleNavigation.join(`, `)}]`;
|
|
118
129
|
}
|
|
119
130
|
undefined() {
|
|
@@ -140,7 +151,7 @@ export class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
|
|
|
140
151
|
return '';
|
|
141
152
|
}
|
|
142
153
|
// Always safe navigate the path to ensure we don't throw an error if the property doesn't exist
|
|
143
|
-
const path = paths.reduce((acc, part) => `${acc}?.['${part}']
|
|
154
|
+
const path = paths.reduce((acc, part) => (typeof part === 'number' ? `${acc}?.[${part}]` : `${acc}?.['${part}']`), '');
|
|
144
155
|
// To satisfy TypeScript's type system, tell it the value is always defined
|
|
145
156
|
return `${path}!`;
|
|
146
157
|
}
|
|
@@ -12,6 +12,7 @@ export declare function isAny(schema: $ZodType): schema is z.ZodAny;
|
|
|
12
12
|
export declare function isArray(schema: $ZodType): schema is z.ZodArray<z.ZodTypeAny>;
|
|
13
13
|
export declare function isObject(schema: $ZodType): schema is z.ZodObject<z.ZodRawShape>;
|
|
14
14
|
export declare function isTuple(schema: $ZodType): schema is z.ZodTuple;
|
|
15
|
+
export declare function isIntersection(schema: $ZodType): schema is z.ZodIntersection<z.ZodTypeAny, z.ZodTypeAny>;
|
|
15
16
|
export declare function isRecord(schema: $ZodType): schema is z.ZodRecord;
|
|
16
17
|
export declare function isEnum(schema: $ZodType): schema is z.ZodEnum<util.EnumLike>;
|
|
17
18
|
export declare function isUnion(schema: $ZodType): schema is z.ZodUnion<[z.ZodTypeAny, ...z.ZodTypeAny[]]>;
|
|
@@ -31,6 +32,17 @@ export declare function getObjectShape(schema: z.ZodObject<z.ZodRawShape>): z.Zo
|
|
|
31
32
|
* Gets the items from a tuple schema
|
|
32
33
|
*/
|
|
33
34
|
export declare function getTupleItems(schema: z.ZodTuple): readonly $ZodType[];
|
|
35
|
+
/**
|
|
36
|
+
* Gets the rest element from a tuple schema (`z.tuple([...]).rest(x)`), or undefined when it has none
|
|
37
|
+
*/
|
|
38
|
+
export declare function getTupleRest(schema: z.ZodTuple): $ZodType | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Gets both sides of an intersection schema
|
|
41
|
+
*/
|
|
42
|
+
export declare function getIntersectionTypes(schema: z.ZodIntersection<z.ZodTypeAny, z.ZodTypeAny>): {
|
|
43
|
+
left: $ZodType;
|
|
44
|
+
right: $ZodType;
|
|
45
|
+
};
|
|
34
46
|
/**
|
|
35
47
|
* Gets the key and value types from a record schema
|
|
36
48
|
*/
|
|
@@ -38,6 +38,9 @@ export function isObject(schema) {
|
|
|
38
38
|
export function isTuple(schema) {
|
|
39
39
|
return schema instanceof z.ZodTuple;
|
|
40
40
|
}
|
|
41
|
+
export function isIntersection(schema) {
|
|
42
|
+
return schema instanceof z.ZodIntersection;
|
|
43
|
+
}
|
|
41
44
|
export function isRecord(schema) {
|
|
42
45
|
return schema instanceof z.ZodRecord;
|
|
43
46
|
}
|
|
@@ -83,6 +86,18 @@ export function getObjectShape(schema) {
|
|
|
83
86
|
export function getTupleItems(schema) {
|
|
84
87
|
return schema.def.items;
|
|
85
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Gets the rest element from a tuple schema (`z.tuple([...]).rest(x)`), or undefined when it has none
|
|
91
|
+
*/
|
|
92
|
+
export function getTupleRest(schema) {
|
|
93
|
+
return schema.def.rest ?? undefined;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Gets both sides of an intersection schema
|
|
97
|
+
*/
|
|
98
|
+
export function getIntersectionTypes(schema) {
|
|
99
|
+
return { left: schema.def.left, right: schema.def.right };
|
|
100
|
+
}
|
|
86
101
|
/**
|
|
87
102
|
* Gets the key and value types from a record schema
|
|
88
103
|
*/
|
package/dist/commands/push.js
CHANGED
|
@@ -334,7 +334,7 @@ export function buildRealDeps(cmd, orgSlug) {
|
|
|
334
334
|
},
|
|
335
335
|
async validate(dir) {
|
|
336
336
|
const { validateWorkspace } = await import('../verify/validate.js');
|
|
337
|
-
const result = validateWorkspace(dir);
|
|
337
|
+
const result = validateWorkspace(dir, { validateValues: true });
|
|
338
338
|
const errors = result.issues.filter((i) => i.severity === 'error').map((i) => i.message);
|
|
339
339
|
return { errors };
|
|
340
340
|
},
|
package/dist/commands/verify.js
CHANGED
|
@@ -23,7 +23,7 @@ export default class Verify extends BaseCommand {
|
|
|
23
23
|
async run() {
|
|
24
24
|
const { args, flags } = await this.parse(Verify);
|
|
25
25
|
const dir = args.path;
|
|
26
|
-
const result = validateWorkspace(dir);
|
|
26
|
+
const result = validateWorkspace(dir, { validateValues: true });
|
|
27
27
|
if (flags.strict) {
|
|
28
28
|
// Promote warnings to errors
|
|
29
29
|
for (const issue of result.issues) {
|
|
@@ -83,7 +83,7 @@ export default class WorkspaceBootstrap extends BaseCommand {
|
|
|
83
83
|
this.log('Verifying config files...');
|
|
84
84
|
try {
|
|
85
85
|
const { validateWorkspace } = await import('../../verify/validate.js');
|
|
86
|
-
const result = validateWorkspace(resolvedDir);
|
|
86
|
+
const result = validateWorkspace(resolvedDir, { validateValues: true });
|
|
87
87
|
const errors = result.issues.filter((i) => i.severity === 'error');
|
|
88
88
|
if (errors.length > 0) {
|
|
89
89
|
this.log(`\nFound ${errors.length} validation error(s):\n`);
|
|
@@ -47,7 +47,7 @@ const verifyOnDisk = (dir) => {
|
|
|
47
47
|
// qfg-52qg: client-side verify against the cumulative tree before commit
|
|
48
48
|
// lands. The Gitea pre-receive hook runs against the final HEAD; failing
|
|
49
49
|
// here matches what the server would reject and avoids a wasted push.
|
|
50
|
-
const verifyResult = validateWorkspace(dir);
|
|
50
|
+
const verifyResult = validateWorkspace(dir, { validateValues: true });
|
|
51
51
|
if (!verifyResult.valid)
|
|
52
52
|
throw new MigratorVerifyError(verifyResult);
|
|
53
53
|
};
|
package/dist/util/git-ops.js
CHANGED
|
@@ -509,7 +509,7 @@ const removeWorktree = async (dir, worktree) => {
|
|
|
509
509
|
*/
|
|
510
510
|
const requireWorkspaceValidates = async (tree) => {
|
|
511
511
|
const { validateWorkspace } = await import('../verify/validate.js');
|
|
512
|
-
const errors = validateWorkspace(tree).issues.filter((i) => i.severity === 'error');
|
|
512
|
+
const errors = validateWorkspace(tree, { validateValues: true }).issues.filter((i) => i.severity === 'error');
|
|
513
513
|
if (errors.length === 0)
|
|
514
514
|
return;
|
|
515
515
|
const shown = errors.slice(0, 10).map((i) => ` ${i.file}: ${i.message}`);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ajv errors -> readable `{ path, message }` violations (qfg-q5f6.1).
|
|
3
|
+
*
|
|
4
|
+
* SELF-CONTAINED ON PURPOSE. This file has no imports: it is copied verbatim
|
|
5
|
+
* into `cli/src/verify/` so `qfg verify`, the app server and the browser
|
|
6
|
+
* (list badge, view page) word every violation the same way. Change it here
|
|
7
|
+
* first and re-copy; do not let the two drift.
|
|
8
|
+
*
|
|
9
|
+
* It works on any error object shaped like Ajv's `ErrorObject` (keyword,
|
|
10
|
+
* instancePath, schemaPath, params, message), from Ajv run with
|
|
11
|
+
* `allErrors: true`.
|
|
12
|
+
*
|
|
13
|
+
* Tagged `oneOf` (plan 2026-09-25-advanced-schema-for-jev.md, W1): Ajv
|
|
14
|
+
* reports every branch's failures, which for a three-way union is mostly
|
|
15
|
+
* noise. When every branch is an object with the same `const` (or one-value
|
|
16
|
+
* `enum`) property, that property is the tag:
|
|
17
|
+
* - the value's tag picks a branch -> only that branch's errors are kept;
|
|
18
|
+
* - the tag is missing or unknown -> ONE error:
|
|
19
|
+
* "`type` must be one of noul, score, choice".
|
|
20
|
+
* A `oneOf` without a tag is left as Ajv reported it.
|
|
21
|
+
*/
|
|
22
|
+
/** The subset of Ajv's `ErrorObject` this module reads. */
|
|
23
|
+
export interface SchemaErrorLike {
|
|
24
|
+
keyword: string;
|
|
25
|
+
instancePath: string;
|
|
26
|
+
schemaPath: string;
|
|
27
|
+
params: object;
|
|
28
|
+
message?: string;
|
|
29
|
+
propertyName?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface SchemaViolation {
|
|
32
|
+
/** Dotted path inside the value (`criteria[1]`, `a.b`); "" for the root. */
|
|
33
|
+
path: string;
|
|
34
|
+
message: string;
|
|
35
|
+
}
|
|
36
|
+
/** Keyword of the single error that replaces a missing/unknown-tag `oneOf`. */
|
|
37
|
+
export declare const ONE_OF_TAG_KEYWORD = "oneOfTag";
|
|
38
|
+
/**
|
|
39
|
+
* Ajv `instancePath` (JSON pointer) -> dotted path:
|
|
40
|
+
* `/questions/tone/criteria/1` -> `questions.tone.criteria[1]`.
|
|
41
|
+
* Walks the value so only real array indexes become `[n]`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function instancePathToDotted(instancePath: string, value: unknown): string;
|
|
44
|
+
export interface OneOfTag {
|
|
45
|
+
/** The tag property name, e.g. `type`. */
|
|
46
|
+
name: string;
|
|
47
|
+
/** Tag value of each branch, in branch order. */
|
|
48
|
+
values: unknown[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Find the tag of a `oneOf`: the ONE property that is a `const` (or a
|
|
52
|
+
* one-value `enum`) in every branch, with distinct values. Undefined when
|
|
53
|
+
* there is none, or more than one candidate.
|
|
54
|
+
*/
|
|
55
|
+
export declare function findOneOfTag(branches: unknown[], root: unknown): OneOfTag | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Collapse tagged `oneOf` noise. Returns a new list in Ajv's order: errors
|
|
58
|
+
* from non-selected branches are dropped, and a missing/unknown tag becomes
|
|
59
|
+
* a single `oneOfTag` error at the union's position.
|
|
60
|
+
*/
|
|
61
|
+
export declare function reshapeOneOfErrors<E extends SchemaErrorLike>(errors: readonly E[], rootSchema: unknown, value: unknown): (E | SchemaErrorLike)[];
|
|
62
|
+
/** One error -> message. Undefined means "skip it, a nested error says why". */
|
|
63
|
+
export declare function describeSchemaError(error: SchemaErrorLike): string | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Ajv errors for `value` against `rootSchema` -> violations, with tagged
|
|
66
|
+
* `oneOf` noise collapsed. Call it only when validation failed: it never
|
|
67
|
+
* returns an empty list.
|
|
68
|
+
*/
|
|
69
|
+
export declare function schemaErrorsToViolations(errors: readonly SchemaErrorLike[], rootSchema: unknown, value: unknown): SchemaViolation[];
|