@amritk/generate-validators 0.13.0 → 0.14.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.
@@ -1,17 +1,19 @@
1
+ import { declaresKey, readKey } from "@amritk/helpers/read-key";
1
2
  const tupleShapeOf = (schema) => {
2
- const items = schema["items"];
3
- const prefix = schema["prefixItems"];
3
+ const items = readKey(schema, "items");
4
+ const prefix = readKey(schema, "prefixItems");
4
5
  if (Array.isArray(prefix)) {
5
6
  return {
6
7
  tuple: prefix,
7
- tail: "items" in schema && !Array.isArray(items) ? items : void 0,
8
+ tail: declaresKey(schema, "items") && !Array.isArray(items) ? items : void 0,
8
9
  tailIsClosed: items === false
9
10
  };
10
11
  }
11
12
  if (Array.isArray(items)) {
12
- return { tuple: items, tail: schema["additionalItems"], tailIsClosed: schema["additionalItems"] === false };
13
+ const additionalItems = readKey(schema, "additionalItems");
14
+ return { tuple: items, tail: additionalItems, tailIsClosed: additionalItems === false };
13
15
  }
14
- return { tuple: void 0, tail: "items" in schema ? items : void 0, tailIsClosed: items === false };
16
+ return { tuple: void 0, tail: declaresKey(schema, "items") ? items : void 0, tailIsClosed: items === false };
15
17
  };
