@maroonedog/luq 2.4.0 → 2.4.1
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/dist/standard-schema/emit-field-schema.js +10 -0
- package/dist/standard-schema/emit-field-schema.mjs +10 -0
- package/dist/standard-schema/plugin-keyword-map.d.ts +15 -2
- package/dist/standard-schema/plugin-keyword-map.js +11 -4
- package/dist/standard-schema/plugin-keyword-map.mjs +11 -4
- package/package.json +1 -1
|
@@ -55,6 +55,16 @@ function emitFieldSchema(fieldPath, calls, policy) {
|
|
|
55
55
|
continue;
|
|
56
56
|
}
|
|
57
57
|
const keywords = toKeywords(call.args);
|
|
58
|
+
// undefined is the table saying it cannot express THESE arguments, which
|
|
59
|
+
// is the same answer as having no entry at all: refuse, rather than emit a
|
|
60
|
+
// schema missing a constraint the validator enforces. null is different —
|
|
61
|
+
// it means type or presence already carries the declaration.
|
|
62
|
+
if (keywords === undefined) {
|
|
63
|
+
if (policy === "throw") {
|
|
64
|
+
throw new unrepresentable_rule_error_1.UnrepresentableRuleError(fieldPath, call.pluginName, "no JSON Schema keyword expresses the arguments it was given");
|
|
65
|
+
}
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
58
68
|
if (keywords === null)
|
|
59
69
|
continue;
|
|
60
70
|
Object.assign(schema, keywords);
|
|
@@ -52,6 +52,16 @@ export function emitFieldSchema(fieldPath, calls, policy) {
|
|
|
52
52
|
continue;
|
|
53
53
|
}
|
|
54
54
|
const keywords = toKeywords(call.args);
|
|
55
|
+
// undefined is the table saying it cannot express THESE arguments, which
|
|
56
|
+
// is the same answer as having no entry at all: refuse, rather than emit a
|
|
57
|
+
// schema missing a constraint the validator enforces. null is different —
|
|
58
|
+
// it means type or presence already carries the declaration.
|
|
59
|
+
if (keywords === undefined) {
|
|
60
|
+
if (policy === "throw") {
|
|
61
|
+
throw new UnrepresentableRuleError(fieldPath, call.pluginName, "no JSON Schema keyword expresses the arguments it was given");
|
|
62
|
+
}
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
55
65
|
if (keywords === null)
|
|
56
66
|
continue;
|
|
57
67
|
Object.assign(schema, keywords);
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* A keyword fragment made from the arguments. Three answers, and the
|
|
3
|
+
* difference between the last two is the point:
|
|
4
|
+
*
|
|
5
|
+
* an object the keywords this declaration means
|
|
6
|
+
* null it adds no keyword, and that is correct — type or presence
|
|
7
|
+
* already carries it
|
|
8
|
+
* undefined it cannot be expressed with these arguments, so the caller
|
|
9
|
+
* must refuse rather than emit a schema that quietly says
|
|
10
|
+
* something else
|
|
11
|
+
*
|
|
12
|
+
* Collapsing the last two into `null` is how a constraint disappears without
|
|
13
|
+
* a trace, which is the failure UnrepresentableRuleError exists to prevent.
|
|
14
|
+
*/
|
|
15
|
+
export type ToKeywords = (args: readonly unknown[]) => Record<string, unknown> | null | undefined;
|
|
3
16
|
export declare const PLUGIN_KEYWORDS: Readonly<Record<string, ToKeywords>>;
|
|
@@ -37,9 +37,14 @@ exports.PLUGIN_KEYWORDS = Object.freeze({
|
|
|
37
37
|
maxLength: numberAt(args, 0),
|
|
38
38
|
}),
|
|
39
39
|
// Draft-07's `pattern` is an ECMA-262 SOURCE string. Flags cannot be
|
|
40
|
-
// spelled there, and dropping them changes the meaning
|
|
41
|
-
//
|
|
42
|
-
|
|
40
|
+
// spelled there, and dropping them changes the meaning — `/^a.c$/i`
|
|
41
|
+
// accepts "ABC" and `{"pattern":"^a.c$"}` does not — so a flagged RegExp
|
|
42
|
+
// is unwritable rather than something to narrow quietly. Anything that is
|
|
43
|
+
// not a RegExp at all is unwritable for the same reason: refusing is the
|
|
44
|
+
// only answer that does not lose the constraint in silence.
|
|
45
|
+
stringPattern: (args) => args[0] instanceof RegExp && args[0].flags === ""
|
|
46
|
+
? { pattern: args[0].source }
|
|
47
|
+
: undefined,
|
|
43
48
|
stringContentEncoding: (args) => ({ contentEncoding: args[0] }),
|
|
44
49
|
stringContentMediaType: (args) => ({ contentMediaType: args[0] }),
|
|
45
50
|
// --- formats (names taken verbatim from the format map) ---------------
|
|
@@ -81,7 +86,9 @@ exports.PLUGIN_KEYWORDS = Object.freeze({
|
|
|
81
86
|
arrayUnique: () => ({ uniqueItems: true }),
|
|
82
87
|
// --- values -----------------------------------------------------------
|
|
83
88
|
literal: (args) => ({ const: args[0] }),
|
|
84
|
-
|
|
89
|
+
// `enum` needs the list itself. Given something else there is no list to
|
|
90
|
+
// write, and answering "no keyword" would drop the constraint.
|
|
91
|
+
oneOf: (args) => (Array.isArray(args[0]) ? { enum: args[0] } : undefined),
|
|
85
92
|
// --- handled by type or presence, adding no keyword -------------------
|
|
86
93
|
// numberInteger becomes `type: "integer"`, so it feeds the type decision.
|
|
87
94
|
numberInteger: () => null,
|
|
@@ -34,9 +34,14 @@ export const PLUGIN_KEYWORDS = Object.freeze({
|
|
|
34
34
|
maxLength: numberAt(args, 0),
|
|
35
35
|
}),
|
|
36
36
|
// Draft-07's `pattern` is an ECMA-262 SOURCE string. Flags cannot be
|
|
37
|
-
// spelled there, and dropping them changes the meaning
|
|
38
|
-
//
|
|
39
|
-
|
|
37
|
+
// spelled there, and dropping them changes the meaning — `/^a.c$/i`
|
|
38
|
+
// accepts "ABC" and `{"pattern":"^a.c$"}` does not — so a flagged RegExp
|
|
39
|
+
// is unwritable rather than something to narrow quietly. Anything that is
|
|
40
|
+
// not a RegExp at all is unwritable for the same reason: refusing is the
|
|
41
|
+
// only answer that does not lose the constraint in silence.
|
|
42
|
+
stringPattern: (args) => args[0] instanceof RegExp && args[0].flags === ""
|
|
43
|
+
? { pattern: args[0].source }
|
|
44
|
+
: undefined,
|
|
40
45
|
stringContentEncoding: (args) => ({ contentEncoding: args[0] }),
|
|
41
46
|
stringContentMediaType: (args) => ({ contentMediaType: args[0] }),
|
|
42
47
|
// --- formats (names taken verbatim from the format map) ---------------
|
|
@@ -78,7 +83,9 @@ export const PLUGIN_KEYWORDS = Object.freeze({
|
|
|
78
83
|
arrayUnique: () => ({ uniqueItems: true }),
|
|
79
84
|
// --- values -----------------------------------------------------------
|
|
80
85
|
literal: (args) => ({ const: args[0] }),
|
|
81
|
-
|
|
86
|
+
// `enum` needs the list itself. Given something else there is no list to
|
|
87
|
+
// write, and answering "no keyword" would drop the constraint.
|
|
88
|
+
oneOf: (args) => (Array.isArray(args[0]) ? { enum: args[0] } : undefined),
|
|
82
89
|
// --- handled by type or presence, adding no keyword -------------------
|
|
83
90
|
// numberInteger becomes `type: "integer"`, so it feeds the type decision.
|
|
84
91
|
numberInteger: () => null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maroonedog/luq",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "Universal Model & API Definition Platform - TypeScript validation library evolving into cross-language code generation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|