@amritk/generate-parsers 0.19.3 → 0.19.4

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.
@@ -10,6 +10,7 @@ import { generateDiscriminatedUnionValidation } from "./generate-discriminated-u
10
10
  import { generateEnumCaseInsensitiveCoercion, generateEnumCheck } from "./generate-enum-check.js";
11
11
  import { generateNonDiscriminatedUnionValidation } from "./generate-non-discriminated-union-validation.js";
12
12
  import { generateSchemaChecks } from "./generate-schema-checks.js";
13
+ import { generateUniqueItemsCheck } from "./generate-unique-items-check.js";
13
14
  const getInstanceCoercion = (accessor, instanceOf, defaultValue) => {
14
15
  if (instanceOf === "Date")
15
16
  return `((_d) => Number.isNaN(_d.getTime()) ? ${defaultValue} : _d)(new Date(${accessor} as string | number | Date))`;
@@ -55,7 +56,7 @@ const prefixItemsCapsLength = (schema) => {
55
56
  if (!isSchemaObject(schema))
56
57
  return false;
57
58
  const s = schema;
58
- return s["items"] === false || s["additionalItems"] === false;
59
+ return (Object.hasOwn(s, "items") ? s["items"] : void 0) === false || (Object.hasOwn(s, "additionalItems") ? s["additionalItems"] : void 0) === false;
59
60
  };
60
61
  const singleTypeCheck = (accessor, type) => {
61
62
  switch (type) {
@@ -259,7 +260,7 @@ const generateValidationExpression = (key, schema, defaultValue, isRequired, roo
259
260
  checks.push(`${accessor}.length <= ${schema.maxItems}`);
260
261
  }
261
262
  if (hasUniqueItems(schema) && schema.uniqueItems === true) {
262
- checks.push(`new Set(${accessor}).size === ${accessor}.length`);
263
+ checks.push(generateUniqueItemsCheck(accessor, schema));
263
264
  }
264
265
  break;
265
266
  }
@@ -7,17 +7,17 @@ const collectImports = (schema, options) => {
7
7
  const typesOnly = options?.typesOnly === true;
8
8
  const importExt = options?.importExt ?? "js";
9
9
  const importMap = /* @__PURE__ */ new Map();
10
- for (const [filename, typeName] of collectImportTargets(schema, options)) {
10
+ for (const [filename, { typeName, typeOnly }] of collectImportTargets(schema, options)) {
11
11
  const importPath = getImportPathForFilename(filename, importExt);
12
- const importStatement = typesOnly ? `import type { ${typeName} } from '${importPath}';` : `import { type ${typeName}, parse${typeName}, validate${typeName}Shape } from '${importPath}';`;
12
+ const importStatement = typesOnly || typeOnly ? `import type { ${typeName} } from '${importPath}';` : `import { type ${typeName}, parse${typeName}, validate${typeName}Shape } from '${importPath}';`;
13
13
  importMap.set(filename, importStatement);
14
14
  }
15
15
  return Array.from(importMap.values()).sort();
16
16
  };
17
17
  const collectImportTypeNames = (schema, options) => {
18
18
  const names = /* @__PURE__ */ new Set();
19
- for (const [, typeName] of collectImportTargets(schema, options))
20
- names.add(typeName);
19
+ for (const [, target] of collectImportTargets(schema, options))
20
+ names.add(target.typeName);
21
21
  return names;
22
22
  };
23
23
  const collectImportTargets = (schema, options) => {
@@ -25,6 +25,8 @@ const collectImportTargets = (schema, options) => {
25
25
  const rootSchema = options?.rootSchema;
26
26
  const typeSuffix = options?.typeSuffix;
27
27
  const refs = /* @__PURE__ */ new Set();
28
+ const valueRefs = /* @__PURE__ */ new Set();
29
+ let typeOnlyDepth = 0;
28
30
  const collectRefsFromValue = (value) => {
29
31
  if (typeof value !== "object" || value === null) {
30
32
  return;
@@ -43,21 +45,34 @@ const collectImportTargets = (schema, options) => {
43
45
  const isPropertyFragment = isUri && ref.includes("#/properties/");
44
46
  if (isInternal || isUri && !isPropertyFragment) {
45
47
  refs.add(ref);
48
+ if (typeOnlyDepth === 0)
49
+ valueRefs.add(ref);
46
50
  }
47
51
  return;
48
52
  }
53
+ for (const keyword of ["prefixItems", "items"]) {
54
+ const positions = Object.hasOwn(record, keyword) ? record[keyword] : void 0;
55
+ if (!Array.isArray(positions))
56
+ continue;
57
+ typeOnlyDepth++;
58
+ for (const item of positions) {
59
+ collectRefsFromValue(item);
60
+ }
61
+ if (Object.hasOwn(record, "additionalItems"))
62
+ collectRefsFromValue(record["additionalItems"]);
63
+ typeOnlyDepth--;
64
+ }
49
65
  if (hasAdditionalProperties(record) && hasRef(record.additionalProperties)) {
50
66
  collectRefsFromValue(record.additionalProperties);
51
67
  return;
52
68
  }
53
- if (record.type === "array" && hasItems(record) && hasRef(record.items)) {
69
+ if (record.type === "array" && hasItems(record) && !Array.isArray(record.items) && hasRef(record.items)) {
54
70
  collectRefsFromValue(record.items);
55
71
  return;
56
72
  }
57
- if ("properties" in record && typeof record.properties === "object" && record.properties !== null) {
58
- const props = record.properties;
59
- for (const key in props) {
60
- collectRefsFromValue(props[key]);
73
+ if (Object.hasOwn(record, "properties") && typeof record.properties === "object" && record.properties !== null) {
74
+ for (const value2 of Object.values(record.properties)) {
75
+ collectRefsFromValue(value2);
61
76
  }
62
77
  }
63
78
  if (hasOneOf(record)) {
@@ -75,22 +90,24 @@ const collectImportTargets = (schema, options) => {
75
90
  collectRefsFromValue(item);
76
91
  }
77
92
  }
78
- if (hasItems(record)) {
93
+ if (hasItems(record) && !Array.isArray(record.items)) {
79
94
  collectRefsFromValue(record.items);
80
95
  }
81
96
  if (hasAdditionalProperties(record)) {
82
97
  collectRefsFromValue(record.additionalProperties);
83
98
  }
84
- if ("patternProperties" in record && typeof record.patternProperties === "object" && record.patternProperties !== null) {
85
- const patternProps = record.patternProperties;
86
- for (const key in patternProps) {
87
- collectRefsFromValue(patternProps[key]);
99
+ if (Object.hasOwn(record, "patternProperties") && typeof record.patternProperties === "object" && record.patternProperties !== null) {
100
+ for (const value2 of Object.values(record.patternProperties)) {
101
+ collectRefsFromValue(value2);
88
102
  }
89
103
  }
90
- if ("then" in record) {
104
+ if (Object.hasOwn(record, "if")) {
105
+ collectRefsFromValue(record.if);
106
+ }
107
+ if (Object.hasOwn(record, "then")) {
91
108
  collectRefsFromValue(record.then);
92
109
  }
93
- if ("else" in record) {
110
+ if (Object.hasOwn(record, "else")) {
94
111
  collectRefsFromValue(record.else);
95
112
  }
96
113
  };
@@ -101,26 +118,39 @@ const collectImportTargets = (schema, options) => {
101
118
  const isPropertyFragment = isUri && ref.includes("#/properties/");
102
119
  if (isInternal || isUri && !isPropertyFragment) {
103
120
  refs.add(ref);
121
+ valueRefs.add(ref);
104
122
  }
105
123
  }
106
- if (typeof schema === "object" && schema !== null && "properties" in schema) {
107
- const properties = schema.properties;
108
- for (const key in properties) {
109
- collectRefsFromValue(properties[key]);
124
+ if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "properties") && typeof schema.properties === "object" && schema.properties !== null) {
125
+ for (const value of Object.values(schema.properties)) {
126
+ collectRefsFromValue(value);
110
127
  }
111
128
  }
112
- if (typeof schema === "object" && schema !== null && "additionalProperties" in schema) {
129
+ if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "additionalProperties")) {
113
130
  collectRefsFromValue(schema.additionalProperties);
114
131
  }
115
- if (typeof schema === "object" && schema !== null && "patternProperties" in schema) {
116
- const patternProps = schema.patternProperties;
117
- for (const key in patternProps) {
118
- collectRefsFromValue(patternProps[key]);
132
+ if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "patternProperties") && typeof schema.patternProperties === "object" && schema.patternProperties !== null) {
133
+ for (const value of Object.values(schema.patternProperties)) {
134
+ collectRefsFromValue(value);
119
135
  }
120
136
  }
121
- if (typeof schema === "object" && schema !== null && hasItems(schema)) {
137
+ if (typeof schema === "object" && schema !== null && hasItems(schema) && !Array.isArray(schema.items)) {
122
138
  collectRefsFromValue(schema.items);
123
139
  }
140
+ if (typeof schema === "object" && schema !== null) {
141
+ const record = schema;
142
+ for (const keyword of ["prefixItems", "items"]) {
143
+ const positions = Object.hasOwn(record, keyword) ? record[keyword] : void 0;
144
+ if (!Array.isArray(positions))
145
+ continue;
146
+ typeOnlyDepth++;
147
+ for (const item of positions)
148
+ collectRefsFromValue(item);
149
+ if (Object.hasOwn(record, "additionalItems"))
150
+ collectRefsFromValue(record["additionalItems"]);
151
+ typeOnlyDepth--;
152
+ }
153
+ }
124
154
  if (typeof schema === "object" && schema !== null && hasOneOf(schema)) {
125
155
  for (const item of schema.oneOf) {
126
156
  collectRefsFromValue(item);
@@ -136,13 +166,13 @@ const collectImportTargets = (schema, options) => {
136
166
  collectRefsFromValue(item);
137
167
  }
138
168
  }
139
- if (typeof schema === "object" && schema !== null && "if" in schema) {
169
+ if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "if")) {
140
170
  collectRefsFromValue(schema.if);
141
171
  }
142
- if (typeof schema === "object" && schema !== null && "then" in schema) {
172
+ if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "then")) {
143
173
  collectRefsFromValue(schema.then);
144
174
  }
145
- if (typeof schema === "object" && schema !== null && "else" in schema) {
175
+ if (typeof schema === "object" && schema !== null && Object.hasOwn(schema, "else")) {
146
176
  collectRefsFromValue(schema.else);
147
177
  }
148
178
  const targets = /* @__PURE__ */ new Map();
@@ -156,7 +186,8 @@ const collectImportTargets = (schema, options) => {
156
186
  if (selfFilename !== void 0 && filename === selfFilename) {
157
187
  continue;
158
188
  }
159
- targets.set(filename, typeName);
189
+ const typeOnly = !valueRefs.has(ref) && (targets.get(filename)?.typeOnly ?? true);
190
+ targets.set(filename, { typeName, typeOnly });
160
191
  }
161
192
  return targets;
162
193
  };
@@ -26,8 +26,8 @@ const defaultMatchesType = (value, schema) => {
26
26
  const MAX_FALLBACK_ITEMS = 32;
27
27
  const arrayFallback = (schema) => {
28
28
  const record = schema;
29
- const positions = Array.isArray(record["prefixItems"]) ? record["prefixItems"] : Array.isArray(record["items"]) ? record["items"] : [];
30
- const tail = Array.isArray(record["items"]) ? record["additionalItems"] : record["items"];
29
+ const positions = Array.isArray(Object.hasOwn(record, "prefixItems") ? record["prefixItems"] : void 0) ? Object.hasOwn(record, "prefixItems") ? record["prefixItems"] : void 0 : Array.isArray(Object.hasOwn(record, "items") ? record["items"] : void 0) ? Object.hasOwn(record, "items") ? record["items"] : void 0 : [];
30
+ const tail = Array.isArray(Object.hasOwn(record, "items") ? record["items"] : void 0) ? Object.hasOwn(record, "additionalItems") ? record["additionalItems"] : void 0 : Object.hasOwn(record, "items") ? record["items"] : void 0;
31
31
  const minItems = typeof record["minItems"] === "number" ? record["minItems"] : 0;
32
32
  const wanted = minItems > MAX_FALLBACK_ITEMS ? Math.min(minItems, positions.length) : minItems;
33
33
  if (wanted === 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amritk/generate-parsers",
3
- "version": "0.19.3",
3
+ "version": "0.19.4",
4
4
  "description": "Generate TypeScript parsers and type definitions from JSON Schemas.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -56,10 +56,10 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "json-schema-typed": "^8.0.1",
59
- "@amritk/helpers": "^0.15.3"
59
+ "@amritk/helpers": "^0.15.4"
60
60
  },
61
61
  "devDependencies": {
62
- "@amritk/generate-markdown": "^0.4.8",
62
+ "@amritk/generate-markdown": "^0.4.9",
63
63
  "@sinclair/typebox": "^0.34.49",
64
64
  "ajv": "^8.17.1",
65
65
  "zod": "^4.4.3"