16
18
  export {
17
19
  tupleShapeOf
@@ -1,4 +1,5 @@
1
1
  import { regexLiteral } from "@amritk/helpers/escape-regex-pattern";
2
+ import { declaresKey, readKey } from "@amritk/helpers/read-key";
2
3
  import { resolveRef } from "@amritk/helpers/resolve-ref";
3
4
  import { isSchemaObject } from "@amritk/helpers/schema-guards";
4
5
  const NONE = { all: false, terms: [] };
@@ -21,19 +22,19 @@ const conditioned = (coverage, condition) => {
21
22
  };
22
23
  const merge = (into, from) => into.all || from.all ? ALL : { all: false, terms: [...into.terms, ...from.terms] };
23
24
  const ownPropertyCoverage = (schema, keyVar, ignoreOwnUnevaluated) => {
24
- if ("additionalProperties" in schema)
25
+ if (declaresKey(schema, "additionalProperties"))
25
26
  return ALL;
26
- if (!ignoreOwnUnevaluated && "unevaluatedProperties" in schema && schema["unevaluatedProperties"] !== false) {
27
+ if (!ignoreOwnUnevaluated && declaresKey(schema, "unevaluatedProperties") && schema["unevaluatedProperties"] !== false) {
27
28
  return ALL;
28
29
  }
29
30
  const terms = [];
30
- const properties = schema["properties"];
31
+ const properties = readKey(schema, "properties");
31
32
  if (typeof properties === "object" && properties !== null && !Array.isArray(properties)) {
32
33
  const keys = Object.keys(properties);
33
34
  if (keys.length > 0)
34
35
  terms.push(`${JSON.stringify(keys)}.includes(${keyVar})`);
35
36
  }
36
- const patterns = schema["patternProperties"];
37
+ const patterns = readKey(schema, "patternProperties");
37
38
  if (typeof patterns === "object" && patterns !== null && !Array.isArray(patterns)) {
38
39
  for (const pattern of Object.keys(patterns)) {
39
40
  terms.push(`${regexLiteral(pattern)}.test(${keyVar})`);
@@ -42,20 +43,21 @@ const ownPropertyCoverage = (schema, keyVar, ignoreOwnUnevaluated) => {
42
43
  return { all: false, terms };
43
44
  };
44
45
  const ownItemCoverage = (schema, indexVar, itemVar, ignoreOwnUnevaluated, ctx, match) => {
45
- const tupleItems = Array.isArray(schema["items"]);
46
- if (!tupleItems && "items" in schema)
46
+ const tupleItems = Array.isArray(readKey(schema, "items"));
47
+ if (!tupleItems && declaresKey(schema, "items"))
47
48
  return ALL;
48
- if (tupleItems && "additionalItems" in schema)
49
+ if (tupleItems && declaresKey(schema, "additionalItems"))
49
50
  return ALL;
50
- if (!ignoreOwnUnevaluated && "unevaluatedItems" in schema && schema["unevaluatedItems"] !== false) {
51
+ if (!ignoreOwnUnevaluated && declaresKey(schema, "unevaluatedItems") && schema["unevaluatedItems"] !== false) {
51
52
  return ALL;
52
53
  }
53
54
  const terms = [];
54
- const prefix = Array.isArray(schema["prefixItems"]) ? schema["prefixItems"] : tupleItems ? schema["items"] : null;
55
+ const declaredPrefix = readKey(schema, "prefixItems");
56
+ const prefix = Array.isArray(declaredPrefix) ? declaredPrefix : tupleItems ? readKey(schema, "items") : null;
55
57
  if (prefix && prefix.length > 0)
56
58
  terms.push(`${indexVar} < ${prefix.length}`);
57
- if ("contains" in schema) {
58
- const contained = match(itemVar, schema["contains"], ctx.depth);
59
+ if (declaresKey(schema, "contains")) {
60
+ const contained = match(itemVar, readKey(schema, "contains"), ctx.depth);
59
61
  if (contained === "true")
60
62
  return ALL;
61
63
  if (contained !== "false")
@@ -71,10 +73,10 @@ const coverageOf = (kind, schema, indexVar, itemVar, acc, ctx, sink, match, igno
71
73
  if (ctx.depth > MAX_COVERAGE_DEPTH)
72
74
  return null;
73
75
  const s = schema;
74
- if (typeof s["$dynamicRef"] === "string")
76
+ if (typeof readKey(s, "$dynamicRef") === "string")
75
77
  return null;
76
78
  let coverage = kind === "properties" ? ownPropertyCoverage(s, indexVar, ignoreOwnUnevaluated) : ownItemCoverage(s, indexVar, itemVar, ignoreOwnUnevaluated, ctx, match);
77
- const ref = s["$ref"];
79
+ const ref = readKey(s, "$ref");
78
80
  if (typeof ref === "string") {
79
81
  if (ctx.rootSchema === void 0 || ctx.seen.has(ref))
80
82
  return null;
@@ -88,8 +90,9 @@ const coverageOf = (kind, schema, indexVar, itemVar, acc, ctx, sink, match, igno
88
90
  return null;
89
91
  coverage = merge(coverage, refCoverage);
90
92
  }
91
- if (Array.isArray(s["allOf"])) {
92
- for (const member of s["allOf"]) {
93
+ const allOf = readKey(s, "allOf");
94
+ if (Array.isArray(allOf)) {
95
+ for (const member of allOf) {
93
96
  const memberCoverage = coverageOf(kind, member, indexVar, itemVar, acc, nest(ctx), sink, match);
94
97
  if (memberCoverage === null)
95
98
  return null;
@@ -97,9 +100,10 @@ const coverageOf = (kind, schema, indexVar, itemVar, acc, ctx, sink, match, igno
97
100
  }
98
101
  }
99
102
  for (const keyword of ["anyOf", "oneOf"]) {
100
- if (!Array.isArray(s[keyword]))
103
+ const branches = readKey(s, keyword);
104
+ if (!Array.isArray(branches))
101
105
  continue;
102
- for (const branch of s[keyword]) {
106
+ for (const branch of branches) {
103
107
  const branchCoverage = coverageOf(kind, branch, indexVar, itemVar, acc, nest(ctx), sink, match);
104
108
  if (branchCoverage === null)
105
109
  return null;
@@ -108,16 +112,16 @@ const coverageOf = (kind, schema, indexVar, itemVar, acc, ctx, sink, match, igno
108
112
  coverage = merge(coverage, conditioned(branchCoverage, hoistCondition(sink, match(acc, branch, ctx.depth))));
109
113
  }
110
114
  }
111
- if ("if" in s) {
115
+ if (declaresKey(s, "if")) {
112
116
  const branches = [];
113
117
  for (const [keyword, negated] of [
114
118
  ["if", false],
115
119
  ["then", false],
116
120
  ["else", true]
117
121
  ]) {
118
- if (!(keyword in s))
122
+ if (!declaresKey(s, keyword))
119
123
  continue;
120
- const branchCoverage = coverageOf(kind, s[keyword], indexVar, itemVar, acc, nest(ctx), sink, match);
124
+ const branchCoverage = coverageOf(kind, readKey(s, keyword), indexVar, itemVar, acc, nest(ctx), sink, match);
121
125
  if (branchCoverage === null)
122
126
  return null;
123
127
  if (!branchCoverage.all && branchCoverage.terms.length === 0)
@@ -125,14 +129,14 @@ const coverageOf = (kind, schema, indexVar, itemVar, acc, ctx, sink, match, igno
125
129
  branches.push({ coverage: branchCoverage, negated });
126
130
  }
127
131
  if (branches.length > 0) {
128
- const ifMatch = hoistCondition(sink, match(acc, s["if"], ctx.depth));
132
+ const ifMatch = hoistCondition(sink, match(acc, readKey(s, "if"), ctx.depth));
129
133
  for (const branch of branches) {
130
134
  coverage = merge(coverage, conditioned(branch.coverage, branch.negated ? `!${ifMatch}` : ifMatch));
131
135
  }
132
136
  }
133
137
  }
134
138
  for (const keyword of ["dependentSchemas", "dependencies"]) {
135
- const dependents = s[keyword];
139
+ const dependents = readKey(s, keyword);
136
140
  if (typeof dependents !== "object" || dependents === null || Array.isArray(dependents))
137
141
  continue;
138
142
  for (const [trigger, sub] of Object.entries(dependents)) {
@@ -153,9 +157,9 @@ const unevaluatedPropertiesExpr = (acc, schema, rootSchema, depth, match) => {
153
157
  if (!isSchemaObject(schema))
154
158
  return void 0;
155
159
  const s = schema;
156
- if (!("unevaluatedProperties" in s))
160
+ if (!declaresKey(s, "unevaluatedProperties"))
157
161
  return void 0;
158
- const unevaluated = s["unevaluatedProperties"];
162
+ const unevaluated = readKey(s, "unevaluatedProperties");
159
163
  if (unevaluated === true)
160
164
  return void 0;
161
165
  const keyVar = `_uk${depth}`;
@@ -186,9 +190,9 @@ const unevaluatedItemsExpr = (acc, schema, rootSchema, depth, match) => {
186
190
  if (!isSchemaObject(schema))
187
191
  return void 0;
188
192
  const s = schema;
189
- if (!("unevaluatedItems" in s))
193
+ if (!declaresKey(s, "unevaluatedItems"))
190
194
  return void 0;
191
- const unevaluated = s["unevaluatedItems"];
195
+ const unevaluated = readKey(s, "unevaluatedItems");
192
196
  if (unevaluated === true)
193
197
  return void 0;
194
198
  const indexVar = `_un${depth}`;
@@ -201,15 +205,16 @@ const unevaluatedItemsExpr = (acc, schema, rootSchema, depth, match) => {
201
205
  if (coverage.all)
202
206
  return void 0;
203
207
  const elements = `(${acc} as unknown[])`;
208
+ const visited = `Array.from(${elements})`;
204
209
  const covered = coverage.terms.length > 0 ? orJoin(coverage.terms) : null;
205
210
  if (unevaluated === false) {
206
- const expr2 = covered === null ? `${elements}.length === 0` : `${elements}.every((${itemVar}, ${indexVar}) => ${covered})`;
211
+ const expr2 = covered === null ? `${elements}.length === 0` : `${visited}.every((${itemVar}, ${indexVar}) => ${covered})`;
207
212
  return { setup: sink.setup, expr: expr2 };
208
213
  }
209
214
  const valueMatch = match(itemVar, unevaluated, depth);
210
215
  if (valueMatch === "true")
211
216
  return void 0;
212
- const expr = covered === null ? `${elements}.every((${itemVar}) => ${valueMatch})` : `${elements}.every((${itemVar}, ${indexVar}) => ${covered} || ${valueMatch})`;
217
+ const expr = covered === null ? `${visited}.every((${itemVar}) => ${valueMatch})` : `${visited}.every((${itemVar}, ${indexVar}) => ${covered} || ${valueMatch})`;
213
218
  return { setup: sink.setup, expr };
214
219
  };
215
220
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amritk/generate-validators",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Generate TypeScript validation functions from JSON Schemas.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -54,10 +54,10 @@
54
54
  },
55
55
  "dependencies": {
56
56
  "json-schema-typed": "^8.0.1",
57
- "@amritk/helpers": "^0.15.3"
57
+ "@amritk/helpers": "^0.16.0"
58
58
  },
59
59
  "devDependencies": {
60
- "@amritk/runtime-validators": "^0.10.1",
60
+ "@amritk/runtime-validators": "^0.12.0",
61
61
  "@ryoppippi/unplugin-typia": "^2.6.5",
62
62
  "@scalar/openapi-parser": "^0.26.1",
63
63
  "@sinclair/typebox": "^0.34.49",