@versionzero/schema 1.0.1 → 1.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/package.json +1 -1
- package/src/compiled-schema.js +1 -1
- package/src/schema-resolver.js +48 -18
- package/src/traversal/traversal-context.js +11 -2
- package/src/value-processor/value-processor.js +2 -0
- package/types/schema-resolver.d.ts +17 -7
- package/types/traversal/traversal-context.d.ts +5 -0
- package/types/value-processor/value-processor.d.ts +4 -0
package/package.json
CHANGED
package/src/compiled-schema.js
CHANGED
|
@@ -1256,7 +1256,7 @@ export class CompiledSchema
|
|
|
1256
1256
|
*/
|
|
1257
1257
|
_process(input, target, options = {}) {
|
|
1258
1258
|
const location = options?.location ?? new SchemaLocation(this);
|
|
1259
|
-
const context = (options.context instanceof TraversalContext) ? options.context : new TraversalContext(location, {strict: options?.strict, deep: options?.deep, debug: options?.debug});
|
|
1259
|
+
const context = (options.context instanceof TraversalContext) ? options.context : new TraversalContext(location, {strict: options?.strict, deep: options?.deep, debug: options?.debug, stats: options?.stats});
|
|
1260
1260
|
|
|
1261
1261
|
const executors = [];
|
|
1262
1262
|
|
package/src/schema-resolver.js
CHANGED
|
@@ -51,6 +51,8 @@ export function registerCoreLibrary(libraryFn) {
|
|
|
51
51
|
/** @import { SchemaData } from './types.js' */
|
|
52
52
|
/** @import { ValueProcessorDefinition, ValueProcessorSpec, ValueProcessorBuilder, ValueProcessorFunction, ValueProcessorArgs, ValueProcessorParameter, KeywordValueProcessorSpec } from './value-processor/value-processor.js' */
|
|
53
53
|
|
|
54
|
+
/** @typedef {{name:string, namespace?:string, schema:Schema}} RegisteredSchemaInfo */
|
|
55
|
+
|
|
54
56
|
/**
|
|
55
57
|
* The SchemaResolver uses its internal registries of named schemas and value processor keywords to
|
|
56
58
|
* convert Schemas containing unresolved references into resolved Schemas that are fully self-contained.
|
|
@@ -58,7 +60,7 @@ export function registerCoreLibrary(libraryFn) {
|
|
|
58
60
|
export class SchemaResolver
|
|
59
61
|
{
|
|
60
62
|
/**
|
|
61
|
-
* @type {Map<string,
|
|
63
|
+
* @type {Map<string,RegisteredSchemaInfo>}
|
|
62
64
|
*/
|
|
63
65
|
#schemaMap = new Map();
|
|
64
66
|
/**
|
|
@@ -85,7 +87,7 @@ export class SchemaResolver
|
|
|
85
87
|
throw new ResolverError(`Registry can only store Schema instances`);
|
|
86
88
|
}
|
|
87
89
|
const registryName = toKebabCase(name);
|
|
88
|
-
this.#schemaMap.set(registryName, schema);
|
|
90
|
+
this.#schemaMap.set(registryName, {name: registryName, schema});
|
|
89
91
|
return this;
|
|
90
92
|
}
|
|
91
93
|
|
|
@@ -96,11 +98,11 @@ export class SchemaResolver
|
|
|
96
98
|
*/
|
|
97
99
|
getSchema(name) {
|
|
98
100
|
const registryName = toKebabCase(name);
|
|
99
|
-
const
|
|
100
|
-
if (!
|
|
101
|
+
const schemaInfo = this.#schemaMap.get(registryName);
|
|
102
|
+
if (!schemaInfo) {
|
|
101
103
|
throw new ResolverError(`Unable to resolve "${name}"`);
|
|
102
104
|
}
|
|
103
|
-
return schema;
|
|
105
|
+
return schemaInfo.schema;
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
/**
|
|
@@ -113,6 +115,14 @@ export class SchemaResolver
|
|
|
113
115
|
return this.#schemaMap.has(registryName);
|
|
114
116
|
}
|
|
115
117
|
|
|
118
|
+
/**
|
|
119
|
+
* return all registered schemas
|
|
120
|
+
* @returns {RegisteredSchemaInfo[]}
|
|
121
|
+
*/
|
|
122
|
+
listRegisteredSchemas() {
|
|
123
|
+
return [...this.#schemaMap.values()];
|
|
124
|
+
}
|
|
125
|
+
|
|
116
126
|
/**
|
|
117
127
|
* Register a value processor definition
|
|
118
128
|
* @param {ValueProcessorDefinition} definition
|
|
@@ -121,20 +131,24 @@ export class SchemaResolver
|
|
|
121
131
|
registerValueProcessorDefinition(definition) {
|
|
122
132
|
const {keyword, process, description, build} = definition;
|
|
123
133
|
|
|
124
|
-
if (!keyword) {
|
|
134
|
+
if (!keyword || typeof keyword !== 'string') {
|
|
125
135
|
throw new ResolverError('Missing keyword in processor definition');
|
|
126
136
|
}
|
|
127
137
|
|
|
128
138
|
if (process && build) {
|
|
129
|
-
throw new ResolverError(`Processor definition for '
|
|
139
|
+
throw new ResolverError(`Processor definition for '$${keyword}' cannot define both process and build functions`);
|
|
130
140
|
}
|
|
131
141
|
|
|
132
142
|
if (!process && !build) {
|
|
133
|
-
throw new ResolverError(`Processor definition for '
|
|
143
|
+
throw new ResolverError(`Processor definition for '$${keyword}' must have define a process or build function`);
|
|
134
144
|
}
|
|
135
145
|
|
|
136
146
|
if (description && typeof description !== 'string') {
|
|
137
|
-
throw new ResolverError(`Processor definition description for '
|
|
147
|
+
throw new ResolverError(`Processor definition description for '$${keyword}' must be a string`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (this.#constantKeywordProcessors[`${keyword}`]) {
|
|
151
|
+
throw new ResolverError(`Processor keyword conflict with builtin literal '$${keyword}'`)
|
|
138
152
|
}
|
|
139
153
|
|
|
140
154
|
this.#processorMap.set(keyword, definition);
|
|
@@ -176,6 +190,24 @@ export class SchemaResolver
|
|
|
176
190
|
});
|
|
177
191
|
}
|
|
178
192
|
|
|
193
|
+
/**
|
|
194
|
+
* List all registered value processors (and reserved builtins)
|
|
195
|
+
*
|
|
196
|
+
* @returns {ValueProcessorDefinition[]}
|
|
197
|
+
*/
|
|
198
|
+
listValueProcessorDefinitions() {
|
|
199
|
+
|
|
200
|
+
return [
|
|
201
|
+
...Object.entries(this.#constantKeywordProcessors).map(([k,v]) => ({
|
|
202
|
+
keyword: k,
|
|
203
|
+
build: (() => v),
|
|
204
|
+
spec: `$${k}`,
|
|
205
|
+
reserved: true
|
|
206
|
+
})),
|
|
207
|
+
...this.#processorMap.values()
|
|
208
|
+
];
|
|
209
|
+
}
|
|
210
|
+
|
|
179
211
|
|
|
180
212
|
/**
|
|
181
213
|
* Load a library of schemas and/or value processors.
|
|
@@ -209,13 +241,11 @@ export class SchemaResolver
|
|
|
209
241
|
|
|
210
242
|
}
|
|
211
243
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
$true: TRUE_EXECUTOR,
|
|
218
|
-
$false: FALSE_EXECUTOR
|
|
244
|
+
#constantKeywordProcessors = {
|
|
245
|
+
'null': new ComposedValueProcessor(NULL_EXECUTOR, '$null'),
|
|
246
|
+
'undefined': new ComposedValueProcessor(UNDEFINED_EXECUTOR, '$undefined'),
|
|
247
|
+
'true': new ComposedValueProcessor(TRUE_EXECUTOR, '$true'),
|
|
248
|
+
'false': new ComposedValueProcessor(FALSE_EXECUTOR, '$false')
|
|
219
249
|
}
|
|
220
250
|
|
|
221
251
|
/**
|
|
@@ -230,8 +260,8 @@ export class SchemaResolver
|
|
|
230
260
|
}
|
|
231
261
|
const [keyword, rawArgs] = extractKeywordValueProcessorSpec(spec);
|
|
232
262
|
|
|
233
|
-
if (this
|
|
234
|
-
return
|
|
263
|
+
if (this.#constantKeywordProcessors[keyword]) {
|
|
264
|
+
return this.#constantKeywordProcessors[keyword];
|
|
235
265
|
}
|
|
236
266
|
|
|
237
267
|
if (keyword === 'literal') {
|
|
@@ -13,6 +13,7 @@ import { SchemaError } from '../errors.js';
|
|
|
13
13
|
* @property {boolean} [strict]
|
|
14
14
|
* @property {boolean} [deep]
|
|
15
15
|
* @property {boolean} [debug]
|
|
16
|
+
* @property {object} [stats]
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
/** @typedef {TraversalContextStandardOptions & {[key:string]:any}} TraversalContextOptions */
|
|
@@ -28,7 +29,7 @@ export class TraversalContext
|
|
|
28
29
|
this.root = (root instanceof CompiledSchema)? new SchemaLocation(root) : root;
|
|
29
30
|
this._final = false;
|
|
30
31
|
|
|
31
|
-
this._options = {...options, deep: options.deep ?? false, strict: options.strict ?? true, debug: options.debug ?? false}
|
|
32
|
+
this._options = {...options, deep: options.deep ?? false, strict: options.strict ?? true, debug: options.debug ?? false, stats: options.stats ?? {}}
|
|
32
33
|
|
|
33
34
|
this.traversals = 0;
|
|
34
35
|
this.counter = 0;
|
|
@@ -52,6 +53,10 @@ export class TraversalContext
|
|
|
52
53
|
return this._options.strict;
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
get stats() {
|
|
57
|
+
return this._options.stats;
|
|
58
|
+
}
|
|
59
|
+
|
|
55
60
|
update() {
|
|
56
61
|
this.counter++;
|
|
57
62
|
this.final = false;
|
|
@@ -192,6 +197,11 @@ export class TraversalContext
|
|
|
192
197
|
let done = false;
|
|
193
198
|
|
|
194
199
|
const updateDone = (counter) => {
|
|
200
|
+
this.traversals++;
|
|
201
|
+
|
|
202
|
+
this.stats.traversals = this.traversals;
|
|
203
|
+
this.stats.updates = this.counter;
|
|
204
|
+
|
|
195
205
|
if (this.isComplete) {
|
|
196
206
|
done = true;
|
|
197
207
|
}
|
|
@@ -222,7 +232,6 @@ export class TraversalContext
|
|
|
222
232
|
);
|
|
223
233
|
}
|
|
224
234
|
updateDone(counter);
|
|
225
|
-
this.traversals++;
|
|
226
235
|
}
|
|
227
236
|
return result;
|
|
228
237
|
}
|
|
@@ -44,11 +44,13 @@ import { SchemaLocation } from '../schema-location.js';
|
|
|
44
44
|
/**
|
|
45
45
|
* @typedef {object} ValueProcessorDefinition
|
|
46
46
|
* @property {string} keyword
|
|
47
|
+
* @property {string} [namespace]
|
|
47
48
|
* @property {ValueProcessorFunction} [process]
|
|
48
49
|
* @property {ValueProcessorParameter[]} [parameters]
|
|
49
50
|
* @property {string} [description]
|
|
50
51
|
* @property {ValueProcessorBuilder} [build]
|
|
51
52
|
* @property {ValueProcessorDescriber} [describe]
|
|
53
|
+
* @property {boolean} [reserved]
|
|
52
54
|
*/
|
|
53
55
|
|
|
54
56
|
|
|
@@ -9,6 +9,7 @@ export function registerCoreLibrary(libraryFn: (resolver: SchemaResolver, option
|
|
|
9
9
|
/** @typedef {{name:string, [key:string]:any}} SchemaResolverLibraryOptions */
|
|
10
10
|
/** @import { SchemaData } from './types.js' */
|
|
11
11
|
/** @import { ValueProcessorDefinition, ValueProcessorSpec, ValueProcessorBuilder, ValueProcessorFunction, ValueProcessorArgs, ValueProcessorParameter, KeywordValueProcessorSpec } from './value-processor/value-processor.js' */
|
|
12
|
+
/** @typedef {{name:string, namespace?:string, schema:Schema}} RegisteredSchemaInfo */
|
|
12
13
|
/**
|
|
13
14
|
* The SchemaResolver uses its internal registries of named schemas and value processor keywords to
|
|
14
15
|
* convert Schemas containing unresolved references into resolved Schemas that are fully self-contained.
|
|
@@ -33,6 +34,11 @@ export class SchemaResolver {
|
|
|
33
34
|
* @returns {boolean}
|
|
34
35
|
*/
|
|
35
36
|
hasSchema(name: string): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* return all registered schemas
|
|
39
|
+
* @returns {RegisteredSchemaInfo[]}
|
|
40
|
+
*/
|
|
41
|
+
listRegisteredSchemas(): RegisteredSchemaInfo[];
|
|
36
42
|
/**
|
|
37
43
|
* Register a value processor definition
|
|
38
44
|
* @param {ValueProcessorDefinition} definition
|
|
@@ -54,6 +60,12 @@ export class SchemaResolver {
|
|
|
54
60
|
* @returns {SchemaResolver}
|
|
55
61
|
*/
|
|
56
62
|
registerValueProcessorBuilder(keyword: string, build: ValueProcessorBuilder): SchemaResolver;
|
|
63
|
+
/**
|
|
64
|
+
* List all registered value processors (and reserved builtins)
|
|
65
|
+
*
|
|
66
|
+
* @returns {ValueProcessorDefinition[]}
|
|
67
|
+
*/
|
|
68
|
+
listValueProcessorDefinitions(): ValueProcessorDefinition[];
|
|
57
69
|
/**
|
|
58
70
|
* Load a library of schemas and/or value processors.
|
|
59
71
|
*
|
|
@@ -68,12 +80,6 @@ export class SchemaResolver {
|
|
|
68
80
|
* @returns {Promise<void>}
|
|
69
81
|
*/
|
|
70
82
|
use(libraryFunction: (resolver: SchemaResolver, options: object) => Promise<void> | void, options?: object): Promise<void>;
|
|
71
|
-
_constantKeywords: {
|
|
72
|
-
$null: ConstantExecutor;
|
|
73
|
-
$undefined: ConstantExecutor;
|
|
74
|
-
$true: ConstantExecutor;
|
|
75
|
-
$false: ConstantExecutor;
|
|
76
|
-
};
|
|
77
83
|
/**
|
|
78
84
|
* @param {SchemaCompiler} compiler
|
|
79
85
|
* @param {KeywordValueProcessorSpec} spec
|
|
@@ -131,11 +137,15 @@ export type SchemaResolverLibraryOptions = {
|
|
|
131
137
|
name: string;
|
|
132
138
|
[key: string]: any;
|
|
133
139
|
};
|
|
140
|
+
export type RegisteredSchemaInfo = {
|
|
141
|
+
name: string;
|
|
142
|
+
namespace?: string;
|
|
143
|
+
schema: Schema;
|
|
144
|
+
};
|
|
134
145
|
import { Schema } from './schema.js';
|
|
135
146
|
import type { ValueProcessorDefinition } from './value-processor/value-processor.js';
|
|
136
147
|
import type { ValueProcessorFunction } from './value-processor/value-processor.js';
|
|
137
148
|
import type { ValueProcessorBuilder } from './value-processor/value-processor.js';
|
|
138
|
-
import { ConstantExecutor } from './executor/executor.js';
|
|
139
149
|
import { SchemaCompiler } from './schema-compiler.js';
|
|
140
150
|
import type { KeywordValueProcessorSpec } from './value-processor/value-processor.js';
|
|
141
151
|
import { ValueProcessor } from './value-processor/value-processor.js';
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @property {boolean} [strict]
|
|
4
4
|
* @property {boolean} [deep]
|
|
5
5
|
* @property {boolean} [debug]
|
|
6
|
+
* @property {object} [stats]
|
|
6
7
|
*/
|
|
7
8
|
/** @typedef {TraversalContextStandardOptions & {[key:string]:any}} TraversalContextOptions */
|
|
8
9
|
export class TraversalContext {
|
|
@@ -17,6 +18,7 @@ export class TraversalContext {
|
|
|
17
18
|
deep: boolean;
|
|
18
19
|
strict: boolean;
|
|
19
20
|
debug: boolean;
|
|
21
|
+
stats: any;
|
|
20
22
|
};
|
|
21
23
|
traversals: number;
|
|
22
24
|
counter: number;
|
|
@@ -28,9 +30,11 @@ export class TraversalContext {
|
|
|
28
30
|
deep: boolean;
|
|
29
31
|
strict: boolean;
|
|
30
32
|
debug: boolean;
|
|
33
|
+
stats: any;
|
|
31
34
|
};
|
|
32
35
|
get deep(): boolean;
|
|
33
36
|
get strict(): boolean;
|
|
37
|
+
get stats(): any;
|
|
34
38
|
update(): void;
|
|
35
39
|
set final(finalize: boolean);
|
|
36
40
|
get final(): boolean;
|
|
@@ -58,6 +62,7 @@ export type TraversalContextStandardOptions = {
|
|
|
58
62
|
strict?: boolean | undefined;
|
|
59
63
|
deep?: boolean | undefined;
|
|
60
64
|
debug?: boolean | undefined;
|
|
65
|
+
stats?: object;
|
|
61
66
|
};
|
|
62
67
|
export type TraversalContextOptions = TraversalContextStandardOptions & {
|
|
63
68
|
[key: string]: any;
|
|
@@ -31,11 +31,13 @@
|
|
|
31
31
|
/**
|
|
32
32
|
* @typedef {object} ValueProcessorDefinition
|
|
33
33
|
* @property {string} keyword
|
|
34
|
+
* @property {string} [namespace]
|
|
34
35
|
* @property {ValueProcessorFunction} [process]
|
|
35
36
|
* @property {ValueProcessorParameter[]} [parameters]
|
|
36
37
|
* @property {string} [description]
|
|
37
38
|
* @property {ValueProcessorBuilder} [build]
|
|
38
39
|
* @property {ValueProcessorDescriber} [describe]
|
|
40
|
+
* @property {boolean} [reserved]
|
|
39
41
|
*/
|
|
40
42
|
/**
|
|
41
43
|
* @augments {Executor<any>}
|
|
@@ -82,11 +84,13 @@ export type ValueProcessorDescriber = (args: {
|
|
|
82
84
|
} | ValueProcessor[] | undefined) => string | undefined;
|
|
83
85
|
export type ValueProcessorDefinition = {
|
|
84
86
|
keyword: string;
|
|
87
|
+
namespace?: string | undefined;
|
|
85
88
|
process?: ValueProcessorFunction | undefined;
|
|
86
89
|
parameters?: ValueProcessorParameter[] | undefined;
|
|
87
90
|
description?: string | undefined;
|
|
88
91
|
build?: ValueProcessorBuilder | undefined;
|
|
89
92
|
describe?: ValueProcessorDescriber | undefined;
|
|
93
|
+
reserved?: boolean | undefined;
|
|
90
94
|
};
|
|
91
95
|
import { Executor } from '../executor/executor.js';
|
|
92
96
|
import { SchemaLocation } from '../schema-location.js';
|