@maroonedog/luq 2.0.0 → 2.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 +364 -57
- package/dist/builder/builder-surface.types.d.ts +1 -0
- package/dist/builder/create-builder.js +9 -0
- package/dist/builder/create-builder.mjs +9 -0
- package/dist/builder/field-builder.types.d.ts +13 -0
- package/dist/chain/bundle-paths.types.d.ts +26 -0
- package/dist/chain/bundle-paths.types.js +2 -0
- package/dist/chain/bundle-paths.types.mjs +1 -0
- package/dist/chain/chain-method.types.d.ts +8 -3
- package/dist/chain/create-chain-node.js +22 -1
- package/dist/chain/create-chain-node.mjs +22 -1
- package/dist/chain/resolve-args.types.d.ts +4 -2
- package/dist/compile/compile-array-node.d.ts +0 -7
- package/dist/compile/compile-array-node.js +4 -0
- package/dist/compile/compile-array-node.mjs +4 -0
- package/dist/compile/compile-field.js +10 -1
- package/dist/compile/compile-field.mjs +10 -1
- package/dist/compile/resolve-conditional-presence.js +1 -0
- package/dist/compile/resolve-conditional-presence.mjs +1 -0
- package/dist/compile/resolve-presence.js +4 -0
- package/dist/compile/resolve-presence.mjs +4 -0
- package/dist/compile/split-rules-by-kind.js +31 -7
- package/dist/compile/split-rules-by-kind.mjs +31 -7
- package/dist/compile/validation-plan.types.d.ts +33 -0
- package/dist/json-schema/build-from-schema.js +2 -3
- package/dist/json-schema/build-from-schema.mjs +2 -3
- package/dist/json-schema/collect-definitions.d.ts +30 -0
- package/dist/json-schema/collect-definitions.js +47 -3
- package/dist/json-schema/collect-definitions.mjs +46 -4
- package/dist/json-schema/collect-sub-schema-rules.d.ts +12 -1
- package/dist/json-schema/collect-sub-schema-rules.js +37 -7
- package/dist/json-schema/collect-sub-schema-rules.mjs +38 -8
- package/dist/json-schema/create-structural-context.d.ts +13 -3
- package/dist/json-schema/create-structural-context.js +72 -6
- package/dist/json-schema/create-structural-context.mjs +72 -7
- package/dist/json-schema/declare-additional-properties.d.ts +19 -0
- package/dist/json-schema/declare-additional-properties.js +42 -0
- package/dist/json-schema/declare-additional-properties.mjs +37 -0
- package/dist/json-schema/declare-object-keywords.d.ts +0 -2
- package/dist/json-schema/declare-object-keywords.js +6 -13
- package/dist/json-schema/declare-object-keywords.mjs +7 -13
- package/dist/json-schema/declare-presence.d.ts +9 -3
- package/dist/json-schema/declare-presence.js +12 -6
- package/dist/json-schema/declare-presence.mjs +12 -6
- package/dist/json-schema/extensions/json-schema/index.d.ts +1 -0
- package/dist/json-schema/extensions/json-schema/json-schema.d.ts +17 -2
- package/dist/json-schema/extensions/json-schema/json-schema.js +15 -7
- package/dist/json-schema/extensions/json-schema/json-schema.mjs +16 -8
- package/dist/json-schema/extensions/json-schema-full-feature/index.d.ts +1 -0
- package/dist/json-schema/extensions/json-schema-full-feature/json-schema-full-feature.d.ts +2 -1
- package/dist/json-schema/extensions/json-schema-full-feature/json-schema-full-feature.js +3 -1
- package/dist/json-schema/extensions/json-schema-full-feature/json-schema-full-feature.mjs +3 -1
- package/dist/json-schema/flatten-schema.js +1 -1
- package/dist/json-schema/flatten-schema.mjs +1 -1
- package/dist/json-schema/follow-json-pointer.d.ts +23 -0
- package/dist/json-schema/follow-json-pointer.js +87 -0
- package/dist/json-schema/follow-json-pointer.mjs +82 -0
- package/dist/json-schema/index.d.ts +7 -2
- package/dist/json-schema/index.js +10 -2
- package/dist/json-schema/index.mjs +5 -2
- package/dist/json-schema/keyword-map-object.d.ts +1 -1
- package/dist/json-schema/ref-resolution-error.d.ts +4 -0
- package/dist/json-schema/ref-resolution-error.js +20 -0
- package/dist/json-schema/ref-resolution-error.mjs +16 -0
- package/dist/json-schema/ref-scope.d.ts +18 -0
- package/dist/json-schema/ref-scope.js +37 -0
- package/dist/json-schema/ref-scope.mjs +33 -0
- package/dist/json-schema/resolve-ref.d.ts +14 -9
- package/dist/json-schema/resolve-ref.js +89 -59
- package/dist/json-schema/resolve-ref.mjs +86 -55
- package/dist/json-schema/schema-registry.d.ts +30 -0
- package/dist/json-schema/schema-registry.js +142 -0
- package/dist/json-schema/schema-registry.mjs +139 -0
- package/dist/json-schema/schema-to-declarations.js +2 -1
- package/dist/json-schema/schema-to-declarations.mjs +2 -1
- package/dist/json-schema/structural-expansion.types.d.ts +8 -1
- package/dist/json-schema/uri-reference.d.ts +29 -0
- package/dist/json-schema/uri-reference.js +118 -0
- package/dist/json-schema/uri-reference.mjs +111 -0
- package/dist/path/create-value-writer.js +27 -2
- package/dist/path/create-value-writer.mjs +27 -2
- package/dist/path/reserved-segment.d.ts +22 -4
- package/dist/path/reserved-segment.js +27 -7
- package/dist/path/reserved-segment.mjs +27 -7
- package/dist/plugin-kit/compiled-rule.d.ts +13 -0
- package/dist/plugin-kit/create-rule.d.ts +11 -0
- package/dist/plugin-kit/create-rule.js +1 -0
- package/dist/plugin-kit/create-rule.mjs +1 -0
- package/dist/plugin-kit/marker.types.d.ts +18 -0
- package/dist/plugin-kit/plugin-definition.d.ts +15 -0
- package/dist/plugin-kit/plugin-definition.js +1 -0
- package/dist/plugin-kit/plugin-definition.mjs +1 -0
- package/dist/plugins/index.generated.d.ts +1 -0
- package/dist/plugins/index.generated.js +4 -2
- package/dist/plugins/index.generated.mjs +1 -0
- package/dist/plugins/manifest.generated.js +1 -0
- package/dist/plugins/manifest.generated.mjs +1 -0
- package/dist/plugins/object-additional-properties/object-additional-properties-schema.d.ts +1 -1
- package/dist/plugins/object-additional-properties/object-additional-properties-schema.js +4 -2
- package/dist/plugins/object-additional-properties/object-additional-properties-schema.mjs +4 -2
- package/dist/plugins/object-additional-properties/object-additional-properties.d.ts +1 -1
- package/dist/plugins/object-additional-properties/object-additional-properties.js +4 -2
- package/dist/plugins/object-additional-properties/object-additional-properties.mjs +4 -2
- package/dist/plugins/object-additional-properties/select-additional-keys.d.ts +15 -0
- package/dist/plugins/object-additional-properties/select-additional-keys.js +51 -0
- package/dist/plugins/object-additional-properties/select-additional-keys.mjs +47 -0
- package/dist/plugins/stitch/stitch.d.ts +28 -8
- package/dist/plugins/stitch-with/index.d.ts +2 -0
- package/dist/plugins/stitch-with/index.js +5 -0
- package/dist/plugins/stitch-with/index.mjs +1 -0
- package/dist/plugins/stitch-with/stitch-with.d.ts +12 -0
- package/dist/plugins/stitch-with/stitch-with.js +94 -0
- package/dist/plugins/stitch-with/stitch-with.mjs +91 -0
- package/dist/plugins/stitchWith.d.ts +1 -0
- package/dist/plugins/stitchWith.js +2 -0
- package/dist/plugins/stitchWith.mjs +1 -0
- package/dist/plugins/string-exact-length/string-exact-length.js +2 -2
- package/dist/plugins/string-exact-length/string-exact-length.mjs +3 -3
- package/dist/plugins/string-max/string-max.js +2 -2
- package/dist/plugins/string-max/string-max.mjs +3 -3
- package/dist/plugins/string-min/string-min.js +21 -3
- package/dist/plugins/string-min/string-min.mjs +21 -3
- package/dist/presets/index.d.ts +1 -0
- package/dist/presets/index.js +9 -0
- package/dist/presets/index.mjs +1 -0
- package/dist/presets/presets.d.ts +165 -0
- package/dist/presets/presets.js +80 -0
- package/dist/presets/presets.mjs +77 -0
- package/dist/runtime/create-field-validator.js +24 -8
- package/dist/runtime/create-field-validator.mjs +24 -8
- package/dist/runtime/create-validator.js +38 -8
- package/dist/runtime/create-validator.mjs +38 -8
- package/dist/runtime/decide-presence.js +2 -1
- package/dist/runtime/decide-presence.mjs +2 -1
- package/dist/runtime/field-rule-context.d.ts +32 -0
- package/dist/runtime/field-rule-context.js +48 -0
- package/dist/runtime/field-rule-context.mjs +44 -0
- package/dist/runtime/index-stack.d.ts +29 -4
- package/dist/runtime/index-stack.js +76 -15
- package/dist/runtime/index-stack.mjs +76 -15
- package/dist/runtime/run-array-node.js +22 -10
- package/dist/runtime/run-array-node.mjs +22 -10
- package/dist/runtime/run-field.js +47 -17
- package/dist/runtime/run-field.mjs +47 -17
- package/dist/runtime/run-plan.js +5 -1
- package/dist/runtime/run-plan.mjs +5 -1
- package/dist/standard-schema/index.d.ts +6 -0
- package/dist/standard-schema/index.js +7 -0
- package/dist/standard-schema/index.mjs +2 -0
- package/dist/standard-schema/split-issue-path.d.ts +9 -0
- package/dist/standard-schema/split-issue-path.js +66 -0
- package/dist/standard-schema/split-issue-path.mjs +63 -0
- package/dist/standard-schema/standard-schema.types.d.ts +46 -0
- package/dist/standard-schema/standard-schema.types.js +13 -0
- package/dist/standard-schema/standard-schema.types.mjs +12 -0
- package/dist/standard-schema/to-standard-schema.d.ts +41 -0
- package/dist/standard-schema/to-standard-schema.js +60 -0
- package/dist/standard-schema/to-standard-schema.mjs +57 -0
- package/dist/standard-schema.d.ts +1 -0
- package/dist/standard-schema.js +2 -0
- package/dist/standard-schema.mjs +1 -0
- package/dist/types/index.d.ts +24 -0
- package/dist/types/index.js +18 -0
- package/dist/types/index.mjs +17 -0
- package/package.json +42 -19
|
@@ -32,9 +32,32 @@ function writeInto(container, keys, depth, value) {
|
|
|
32
32
|
* conjure an array — the declaration grammar cannot express `items[0]`, so a
|
|
33
33
|
* numeric key here is a Record key.
|
|
34
34
|
*/
|
|
35
|
+
/**
|
|
36
|
+
* キーを own プロパティとして置く。**代入演算子を使わない。**
|
|
37
|
+
*
|
|
38
|
+
* `copy[key] = value` は key が "__proto__" のとき Object.prototype の
|
|
39
|
+
* アクセサ (setter) を呼び、own プロパティを作る代わりにプロトタイプを
|
|
40
|
+
* 差し替えてしまう。defineProperty はアクセサを見ずに own プロパティを
|
|
41
|
+
* 定義するので、"__proto__" という名前のプロパティを安全に持てる。
|
|
42
|
+
*
|
|
43
|
+
* "constructor" と "prototype" は Object.prototype 上でデータプロパティ
|
|
44
|
+
* なので代入でも own プロパティになるが、キーごとに分岐すると分岐のほうを
|
|
45
|
+
* 間違えるので一律にこちらを通す。
|
|
46
|
+
*
|
|
47
|
+
* これが「宣言パスに __proto__ を書けるようにする」の前提。書き込みが安全に
|
|
48
|
+
* なったので、パス文法の側で拒否する必要が無くなった (reserved-segment.ts)。
|
|
49
|
+
*/
|
|
50
|
+
function putOwnProperty(target, key, value) {
|
|
51
|
+
Object.defineProperty(target, key, {
|
|
52
|
+
value,
|
|
53
|
+
writable: true,
|
|
54
|
+
enumerable: true,
|
|
55
|
+
configurable: true,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
35
58
|
function vivify(key, written) {
|
|
36
59
|
const created = {};
|
|
37
|
-
created
|
|
60
|
+
putOwnProperty(created, key, written);
|
|
38
61
|
return created;
|
|
39
62
|
}
|
|
40
63
|
function copyWith(container, key, value) {
|
|
@@ -46,7 +69,9 @@ function copyWith(container, key, value) {
|
|
|
46
69
|
copy[index] = value;
|
|
47
70
|
return copy;
|
|
48
71
|
}
|
|
72
|
+
// スプレッドは own の列挙可能プロパティを CreateDataProperty で写すので、
|
|
73
|
+
// ここでは setter は動かない。危ないのは下の代入だけ。
|
|
49
74
|
const copy = { ...container };
|
|
50
|
-
copy
|
|
75
|
+
putOwnProperty(copy, key, value);
|
|
51
76
|
return copy;
|
|
52
77
|
}
|
|
@@ -1,7 +1,25 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
1
|
+
/**
|
|
2
|
+
* `Object.prototype` 上に同名のものがあるキー。
|
|
3
|
+
*
|
|
4
|
+
* **これはもう拒否リストではない。** 以前はこの3つを宣言パスに書けなくして
|
|
5
|
+
* いたが、その拒否は過剰だった。危険なのは書き込みだけで、しかも本当に危ない
|
|
6
|
+
* のは "__proto__" ひとつである:
|
|
7
|
+
*
|
|
8
|
+
* 読み取り create-value-reader.ts が hasOwnProperty.call で own プロパティ
|
|
9
|
+
* しか読まないので、プロトタイプは最初から辿らない
|
|
10
|
+
* 書き込み `target[key] = value` は "__proto__" のとき Object.prototype の
|
|
11
|
+
* **アクセサ** を呼び、own プロパティを作らずプロトタイプを差し替える。
|
|
12
|
+
* "constructor" と "prototype" はデータプロパティなので代入でも
|
|
13
|
+
* own プロパティになるだけで、汚染にはならない
|
|
14
|
+
*
|
|
15
|
+
* create-value-writer.ts が代入をやめて defineProperty に移したことで、
|
|
16
|
+
* この経路が閉じた。したがって名前で拒否する必要が無くなり、
|
|
17
|
+
* `{ "properties": { "__proto__": ... } }` のようなスキーマを検証できる
|
|
18
|
+
* ようになった (JSON-Schema-Test-Suite の properties.json が要求している)。
|
|
19
|
+
*
|
|
20
|
+
* リスト自体は残す。テストが「この3つを書いても Object.prototype が汚れない」
|
|
21
|
+
* ことを名指しで確認するのに使う (test/unit/path/create-value-writer.test.ts)。
|
|
22
|
+
*/
|
|
5
23
|
export declare const RESERVED_SEGMENTS: readonly string[];
|
|
6
24
|
/** Thrown at BUILD time for every malformed or unsafe path. A declared rule
|
|
7
25
|
* must either execute or fail loudly; the legacy silent `return () => null`
|
|
@@ -13,10 +13,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
13
13
|
exports.PathSyntaxError = exports.RESERVED_SEGMENTS = void 0;
|
|
14
14
|
exports.isReservedSegment = isReservedSegment;
|
|
15
15
|
exports.assertDeclarableKey = assertDeclarableKey;
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
/**
|
|
17
|
+
* `Object.prototype` 上に同名のものがあるキー。
|
|
18
|
+
*
|
|
19
|
+
* **これはもう拒否リストではない。** 以前はこの3つを宣言パスに書けなくして
|
|
20
|
+
* いたが、その拒否は過剰だった。危険なのは書き込みだけで、しかも本当に危ない
|
|
21
|
+
* のは "__proto__" ひとつである:
|
|
22
|
+
*
|
|
23
|
+
* 読み取り create-value-reader.ts が hasOwnProperty.call で own プロパティ
|
|
24
|
+
* しか読まないので、プロトタイプは最初から辿らない
|
|
25
|
+
* 書き込み `target[key] = value` は "__proto__" のとき Object.prototype の
|
|
26
|
+
* **アクセサ** を呼び、own プロパティを作らずプロトタイプを差し替える。
|
|
27
|
+
* "constructor" と "prototype" はデータプロパティなので代入でも
|
|
28
|
+
* own プロパティになるだけで、汚染にはならない
|
|
29
|
+
*
|
|
30
|
+
* create-value-writer.ts が代入をやめて defineProperty に移したことで、
|
|
31
|
+
* この経路が閉じた。したがって名前で拒否する必要が無くなり、
|
|
32
|
+
* `{ "properties": { "__proto__": ... } }` のようなスキーマを検証できる
|
|
33
|
+
* ようになった (JSON-Schema-Test-Suite の properties.json が要求している)。
|
|
34
|
+
*
|
|
35
|
+
* リスト自体は残す。テストが「この3つを書いても Object.prototype が汚れない」
|
|
36
|
+
* ことを名指しで確認するのに使う (test/unit/path/create-value-writer.test.ts)。
|
|
37
|
+
*/
|
|
20
38
|
exports.RESERVED_SEGMENTS = Object.freeze([
|
|
21
39
|
"__proto__",
|
|
22
40
|
"constructor",
|
|
@@ -62,7 +80,9 @@ function assertDeclarableKey(key, source) {
|
|
|
62
80
|
throw new PathSyntaxError(source, `the key ${JSON.stringify(key)} contains a bracket; "[*]" is the only ` +
|
|
63
81
|
"bracket form and it must trail a key");
|
|
64
82
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
83
|
+
// 予約セグメントの拒否はここから外した。理由は RESERVED_SEGMENTS の
|
|
84
|
+
// コメントに書いてある。要約すると、危険なのは書き込みだけで、その書き込みは
|
|
85
|
+
// create-value-writer.ts が defineProperty に移したので安全になった。
|
|
86
|
+
// 名前で拒否する必要が無くなり、JSON Schema が "__proto__" というキーを
|
|
87
|
+
// 持つオブジェクトを検証できるようになった。
|
|
68
88
|
}
|
|
@@ -8,10 +8,28 @@
|
|
|
8
8
|
// Putting the class the other way round would make the two files mutually
|
|
9
9
|
// dependent for no gain.
|
|
10
10
|
// ===========================================================================
|
|
11
|
-
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
/**
|
|
12
|
+
* `Object.prototype` 上に同名のものがあるキー。
|
|
13
|
+
*
|
|
14
|
+
* **これはもう拒否リストではない。** 以前はこの3つを宣言パスに書けなくして
|
|
15
|
+
* いたが、その拒否は過剰だった。危険なのは書き込みだけで、しかも本当に危ない
|
|
16
|
+
* のは "__proto__" ひとつである:
|
|
17
|
+
*
|
|
18
|
+
* 読み取り create-value-reader.ts が hasOwnProperty.call で own プロパティ
|
|
19
|
+
* しか読まないので、プロトタイプは最初から辿らない
|
|
20
|
+
* 書き込み `target[key] = value` は "__proto__" のとき Object.prototype の
|
|
21
|
+
* **アクセサ** を呼び、own プロパティを作らずプロトタイプを差し替える。
|
|
22
|
+
* "constructor" と "prototype" はデータプロパティなので代入でも
|
|
23
|
+
* own プロパティになるだけで、汚染にはならない
|
|
24
|
+
*
|
|
25
|
+
* create-value-writer.ts が代入をやめて defineProperty に移したことで、
|
|
26
|
+
* この経路が閉じた。したがって名前で拒否する必要が無くなり、
|
|
27
|
+
* `{ "properties": { "__proto__": ... } }` のようなスキーマを検証できる
|
|
28
|
+
* ようになった (JSON-Schema-Test-Suite の properties.json が要求している)。
|
|
29
|
+
*
|
|
30
|
+
* リスト自体は残す。テストが「この3つを書いても Object.prototype が汚れない」
|
|
31
|
+
* ことを名指しで確認するのに使う (test/unit/path/create-value-writer.test.ts)。
|
|
32
|
+
*/
|
|
15
33
|
export const RESERVED_SEGMENTS = Object.freeze([
|
|
16
34
|
"__proto__",
|
|
17
35
|
"constructor",
|
|
@@ -56,7 +74,9 @@ export function assertDeclarableKey(key, source) {
|
|
|
56
74
|
throw new PathSyntaxError(source, `the key ${JSON.stringify(key)} contains a bracket; "[*]" is the only ` +
|
|
57
75
|
"bracket form and it must trail a key");
|
|
58
76
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
77
|
+
// 予約セグメントの拒否はここから外した。理由は RESERVED_SEGMENTS の
|
|
78
|
+
// コメントに書いてある。要約すると、危険なのは書き込みだけで、その書き込みは
|
|
79
|
+
// create-value-writer.ts が defineProperty に移したので安全になった。
|
|
80
|
+
// 名前で拒否する必要が無くなり、JSON Schema が "__proto__" というキーを
|
|
81
|
+
// 持つオブジェクトを検証できるようになった。
|
|
62
82
|
}
|
|
@@ -16,6 +16,19 @@ export interface PresenceAllowance {
|
|
|
16
16
|
readonly allowUndefined: boolean;
|
|
17
17
|
readonly allowNull: boolean;
|
|
18
18
|
readonly emptyStringIsMissing: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* True when `null` is a VALUE this subject has to judge, rather than an
|
|
21
|
+
* absence presence may settle. Draft-07 sub-schemas need it: `false`,
|
|
22
|
+
* `{"not": {}}` and an `enum` without null all forbid null WITHOUT saying
|
|
23
|
+
* anything about `type`, and presence — which runs first — was answering
|
|
24
|
+
* for them. `[null]` passed `{"items":{"not":{}}}` because no check ever
|
|
25
|
+
* ran.
|
|
26
|
+
*
|
|
27
|
+
* Optional, and absent means false: a field the user declared keeps the
|
|
28
|
+
* builder's meaning, where `.nullable()` ENDS the field on null. Only
|
|
29
|
+
* src/json-schema/ turns it on.
|
|
30
|
+
*/
|
|
31
|
+
readonly nullIsValue?: boolean;
|
|
19
32
|
}
|
|
20
33
|
export interface PresenceRule extends PresenceAllowance {
|
|
21
34
|
readonly kind: "presence";
|
|
@@ -16,6 +16,17 @@ export interface PresenceSpec<C extends MessageContextExtra> {
|
|
|
16
16
|
readonly allowUndefined: boolean;
|
|
17
17
|
readonly allowNull: boolean;
|
|
18
18
|
readonly emptyStringIsMissing: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* True when `null` must be JUDGED here rather than settled by presence.
|
|
21
|
+
*
|
|
22
|
+
* OPTIONAL, and false by default, because `presence()` is an API plugin
|
|
23
|
+
* AUTHORS use: making it required would break every plugin outside this
|
|
24
|
+
* repository to add a flag almost none of them want. The default is the
|
|
25
|
+
* behaviour that was always there — `.nullable()` ends the field on null.
|
|
26
|
+
* src/json-schema/ sets it, because a DOCUMENT decides whether null is
|
|
27
|
+
* allowed and `type` is not the only keyword that decides it.
|
|
28
|
+
*/
|
|
29
|
+
readonly nullIsValue?: boolean;
|
|
19
30
|
describe(ctx: MessageContext): string;
|
|
20
31
|
buildMessageContext(): C;
|
|
21
32
|
}
|
|
@@ -28,6 +28,7 @@ function presence(spec) {
|
|
|
28
28
|
allowUndefined: spec.allowUndefined,
|
|
29
29
|
allowNull: spec.allowNull,
|
|
30
30
|
emptyStringIsMissing: spec.emptyStringIsMissing,
|
|
31
|
+
nullIsValue: spec.nullIsValue === true,
|
|
31
32
|
describe: (ctx) => (0, rule_build_context_1.renderMessage)(spec.messageFactory, ctx, spec.buildMessageContext(), spec.describe(ctx)),
|
|
32
33
|
};
|
|
33
34
|
}
|
|
@@ -18,6 +18,7 @@ export function presence(spec) {
|
|
|
18
18
|
allowUndefined: spec.allowUndefined,
|
|
19
19
|
allowNull: spec.allowNull,
|
|
20
20
|
emptyStringIsMissing: spec.emptyStringIsMissing,
|
|
21
|
+
nullIsValue: spec.nullIsValue === true,
|
|
21
22
|
describe: (ctx) => renderMessage(spec.messageFactory, ctx, spec.buildMessageContext(), spec.describe(ctx)),
|
|
22
23
|
};
|
|
23
24
|
}
|
|
@@ -45,6 +45,22 @@ export interface TransformOut {
|
|
|
45
45
|
export interface GuardOut {
|
|
46
46
|
readonly [MARKER]: "guardOut";
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Like GuardOut, these exist so ChainMethod can give the method a call-site
|
|
50
|
+
* type parameter. ResolveArgs resolves each argument against a FIXED
|
|
51
|
+
* TRoot/TValue and cannot make argument 2 depend on argument 1, so a plugin
|
|
52
|
+
* whose second argument is typed by its first has to come through this door.
|
|
53
|
+
*
|
|
54
|
+
* `StitchOut` types the FIELD VALUES a cross-field predicate receives, from
|
|
55
|
+
* the paths named in argument 1. `BundleOut` types the SUBJECT of a sub-chain,
|
|
56
|
+
* from the alias-to-path map in argument 1.
|
|
57
|
+
*/
|
|
58
|
+
export interface StitchOut {
|
|
59
|
+
readonly [MARKER]: "stitchOut";
|
|
60
|
+
}
|
|
61
|
+
export interface BundleOut {
|
|
62
|
+
readonly [MARKER]: "bundleOut";
|
|
63
|
+
}
|
|
48
64
|
export type PresenceShiftKind = "excludeMissing" | "excludeUndefined" | "excludeNull" | "allowNull";
|
|
49
65
|
export interface PresenceShift<K extends PresenceShiftKind> {
|
|
50
66
|
readonly [MARKER]: "presence";
|
|
@@ -75,6 +91,8 @@ export interface OutputMarkerRegistry {
|
|
|
75
91
|
readonly unchanged: Unchanged;
|
|
76
92
|
readonly transformOut: TransformOut;
|
|
77
93
|
readonly guardOut: GuardOut;
|
|
94
|
+
readonly stitchOut: StitchOut;
|
|
95
|
+
readonly bundleOut: BundleOut;
|
|
78
96
|
readonly excludeMissing: PresenceShift<"excludeMissing">;
|
|
79
97
|
readonly excludeUndefined: PresenceShift<"excludeUndefined">;
|
|
80
98
|
readonly excludeNull: PresenceShift<"excludeNull">;
|
|
@@ -21,6 +21,8 @@ export interface PluginDefinition<TName extends string, TMethod extends string,
|
|
|
21
21
|
* resolves exactly those positions to `readonly Rule[]` before build() runs.
|
|
22
22
|
*/
|
|
23
23
|
readonly subChainArguments?: readonly number[];
|
|
24
|
+
/** See PluginSpec.judgesNull. Read by src/chain/create-chain-node.ts. */
|
|
25
|
+
readonly judgesNull?: boolean;
|
|
24
26
|
readonly signature?: TSig;
|
|
25
27
|
}
|
|
26
28
|
export type AnyPlugin = PluginDefinition<string, string, readonly TypeName[], PluginSignature>;
|
|
@@ -30,6 +32,19 @@ export interface PluginSpec<TName extends string, TMethod extends string, TSlots
|
|
|
30
32
|
readonly slots: TSlots;
|
|
31
33
|
readonly build: PluginBuild<TSig>;
|
|
32
34
|
readonly subChainArguments?: readonly number[];
|
|
35
|
+
/**
|
|
36
|
+
* True when this plugin's rule must be given `null` to judge, instead of
|
|
37
|
+
* presence settling it first.
|
|
38
|
+
*
|
|
39
|
+
* A field with no presence rule carries OPEN_PRESENCE, which ENDS the field
|
|
40
|
+
* on null before a single check runs. For most plugins that is right —
|
|
41
|
+
* `.min(3)` has no business firing on a value the schema said may be
|
|
42
|
+
* absent. It is wrong for a plugin that carries a whole document: a JSON
|
|
43
|
+
* Schema says whether null is allowed, and `false`, `{"not":{}}` and an
|
|
44
|
+
* `enum` without null all forbid it while saying nothing about `type`.
|
|
45
|
+
* Without this, `.jsonSchemaFullFeature({"type":"string"})` accepted null.
|
|
46
|
+
*/
|
|
47
|
+
readonly judgesNull?: boolean;
|
|
33
48
|
}
|
|
34
49
|
/** Curried: the signature is explicit, the identity literals are inferred. */
|
|
35
50
|
export declare function definePlugin<TSig extends PluginSignature>(): <TName extends string, TMethod extends string, TSlots extends readonly TypeName[]>(spec: PluginSpec<TName, TMethod, TSlots, TSig>) => PluginDefinition<TName, TMethod, TSlots, TSig>;
|
|
@@ -9,6 +9,7 @@ function definePlugin() {
|
|
|
9
9
|
method: spec.method,
|
|
10
10
|
slots: spec.slots,
|
|
11
11
|
build: spec.build,
|
|
12
|
+
judgesNull: spec.judgesNull,
|
|
12
13
|
// Only present when the plugin declared one, so a plugin that takes no
|
|
13
14
|
// sub-chain keeps exactly the four members it always had.
|
|
14
15
|
...(spec.subChainArguments === undefined
|
|
@@ -5,6 +5,7 @@ export function definePlugin() {
|
|
|
5
5
|
method: spec.method,
|
|
6
6
|
slots: spec.slots,
|
|
7
7
|
build: spec.build,
|
|
8
|
+
judgesNull: spec.judgesNull,
|
|
8
9
|
// Only present when the plugin declared one, so a plugin that takes no
|
|
9
10
|
// sub-chain keeps exactly the four members it always had.
|
|
10
11
|
...(spec.subChainArguments === undefined
|
|
@@ -41,6 +41,7 @@ export { requiredPlugin } from "./required";
|
|
|
41
41
|
export { requiredIfPlugin } from "./required-if";
|
|
42
42
|
export { skipPlugin } from "./skip";
|
|
43
43
|
export { stitchPlugin } from "./stitch";
|
|
44
|
+
export { stitchWithPlugin } from "./stitch-with";
|
|
44
45
|
export { stringAlphanumericPlugin } from "./string-alphanumeric";
|
|
45
46
|
export { stringBase64Plugin } from "./string-base64";
|
|
46
47
|
export { stringContentEncodingPlugin } from "./string-content-encoding";
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// GENERATED FILE - 手で編集しないでください。
|
|
3
3
|
// 生成元: プラグインディレクトリ構造 (scripts/catalog/build-plugin-catalog.ts)。
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.
|
|
6
|
-
exports.writeOnlyPlugin = exports.validateIfPlugin = exports.uuidPlugin = exports.unionGuardPlugin = exports.tupleBuilderPlugin = exports.transformPlugin = exports.stringUrlPlugin = exports.stringUriTemplatePlugin = exports.stringUriReferencePlugin = exports.stringTimePlugin = exports.stringStartsWithPlugin = exports.stringRelativeJsonPointerPlugin = exports.stringRegexPlugin = exports.stringPatternPlugin = exports.stringMinPlugin = exports.stringMaxPlugin = exports.stringJsonPointerPlugin = exports.stringIriReferencePlugin = exports.stringIriPlugin = exports.stringIpv6Plugin = exports.stringIpv4Plugin = exports.stringIdnHostnamePlugin = exports.stringIdnEmailPlugin = exports.stringHostnamePlugin = exports.stringExactLengthPlugin = exports.stringEndsWithPlugin = exports.stringEmailPlugin = void 0;
|
|
5
|
+
exports.stringDatetimePlugin = exports.stringDatePlugin = exports.stringContentMediaTypePlugin = exports.stringContentEncodingPlugin = exports.stringBase64Plugin = exports.stringAlphanumericPlugin = exports.stitchWithPlugin = exports.stitchPlugin = exports.skipPlugin = exports.requiredIfPlugin = exports.requiredPlugin = exports.readOnlyPlugin = exports.orFailPlugin = exports.optionalIfPlugin = exports.optionalPlugin = exports.oneOfPlugin = exports.objectRecursivelyPlugin = exports.objectPropertyNamesPlugin = exports.objectPatternPropertiesPlugin = exports.objectMinPropertiesPlugin = exports.objectMaxPropertiesPlugin = exports.objectDependentSchemasPlugin = exports.objectDependentRequiredPlugin = exports.objectAdditionalPropertiesSchemaPlugin = exports.objectAdditionalPropertiesPlugin = exports.objectPlugin = exports.numberRangePlugin = exports.numberPositivePlugin = exports.numberNegativePlugin = exports.numberMultipleOfPlugin = exports.numberMinPlugin = exports.numberMaxPlugin = exports.numberIntegerPlugin = exports.numberFinitePlugin = exports.nullablePlugin = exports.literalPlugin = exports.jsonSchemaFullFeaturePlugin = exports.jsonSchemaPlugin = exports.fromContextPlugin = exports.customPlugin = exports.conditionalSchemaPlugin = exports.compareFieldPlugin = exports.booleanTruthyPlugin = exports.booleanFalsyPlugin = exports.arrayUniquePlugin = exports.arrayMinLengthPlugin = exports.arrayMaxLengthPlugin = exports.arrayIncludesPlugin = exports.arrayEachPlugin = exports.arrayContainsPlugin = void 0;
|
|
6
|
+
exports.writeOnlyPlugin = exports.validateIfPlugin = exports.uuidPlugin = exports.unionGuardPlugin = exports.tupleBuilderPlugin = exports.transformPlugin = exports.stringUrlPlugin = exports.stringUriTemplatePlugin = exports.stringUriReferencePlugin = exports.stringTimePlugin = exports.stringStartsWithPlugin = exports.stringRelativeJsonPointerPlugin = exports.stringRegexPlugin = exports.stringPatternPlugin = exports.stringMinPlugin = exports.stringMaxPlugin = exports.stringJsonPointerPlugin = exports.stringIriReferencePlugin = exports.stringIriPlugin = exports.stringIpv6Plugin = exports.stringIpv4Plugin = exports.stringIdnHostnamePlugin = exports.stringIdnEmailPlugin = exports.stringHostnamePlugin = exports.stringExactLengthPlugin = exports.stringEndsWithPlugin = exports.stringEmailPlugin = exports.stringDurationPlugin = void 0;
|
|
7
7
|
var array_contains_1 = require("./array-contains");
|
|
8
8
|
Object.defineProperty(exports, "arrayContainsPlugin", { enumerable: true, get: function () { return array_contains_1.arrayContainsPlugin; } });
|
|
9
9
|
var array_each_1 = require("./array-each");
|
|
@@ -90,6 +90,8 @@ var skip_1 = require("./skip");
|
|
|
90
90
|
Object.defineProperty(exports, "skipPlugin", { enumerable: true, get: function () { return skip_1.skipPlugin; } });
|
|
91
91
|
var stitch_1 = require("./stitch");
|
|
92
92
|
Object.defineProperty(exports, "stitchPlugin", { enumerable: true, get: function () { return stitch_1.stitchPlugin; } });
|
|
93
|
+
var stitch_with_1 = require("./stitch-with");
|
|
94
|
+
Object.defineProperty(exports, "stitchWithPlugin", { enumerable: true, get: function () { return stitch_with_1.stitchWithPlugin; } });
|
|
93
95
|
var string_alphanumeric_1 = require("./string-alphanumeric");
|
|
94
96
|
Object.defineProperty(exports, "stringAlphanumericPlugin", { enumerable: true, get: function () { return string_alphanumeric_1.stringAlphanumericPlugin; } });
|
|
95
97
|
var string_base64_1 = require("./string-base64");
|
|
@@ -43,6 +43,7 @@ export { requiredPlugin } from "./required/index.mjs";
|
|
|
43
43
|
export { requiredIfPlugin } from "./required-if/index.mjs";
|
|
44
44
|
export { skipPlugin } from "./skip/index.mjs";
|
|
45
45
|
export { stitchPlugin } from "./stitch/index.mjs";
|
|
46
|
+
export { stitchWithPlugin } from "./stitch-with/index.mjs";
|
|
46
47
|
export { stringAlphanumericPlugin } from "./string-alphanumeric/index.mjs";
|
|
47
48
|
export { stringBase64Plugin } from "./string-base64/index.mjs";
|
|
48
49
|
export { stringContentEncodingPlugin } from "./string-content-encoding/index.mjs";
|
|
@@ -46,6 +46,7 @@ exports.PLUGIN_MANIFEST = [
|
|
|
46
46
|
{ directoryName: "required-if", subpathName: "requiredIf", tier: "isolated", entryFile: "src/plugins/required-if/index.ts", exportedSymbols: ["requiredIfPlugin"] },
|
|
47
47
|
{ directoryName: "skip", subpathName: "skip", tier: "isolated", entryFile: "src/plugins/skip/index.ts", exportedSymbols: ["skipPlugin"] },
|
|
48
48
|
{ directoryName: "stitch", subpathName: "stitch", tier: "isolated", entryFile: "src/plugins/stitch/index.ts", exportedSymbols: ["stitchPlugin"] },
|
|
49
|
+
{ directoryName: "stitch-with", subpathName: "stitchWith", tier: "isolated", entryFile: "src/plugins/stitch-with/index.ts", exportedSymbols: ["stitchWithPlugin"] },
|
|
49
50
|
{ directoryName: "string-alphanumeric", subpathName: "stringAlphanumeric", tier: "isolated", entryFile: "src/plugins/string-alphanumeric/index.ts", exportedSymbols: ["stringAlphanumericPlugin"] },
|
|
50
51
|
{ directoryName: "string-base64", subpathName: "stringBase64", tier: "isolated", entryFile: "src/plugins/string-base64/index.ts", exportedSymbols: ["stringBase64Plugin"] },
|
|
51
52
|
{ directoryName: "string-content-encoding", subpathName: "stringContentEncoding", tier: "isolated", entryFile: "src/plugins/string-content-encoding/index.ts", exportedSymbols: ["stringContentEncodingPlugin"] },
|
|
@@ -43,6 +43,7 @@ export const PLUGIN_MANIFEST = [
|
|
|
43
43
|
{ directoryName: "required-if", subpathName: "requiredIf", tier: "isolated", entryFile: "src/plugins/required-if/index.ts", exportedSymbols: ["requiredIfPlugin"] },
|
|
44
44
|
{ directoryName: "skip", subpathName: "skip", tier: "isolated", entryFile: "src/plugins/skip/index.ts", exportedSymbols: ["skipPlugin"] },
|
|
45
45
|
{ directoryName: "stitch", subpathName: "stitch", tier: "isolated", entryFile: "src/plugins/stitch/index.ts", exportedSymbols: ["stitchPlugin"] },
|
|
46
|
+
{ directoryName: "stitch-with", subpathName: "stitchWith", tier: "isolated", entryFile: "src/plugins/stitch-with/index.ts", exportedSymbols: ["stitchWithPlugin"] },
|
|
46
47
|
{ directoryName: "string-alphanumeric", subpathName: "stringAlphanumeric", tier: "isolated", entryFile: "src/plugins/string-alphanumeric/index.ts", exportedSymbols: ["stringAlphanumericPlugin"] },
|
|
47
48
|
{ directoryName: "string-base64", subpathName: "stringBase64", tier: "isolated", entryFile: "src/plugins/string-base64/index.ts", exportedSymbols: ["stringBase64Plugin"] },
|
|
48
49
|
{ directoryName: "string-content-encoding", subpathName: "stringContentEncoding", tier: "isolated", entryFile: "src/plugins/string-content-encoding/index.ts", exportedSymbols: ["stringContentEncodingPlugin"] },
|
|
@@ -8,7 +8,7 @@ import type { UnexpectedPropertiesExtra } from "./object-additional-properties";
|
|
|
8
8
|
* needsFromOthers), which is why it is spread on rather than passed in.
|
|
9
9
|
*/
|
|
10
10
|
export declare const objectAdditionalPropertiesSchemaPlugin: import("../../plugin-kit/plugin-definition").PluginDefinition<"objectAdditionalPropertiesSchema", "additionalPropertiesSchema", readonly ["object"], {
|
|
11
|
-
args: readonly [schema: PropertyValueChain, allowedProperties?: readonly string[]];
|
|
11
|
+
args: readonly [schema: PropertyValueChain, allowedProperties?: readonly string[], allowedPatterns?: readonly string[]];
|
|
12
12
|
out: Unchanged;
|
|
13
13
|
context: UnexpectedPropertiesExtra;
|
|
14
14
|
}>;
|
|
@@ -12,6 +12,7 @@ exports.objectAdditionalPropertiesSchemaPlugin = void 0;
|
|
|
12
12
|
const types_1 = require("../../types");
|
|
13
13
|
const create_rule_1 = require("../../plugin-kit/create-rule");
|
|
14
14
|
const plugin_definition_1 = require("../../plugin-kit/plugin-definition");
|
|
15
|
+
const select_additional_keys_1 = require("./select-additional-keys");
|
|
15
16
|
/**
|
|
16
17
|
* WHICH argument positions carry a sub-chain cannot be recovered from a
|
|
17
18
|
* plugin's type at run time — a NarrowedChain and a RootPredicate are both
|
|
@@ -24,8 +25,9 @@ exports.objectAdditionalPropertiesSchemaPlugin =
|
|
|
24
25
|
name: "objectAdditionalPropertiesSchema",
|
|
25
26
|
method: "additionalPropertiesSchema",
|
|
26
27
|
slots: ["object"],
|
|
27
|
-
build: (ctx, schema, allowedProperties) => {
|
|
28
|
+
build: (ctx, schema, allowedProperties, allowedPatterns) => {
|
|
28
29
|
const known = new Set(allowedProperties ?? ctx.declaredSiblingKeys);
|
|
30
|
+
const patterns = (0, select_additional_keys_1.compilePatterns)(allowedPatterns);
|
|
29
31
|
const branches = [
|
|
30
32
|
(0, create_rule_1.branch)("additional", schema),
|
|
31
33
|
];
|
|
@@ -37,7 +39,7 @@ exports.objectAdditionalPropertiesSchemaPlugin =
|
|
|
37
39
|
combine: (runners) => (value, runCtx) => {
|
|
38
40
|
if (!(0, types_1.isPlainObject)(value))
|
|
39
41
|
return types_1.PASS;
|
|
40
|
-
const extra =
|
|
42
|
+
const extra = (0, select_additional_keys_1.selectAdditionalKeys)(value, known, patterns);
|
|
41
43
|
if (extra.length === 0)
|
|
42
44
|
return types_1.PASS;
|
|
43
45
|
const runner = runners[0];
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { PASS, fail, isPlainObject, isStringArray } from "../../types/index.mjs";
|
|
10
10
|
import { branch, composite } from "../../plugin-kit/create-rule.mjs";
|
|
11
11
|
import { definePlugin } from "../../plugin-kit/plugin-definition.mjs";
|
|
12
|
+
import { compilePatterns, selectAdditionalKeys, } from "./select-additional-keys.mjs";
|
|
12
13
|
/**
|
|
13
14
|
* WHICH argument positions carry a sub-chain cannot be recovered from a
|
|
14
15
|
* plugin's type at run time — a NarrowedChain and a RootPredicate are both
|
|
@@ -21,8 +22,9 @@ export const objectAdditionalPropertiesSchemaPlugin =
|
|
|
21
22
|
name: "objectAdditionalPropertiesSchema",
|
|
22
23
|
method: "additionalPropertiesSchema",
|
|
23
24
|
slots: ["object"],
|
|
24
|
-
build: (ctx, schema, allowedProperties) => {
|
|
25
|
+
build: (ctx, schema, allowedProperties, allowedPatterns) => {
|
|
25
26
|
const known = new Set(allowedProperties ?? ctx.declaredSiblingKeys);
|
|
27
|
+
const patterns = compilePatterns(allowedPatterns);
|
|
26
28
|
const branches = [
|
|
27
29
|
branch("additional", schema),
|
|
28
30
|
];
|
|
@@ -34,7 +36,7 @@ export const objectAdditionalPropertiesSchemaPlugin =
|
|
|
34
36
|
combine: (runners) => (value, runCtx) => {
|
|
35
37
|
if (!isPlainObject(value))
|
|
36
38
|
return PASS;
|
|
37
|
-
const extra =
|
|
39
|
+
const extra = selectAdditionalKeys(value, known, patterns);
|
|
38
40
|
if (extra.length === 0)
|
|
39
41
|
return PASS;
|
|
40
42
|
const runner = runners[0];
|
|
@@ -3,7 +3,7 @@ export interface UnexpectedPropertiesExtra {
|
|
|
3
3
|
readonly extraProperties: readonly string[];
|
|
4
4
|
}
|
|
5
5
|
export declare const objectAdditionalPropertiesPlugin: import("../../plugin-kit/plugin-definition").PluginDefinition<"objectAdditionalProperties", "additionalProperties", readonly ["object"], {
|
|
6
|
-
args: readonly [allowed: boolean, allowedProperties?: readonly string[]];
|
|
6
|
+
args: readonly [allowed: boolean, allowedProperties?: readonly string[], allowedPatterns?: readonly string[]];
|
|
7
7
|
out: Unchanged;
|
|
8
8
|
context: UnexpectedPropertiesExtra;
|
|
9
9
|
}>;
|
|
@@ -13,12 +13,14 @@ exports.objectAdditionalPropertiesPlugin = void 0;
|
|
|
13
13
|
const types_1 = require("../../types");
|
|
14
14
|
const create_rule_1 = require("../../plugin-kit/create-rule");
|
|
15
15
|
const plugin_definition_1 = require("../../plugin-kit/plugin-definition");
|
|
16
|
+
const select_additional_keys_1 = require("./select-additional-keys");
|
|
16
17
|
exports.objectAdditionalPropertiesPlugin = (0, plugin_definition_1.definePlugin)()({
|
|
17
18
|
name: "objectAdditionalProperties",
|
|
18
19
|
method: "additionalProperties",
|
|
19
20
|
slots: ["object"],
|
|
20
|
-
build: (ctx, allowed, allowedProperties) => {
|
|
21
|
+
build: (ctx, allowed, allowedProperties, allowedPatterns) => {
|
|
21
22
|
const known = new Set(allowedProperties ?? ctx.declaredSiblingKeys);
|
|
23
|
+
const patterns = (0, select_additional_keys_1.compilePatterns)(allowedPatterns);
|
|
22
24
|
return (0, create_rule_1.check)({
|
|
23
25
|
code: ctx.code,
|
|
24
26
|
messageFactory: ctx.messageFactory,
|
|
@@ -28,7 +30,7 @@ exports.objectAdditionalPropertiesPlugin = (0, plugin_definition_1.definePlugin)
|
|
|
28
30
|
return types_1.PASS;
|
|
29
31
|
if (!(0, types_1.isPlainObject)(value))
|
|
30
32
|
return types_1.PASS;
|
|
31
|
-
const extra =
|
|
33
|
+
const extra = (0, select_additional_keys_1.selectAdditionalKeys)(value, known, patterns);
|
|
32
34
|
return extra.length === 0 ? types_1.PASS : (0, types_1.fail)({ actual: extra });
|
|
33
35
|
},
|
|
34
36
|
describe: (detail) => `Unexpected properties: ${String(detail.actual)}`,
|
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
import { PASS, fail, isPlainObject, isStringArray } from "../../types/index.mjs";
|
|
11
11
|
import { check } from "../../plugin-kit/create-rule.mjs";
|
|
12
12
|
import { definePlugin } from "../../plugin-kit/plugin-definition.mjs";
|
|
13
|
+
import { compilePatterns, selectAdditionalKeys, } from "./select-additional-keys.mjs";
|
|
13
14
|
export const objectAdditionalPropertiesPlugin = /*#__PURE__*/ definePlugin()({
|
|
14
15
|
name: "objectAdditionalProperties",
|
|
15
16
|
method: "additionalProperties",
|
|
16
17
|
slots: ["object"],
|
|
17
|
-
build: (ctx, allowed, allowedProperties) => {
|
|
18
|
+
build: (ctx, allowed, allowedProperties, allowedPatterns) => {
|
|
18
19
|
const known = new Set(allowedProperties ?? ctx.declaredSiblingKeys);
|
|
20
|
+
const patterns = compilePatterns(allowedPatterns);
|
|
19
21
|
return check({
|
|
20
22
|
code: ctx.code,
|
|
21
23
|
messageFactory: ctx.messageFactory,
|
|
@@ -25,7 +27,7 @@ export const objectAdditionalPropertiesPlugin = /*#__PURE__*/ definePlugin()({
|
|
|
25
27
|
return PASS;
|
|
26
28
|
if (!isPlainObject(value))
|
|
27
29
|
return PASS;
|
|
28
|
-
const extra =
|
|
30
|
+
const extra = selectAdditionalKeys(value, known, patterns);
|
|
29
31
|
return extra.length === 0 ? PASS : fail({ actual: extra });
|
|
30
32
|
},
|
|
31
33
|
describe: (detail) => `Unexpected properties: ${String(detail.actual)}`,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* パターンは build 時に一度だけコンパイルする。実行時は回すだけ、という
|
|
3
|
+
* 設計に合わせるためで、キーごとに new RegExp すると O(キー数 x パターン数)
|
|
4
|
+
* のコンパイルが毎回走る。
|
|
5
|
+
*
|
|
6
|
+
* 壊れた正規表現は無視する。スキーマ側の誤りでビルド全体を落とすより、
|
|
7
|
+
* そのパターンが誰にも一致しないほうがまし (Draft-07 は ECMA-262 の
|
|
8
|
+
* 正規表現を求めるが、方言差で通らないものが現実には来る)。
|
|
9
|
+
*/
|
|
10
|
+
export declare function compilePatterns(patterns: readonly string[] | undefined): readonly RegExp[];
|
|
11
|
+
/**
|
|
12
|
+
* 宣言済みのキー名にも、どのパターンにも該当しないキーを返す。
|
|
13
|
+
* 返る配列は入力の列挙順を保つ (issue のメッセージが安定する)。
|
|
14
|
+
*/
|
|
15
|
+
export declare function selectAdditionalKeys(value: Readonly<Record<string, unknown>>, known: ReadonlySet<string>, patterns: readonly RegExp[]): readonly string[];
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ===========================================================================
|
|
3
|
+
// L7 src/plugins/object-additional-properties/select-additional-keys.ts
|
|
4
|
+
//
|
|
5
|
+
// 「additional なキー」を選ぶ規則。boolean 形とスキーマ形の両方が使う。
|
|
6
|
+
//
|
|
7
|
+
// Draft-07 §6.5.4 は additionalProperties の対象を「properties にも
|
|
8
|
+
// patternProperties にも該当しないキー」と定めている。パターンを見落とすと
|
|
9
|
+
// `{"patternProperties":{"^v":{}},"additionalProperties":false}` が
|
|
10
|
+
// {"vroom":2} を誤って拒否する (スイートの
|
|
11
|
+
// "patternProperties are not additional properties" がそれを突く)。
|
|
12
|
+
// ===========================================================================
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.compilePatterns = compilePatterns;
|
|
15
|
+
exports.selectAdditionalKeys = selectAdditionalKeys;
|
|
16
|
+
/**
|
|
17
|
+
* パターンは build 時に一度だけコンパイルする。実行時は回すだけ、という
|
|
18
|
+
* 設計に合わせるためで、キーごとに new RegExp すると O(キー数 x パターン数)
|
|
19
|
+
* のコンパイルが毎回走る。
|
|
20
|
+
*
|
|
21
|
+
* 壊れた正規表現は無視する。スキーマ側の誤りでビルド全体を落とすより、
|
|
22
|
+
* そのパターンが誰にも一致しないほうがまし (Draft-07 は ECMA-262 の
|
|
23
|
+
* 正規表現を求めるが、方言差で通らないものが現実には来る)。
|
|
24
|
+
*/
|
|
25
|
+
function compilePatterns(patterns) {
|
|
26
|
+
if (patterns === undefined || patterns.length === 0)
|
|
27
|
+
return Object.freeze([]);
|
|
28
|
+
const compiled = [];
|
|
29
|
+
for (const pattern of patterns) {
|
|
30
|
+
try {
|
|
31
|
+
compiled.push(new RegExp(pattern, "u"));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
try {
|
|
35
|
+
// "u" が付くと通らない書き方が現実にはある。付けずにもう一度試す。
|
|
36
|
+
compiled.push(new RegExp(pattern));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// どちらでも駄目なら、このパターンは一致しないものとして扱う。
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return Object.freeze(compiled);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 宣言済みのキー名にも、どのパターンにも該当しないキーを返す。
|
|
47
|
+
* 返る配列は入力の列挙順を保つ (issue のメッセージが安定する)。
|
|
48
|
+
*/
|
|
49
|
+
function selectAdditionalKeys(value, known, patterns) {
|
|
50
|
+
return Object.keys(value).filter((key) => !known.has(key) && !patterns.some((pattern) => pattern.test(key)));
|
|
51
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// ===========================================================================
|
|
2
|
+
// L7 src/plugins/object-additional-properties/select-additional-keys.ts
|
|
3
|
+
//
|
|
4
|
+
// 「additional なキー」を選ぶ規則。boolean 形とスキーマ形の両方が使う。
|
|
5
|
+
//
|
|
6
|
+
// Draft-07 §6.5.4 は additionalProperties の対象を「properties にも
|
|
7
|
+
// patternProperties にも該当しないキー」と定めている。パターンを見落とすと
|
|
8
|
+
// `{"patternProperties":{"^v":{}},"additionalProperties":false}` が
|
|
9
|
+
// {"vroom":2} を誤って拒否する (スイートの
|
|
10
|
+
// "patternProperties are not additional properties" がそれを突く)。
|
|
11
|
+
// ===========================================================================
|
|
12
|
+
/**
|
|
13
|
+
* パターンは build 時に一度だけコンパイルする。実行時は回すだけ、という
|
|
14
|
+
* 設計に合わせるためで、キーごとに new RegExp すると O(キー数 x パターン数)
|
|
15
|
+
* のコンパイルが毎回走る。
|
|
16
|
+
*
|
|
17
|
+
* 壊れた正規表現は無視する。スキーマ側の誤りでビルド全体を落とすより、
|
|
18
|
+
* そのパターンが誰にも一致しないほうがまし (Draft-07 は ECMA-262 の
|
|
19
|
+
* 正規表現を求めるが、方言差で通らないものが現実には来る)。
|
|
20
|
+
*/
|
|
21
|
+
export function compilePatterns(patterns) {
|
|
22
|
+
if (patterns === undefined || patterns.length === 0)
|
|
23
|
+
return Object.freeze([]);
|
|
24
|
+
const compiled = [];
|
|
25
|
+
for (const pattern of patterns) {
|
|
26
|
+
try {
|
|
27
|
+
compiled.push(new RegExp(pattern, "u"));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
try {
|
|
31
|
+
// "u" が付くと通らない書き方が現実にはある。付けずにもう一度試す。
|
|
32
|
+
compiled.push(new RegExp(pattern));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// どちらでも駄目なら、このパターンは一致しないものとして扱う。
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return Object.freeze(compiled);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 宣言済みのキー名にも、どのパターンにも該当しないキーを返す。
|
|
43
|
+
* 返る配列は入力の列挙順を保つ (issue のメッセージが安定する)。
|
|
44
|
+
*/
|
|
45
|
+
export function selectAdditionalKeys(value, known, patterns) {
|
|
46
|
+
return Object.keys(value).filter((key) => !known.has(key) && !patterns.some((pattern) => pattern.test(key)));
|
|
47
|
+
}
|