@amritk/generate-parsers 0.7.1 → 0.8.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.
Files changed (76) hide show
  1. package/README.md +1 -1
  2. package/dist/generators/build-schema.d.ts +0 -1
  3. package/dist/generators/generate-default-from-pattern.d.ts +0 -1
  4. package/dist/generators/generate-discriminated-union-validation.d.ts +0 -1
  5. package/dist/generators/generate-enum-check.d.ts +0 -1
  6. package/dist/generators/generate-files.d.ts +0 -1
  7. package/dist/generators/generate-non-discriminated-union-validation.d.ts +0 -1
  8. package/dist/generators/generate-parser-function.d.ts +3 -3
  9. package/dist/generators/generate-parser-function.js +165 -37
  10. package/dist/generators/generate-schema-checks.d.ts +0 -1
  11. package/dist/generators/generate-schema-checks.js +2 -1
  12. package/dist/generators/generate-strict-assertion.d.ts +0 -1
  13. package/dist/generators/generate-strict-assertion.js +1 -6
  14. package/dist/generators/generate-validation-expression.d.ts +0 -1
  15. package/dist/generators/generate-validation-expression.js +2 -1
  16. package/dist/helpers/apply-schema-extensions.d.ts +0 -1
  17. package/dist/helpers/collect-helpers.d.ts +0 -1
  18. package/dist/helpers/collect-imports.d.ts +0 -1
  19. package/dist/helpers/find-discriminator.d.ts +0 -1
  20. package/dist/helpers/get-default-value.d.ts +0 -1
  21. package/dist/helpers/get-discriminator-value.d.ts +0 -1
  22. package/dist/index.d.ts +0 -1
  23. package/dist/types/schema-extensions.d.ts +0 -1
  24. package/package.json +3 -5
  25. package/dist/generators/build-schema.d.ts.map +0 -1
  26. package/dist/generators/generate-default-from-pattern.d.ts.map +0 -1
  27. package/dist/generators/generate-discriminated-union-validation.d.ts.map +0 -1
  28. package/dist/generators/generate-enum-check.d.ts.map +0 -1
  29. package/dist/generators/generate-files.d.ts.map +0 -1
  30. package/dist/generators/generate-non-discriminated-union-validation.d.ts.map +0 -1
  31. package/dist/generators/generate-parser-function.d.ts.map +0 -1
  32. package/dist/generators/generate-schema-checks.d.ts.map +0 -1
  33. package/dist/generators/generate-strict-assertion.d.ts.map +0 -1
  34. package/dist/generators/generate-validation-expression.d.ts.map +0 -1
  35. package/dist/helpers/apply-schema-extensions.d.ts.map +0 -1
  36. package/dist/helpers/collect-helpers.d.ts.map +0 -1
  37. package/dist/helpers/collect-imports.d.ts.map +0 -1
  38. package/dist/helpers/find-discriminator.d.ts.map +0 -1
  39. package/dist/helpers/get-default-value.d.ts.map +0 -1
  40. package/dist/helpers/get-discriminator-value.d.ts.map +0 -1
  41. package/dist/index.d.ts.map +0 -1
  42. package/dist/types/schema-extensions.d.ts.map +0 -1
  43. package/src/generators/build-schema.test.ts +0 -854
  44. package/src/generators/build-schema.ts +0 -147
  45. package/src/generators/generate-default-from-pattern.test.ts +0 -81
  46. package/src/generators/generate-default-from-pattern.ts +0 -39
  47. package/src/generators/generate-discriminated-union-validation.test.ts +0 -84
  48. package/src/generators/generate-discriminated-union-validation.ts +0 -54
  49. package/src/generators/generate-enum-check.test.ts +0 -45
  50. package/src/generators/generate-enum-check.ts +0 -8
  51. package/src/generators/generate-files.test.ts +0 -448
  52. package/src/generators/generate-files.ts +0 -155
  53. package/src/generators/generate-non-discriminated-union-validation.test.ts +0 -74
  54. package/src/generators/generate-non-discriminated-union-validation.ts +0 -40
  55. package/src/generators/generate-parser-function.test.ts +0 -1794
  56. package/src/generators/generate-parser-function.ts +0 -1348
  57. package/src/generators/generate-schema-checks.test.ts +0 -330
  58. package/src/generators/generate-schema-checks.ts +0 -127
  59. package/src/generators/generate-strict-assertion.test.ts +0 -67
  60. package/src/generators/generate-strict-assertion.ts +0 -249
  61. package/src/generators/generate-validation-expression.test.ts +0 -831
  62. package/src/generators/generate-validation-expression.ts +0 -326
  63. package/src/helpers/apply-schema-extensions.test.ts +0 -194
  64. package/src/helpers/apply-schema-extensions.ts +0 -63
  65. package/src/helpers/collect-helpers.test.ts +0 -115
  66. package/src/helpers/collect-helpers.ts +0 -79
  67. package/src/helpers/collect-imports.test.ts +0 -547
  68. package/src/helpers/collect-imports.ts +0 -275
  69. package/src/helpers/find-discriminator.test.ts +0 -88
  70. package/src/helpers/find-discriminator.ts +0 -39
  71. package/src/helpers/get-default-value.test.ts +0 -139
  72. package/src/helpers/get-default-value.ts +0 -95
  73. package/src/helpers/get-discriminator-value.test.ts +0 -83
  74. package/src/helpers/get-discriminator-value.ts +0 -21
  75. package/src/index.ts +0 -1
  76. package/src/types/schema-extensions.ts +0 -35
