@maroonedog/luq 2.2.0 → 2.3.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 +47 -602
- package/dist/builder/compile-declarations.d.ts +7 -1
- package/dist/builder/compile-declarations.js +18 -8
- package/dist/builder/compile-declarations.mjs +18 -8
- package/dist/builder/create-builder.js +2 -3
- package/dist/builder/create-builder.mjs +2 -3
- package/dist/builder/create-field-builder.js +13 -1
- package/dist/builder/create-field-builder.mjs +13 -1
- package/dist/builder/declared-calls-store.d.ts +9 -0
- package/dist/builder/declared-calls-store.js +19 -0
- package/dist/builder/declared-calls-store.mjs +15 -0
- package/dist/builder/field-declared-calls.types.d.ts +6 -0
- package/dist/builder/field-declared-calls.types.js +2 -0
- package/dist/builder/field-declared-calls.types.mjs +1 -0
- package/dist/builder/field-entry.types.d.ts +9 -3
- package/dist/builder/field-options.types.d.ts +26 -0
- package/dist/chain/bundle-paths.types.d.ts +9 -12
- package/dist/chain/chain-node-store.d.ts +5 -0
- package/dist/chain/chain-node-store.js +15 -0
- package/dist/chain/chain-node-store.mjs +11 -0
- package/dist/chain/collect-field-rules.d.ts +13 -2
- package/dist/chain/collect-field-rules.js +10 -3
- package/dist/chain/collect-field-rules.mjs +10 -3
- package/dist/chain/create-chain-node.js +19 -9
- package/dist/chain/create-chain-node.mjs +19 -9
- package/dist/chain/declaration-recorder.port.d.ts +31 -0
- package/dist/chain/declaration-recorder.port.js +17 -0
- package/dist/chain/declaration-recorder.port.mjs +13 -0
- package/dist/chain/declared-call.types.d.ts +15 -0
- package/dist/chain/declared-call.types.js +2 -0
- package/dist/chain/declared-call.types.mjs +1 -0
- package/dist/chain/index.d.ts +3 -1
- package/dist/compile/compile-array-node.js +1 -0
- package/dist/compile/compile-array-node.mjs +1 -0
- package/dist/compile/compile-field.d.ts +1 -0
- package/dist/compile/compile-field.js +8 -6
- package/dist/compile/compile-field.mjs +8 -6
- package/dist/compile/compile-schema.js +4 -0
- package/dist/compile/compile-schema.mjs +4 -0
- package/dist/compile/group-array-fields.d.ts +1 -0
- package/dist/compile/split-rules-by-kind.js +10 -14
- package/dist/compile/split-rules-by-kind.mjs +10 -14
- package/dist/compile/validation-plan.types.d.ts +19 -6
- package/dist/core/type-erasure.d.ts +36 -30
- package/dist/core/type-erasure.js +36 -30
- package/dist/core/type-erasure.mjs +36 -30
- package/dist/json-schema/build-from-schema.js +8 -1
- package/dist/json-schema/build-from-schema.mjs +8 -1
- package/dist/json-schema/declare-additional-properties.d.ts +7 -7
- package/dist/json-schema/declare-additional-properties.js +7 -7
- package/dist/json-schema/declare-additional-properties.mjs +7 -7
- package/dist/json-schema/declare-object-keywords.js +4 -4
- package/dist/json-schema/declare-object-keywords.mjs +4 -4
- package/dist/json-schema/follow-json-pointer.d.ts +7 -6
- package/dist/json-schema/follow-json-pointer.js +24 -24
- package/dist/json-schema/follow-json-pointer.mjs +24 -24
- package/dist/json-schema/ref-resolution-error.js +3 -3
- package/dist/json-schema/ref-resolution-error.mjs +3 -3
- package/dist/json-schema/schema-registry.js +12 -11
- package/dist/json-schema/schema-registry.mjs +12 -11
- package/dist/json-schema/uri-reference.js +12 -12
- package/dist/json-schema/uri-reference.mjs +12 -12
- package/dist/path/create-value-writer.js +12 -12
- package/dist/path/create-value-writer.mjs +12 -12
- package/dist/path/reserved-segment.d.ts +16 -16
- package/dist/path/reserved-segment.js +17 -21
- package/dist/path/reserved-segment.mjs +17 -21
- package/dist/plugins/index.generated.js +2 -2
- package/dist/plugins/index.generated.mjs +2 -2
- package/dist/plugins/manifest.generated.js +2 -2
- package/dist/plugins/manifest.generated.mjs +2 -2
- package/dist/plugins/object-additional-properties/select-additional-keys.d.ts +8 -8
- package/dist/plugins/object-additional-properties/select-additional-keys.js +16 -16
- package/dist/plugins/object-additional-properties/select-additional-keys.mjs +16 -16
- package/dist/plugins/stitch/stitch.d.ts +10 -14
- package/dist/plugins/stitch-with/stitch-with.d.ts +1 -1
- package/dist/plugins/stitch-with/stitch-with.js +22 -24
- package/dist/plugins/stitch-with/stitch-with.mjs +22 -24
- package/dist/plugins/string-min/string-min.js +6 -8
- package/dist/plugins/string-min/string-min.mjs +6 -8
- package/dist/presets/presets.d.ts +10 -11
- package/dist/presets/presets.js +22 -23
- package/dist/presets/presets.mjs +22 -23
- package/dist/runtime/create-field-validator.js +4 -6
- package/dist/runtime/create-field-validator.mjs +4 -6
- package/dist/runtime/create-validator.js +11 -11
- package/dist/runtime/create-validator.mjs +11 -11
- package/dist/runtime/output-writer.js +5 -1
- package/dist/runtime/output-writer.mjs +5 -1
- package/dist/runtime/run-array-node.js +6 -6
- package/dist/runtime/run-array-node.mjs +6 -6
- package/dist/runtime/run-field.js +18 -19
- package/dist/runtime/run-field.mjs +18 -19
- package/dist/standard-schema/assemble-json-schema.d.ts +4 -0
- package/dist/standard-schema/assemble-json-schema.js +95 -0
- package/dist/standard-schema/assemble-json-schema.mjs +92 -0
- package/dist/standard-schema/declaration-recorder.d.ts +6 -0
- package/dist/standard-schema/declaration-recorder.js +30 -0
- package/dist/standard-schema/declaration-recorder.mjs +27 -0
- package/dist/standard-schema/declarations-unavailable-error.d.ts +4 -0
- package/dist/standard-schema/declarations-unavailable-error.js +32 -0
- package/dist/standard-schema/declarations-unavailable-error.mjs +28 -0
- package/dist/standard-schema/emit-field-schema.d.ts +9 -0
- package/dist/standard-schema/emit-field-schema.js +68 -0
- package/dist/standard-schema/emit-field-schema.mjs +65 -0
- package/dist/standard-schema/index.d.ts +5 -0
- package/dist/standard-schema/index.js +9 -1
- package/dist/standard-schema/index.mjs +4 -0
- package/dist/standard-schema/json-schema-target.d.ts +6 -0
- package/dist/standard-schema/json-schema-target.js +44 -0
- package/dist/standard-schema/json-schema-target.mjs +39 -0
- package/dist/standard-schema/plugin-keyword-map.d.ts +3 -0
- package/dist/standard-schema/plugin-keyword-map.js +93 -0
- package/dist/standard-schema/plugin-keyword-map.mjs +90 -0
- package/dist/standard-schema/split-issue-path.d.ts +6 -4
- package/dist/standard-schema/split-issue-path.js +15 -13
- package/dist/standard-schema/split-issue-path.mjs +15 -13
- package/dist/standard-schema/standard-schema.types.d.ts +8 -7
- package/dist/standard-schema/standard-schema.types.js +6 -6
- package/dist/standard-schema/standard-schema.types.mjs +6 -6
- package/dist/standard-schema/to-standard-json-schema.d.ts +19 -0
- package/dist/standard-schema/to-standard-json-schema.js +36 -0
- package/dist/standard-schema/to-standard-json-schema.mjs +33 -0
- package/dist/standard-schema/to-standard-schema.d.ts +16 -15
- package/dist/standard-schema/to-standard-schema.js +15 -22
- package/dist/standard-schema/to-standard-schema.mjs +15 -22
- package/dist/standard-schema/unrepresentable-rule-error.d.ts +15 -0
- package/dist/standard-schema/unrepresentable-rule-error.js +43 -0
- package/dist/standard-schema/unrepresentable-rule-error.mjs +38 -0
- package/dist/types/index.d.ts +12 -12
- package/dist/types/index.js +7 -7
- package/dist/types/index.mjs +7 -7
- package/package.json +1 -1
|
@@ -42,7 +42,14 @@ function buildFieldEntries(bag, schema) {
|
|
|
42
42
|
path: declaration.path,
|
|
43
43
|
defaultOf: null,
|
|
44
44
|
applyDefaultToNull: false,
|
|
45
|
-
|
|
45
|
+
normalize: null,
|
|
46
|
+
// No record of declared calls: what is assembled here comes from a
|
|
47
|
+
// document, and nobody called a chain method. null rather than the empty
|
|
48
|
+
// list is what lets a writer say "not known" instead of "none".
|
|
49
|
+
collectRules: (chain) => ({
|
|
50
|
+
rules: collectDeclaredRules(declaration, bag, schema, chain),
|
|
51
|
+
calls: null,
|
|
52
|
+
}),
|
|
46
53
|
}));
|
|
47
54
|
}
|
|
48
55
|
/** The erased front door: the declarations, with nothing compiled yet. */
|
|
@@ -35,7 +35,14 @@ export function buildFieldEntries(bag, schema) {
|
|
|
35
35
|
path: declaration.path,
|
|
36
36
|
defaultOf: null,
|
|
37
37
|
applyDefaultToNull: false,
|
|
38
|
-
|
|
38
|
+
normalize: null,
|
|
39
|
+
// No record of declared calls: what is assembled here comes from a
|
|
40
|
+
// document, and nobody called a chain method. null rather than the empty
|
|
41
|
+
// list is what lets a writer say "not known" instead of "none".
|
|
42
|
+
collectRules: (chain) => ({
|
|
43
|
+
rules: collectDeclaredRules(declaration, bag, schema, chain),
|
|
44
|
+
calls: null,
|
|
45
|
+
}),
|
|
39
46
|
}));
|
|
40
47
|
}
|
|
41
48
|
/** The erased front door: the declarations, with nothing compiled yet. */
|
|
@@ -3,17 +3,17 @@ import type { ConverterChain } from "./apply-keyword-binding";
|
|
|
3
3
|
import type { Draft07SchemaObject } from "./draft07.types";
|
|
4
4
|
import type { StructuralContext } from "./structural-expansion.types";
|
|
5
5
|
/**
|
|
6
|
-
* `patternProperties
|
|
7
|
-
* additionalProperties
|
|
6
|
+
* The keys of `patternProperties`, which are regular expression strings.
|
|
7
|
+
* additionalProperties needs them to pick out the keys that match none.
|
|
8
8
|
*/
|
|
9
9
|
export declare function patternPropertyKeys(schema: Draft07SchemaObject): readonly string[];
|
|
10
10
|
/**
|
|
11
|
-
* BOOLEAN
|
|
11
|
+
* The BOOLEAN form.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* A keyword binding can only carry its own value, so when patterns are present
|
|
14
|
+
* the plugin is called directly. The binding stays either way: it is what
|
|
15
|
+
* holds the keyword table and the compile-time check that the method exists.
|
|
16
16
|
*/
|
|
17
17
|
export declare function applyAdditionalPropertiesBoolean(chain: ConverterChain<"object">, schema: Draft07SchemaObject, allowed: boolean): ConverterChain<"object">;
|
|
18
|
-
/** SCHEMA
|
|
18
|
+
/** The SCHEMA form: whatever matches neither a declaration nor a pattern follows it. */
|
|
19
19
|
export declare function declareAdditionalPropertiesSchema(schema: Draft07SchemaObject, context: StructuralContext): readonly Rule[];
|
|
@@ -7,8 +7,8 @@ const apply_keyword_binding_1 = require("./apply-keyword-binding");
|
|
|
7
7
|
const keyword_map_object_1 = require("./keyword-map-object");
|
|
8
8
|
const NO_RULES = Object.freeze([]);
|
|
9
9
|
/**
|
|
10
|
-
* `patternProperties
|
|
11
|
-
* additionalProperties
|
|
10
|
+
* The keys of `patternProperties`, which are regular expression strings.
|
|
11
|
+
* additionalProperties needs them to pick out the keys that match none.
|
|
12
12
|
*/
|
|
13
13
|
function patternPropertyKeys(schema) {
|
|
14
14
|
const patterns = schema.patternProperties;
|
|
@@ -17,11 +17,11 @@ function patternPropertyKeys(schema) {
|
|
|
17
17
|
return Object.freeze(Object.keys(patterns));
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
* BOOLEAN
|
|
20
|
+
* The BOOLEAN form.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* A keyword binding can only carry its own value, so when patterns are present
|
|
23
|
+
* the plugin is called directly. The binding stays either way: it is what
|
|
24
|
+
* holds the keyword table and the compile-time check that the method exists.
|
|
25
25
|
*/
|
|
26
26
|
function applyAdditionalPropertiesBoolean(chain, schema, allowed) {
|
|
27
27
|
const patterns = patternPropertyKeys(schema);
|
|
@@ -29,7 +29,7 @@ function applyAdditionalPropertiesBoolean(chain, schema, allowed) {
|
|
|
29
29
|
? (0, apply_keyword_binding_1.applyKeywordBinding)(chain, keyword_map_object_1.additionalPropertiesBinding, allowed)
|
|
30
30
|
: chain.additionalProperties(allowed, undefined, patterns);
|
|
31
31
|
}
|
|
32
|
-
/** SCHEMA
|
|
32
|
+
/** The SCHEMA form: whatever matches neither a declaration nor a pattern follows it. */
|
|
33
33
|
function declareAdditionalPropertiesSchema(schema, context) {
|
|
34
34
|
const additional = schema.additionalProperties;
|
|
35
35
|
if (additional === undefined || typeof additional === "boolean") {
|
|
@@ -2,8 +2,8 @@ import { applyKeywordBinding } from "./apply-keyword-binding.mjs";
|
|
|
2
2
|
import { additionalPropertiesBinding } from "./keyword-map-object.mjs";
|
|
3
3
|
const NO_RULES = Object.freeze([]);
|
|
4
4
|
/**
|
|
5
|
-
* `patternProperties
|
|
6
|
-
* additionalProperties
|
|
5
|
+
* The keys of `patternProperties`, which are regular expression strings.
|
|
6
|
+
* additionalProperties needs them to pick out the keys that match none.
|
|
7
7
|
*/
|
|
8
8
|
export function patternPropertyKeys(schema) {
|
|
9
9
|
const patterns = schema.patternProperties;
|
|
@@ -12,11 +12,11 @@ export function patternPropertyKeys(schema) {
|
|
|
12
12
|
return Object.freeze(Object.keys(patterns));
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* BOOLEAN
|
|
15
|
+
* The BOOLEAN form.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* A keyword binding can only carry its own value, so when patterns are present
|
|
18
|
+
* the plugin is called directly. The binding stays either way: it is what
|
|
19
|
+
* holds the keyword table and the compile-time check that the method exists.
|
|
20
20
|
*/
|
|
21
21
|
export function applyAdditionalPropertiesBoolean(chain, schema, allowed) {
|
|
22
22
|
const patterns = patternPropertyKeys(schema);
|
|
@@ -24,7 +24,7 @@ export function applyAdditionalPropertiesBoolean(chain, schema, allowed) {
|
|
|
24
24
|
? applyKeywordBinding(chain, additionalPropertiesBinding, allowed)
|
|
25
25
|
: chain.additionalProperties(allowed, undefined, patterns);
|
|
26
26
|
}
|
|
27
|
-
/** SCHEMA
|
|
27
|
+
/** The SCHEMA form: whatever matches neither a declaration nor a pattern follows it. */
|
|
28
28
|
export function declareAdditionalPropertiesSchema(schema, context) {
|
|
29
29
|
const additional = schema.additionalProperties;
|
|
30
30
|
if (additional === undefined || typeof additional === "boolean") {
|
|
@@ -40,10 +40,10 @@ function declareObjectRules(schema, context) {
|
|
|
40
40
|
}
|
|
41
41
|
const additional = schema.additionalProperties;
|
|
42
42
|
if (typeof additional === "boolean") {
|
|
43
|
-
// §6.5.4
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
43
|
+
// §6.5.4 applies to the keys matched by neither properties nor
|
|
44
|
+
// patternProperties. A keyword binding can only carry its own value, so
|
|
45
|
+
// when patterns are present the plugin is called directly. The binding
|
|
46
|
+
// stays: it holds the keyword table and the check that the method exists.
|
|
47
47
|
chain = (0, declare_additional_properties_1.applyAdditionalPropertiesBoolean)(chain, schema, additional);
|
|
48
48
|
}
|
|
49
49
|
return readRules(chain);
|
|
@@ -33,10 +33,10 @@ export function declareObjectRules(schema, context) {
|
|
|
33
33
|
}
|
|
34
34
|
const additional = schema.additionalProperties;
|
|
35
35
|
if (typeof additional === "boolean") {
|
|
36
|
-
// §6.5.4
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
36
|
+
// §6.5.4 applies to the keys matched by neither properties nor
|
|
37
|
+
// patternProperties. A keyword binding can only carry its own value, so
|
|
38
|
+
// when patterns are present the plugin is called directly. The binding
|
|
39
|
+
// stays: it holds the keyword table and the check that the method exists.
|
|
40
40
|
chain = applyAdditionalPropertiesBoolean(chain, schema, additional);
|
|
41
41
|
}
|
|
42
42
|
return readRules(chain);
|
|
@@ -8,14 +8,15 @@ export declare function toPointerTokens(fragment: string): readonly string[];
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function stepInto(current: unknown, token: string): unknown;
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Walks the pointer while **counting every `$id` crossed on the way**.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* When an intermediate node along the path carries `$id: "folder/"`, a
|
|
14
|
+
* relative `$ref` written deeper in must resolve under folder/. Looking only
|
|
15
|
+
* at the `$id` of the node landed on loses every node passed through.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* How the base advances is supplied by the caller. This function only needs
|
|
18
|
+
* to know which nodes were crossed and in what order; it does no URI
|
|
19
|
+
* arithmetic of its own.
|
|
19
20
|
*/
|
|
20
21
|
export declare function walkPointer<TScope>(fragment: string, document: unknown, scope: TScope, advance: (scope: TScope, node: unknown) => TScope, onMissing: (token: string) => never): {
|
|
21
22
|
readonly node: unknown;
|
|
@@ -4,13 +4,12 @@ exports.toPointerTokens = toPointerTokens;
|
|
|
4
4
|
exports.stepInto = stepInto;
|
|
5
5
|
exports.walkPointer = walkPointer;
|
|
6
6
|
// ===========================================================================
|
|
7
|
-
// L8 src/json-schema/follow-json-pointer.ts — RFC 6901
|
|
7
|
+
// L8 src/json-schema/follow-json-pointer.ts — walks an RFC 6901 pointer.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// なるからである。
|
|
9
|
+
// Answers only WHERE INSIDE a document, never WHICH document. Choosing the
|
|
10
|
+
// document is a separate job, kept separate because base-URI arithmetic and
|
|
11
|
+
// pointer decoding are different problems and neither reads well once they
|
|
12
|
+
// share a file.
|
|
14
13
|
// ===========================================================================
|
|
15
14
|
const types_1 = require("../types");
|
|
16
15
|
/** RFC 6901: `~1` is "/" and `~0` is "~", decoded in that order. */
|
|
@@ -18,18 +17,18 @@ function decodePointerToken(token) {
|
|
|
18
17
|
return token.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
19
18
|
}
|
|
20
19
|
/**
|
|
21
|
-
* `$ref`
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* A `$ref` is a URI and the pointer is its fragment. RFC 6901 §6 says the
|
|
21
|
+
* fragment is percent-encoded by the fragment rules, so **the whole fragment
|
|
22
|
+
* is decoded before splitting on slashes**.
|
|
24
23
|
*
|
|
25
|
-
*
|
|
26
|
-
* `/definitions/percent%field`
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* The order matters. `#/definitions/percent%25field` decodes to
|
|
25
|
+
* `/definitions/percent%field` and is split from there. Splitting first and
|
|
26
|
+
* decoding each token does decode `%25`, but then `%2F` turns back into a
|
|
27
|
+
* separator, which is not what the spec says it means.
|
|
29
28
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
29
|
+
* decodeURIComponent throws on a malformed sequence like `%zz`, and a
|
|
30
|
+
* pointer that cannot be decoded is used as-is. Throwing here would make one
|
|
31
|
+
* broken pointer take the whole document down.
|
|
33
32
|
*/
|
|
34
33
|
function decodeFragment(pointer) {
|
|
35
34
|
try {
|
|
@@ -44,8 +43,8 @@ function toPointerTokens(fragment) {
|
|
|
44
43
|
const pointer = decodeFragment(fragment);
|
|
45
44
|
if (pointer === "")
|
|
46
45
|
return [];
|
|
47
|
-
// "/"
|
|
48
|
-
//
|
|
46
|
+
// "/" is the empty-string key directly under the root, not an empty token
|
|
47
|
+
// list. Returning [] here would turn a pointer at `{"": ...}` into the root.
|
|
49
48
|
return pointer.split("/").slice(1).map(decodePointerToken);
|
|
50
49
|
}
|
|
51
50
|
/**
|
|
@@ -65,14 +64,15 @@ function stepInto(current, token) {
|
|
|
65
64
|
return current[token];
|
|
66
65
|
}
|
|
67
66
|
/**
|
|
68
|
-
*
|
|
67
|
+
* Walks the pointer while **counting every `$id` crossed on the way**.
|
|
69
68
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
69
|
+
* When an intermediate node along the path carries `$id: "folder/"`, a
|
|
70
|
+
* relative `$ref` written deeper in must resolve under folder/. Looking only
|
|
71
|
+
* at the `$id` of the node landed on loses every node passed through.
|
|
73
72
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
73
|
+
* How the base advances is supplied by the caller. This function only needs
|
|
74
|
+
* to know which nodes were crossed and in what order; it does no URI
|
|
75
|
+
* arithmetic of its own.
|
|
76
76
|
*/
|
|
77
77
|
function walkPointer(fragment, document, scope, advance, onMissing) {
|
|
78
78
|
let current = document;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
// ===========================================================================
|
|
2
|
-
// L8 src/json-schema/follow-json-pointer.ts — RFC 6901
|
|
2
|
+
// L8 src/json-schema/follow-json-pointer.ts — walks an RFC 6901 pointer.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// なるからである。
|
|
4
|
+
// Answers only WHERE INSIDE a document, never WHICH document. Choosing the
|
|
5
|
+
// document is a separate job, kept separate because base-URI arithmetic and
|
|
6
|
+
// pointer decoding are different problems and neither reads well once they
|
|
7
|
+
// share a file.
|
|
9
8
|
// ===========================================================================
|
|
10
9
|
import { isArray, isPlainObject } from "../types/index.mjs";
|
|
11
10
|
/** RFC 6901: `~1` is "/" and `~0` is "~", decoded in that order. */
|
|
@@ -13,18 +12,18 @@ function decodePointerToken(token) {
|
|
|
13
12
|
return token.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
14
13
|
}
|
|
15
14
|
/**
|
|
16
|
-
* `$ref`
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* A `$ref` is a URI and the pointer is its fragment. RFC 6901 §6 says the
|
|
16
|
+
* fragment is percent-encoded by the fragment rules, so **the whole fragment
|
|
17
|
+
* is decoded before splitting on slashes**.
|
|
19
18
|
*
|
|
20
|
-
*
|
|
21
|
-
* `/definitions/percent%field`
|
|
22
|
-
*
|
|
23
|
-
*
|
|
19
|
+
* The order matters. `#/definitions/percent%25field` decodes to
|
|
20
|
+
* `/definitions/percent%field` and is split from there. Splitting first and
|
|
21
|
+
* decoding each token does decode `%25`, but then `%2F` turns back into a
|
|
22
|
+
* separator, which is not what the spec says it means.
|
|
24
23
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* decodeURIComponent throws on a malformed sequence like `%zz`, and a
|
|
25
|
+
* pointer that cannot be decoded is used as-is. Throwing here would make one
|
|
26
|
+
* broken pointer take the whole document down.
|
|
28
27
|
*/
|
|
29
28
|
function decodeFragment(pointer) {
|
|
30
29
|
try {
|
|
@@ -39,8 +38,8 @@ export function toPointerTokens(fragment) {
|
|
|
39
38
|
const pointer = decodeFragment(fragment);
|
|
40
39
|
if (pointer === "")
|
|
41
40
|
return [];
|
|
42
|
-
// "/"
|
|
43
|
-
//
|
|
41
|
+
// "/" is the empty-string key directly under the root, not an empty token
|
|
42
|
+
// list. Returning [] here would turn a pointer at `{"": ...}` into the root.
|
|
44
43
|
return pointer.split("/").slice(1).map(decodePointerToken);
|
|
45
44
|
}
|
|
46
45
|
/**
|
|
@@ -60,14 +59,15 @@ export function stepInto(current, token) {
|
|
|
60
59
|
return current[token];
|
|
61
60
|
}
|
|
62
61
|
/**
|
|
63
|
-
*
|
|
62
|
+
* Walks the pointer while **counting every `$id` crossed on the way**.
|
|
64
63
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
64
|
+
* When an intermediate node along the path carries `$id: "folder/"`, a
|
|
65
|
+
* relative `$ref` written deeper in must resolve under folder/. Looking only
|
|
66
|
+
* at the `$id` of the node landed on loses every node passed through.
|
|
68
67
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
68
|
+
* How the base advances is supplied by the caller. This function only needs
|
|
69
|
+
* to know which nodes were crossed and in what order; it does no URI
|
|
70
|
+
* arithmetic of its own.
|
|
71
71
|
*/
|
|
72
72
|
export function walkPointer(fragment, document, scope, advance, onMissing) {
|
|
73
73
|
let current = document;
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// ===========================================================================
|
|
3
3
|
// L8 src/json-schema/ref-resolution-error.ts
|
|
4
4
|
//
|
|
5
|
-
// `$ref`
|
|
6
|
-
//
|
|
7
|
-
//
|
|
5
|
+
// Raised when a `$ref` cannot be resolved. Callers must be able to catch it
|
|
6
|
+
// **by identity**, so it is its own class — and its own module, so catching it
|
|
7
|
+
// does not drag in the resolver's dependencies.
|
|
8
8
|
// ===========================================================================
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.RefResolutionError = void 0;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// ===========================================================================
|
|
2
2
|
// L8 src/json-schema/ref-resolution-error.ts
|
|
3
3
|
//
|
|
4
|
-
// `$ref`
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// Raised when a `$ref` cannot be resolved. Callers must be able to catch it
|
|
5
|
+
// **by identity**, so it is its own class — and its own module, so catching it
|
|
6
|
+
// does not drag in the resolver's dependencies.
|
|
7
7
|
// ===========================================================================
|
|
8
8
|
export class RefResolutionError extends Error {
|
|
9
9
|
constructor(ref, reason) {
|
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createSchemaRegistry = createSchemaRegistry;
|
|
4
4
|
// ===========================================================================
|
|
5
|
-
// L8 src/json-schema/schema-registry.ts —
|
|
5
|
+
// L8 src/json-schema/schema-registry.ts — which URI names which schema.
|
|
6
6
|
//
|
|
7
|
-
// Draft-07 §8.2
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
7
|
+
// Draft-07 §8.2 gives `$id` two jobs: a URI that names a location re-bases
|
|
8
|
+
// what follows, and the `#name` form gives a **location-independent name**.
|
|
9
|
+
// Both are the same index — this URI is that node — which is this file's whole
|
|
10
|
+
// responsibility. Walking a pointer is about location, and lives elsewhere.
|
|
11
11
|
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// *
|
|
16
|
-
// *
|
|
17
|
-
//
|
|
12
|
+
// External documents are **only what the caller passed in**; nothing is
|
|
13
|
+
// fetched. Taking a map rather than a loader function is what makes all three
|
|
14
|
+
// of these true at once:
|
|
15
|
+
// * a URI written in a schema can never make this process open a socket,
|
|
16
|
+
// * conversion stays synchronous, so it works under CSP,
|
|
17
|
+
// * everything that could possibly be read is visible in the caller's code.
|
|
18
|
+
// An async loader gives up all three.
|
|
18
19
|
// ===========================================================================
|
|
19
20
|
const draft07_types_1 = require("./draft07.types");
|
|
20
21
|
const types_1 = require("../types");
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
// ===========================================================================
|
|
2
|
-
// L8 src/json-schema/schema-registry.ts —
|
|
2
|
+
// L8 src/json-schema/schema-registry.ts — which URI names which schema.
|
|
3
3
|
//
|
|
4
|
-
// Draft-07 §8.2
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
4
|
+
// Draft-07 §8.2 gives `$id` two jobs: a URI that names a location re-bases
|
|
5
|
+
// what follows, and the `#name` form gives a **location-independent name**.
|
|
6
|
+
// Both are the same index — this URI is that node — which is this file's whole
|
|
7
|
+
// responsibility. Walking a pointer is about location, and lives elsewhere.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// *
|
|
13
|
-
// *
|
|
14
|
-
//
|
|
9
|
+
// External documents are **only what the caller passed in**; nothing is
|
|
10
|
+
// fetched. Taking a map rather than a loader function is what makes all three
|
|
11
|
+
// of these true at once:
|
|
12
|
+
// * a URI written in a schema can never make this process open a socket,
|
|
13
|
+
// * conversion stays synchronous, so it works under CSP,
|
|
14
|
+
// * everything that could possibly be read is visible in the caller's code.
|
|
15
|
+
// An async loader gives up all three.
|
|
15
16
|
// ===========================================================================
|
|
16
17
|
import { isDraft07Schema, isSchemaObject } from "./draft07.types.mjs";
|
|
17
18
|
import { isArray, isPlainObject } from "../types/index.mjs";
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// ===========================================================================
|
|
3
|
-
// L8 src/json-schema/uri-reference.ts —
|
|
3
|
+
// L8 src/json-schema/uri-reference.ts — the URI arithmetic of `$id`/`$ref`.
|
|
4
4
|
//
|
|
5
|
-
// Draft-07 §8.2
|
|
6
|
-
//
|
|
7
|
-
//
|
|
5
|
+
// Draft-07 §8.2 makes `$id` establish a base URI that `$ref` resolves
|
|
6
|
+
// against. A `$ref` is therefore a **URI reference** and not a pointer within
|
|
7
|
+
// a document: the same string points somewhere else depending on which `$id`
|
|
8
|
+
// it was written under.
|
|
8
9
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// eval
|
|
10
|
+
// Resolution is delegated to the WHATWG URL. Rewriting RFC 3986 §5.3 by hand
|
|
11
|
+
// goes wrong on percent-encoding, dot segments and scheme-relative
|
|
12
|
+
// (`//host/x`) every time — and URL is a standard global in both browsers and
|
|
13
|
+
// Node, needing neither eval nor new Function.
|
|
13
14
|
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
// このプロセスがソケットを開くことは無い。
|
|
15
|
+
// **Nothing here touches the network.** This is string arithmetic; how a
|
|
16
|
+
// resolved URI is actually obtained is the caller's responsibility. A URI
|
|
17
|
+
// written in a schema never causes this process to open a socket.
|
|
18
18
|
// ===========================================================================
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
20
|
exports.splitUri = splitUri;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
// ===========================================================================
|
|
2
|
-
// L8 src/json-schema/uri-reference.ts —
|
|
2
|
+
// L8 src/json-schema/uri-reference.ts — the URI arithmetic of `$id`/`$ref`.
|
|
3
3
|
//
|
|
4
|
-
// Draft-07 §8.2
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// Draft-07 §8.2 makes `$id` establish a base URI that `$ref` resolves
|
|
5
|
+
// against. A `$ref` is therefore a **URI reference** and not a pointer within
|
|
6
|
+
// a document: the same string points somewhere else depending on which `$id`
|
|
7
|
+
// it was written under.
|
|
7
8
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// eval
|
|
9
|
+
// Resolution is delegated to the WHATWG URL. Rewriting RFC 3986 §5.3 by hand
|
|
10
|
+
// goes wrong on percent-encoding, dot segments and scheme-relative
|
|
11
|
+
// (`//host/x`) every time — and URL is a standard global in both browsers and
|
|
12
|
+
// Node, needing neither eval nor new Function.
|
|
12
13
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// このプロセスがソケットを開くことは無い。
|
|
14
|
+
// **Nothing here touches the network.** This is string arithmetic; how a
|
|
15
|
+
// resolved URI is actually obtained is the caller's responsibility. A URI
|
|
16
|
+
// written in a schema never causes this process to open a socket.
|
|
17
17
|
// ===========================================================================
|
|
18
18
|
export function splitUri(uri) {
|
|
19
19
|
const hash = uri.indexOf("#");
|
|
@@ -36,19 +36,19 @@ function writeInto(container, keys, depth, value) {
|
|
|
36
36
|
* numeric key here is a Record key.
|
|
37
37
|
*/
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* Places a key as an own property. **Never with the assignment operator.**
|
|
40
40
|
*
|
|
41
|
-
* `copy[key] = value`
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
41
|
+
* `copy[key] = value` on "__proto__" invokes the accessor on
|
|
42
|
+
* Object.prototype: instead of creating an own property it swaps the
|
|
43
|
+
* prototype. defineProperty ignores accessors and defines the own property, so
|
|
44
|
+
* a property actually named "__proto__" can be held safely.
|
|
45
45
|
*
|
|
46
|
-
* "constructor"
|
|
47
|
-
*
|
|
48
|
-
*
|
|
46
|
+
* "constructor" and "prototype" are data properties, so assignment would only
|
|
47
|
+
* make own properties of them — but branching per key is how the branch gets
|
|
48
|
+
* written wrong, so everything goes through this one path.
|
|
49
49
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
50
|
+
* This is what makes writing safe, and therefore what makes refusing these
|
|
51
|
+
* names in the path grammar unnecessary. See reserved-segment.ts.
|
|
52
52
|
*/
|
|
53
53
|
function putOwnProperty(target, key, value) {
|
|
54
54
|
Object.defineProperty(target, key, {
|
|
@@ -72,8 +72,8 @@ function copyWith(container, key, value) {
|
|
|
72
72
|
copy[index] = value;
|
|
73
73
|
return copy;
|
|
74
74
|
}
|
|
75
|
-
//
|
|
76
|
-
//
|
|
75
|
+
// Spread copies own enumerable properties with CreateDataProperty, so no
|
|
76
|
+
// setter runs here. Only assignment is dangerous.
|
|
77
77
|
const copy = { ...container };
|
|
78
78
|
putOwnProperty(copy, key, value);
|
|
79
79
|
return copy;
|
|
@@ -33,19 +33,19 @@ function writeInto(container, keys, depth, value) {
|
|
|
33
33
|
* numeric key here is a Record key.
|
|
34
34
|
*/
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Places a key as an own property. **Never with the assignment operator.**
|
|
37
37
|
*
|
|
38
|
-
* `copy[key] = value`
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
38
|
+
* `copy[key] = value` on "__proto__" invokes the accessor on
|
|
39
|
+
* Object.prototype: instead of creating an own property it swaps the
|
|
40
|
+
* prototype. defineProperty ignores accessors and defines the own property, so
|
|
41
|
+
* a property actually named "__proto__" can be held safely.
|
|
42
42
|
*
|
|
43
|
-
* "constructor"
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* "constructor" and "prototype" are data properties, so assignment would only
|
|
44
|
+
* make own properties of them — but branching per key is how the branch gets
|
|
45
|
+
* written wrong, so everything goes through this one path.
|
|
46
46
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
47
|
+
* This is what makes writing safe, and therefore what makes refusing these
|
|
48
|
+
* names in the path grammar unnecessary. See reserved-segment.ts.
|
|
49
49
|
*/
|
|
50
50
|
function putOwnProperty(target, key, value) {
|
|
51
51
|
Object.defineProperty(target, key, {
|
|
@@ -69,8 +69,8 @@ function copyWith(container, key, value) {
|
|
|
69
69
|
copy[index] = value;
|
|
70
70
|
return copy;
|
|
71
71
|
}
|
|
72
|
-
//
|
|
73
|
-
//
|
|
72
|
+
// Spread copies own enumerable properties with CreateDataProperty, so no
|
|
73
|
+
// setter runs here. Only assignment is dangerous.
|
|
74
74
|
const copy = { ...container };
|
|
75
75
|
putOwnProperty(copy, key, value);
|
|
76
76
|
return copy;
|