@maroonedog/luq 2.0.0 → 2.1.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 +100 -10
- package/dist/chain/create-chain-node.js +22 -1
- package/dist/chain/create-chain-node.mjs +22 -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/validation-plan.types.d.ts +10 -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/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/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/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/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 +2 -2
- package/dist/plugins/string-min/string-min.mjs +3 -3
- package/dist/runtime/decide-presence.js +2 -1
- package/dist/runtime/decide-presence.mjs +2 -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 +12 -0
- package/dist/types/index.js +18 -0
- package/dist/types/index.mjs +17 -0
- package/package.json +10 -3
|
@@ -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
|
}
|
|
@@ -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
|
|
@@ -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
|
+
}
|
|
@@ -20,9 +20,9 @@ exports.stringExactLengthPlugin = (0, plugin_definition_1.definePlugin)()({
|
|
|
20
20
|
code: ctx.code,
|
|
21
21
|
messageFactory: ctx.messageFactory,
|
|
22
22
|
severity: ctx.severity,
|
|
23
|
-
run: (value) => !(0, types_1.isString)(value) || value
|
|
23
|
+
run: (value) => !(0, types_1.isString)(value) || (0, types_1.countCodePoints)(value) === expected
|
|
24
24
|
? types_1.PASS
|
|
25
|
-
: (0, types_1.fail)({ expected, actual: value
|
|
25
|
+
: (0, types_1.fail)({ expected, actual: (0, types_1.countCodePoints)(value) }),
|
|
26
26
|
describe: (detail) => `String must have exactly ${String(expected)} characters, but got ` +
|
|
27
27
|
`${String(detail.actual)}`,
|
|
28
28
|
buildMessageContext: (detail) => ({
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// ===========================================================================
|
|
5
5
|
import { check } from "../../plugin-kit/create-rule.mjs";
|
|
6
6
|
import { PluginArgumentError, definePlugin, } from "../../plugin-kit/plugin-definition.mjs";
|
|
7
|
-
import { PASS, fail, isNumber, isString } from "../../types/index.mjs";
|
|
7
|
+
import { PASS, fail, isNumber, countCodePoints, isString } from "../../types/index.mjs";
|
|
8
8
|
export const stringExactLengthPlugin = /*#__PURE__*/ definePlugin()({
|
|
9
9
|
name: "stringExactLength",
|
|
10
10
|
method: "exactLength",
|
|
@@ -17,9 +17,9 @@ export const stringExactLengthPlugin = /*#__PURE__*/ definePlugin()({
|
|
|
17
17
|
code: ctx.code,
|
|
18
18
|
messageFactory: ctx.messageFactory,
|
|
19
19
|
severity: ctx.severity,
|
|
20
|
-
run: (value) => !isString(value) || value
|
|
20
|
+
run: (value) => !isString(value) || countCodePoints(value) === expected
|
|
21
21
|
? PASS
|
|
22
|
-
: fail({ expected, actual: value
|
|
22
|
+
: fail({ expected, actual: countCodePoints(value) }),
|
|
23
23
|
describe: (detail) => `String must have exactly ${String(expected)} characters, but got ` +
|
|
24
24
|
`${String(detail.actual)}`,
|
|
25
25
|
buildMessageContext: (detail) => ({
|
|
@@ -20,9 +20,9 @@ exports.stringMaxPlugin = (0, plugin_definition_1.definePlugin)()({
|
|
|
20
20
|
code: ctx.code,
|
|
21
21
|
messageFactory: ctx.messageFactory,
|
|
22
22
|
severity: ctx.severity,
|
|
23
|
-
run: (value) => !(0, types_1.isString)(value) || value
|
|
23
|
+
run: (value) => !(0, types_1.isString)(value) || (0, types_1.countCodePoints)(value) <= max
|
|
24
24
|
? types_1.PASS
|
|
25
|
-
: (0, types_1.fail)({ expected: max, actual: value
|
|
25
|
+
: (0, types_1.fail)({ expected: max, actual: (0, types_1.countCodePoints)(value) }),
|
|
26
26
|
describe: (detail) => `String must have at most ${String(max)} characters, but got ` +
|
|
27
27
|
`${String(detail.actual)}`,
|
|
28
28
|
buildMessageContext: (detail) => ({
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// ===========================================================================
|
|
5
5
|
import { check } from "../../plugin-kit/create-rule.mjs";
|
|
6
6
|
import { PluginArgumentError, definePlugin, } from "../../plugin-kit/plugin-definition.mjs";
|
|
7
|
-
import { PASS, fail, isNumber, isString } from "../../types/index.mjs";
|
|
7
|
+
import { PASS, fail, isNumber, countCodePoints, isString } from "../../types/index.mjs";
|
|
8
8
|
export const stringMaxPlugin = /*#__PURE__*/ definePlugin()({
|
|
9
9
|
name: "stringMax",
|
|
10
10
|
method: "max",
|
|
@@ -17,9 +17,9 @@ export const stringMaxPlugin = /*#__PURE__*/ definePlugin()({
|
|
|
17
17
|
code: ctx.code,
|
|
18
18
|
messageFactory: ctx.messageFactory,
|
|
19
19
|
severity: ctx.severity,
|
|
20
|
-
run: (value) => !isString(value) || value
|
|
20
|
+
run: (value) => !isString(value) || countCodePoints(value) <= max
|
|
21
21
|
? PASS
|
|
22
|
-
: fail({ expected: max, actual: value
|
|
22
|
+
: fail({ expected: max, actual: countCodePoints(value) }),
|
|
23
23
|
describe: (detail) => `String must have at most ${String(max)} characters, but got ` +
|
|
24
24
|
`${String(detail.actual)}`,
|
|
25
25
|
buildMessageContext: (detail) => ({
|
|
@@ -23,9 +23,9 @@ exports.stringMinPlugin = (0, plugin_definition_1.definePlugin)()({
|
|
|
23
23
|
code: ctx.code,
|
|
24
24
|
messageFactory: ctx.messageFactory,
|
|
25
25
|
severity: ctx.severity,
|
|
26
|
-
run: (value) => !(0, types_1.isString)(value) || value
|
|
26
|
+
run: (value) => !(0, types_1.isString)(value) || (0, types_1.countCodePoints)(value) >= min
|
|
27
27
|
? types_1.PASS
|
|
28
|
-
: (0, types_1.fail)({ expected: min, actual: value
|
|
28
|
+
: (0, types_1.fail)({ expected: min, actual: (0, types_1.countCodePoints)(value) }),
|
|
29
29
|
describe: (detail) => `String must have at least ${String(min)} characters, but got ` +
|
|
30
30
|
`${String(detail.actual)}`,
|
|
31
31
|
buildMessageContext: (detail) => ({
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// ===========================================================================
|
|
8
8
|
import { check } from "../../plugin-kit/create-rule.mjs";
|
|
9
9
|
import { PluginArgumentError, definePlugin, } from "../../plugin-kit/plugin-definition.mjs";
|
|
10
|
-
import { PASS, fail, isNumber, isString } from "../../types/index.mjs";
|
|
10
|
+
import { PASS, fail, isNumber, countCodePoints, isString } from "../../types/index.mjs";
|
|
11
11
|
export const stringMinPlugin = /*#__PURE__*/ definePlugin()({
|
|
12
12
|
name: "stringMin",
|
|
13
13
|
method: "min",
|
|
@@ -20,9 +20,9 @@ export const stringMinPlugin = /*#__PURE__*/ definePlugin()({
|
|
|
20
20
|
code: ctx.code,
|
|
21
21
|
messageFactory: ctx.messageFactory,
|
|
22
22
|
severity: ctx.severity,
|
|
23
|
-
run: (value) => !isString(value) || value
|
|
23
|
+
run: (value) => !isString(value) || countCodePoints(value) >= min
|
|
24
24
|
? PASS
|
|
25
|
-
: fail({ expected: min, actual: value
|
|
25
|
+
: fail({ expected: min, actual: countCodePoints(value) }),
|
|
26
26
|
describe: (detail) => `String must have at least ${String(min)} characters, but got ` +
|
|
27
27
|
`${String(detail.actual)}`,
|
|
28
28
|
buildMessageContext: (detail) => ({
|
|
@@ -6,7 +6,8 @@ const create_issue_1 = require("./create-issue");
|
|
|
6
6
|
function decidePresence(field, value, ruleContext, sink) {
|
|
7
7
|
const policy = selectPolicy(field, ruleContext);
|
|
8
8
|
const isMissing = value === undefined || (policy.emptyStringIsMissing && value === "");
|
|
9
|
-
|
|
9
|
+
// null continues to the checks when the subject says null is a value.
|
|
10
|
+
if (!isMissing && (value !== null || policy.nullIsValue))
|
|
10
11
|
return true;
|
|
11
12
|
const isAllowed = isMissing ? policy.allowUndefined : policy.allowNull;
|
|
12
13
|
return reportUnlessAllowed(policy, isAllowed, value, ruleContext.path, sink);
|
|
@@ -3,7 +3,8 @@ import { createIssue } from "./create-issue.mjs";
|
|
|
3
3
|
export function decidePresence(field, value, ruleContext, sink) {
|
|
4
4
|
const policy = selectPolicy(field, ruleContext);
|
|
5
5
|
const isMissing = value === undefined || (policy.emptyStringIsMissing && value === "");
|
|
6
|
-
|
|
6
|
+
// null continues to the checks when the subject says null is a value.
|
|
7
|
+
if (!isMissing && (value !== null || policy.nullIsValue))
|
|
7
8
|
return true;
|
|
8
9
|
const isAllowed = isMissing ? policy.allowUndefined : policy.allowNull;
|
|
9
10
|
return reportUnlessAllowed(policy, isAllowed, value, ruleContext.path, sink);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { InferStandardInput, InferStandardOutput, StandardSchemaFailure, StandardSchemaIssue, StandardSchemaPathSegment, StandardSchemaProps, StandardSchemaResult, StandardSchemaSuccess, StandardSchemaTypes, StandardSchemaV1, } from "./standard-schema.types";
|
|
2
|
+
export type { StandardSchemaOptions } from "./standard-schema.types";
|
|
3
|
+
export type { IssuePathSegments } from "./split-issue-path";
|
|
4
|
+
export { splitIssuePath } from "./split-issue-path";
|
|
5
|
+
export type { StandardLuqSchema } from "./to-standard-schema";
|
|
6
|
+
export { toStandardSchema } from "./to-standard-schema";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toStandardSchema = exports.splitIssuePath = void 0;
|
|
4
|
+
var split_issue_path_1 = require("./split-issue-path");
|
|
5
|
+
Object.defineProperty(exports, "splitIssuePath", { enumerable: true, get: function () { return split_issue_path_1.splitIssuePath; } });
|
|
6
|
+
var to_standard_schema_1 = require("./to-standard-schema");
|
|
7
|
+
Object.defineProperty(exports, "toStandardSchema", { enumerable: true, get: function () { return to_standard_schema_1.toStandardSchema; } });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** 開いた結果。オブジェクトのキーは string、配列の添字は number。 */
|
|
2
|
+
export type IssuePathSegments = readonly (string | number)[];
|
|
3
|
+
/**
|
|
4
|
+
* ルート ("") は空配列。空配列は仕様上「ルート自身への issue」を意味する。
|
|
5
|
+
*
|
|
6
|
+
* 解釈できない形が来たら、握り潰さずに path 全体を1つの文字列セグメントとして
|
|
7
|
+
* 返す。issue を落とすより、開けなかったことが分かる形で渡すほうがまし。
|
|
8
|
+
*/
|
|
9
|
+
export declare function splitIssuePath(path: string): IssuePathSegments;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ===========================================================================
|
|
3
|
+
// L10 src/standard-schema/split-issue-path.ts
|
|
4
|
+
//
|
|
5
|
+
// Luq の issue path ("items[1].productId") を Standard Schema の path
|
|
6
|
+
// (["items", 1, "productId"]) に開く。
|
|
7
|
+
//
|
|
8
|
+
// 方向に注意: これは formatIssuePath の逆で、宣言パス (parseFieldPath が
|
|
9
|
+
// 読む "items[*].productId") のパーサではない。issue path には [*] が
|
|
10
|
+
// 決して現れず、代わりに実インデックスが入る。二つの文法を一つの関数で
|
|
11
|
+
// 扱おうとすると、[*] を 0 と読むような取り違えが静かに入るので分けてある。
|
|
12
|
+
//
|
|
13
|
+
// 配列インデックスは number として出す。仕様の PropertyKey は
|
|
14
|
+
// string | number | symbol を許し、消費側 (フォームライブラリ) は
|
|
15
|
+
// 添字を number として受け取る前提で書かれているため。
|
|
16
|
+
// ===========================================================================
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.splitIssuePath = splitIssuePath;
|
|
19
|
+
const INDEX_PATTERN = /^\[(\d+)\]/;
|
|
20
|
+
/**
|
|
21
|
+
* ルート ("") は空配列。空配列は仕様上「ルート自身への issue」を意味する。
|
|
22
|
+
*
|
|
23
|
+
* 解釈できない形が来たら、握り潰さずに path 全体を1つの文字列セグメントとして
|
|
24
|
+
* 返す。issue を落とすより、開けなかったことが分かる形で渡すほうがまし。
|
|
25
|
+
*/
|
|
26
|
+
function splitIssuePath(path) {
|
|
27
|
+
if (path === "")
|
|
28
|
+
return [];
|
|
29
|
+
const segments = [];
|
|
30
|
+
let rest = path;
|
|
31
|
+
let expectKey = true;
|
|
32
|
+
while (rest !== "") {
|
|
33
|
+
if (expectKey) {
|
|
34
|
+
const key = rest.slice(0, findKeyEnd(rest));
|
|
35
|
+
if (key === "")
|
|
36
|
+
return [path];
|
|
37
|
+
segments.push(key);
|
|
38
|
+
rest = rest.slice(key.length);
|
|
39
|
+
expectKey = false;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const index = INDEX_PATTERN.exec(rest);
|
|
43
|
+
if (index !== null) {
|
|
44
|
+
segments.push(Number(index[1]));
|
|
45
|
+
rest = rest.slice(index[0].length);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (rest.startsWith(".")) {
|
|
49
|
+
rest = rest.slice(1);
|
|
50
|
+
expectKey = true;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
return [path];
|
|
54
|
+
}
|
|
55
|
+
return expectKey ? [path] : segments;
|
|
56
|
+
}
|
|
57
|
+
/** キーは "." か "[" の手前まで。どちらも無ければ末尾まで。 */
|
|
58
|
+
function findKeyEnd(rest) {
|
|
59
|
+
const dot = rest.indexOf(".");
|
|
60
|
+
const bracket = rest.indexOf("[");
|
|
61
|
+
if (dot === -1)
|
|
62
|
+
return bracket === -1 ? rest.length : bracket;
|
|
63
|
+
if (bracket === -1)
|
|
64
|
+
return dot;
|
|
65
|
+
return Math.min(dot, bracket);
|
|
66
|
+
}
|