@@ -1,249 +0,0 @@
1
- import { getMjstInstanceOf, getMjstPrimitive } from '@amritk/helpers/mjst-extension'
2
- import { safeAccessor } from '@amritk/helpers/safe-accessor'
3
- import {
4
- hasEnum,
5
- hasExclusiveMaximum,
6
- hasExclusiveMinimum,
7
- hasMaximum,
8
- hasMaxLength,
9
- hasMinimum,
10
- hasMinLength,
11
- hasMultipleOf,
12
- hasPattern,
13
- hasProperties,
14
- hasRef,
15
- hasRequired,
16
- hasType,
17
- isSchemaObject,
18
- } from '@amritk/helpers/schema-guards'
19
- import type { JSONSchema } from 'json-schema-typed/draft-2020-12'
20
-
21
- /**
22
- * Returns the inline condition that is true when `accessor` is the wrong type
23
- * for the given JSON Schema primitive type.
24
- */
25
- const wrongTypeCondition = (accessor: string, type: string): string | null => {
26
- switch (type) {
27
- case 'string':
28
- return `typeof ${accessor} !== "string"`
29
- case 'number':
30
- case 'integer':
31
- return `typeof ${accessor} !== "number"`
32
- case 'boolean':
33
- return `typeof ${accessor} !== "boolean"`
34
- case 'array':
35
- return `!Array.isArray(${accessor})`
36
- case 'object':
37
- return `!isObject(${accessor})`
38
- default:
39
- return null
40
- }
41
- }
42
-
43
- /**
44
- * Maps a JSON Schema type to the label used in error messages.
45
- * `integer` collapses to `number` since both are validated via `typeof === "number"`.
46
- */
47
- const typeLabel = (type: string): string => (type === 'integer' ? 'number' : type)
48
-
49
- /**
50
- * Escapes special regex characters in a pattern string for use in a regex literal.
51
- */
52
- const escapeRegexPattern = (pattern: string): string => {
53
- return pattern.replace(/\\/g, '\\\\').replace(/\//g, '\\/')
54
- }
55
-
56
- /**
57
- * Generates strict-mode constraint checks for a typed property
58
- * (pattern, length, min/max, multipleOf).
59
- */
60
- const generateConstraintChecks = (acc: string, propSchema: JSONSchema, typeName: string, key: string): string[] => {
61
- if (!isSchemaObject(propSchema) || !hasType(propSchema)) return []
62
- const t = propSchema.type as string
63
- const lines: string[] = []
64
-
65
- if (t === 'string') {
66
- if (hasPattern(propSchema)) {
67
- const pattern = escapeRegexPattern(propSchema.pattern)
68
- lines.push(
69
- ` if (typeof ${acc} === "string" && !/${pattern}/.test(${acc})) throw new Error('[${typeName}] field "${key}" must match pattern ${propSchema.pattern}');`,
70
- )
71
- }
72
- if (hasMinLength(propSchema)) {
73
- lines.push(
74
- ` if (typeof ${acc} === "string" && ${acc}.length < ${propSchema.minLength}) throw new Error('[${typeName}] field "${key}" must have at least ${propSchema.minLength} characters');`,
75
- )
76
- }
77
- if (hasMaxLength(propSchema)) {
78
- lines.push(
79
- ` if (typeof ${acc} === "string" && ${acc}.length > ${propSchema.maxLength}) throw new Error('[${typeName}] field "${key}" must have at most ${propSchema.maxLength} characters');`,
80
- )
81
- }
82
- }
83
-
84
- if (t === 'number' || t === 'integer') {
85
- if (hasMinimum(propSchema)) {
86
- lines.push(
87
- ` if (typeof ${acc} === "number" && ${acc} < ${propSchema.minimum}) throw new Error('[${typeName}] field "${key}" must be >= ${propSchema.minimum}');`,
88
- )
89
- }
90
- if (hasMaximum(propSchema)) {
91
- lines.push(
92
- ` if (typeof ${acc} === "number" && ${acc} > ${propSchema.maximum}) throw new Error('[${typeName}] field "${key}" must be <= ${propSchema.maximum}');`,
93
- )
94
- }
95
- if (hasExclusiveMinimum(propSchema)) {
96
- lines.push(
97
- ` if (typeof ${acc} === "number" && ${acc} <= ${propSchema.exclusiveMinimum}) throw new Error('[${typeName}] field "${key}" must be > ${propSchema.exclusiveMinimum}');`,
98
- )
99
- }
100
- if (hasExclusiveMaximum(propSchema)) {
101
- lines.push(
102
- ` if (typeof ${acc} === "number" && ${acc} >= ${propSchema.exclusiveMaximum}) throw new Error('[${typeName}] field "${key}" must be < ${propSchema.exclusiveMaximum}');`,
103
- )
104
- }
105
- if (hasMultipleOf(propSchema)) {
106
- lines.push(
107
- ` if (typeof ${acc} === "number" && ${acc} % ${propSchema.multipleOf} !== 0) throw new Error('[${typeName}] field "${key}" must be a multiple of ${propSchema.multipleOf}');`,
108
- )
109
- }
110
- }
111
-
112
- return lines
113
- }
114
-
115
- /**
116
- * Generates strict-mode lines for a single property of an object schema.
117
- * Properties with a `$ref` are skipped here — the nested parser handles its own
118
- * strict check when called from the parent's slow path.
119
- */
120
- const generatePropertyAssertion = (
121
- key: string,
122
- propSchema: JSONSchema,
123
- isRequired: boolean,
124
- typeName: string,
125
- ): string[] => {
126
- const acc = safeAccessor('input', key)
127
- const lines: string[] = []
128
-
129
- if (isRequired) {
130
- lines.push(
131
- ` if (!(${JSON.stringify(key)} in input)) throw new Error('[${typeName}] missing required property "${key}"');`,
132
- )
133
- }
134
-
135
- if (!isSchemaObject(propSchema)) return lines
136
- if (hasRef(propSchema)) return lines
137
-
138
- const instanceOf = getMjstInstanceOf(propSchema)
139
- if (instanceOf) {
140
- if (isRequired) {
141
- lines.push(
142
- ` if (!(${acc} instanceof ${instanceOf})) throw new Error('[${typeName}] field "${key}" must be ${instanceOf}');`,
143
- )
144
- } else {
145
- lines.push(
146
- ` if (${acc} !== undefined && !(${acc} instanceof ${instanceOf})) throw new Error('[${typeName}] field "${key}" must be ${instanceOf}');`,
147
- )
148
- }
149
- return lines
150
- }
151
-
152
- const primitive = getMjstPrimitive(propSchema)
153
- if (primitive) {
154
- if (isRequired) {
155
- lines.push(
156
- ` if (typeof ${acc} !== "${primitive}") throw new Error('[${typeName}] field "${key}" must be ${primitive}');`,
157
- )
158
- } else {
159
- lines.push(
160
- ` if (${acc} !== undefined && typeof ${acc} !== "${primitive}") throw new Error('[${typeName}] field "${key}" must be ${primitive}');`,
161
- )
162
- }
163
- return lines
164
- }
165
-
166
- if (hasEnum(propSchema)) {
167
- const allowed = JSON.stringify(propSchema.enum)
168
- const label = (propSchema.enum as unknown[]).map((v) => JSON.stringify(v)).join(', ')
169
- if (isRequired) {
170
- lines.push(
171
- ` if (!(${allowed} as readonly unknown[]).includes(${acc})) throw new Error('[${typeName}] field "${key}" must be one of: ${label}');`,
172
- )
173
- } else {
174
- lines.push(
175
- ` if (${acc} !== undefined && !(${allowed} as readonly unknown[]).includes(${acc})) throw new Error('[${typeName}] field "${key}" must be one of: ${label}');`,
176
- )
177
- }
178
- return lines
179
- }
180
-
181
- if (hasType(propSchema)) {
182
- const t = propSchema.type as string
183
- const wrongType = wrongTypeCondition(acc, t)
184
- if (wrongType) {
185
- if (isRequired) {
186
- lines.push(
187
- ` if (${wrongType}) throw new Error(\`[${typeName}] field "${key}" expected ${typeLabel(t)}, got \${typeof ${acc}}\`);`,
188
- )
189
- } else {
190
- lines.push(
191
- ` if (${acc} !== undefined && (${wrongType})) throw new Error(\`[${typeName}] field "${key}" expected ${typeLabel(t)}, got \${typeof ${acc}}\`);`,
192
- )
193
- }
194
- }
195
- lines.push(...generateConstraintChecks(acc, propSchema, typeName, key))
196
- }
197
-
198
- return lines
199
- }
200
-
201
- /**
202
- * Generates strict-mode assertions for the body of an object parser.
203
- * Throws on:
204
- * - non-object input
205
- * - missing required property
206
- * - property of the wrong primitive type
207
- * - enum / pattern / length / min / max / multipleOf violations
208
- *
209
- * Properties with a `$ref` are validated by the nested parser's own strict
210
- * check when that parser is invoked downstream.
211
- */
212
- export const generateObjectStrictAssertion = (schema: JSONSchema, typeName: string): string[] => {
213
- const lines: string[] = []
214
- lines.push(
215
- ` if (!isObject(input)) throw new Error(\`[${typeName}] expected object, got \${input === null ? "null" : typeof input}\`);`,
216
- )
217
-
218
- if (!hasProperties(schema) || !isSchemaObject(schema)) return lines
219
-
220
- const required = new Set<string>(hasRequired(schema) ? schema.required : [])
221
-
222
- for (const [key, propSchema] of Object.entries(schema.properties)) {
223
- lines.push(...generatePropertyAssertion(key, propSchema, required.has(key), typeName))
224
- }
225
-
226
- return lines
227
- }
228
-
229
- /**
230
- * Generates a single strict-mode assertion line for a non-object scalar parser.
231
- * Returns null when the schema has no type information to assert on.
232
- */
233
- export const generateScalarStrictAssertion = (schema: JSONSchema, typeName: string): string | null => {
234
- const instanceOf = getMjstInstanceOf(schema)
235
- if (instanceOf) {
236
- return ` if (!(input instanceof ${instanceOf})) throw new Error(\`[${typeName}] expected ${instanceOf}, got \${input === null ? "null" : typeof input}\`);`
237
- }
238
-
239
- const primitive = getMjstPrimitive(schema)
240
- if (primitive) {
241
- return ` if (typeof input !== "${primitive}") throw new Error(\`[${typeName}] expected ${primitive}, got \${input === null ? "null" : typeof input}\`);`
242
- }
243
-
244
- if (!isSchemaObject(schema) || !hasType(schema)) return null
245
- const t = schema.type as string
246
- const wrongType = wrongTypeCondition('input', t)
247
- if (!wrongType) return null
248
- return ` if (${wrongType}) throw new Error(\`[${typeName}] expected ${typeLabel(t)}, got \${input === null ? "null" : typeof input}\`);`
249
- }