@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,147 +0,0 @@
1
- import { readFile } from 'node:fs/promises'
2
- import { createRequire } from 'node:module'
3
- import { dirname, resolve as resolvePath } from 'node:path'
4
- import { generateIndexBarrel } from '@amritk/helpers/generate-index-barrel'
5
- import { walkRefGraph } from '@amritk/helpers/walk-ref-graph'
6
- import type { JSONSchema } from 'json-schema-typed/draft-2020-12'
7
- import { applySchemaExtensions } from '#helpers/apply-schema-extensions'
8
- import type { HelpersMode, RuntimeHelperName } from '#helpers/collect-helpers'
9
- import type { SchemaExtensions } from '#types/schema-extensions'
10
-
11
- import { generateFile } from './generate-files'
12
-
13
- /** Locate the @amritk/helpers package on disk so we can copy its runtime
14
- * helper source files into the generated output when in embedded mode. */
15
- const readHelperSource = async (helper: RuntimeHelperName): Promise<string> => {
16
- const require = createRequire(import.meta.url)
17
- const helpersPkgPath = require.resolve('@amritk/helpers/package.json')
18
- const helpersRoot = dirname(helpersPkgPath)
19
- return readFile(resolvePath(helpersRoot, 'src', `${helper}.ts`), 'utf-8')
20
- }
21
-
22
- /**
23
- * Represents a generated file with its filename and content.
24
- */
25
- export type GeneratedFile = {
26
- filename: string
27
- content: string
28
- }
29
-
30
- /**
31
- * Builds all TypeScript files from a JSON Schema by traversing its entire
32
- * `$ref` / `$dynamicRef` graph (via the shared `@amritk/helpers/walk-ref-graph`
33
- * walker, which also seeds `$dynamicAnchor` definitions and rewrites
34
- * `$dynamicRef` to `$ref`).
35
- *
36
- * For the root schema and each reachable definition this function generates a
37
- * TypeScript file, then emits an `index.ts` barrel re-exporting them all.
38
- *
39
- * @param rootSchema - The root JSON Schema to build from
40
- * @param rootTypeName - The name for the root type (e.g., "Document")
41
- * @param extensions - Optional map of custom extension properties to add to specific definitions.
42
- * Keys are definition names (matching $defs keys), values are records of extension property
43
- * names to their JSON Schema definitions. Extensions are merged as optional properties before
44
- * type and parser generation.
45
- * @param typesOnly - When true, only generate TypeScript type definitions without parser functions.
46
- * @param logWarnings - When true, the generated parsers emit a console.warn for every input key
47
- * that is not declared in the schema's properties.
48
- * @param strict - When true, the generated parsers throw on type/shape mismatches
49
- * (wrong type, missing required property, enum/pattern/min/max violations) instead
50
- * of coercing invalid input to default values.
51
- * @param helpersMode - `'package'` (default) emits `import ... from '@amritk/helpers/...'`.
52
- * `'embedded'` emits `import ... from './_helpers/...'` and appends the helper sources
53
- * as additional `GeneratedFile` entries so the output directory is self-contained.
54
- * @param helpersImportPrefix - Relative path prefix to the `_helpers/` directory in
55
- * embedded mode. Defaults to `'./'`. The recursive multi-schema build passes `'../'`,
56
- * `'../../'`, etc. so nested parsers can import from a single shared `_helpers/`
57
- * directory while the helper sources are emitted once at the output root.
58
- * @param readonly - When true, every property, array, and record in the generated type
59
- * definitions is emitted as `readonly`.
60
- * @param typeSuffix - Suffix appended to every type/parser name derived from a `$ref`
61
- * (e.g. `'Object'` → `ContactObject`). Defaults to `''` (no suffix). The root type name
62
- * is used verbatim and is not affected by this suffix.
63
- * @returns An array of generated TypeScript files
64
- *
65
- * @example
66
- * ```typescript
67
- * const schema = {
68
- * type: "object",
69
- * properties: {
70
- * info: { $ref: "#/$defs/info" }
71
- * },
72
- * $defs: {
73
- * info: {
74
- * type: "object",
75
- * properties: {
76
- * title: { type: "string" }
77
- * }
78
- * }
79
- * }
80
- * };
81
- *
82
- * const files = buildSchema(schema, "Document");
83
- *
84
- * // Types-only mode — no parser functions or runtime helpers included:
85
- * const typesFiles = buildSchema(schema, "Document", undefined, true);
86
- *
87
- * // With extensions:
88
- * const filesWithExtensions = buildSchema(schema, "Document", {
89
- * info: {
90
- * 'x-internal': { type: 'boolean' },
91
- * },
92
- * });
93
- * ```
94
- */
95
- export const buildSchema = async (
96
- rootSchema: JSONSchema,
97
- rootTypeName: string,
98
- extensions?: SchemaExtensions,
99
- typesOnly?: boolean,
100
- logWarnings?: boolean,
101
- strict?: boolean,
102
- helpersMode: HelpersMode = 'package',
103
- helpersImportPrefix = './',
104
- readonly = false,
105
- typeSuffix = '',
106
- ): Promise<GeneratedFile[]> => {
107
- const files: GeneratedFile[] = []
108
- const usedHelpers = new Set<RuntimeHelperName>()
109
-
110
- walkRefGraph(rootSchema, rootTypeName, { typeSuffix }, (node) => {
111
- // `index` is reserved for the barrel below, so never let a definition of
112
- // that name overwrite it.
113
- if (node.filename === 'index') return
114
-
115
- // Extensions are keyed by definition name, which is the node's filename for
116
- // both the root (the lowercased root type name) and every `$ref` target.
117
- const extended = extensions ? applySchemaExtensions(node.schema, node.filename, extensions) : node.schema
118
- const result = generateFile(extended, node.typeName, {
119
- typesOnly: typesOnly ?? false,
120
- rootSchema: node.rootSchema,
121
- helpersMode,
122
- helpersImportPrefix,
123
- readonly,
124
- typeSuffix,
125
- ...(node.ref !== undefined ? { selfRef: node.ref } : {}),
126
- ...(logWarnings !== undefined ? { logWarnings } : {}),
127
- ...(strict !== undefined ? { strict } : {}),
128
- })
129
-
130
- files.push({ filename: `${node.filename}.ts`, content: result.content })
131
- for (const helper of result.usedHelpers) usedHelpers.add(helper)
132
- })
133
-
134
- // In embedded mode, ship the runtime helper source files alongside the parsers so
135
- // the output directory is self-contained (no `@amritk/helpers` install required).
136
- // typesOnly skips parser generation entirely, so no runtime helpers are needed.
137
- if (helpersMode === 'embedded' && !typesOnly) {
138
- for (const helper of usedHelpers) {
139
- const source = await readHelperSource(helper)
140
- files.push({ filename: `_helpers/${helper}.ts`, content: source })
141
- }
142
- }
143
-
144
- files.push({ filename: 'index.ts', content: generateIndexBarrel(files, { typesOnly: typesOnly ?? false }) })
145
-
146
- return files
147
- }
@@ -1,81 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
-
3
- import { generateDefaultFromPattern } from './generate-default-from-pattern'
4
-
5
- describe('generate-default-from-pattern', () => {
6
- it('returns email default for pattern containing @', () => {
7
- const result = generateDefaultFromPattern('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$')
8
- expect(result).toBe('"user@example.com"')
9
- })
10
-
11
- it('returns email default for pattern with character class and dot', () => {
12
- const result = generateDefaultFromPattern('[a-zA-Z0-9].*\\.')
13
- expect(result).toBe('"user@example.com"')
14
- })
15
-
16
- it('returns UUID default for hex pattern with {8}', () => {
17
- const result = generateDefaultFromPattern('^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$')
18
- expect(result).toBe('"00000000-0000-0000-0000-000000000000"')
19
- })
20
-
21
- it('returns UUID default for pattern with dash separator', () => {
22
- const result = generateDefaultFromPattern('[0-9a-f]{8}\\-[0-9a-f]{4}')
23
- expect(result).toBe('"00000000-0000-0000-0000-000000000000"')
24
- })
25
-
26
- it('returns null for hex pattern without dash or matching structure', () => {
27
- const result = generateDefaultFromPattern('^[0-9a-fA-F]{8}')
28
- expect(result).toBeNull()
29
- })
30
-
31
- it('returns URL default for https? pattern', () => {
32
- const result = generateDefaultFromPattern('^https?://')
33
- expect(result).toBe('"https://example.com"')
34
- })
35
-
36
- it('returns URL default for http pattern', () => {
37
- const result = generateDefaultFromPattern('^http://')
38
- expect(result).toBe('"https://example.com"')
39
- })
40
-
41
- it('returns semver default for version-like pattern with literal digits', () => {
42
- // The regex looks for actual digit chars and escaped dots in the pattern string
43
- const result = generateDefaultFromPattern('3\\.1\\.\\d+')
44
- expect(result).toBe('"1.0.0"')
45
- })
46
-
47
- it('returns null for version pattern without literal digits', () => {
48
- const result = generateDefaultFromPattern('^\\d+\\.\\d+\\.\\d+$')
49
- expect(result).toBeNull()
50
- })
51
-
52
- it('returns ISO date default for date-like pattern', () => {
53
- const result = generateDefaultFromPattern('^\\d{4}-\\d{2}-\\d{2}$')
54
- expect(result).toBe('"2000-01-01"')
55
- })
56
-
57
- it('returns phone number default for phone-like pattern with {3} and {4}', () => {
58
- const result = generateDefaultFromPattern('^\\+?\\d{3}\\d{4}$')
59
- expect(result).toBe('"+1234567890"')
60
- })
61
-
62
- it('returns phone number default for phone-like pattern with {3} and {7}', () => {
63
- const result = generateDefaultFromPattern('^\\d{3}\\d{7}$')
64
- expect(result).toBe('"+1234567890"')
65
- })
66
-
67
- it('returns null for unrecognized pattern', () => {
68
- const result = generateDefaultFromPattern('^[a-z]+$')
69
- expect(result).toBeNull()
70
- })
71
-
72
- it('returns null for empty pattern', () => {
73
- const result = generateDefaultFromPattern('')
74
- expect(result).toBeNull()
75
- })
76
-
77
- it('returns null for simple wildcard pattern', () => {
78
- const result = generateDefaultFromPattern('.*')
79
- expect(result).toBeNull()
80
- })
81
- })
@@ -1,39 +0,0 @@
1
- /**
2
- * Generates a best-guess default value from a regex pattern.
3
- * Recognizes common patterns and returns appropriate defaults.
4
- */
5
- export const generateDefaultFromPattern = (pattern: string): string | null => {
6
- // Email pattern
7
- if (pattern.includes('@') || (pattern.includes('[a-zA-Z0-9]') && pattern.includes('\\.'))) {
8
- return '"user@example.com"'
9
- }
10
-
11
- // UUID pattern
12
- if ((pattern.includes('[0-9a-f]') && pattern.includes('{8}')) || pattern.includes('\\-')) {
13
- if (pattern.match(/[0-9a-f].*\{8\}/i) || pattern.match(/[0-9a-fA-F]{8}/)) {
14
- return '"00000000-0000-0000-0000-000000000000"'
15
- }
16
- }
17
-
18
- // URL pattern
19
- if (pattern.includes('https?') || pattern.includes('http')) {
20
- return '"https://example.com"'
21
- }
22
-
23
- // Semver pattern (3.1.x, x.y.z, etc)
24
- if (pattern.match(/\d.*\\\.\.*\d/)) {
25
- return '"1.0.0"'
26
- }
27
-
28
- // ISO date pattern
29
- if (pattern.includes('\\d{4}') && pattern.includes('\\d{2}')) {
30
- return '"2000-01-01"'
31
- }
32
-
33
- // Phone number patterns
34
- if (pattern.includes('\\d{3}') && (pattern.includes('\\d{4}') || pattern.includes('\\d{7}'))) {
35
- return '"+1234567890"'
36
- }
37
-
38
- return null
39
- }
@@ -1,84 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
-
3
- import { generateDiscriminatedUnionValidation } from './generate-discriminated-union-validation'
4
-
5
- describe('generate-discriminated-union-validation', () => {
6
- it('generates ternary chain for schemas with discriminator values', () => {
7
- const schemas = [
8
- {
9
- type: 'object' as const,
10
- properties: { kind: { const: 'a' }, name: { type: 'string' as const } },
11
- },
12
- {
13
- type: 'object' as const,
14
- properties: { kind: { const: 'b' }, count: { type: 'number' as const } },
15
- },
16
- ]
17
- const result = generateDiscriminatedUnionValidation('value', schemas, 'kind', '{}', true)
18
- expect(result).toContain('value?.kind === "a"')
19
- expect(result).toContain('value?.kind === "b"')
20
- })
21
-
22
- it('returns fallback expression when no schemas have discriminator values', () => {
23
- const schemas = [{ type: 'object' as const, properties: { name: { type: 'string' as const } } }]
24
- const result = generateDiscriminatedUnionValidation('value', schemas, 'kind', '{}', true)
25
- expect(result).toBe('value ?? {}')
26
- })
27
-
28
- it('returns accessor when not required and no discriminator values', () => {
29
- const schemas = [{ type: 'object' as const, properties: { name: { type: 'string' as const } } }]
30
- const result = generateDiscriminatedUnionValidation('value', schemas, 'kind', '{}', false)
31
- expect(result).toBe('value')
32
- })
33
-
34
- it('includes schema checks in ternary when type checks exist', () => {
35
- const schemas = [
36
- {
37
- type: 'object' as const,
38
- properties: { kind: { const: 'user' } },
39
- },
40
- ]
41
- const result = generateDiscriminatedUnionValidation('input', schemas, 'kind', '{}', true)
42
- expect(result).toContain('input?.kind === "user"')
43
- // Should include object type checks
44
- expect(result).toContain('typeof input === "object"')
45
- })
46
-
47
- it('handles schemas with single enum values as discriminators', () => {
48
- const schemas = [
49
- {
50
- type: 'object' as const,
51
- properties: { type: { enum: ['cat'] } },
52
- },
53
- {
54
- type: 'object' as const,
55
- properties: { type: { enum: ['dog'] } },
56
- },
57
- ]
58
- const result = generateDiscriminatedUnionValidation('value', schemas, 'type', '{}', true)
59
- expect(result).toContain('value?.type === "cat"')
60
- expect(result).toContain('value?.type === "dog"')
61
- })
62
-
63
- it('handles empty schemas array', () => {
64
- const result = generateDiscriminatedUnionValidation('value', [], 'type', '{}', true)
65
- expect(result).toBe('value ?? {}')
66
- })
67
-
68
- it('skips schemas without a discriminator value', () => {
69
- const schemas = [
70
- {
71
- type: 'object' as const,
72
- properties: { kind: { const: 'a' } },
73
- },
74
- {
75
- type: 'object' as const,
76
- properties: { name: { type: 'string' as const } },
77
- },
78
- ]
79
- const result = generateDiscriminatedUnionValidation('value', schemas, 'kind', '{}', true)
80
- expect(result).toContain('value?.kind === "a"')
81
- // The second schema has no discriminator, so it does not appear in the ternary chain
82
- expect(result).not.toContain('value?.kind === undefined')
83
- })
84
- })
@@ -1,54 +0,0 @@
1
- import type { JSONSchema } from 'json-schema-typed/draft-2020-12'
2
- import { getDefaultValue } from '#helpers/get-default-value'
3
- import { getDiscriminatorValue } from '#helpers/get-discriminator-value'
4
-
5
- import { generateSchemaChecks } from './generate-schema-checks'
6
-
7
- /**
8
- * Generates a discriminated union validation expression.
9
- * Uses a discriminator property to efficiently choose the correct schema.
10
- */
11
- export const generateDiscriminatedUnionValidation = (
12
- accessor: string,
13
- schemas: readonly JSONSchema[],
14
- discriminatorKey: string,
15
- defaultValue: string,
16
- isRequired: boolean,
17
- ): string => {
18
- const cases: string[] = []
19
-
20
- for (const schema of schemas) {
21
- const discriminatorValue = getDiscriminatorValue(schema, discriminatorKey)
22
- if (discriminatorValue !== null) {
23
- const schemaDefault = getDefaultValue(schema)
24
- const checks = generateSchemaChecks(accessor, schema)
25
-
26
- if (checks.length > 0) {
27
- // checks[0] is safe: we guard with checks.length > 0 above
28
- let combinedChecks = checks[0] as string
29
- for (let i = 1; i < checks.length; i++) {
30
- combinedChecks += ' && ' + checks[i]
31
- }
32
- cases.push(
33
- `${accessor}?.${discriminatorKey} === ${JSON.stringify(discriminatorValue)} && ${combinedChecks} ? ${accessor} : ${schemaDefault}`,
34
- )
35
- } else {
36
- cases.push(
37
- `${accessor}?.${discriminatorKey} === ${JSON.stringify(discriminatorValue)} ? ${accessor} : ${schemaDefault}`,
38
- )
39
- }
40
- }
41
- }
42
-
43
- if (cases.length === 0) {
44
- return isRequired ? `${accessor} ?? ${defaultValue}` : accessor
45
- }
46
-
47
- // Chain the cases together with ternary operators using a for loop instead of .reduce()
48
- // cases[0] is safe: we guard with cases.length === 0 above
49
- let result = cases[0] as string
50
- for (let i = 1; i < cases.length; i++) {
51
- result = cases[i] + ' : ' + result
52
- }
53
- return result
54
- }
@@ -1,45 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
-
3
- import { generateEnumCheck } from './generate-enum-check'
4
-
5
- describe('generate-enum-check', () => {
6
- it('generates an includes check for string enum values', () => {
7
- const result = generateEnumCheck('value', ['a', 'b', 'c'])
8
- expect(result).toBe('["a","b","c"].includes(value as never)')
9
- })
10
-
11
- it('generates an includes check for numeric enum values', () => {
12
- const result = generateEnumCheck('value', [1, 2, 3])
13
- expect(result).toBe('[1,2,3].includes(value as never)')
14
- })
15
-
16
- it('generates an includes check for mixed type enum values', () => {
17
- const result = generateEnumCheck('value', ['a', 1, true, null])
18
- expect(result).toBe('["a",1,true,null].includes(value as never)')
19
- })
20
-
21
- it('handles a single enum value', () => {
22
- const result = generateEnumCheck('value', ['only'])
23
- expect(result).toBe('["only"].includes(value as never)')
24
- })
25
-
26
- it('handles an empty enum array', () => {
27
- const result = generateEnumCheck('value', [])
28
- expect(result).toBe('[].includes(value as never)')
29
- })
30
-
31
- it('uses the provided accessor in the expression', () => {
32
- const result = generateEnumCheck('input?.type', ['a', 'b'])
33
- expect(result).toBe('["a","b"].includes(input?.type as never)')
34
- })
35
-
36
- it('handles enum values with special characters', () => {
37
- const result = generateEnumCheck('value', ['hello world', 'foo"bar'])
38
- expect(result).toBe('["hello world","foo\\"bar"].includes(value as never)')
39
- })
40
-
41
- it('handles boolean enum values', () => {
42
- const result = generateEnumCheck('value', [true, false])
43
- expect(result).toBe('[true,false].includes(value as never)')
44
- })
45
- })
@@ -1,8 +0,0 @@
1
- /**
2
- * Generates an enum validation check expression.
3
- * Returns a string that checks if the value is in the allowed enum values.
4
- */
5
- export const generateEnumCheck = (accessor: string, enumValues: readonly unknown[]): string => {
6
- const serializedEnum = JSON.stringify(enumValues)
7
- return `${serializedEnum}.includes(${accessor} as never)`
8
- }