@amritk/generate-parsers 0.3.1 → 0.4.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.
package/dist/index.js CHANGED
@@ -375,6 +375,31 @@ var isSchemaObject2 = (schema) => {
375
375
  var isObjectSchema = (schema) => {
376
376
  return isSchemaObject2(schema) && (("type" in schema) && schema.type === "object" || ("properties" in schema));
377
377
  };
378
+ var MJST_EXTENSION_KEY = "x-mjst";
379
+ var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
380
+ var SUPPORTED_PRIMITIVES = new Set(["bigint"]);
381
+ var SAFE_BRAND = /^[\w$ -]+$/;
382
+ var readExtensionString = (schema, field) => {
383
+ if (!isSchemaObject2(schema))
384
+ return;
385
+ const extension = schema[MJST_EXTENSION_KEY];
386
+ if (typeof extension !== "object" || extension === null)
387
+ return;
388
+ const value = extension[field];
389
+ return typeof value === "string" ? value : undefined;
390
+ };
391
+ var getMjstInstanceOf = (schema) => {
392
+ const instanceOf = readExtensionString(schema, "instanceOf");
393
+ return instanceOf !== undefined && IDENTIFIER.test(instanceOf) ? instanceOf : undefined;
394
+ };
395
+ var getMjstPrimitive = (schema) => {
396
+ const primitive = readExtensionString(schema, "primitive");
397
+ return primitive !== undefined && SUPPORTED_PRIMITIVES.has(primitive) ? primitive : undefined;
398
+ };
399
+ var getMjstBrand = (schema) => {
400
+ const brand = readExtensionString(schema, "brand");
401
+ return brand !== undefined && SAFE_BRAND.test(brand) ? brand : undefined;
402
+ };
378
403
  var toKebabCase4 = (value) => value.replace(/OAuth/g, "Oauth").replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z\d])([A-Z])/g, "$1-$2").toLowerCase();
379
404
  var uriRefToFilename4 = (uri) => {
380
405
  const hashIndex = uri.indexOf("#");
@@ -516,12 +541,25 @@ var buildJsDocBlock = (title, description, commentUrl) => {
516
541
  return block;
517
542
  };
518
543
  var getTypeScriptType = (schema) => {
544
+ const base = getUnbrandedType(schema);
545
+ const brand = getMjstBrand(schema);
546
+ return brand ? `(${base} & { readonly __brand: '${brand}' })` : base;
547
+ };
548
+ var getUnbrandedType = (schema) => {
519
549
  if (typeof schema === "boolean") {
520
550
  return getBooleanSubSchemaType(schema);
521
551
  }
522
552
  if (typeof schema !== "object" || schema === null) {
523
553
  return "unknown";
524
554
  }
555
+ const instanceOf = getMjstInstanceOf(schema);
556
+ if (instanceOf) {
557
+ return instanceOf;
558
+ }
559
+ const primitive = getMjstPrimitive(schema);
560
+ if (primitive) {
561
+ return primitive;
562
+ }
525
563
  if (schema.$ref) {
526
564
  if (!schema.$ref.startsWith("#")) {
527
565
  return "unknown";
@@ -1082,6 +1120,31 @@ var safeKey2 = (key) => {
1082
1120
  return `'${key}'`;
1083
1121
  };
1084
1122
 
1123
+ // ../helpers/dist/mjst-extension.js
1124
+ var isSchemaObject4 = (schema) => {
1125
+ return typeof schema === "object" && schema !== null && typeof schema !== "boolean";
1126
+ };
1127
+ var MJST_EXTENSION_KEY2 = "x-mjst";
1128
+ var IDENTIFIER2 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
1129
+ var SUPPORTED_PRIMITIVES2 = new Set(["bigint"]);
1130
+ var readExtensionString2 = (schema, field) => {
1131
+ if (!isSchemaObject4(schema))
1132
+ return;
1133
+ const extension = schema[MJST_EXTENSION_KEY2];
1134
+ if (typeof extension !== "object" || extension === null)
1135
+ return;
1136
+ const value = extension[field];
1137
+ return typeof value === "string" ? value : undefined;
1138
+ };
1139
+ var getMjstInstanceOf2 = (schema) => {
1140
+ const instanceOf = readExtensionString2(schema, "instanceOf");
1141
+ return instanceOf !== undefined && IDENTIFIER2.test(instanceOf) ? instanceOf : undefined;
1142
+ };
1143
+ var getMjstPrimitive2 = (schema) => {
1144
+ const primitive = readExtensionString2(schema, "primitive");
1145
+ return primitive !== undefined && SUPPORTED_PRIMITIVES2.has(primitive) ? primitive : undefined;
1146
+ };
1147
+
1085
1148
  // src/generators/generate-default-from-pattern.ts
1086
1149
  var generateDefaultFromPattern = (pattern) => {
1087
1150
  if (pattern.includes("@") || pattern.includes("[a-zA-Z0-9]") && pattern.includes("\\.")) {
@@ -1139,6 +1202,9 @@ var getDefaultValue = (schema) => {
1139
1202
  return getDefaultValue(firstSchema);
1140
1203
  }
1141
1204
  }
1205
+ if (getMjstPrimitive2(schema) === "bigint") {
1206
+ return "0n";
1207
+ }
1142
1208
  if (!hasType(schema)) {
1143
1209
  return "undefined";
1144
1210
  }
@@ -1234,6 +1300,24 @@ var generatePropertyAssertion = (key, propSchema, isRequired, typeName) => {
1234
1300
  return lines;
1235
1301
  if (hasRef(propSchema))
1236
1302
  return lines;
1303
+ const instanceOf = getMjstInstanceOf2(propSchema);
1304
+ if (instanceOf) {
1305
+ if (isRequired) {
1306
+ lines.push(` if (!(${acc} instanceof ${instanceOf})) throw new Error('[${typeName}] field "${key}" must be ${instanceOf}');`);
1307
+ } else {
1308
+ lines.push(` if (${acc} !== undefined && !(${acc} instanceof ${instanceOf})) throw new Error('[${typeName}] field "${key}" must be ${instanceOf}');`);
1309
+ }
1310
+ return lines;
1311
+ }
1312
+ const primitive = getMjstPrimitive2(propSchema);
1313
+ if (primitive) {
1314
+ if (isRequired) {
1315
+ lines.push(` if (typeof ${acc} !== "${primitive}") throw new Error('[${typeName}] field "${key}" must be ${primitive}');`);
1316
+ } else {
1317
+ lines.push(` if (${acc} !== undefined && typeof ${acc} !== "${primitive}") throw new Error('[${typeName}] field "${key}" must be ${primitive}');`);
1318
+ }
1319
+ return lines;
1320
+ }
1237
1321
  if (hasEnum(propSchema)) {
1238
1322
  const allowed = JSON.stringify(propSchema.enum);
1239
1323
  const label = propSchema.enum.map((v) => JSON.stringify(v)).join(", ");
@@ -1270,6 +1354,14 @@ var generateObjectStrictAssertion = (schema, typeName) => {
1270
1354
  return lines;
1271
1355
  };
1272
1356
  var generateScalarStrictAssertion = (schema, typeName) => {
1357
+ const instanceOf = getMjstInstanceOf2(schema);
1358
+ if (instanceOf) {
1359
+ return ` if (!(input instanceof ${instanceOf})) throw new Error(\`[${typeName}] expected ${instanceOf}, got \${input === null ? "null" : typeof input}\`);`;
1360
+ }
1361
+ const primitive = getMjstPrimitive2(schema);
1362
+ if (primitive) {
1363
+ return ` if (typeof input !== "${primitive}") throw new Error(\`[${typeName}] expected ${primitive}, got \${input === null ? "null" : typeof input}\`);`;
1364
+ }
1273
1365
  if (!isSchemaObject3(schema) || !hasType(schema))
1274
1366
  return null;
1275
1367
  const t = schema.type;
@@ -1329,6 +1421,14 @@ var generateEnumCheck = (accessor, enumValues) => {
1329
1421
  // src/generators/generate-schema-checks.ts
1330
1422
  var generateSchemaChecks = (accessor, schema) => {
1331
1423
  const checks = [];
1424
+ const instanceOf = getMjstInstanceOf2(schema);
1425
+ if (instanceOf) {
1426
+ return [`${accessor} instanceof ${instanceOf}`];
1427
+ }
1428
+ const primitive = getMjstPrimitive2(schema);
1429
+ if (primitive) {
1430
+ return [`typeof ${accessor} === "${primitive}"`];
1431
+ }
1332
1432
  if (!hasType(schema)) {
1333
1433
  return checks;
1334
1434
  }
@@ -1461,6 +1561,11 @@ var generateNonDiscriminatedUnionValidation = (accessor, schemas, defaultValue,
1461
1561
  };
1462
1562
 
1463
1563
  // src/generators/generate-validation-expression.ts
1564
+ var getInstanceCoercion = (accessor, instanceOf) => {
1565
+ if (instanceOf === "Date")
1566
+ return `new Date(${accessor} as string | number | Date)`;
1567
+ return null;
1568
+ };
1464
1569
  var getTypeCoercion = (accessor, schema, defaultValue) => {
1465
1570
  if (!hasType(schema)) {
1466
1571
  return null;
@@ -1489,6 +1594,20 @@ var generateValidationExpression = (key, schema, defaultValue, isRequired, rootS
1489
1594
  if (!isSchemaObject3(schema)) {
1490
1595
  return isRequired ? `${accessor} ?? ${defaultValue}` : accessor;
1491
1596
  }
1597
+ const instanceOf = getMjstInstanceOf2(schema);
1598
+ if (instanceOf) {
1599
+ const valid = `${accessor} instanceof ${instanceOf}`;
1600
+ const coercion = getInstanceCoercion(accessor, instanceOf);
1601
+ if (isRequired) {
1602
+ return coercion ? `${valid} ? ${accessor} : (${accessor} !== undefined ? ${coercion} : ${defaultValue})` : `${valid} ? ${accessor} : ${defaultValue}`;
1603
+ }
1604
+ return coercion ? `${valid} ? ${accessor} : (${accessor} !== undefined ? ${coercion} : undefined)` : `${valid} ? ${accessor} : undefined`;
1605
+ }
1606
+ const primitive = getMjstPrimitive2(schema);
1607
+ if (primitive) {
1608
+ const valid = `typeof ${accessor} === "${primitive}"`;
1609
+ return isRequired ? `${valid} ? ${accessor} : ${defaultValue}` : `${valid} ? ${accessor} : undefined`;
1610
+ }
1492
1611
  if (hasRef(schema) && rootSchema) {
1493
1612
  const ref = schema.$ref;
1494
1613
  if (visitedRefs?.has(ref)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amritk/generate-parsers",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Generate TypeScript parsers and type definitions from JSON Schemas.",
5
5
  "module": "./dist/index.js",
6
6
  "type": "module",
@@ -48,8 +48,8 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
- "json-schema-typed": "catalog:",
52
- "@amritk/helpers": "workspace:*",
53
- "@amritk/generate-markdown": "workspace:*"
51
+ "json-schema-typed": "^8.0.1",
52
+ "@amritk/helpers": "0.4.0",
53
+ "@amritk/generate-markdown": "0.2.1"
54
54
  }
55
55
  }
@@ -319,4 +319,12 @@ describe('generate-schema-checks', () => {
319
319
  const result = generateSchemaChecks('input?.name', { type: 'string', minLength: 1 })
320
320
  expect(result).toEqual(['typeof input?.name === "string"', 'input?.name.length >= 1'])
321
321
  })
322
+
323
+ it('returns an instanceof check for an x-mjst instanceOf node', () => {
324
+ expect(generateSchemaChecks('value', { 'x-mjst': { instanceOf: 'Date' } })).toEqual(['value instanceof Date'])
325
+ })
326
+
327
+ it('returns a typeof check for an x-mjst bigint node', () => {
328
+ expect(generateSchemaChecks('value', { 'x-mjst': { primitive: 'bigint' } })).toEqual(['typeof value === "bigint"'])
329
+ })
322
330
  })
@@ -1,3 +1,4 @@
1
+ import { getMjstInstanceOf, getMjstPrimitive } from '@amritk/helpers/mjst-extension'
1
2
  import {
2
3
  hasAdditionalProperties,
3
4
  hasEnum,
@@ -28,6 +29,18 @@ import { generateEnumCheck } from './generate-enum-check'
28
29
  export const generateSchemaChecks = (accessor: string, schema: JSONSchema): string[] => {
29
30
  const checks: string[] = []
30
31
 
32
+ // x-mjst instanceOf nodes validate purely by instance check (no native type).
33
+ const instanceOf = getMjstInstanceOf(schema)
34
+ if (instanceOf) {
35
+ return [`${accessor} instanceof ${instanceOf}`]
36
+ }
37
+
38
+ // x-mjst primitive nodes (e.g. bigint) validate purely by typeof check.
39
+ const primitive = getMjstPrimitive(schema)
40
+ if (primitive) {
41
+ return [`typeof ${accessor} === "${primitive}"`]
42
+ }
43
+
31
44
  if (!hasType(schema)) {
32
45
  return checks
33
46
  }
@@ -0,0 +1,67 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { generateObjectStrictAssertion, generateScalarStrictAssertion } from './generate-strict-assertion'
4
+
5
+ describe('generate-strict-assertion x-mjst instanceOf', () => {
6
+ it('asserts instanceof for a required Date property', () => {
7
+ const schema = {
8
+ type: 'object' as const,
9
+ properties: { createdAt: { 'x-mjst': { instanceOf: 'Date' } } },
10
+ required: ['createdAt'],
11
+ }
12
+ const lines = generateObjectStrictAssertion(schema, 'Event').join('\n')
13
+
14
+ expect(lines).toContain('missing required property "createdAt"')
15
+ expect(lines).toContain('!(input.createdAt instanceof Date)')
16
+ expect(lines).toContain('field "createdAt" must be Date')
17
+ })
18
+
19
+ it('guards undefined before asserting instanceof for an optional Date property', () => {
20
+ const schema = {
21
+ type: 'object' as const,
22
+ properties: { createdAt: { 'x-mjst': { instanceOf: 'Date' } } },
23
+ }
24
+ const lines = generateObjectStrictAssertion(schema, 'Event').join('\n')
25
+
26
+ expect(lines).toContain('input.createdAt !== undefined && !(input.createdAt instanceof Date)')
27
+ })
28
+
29
+ it('asserts instanceof for a top-level Date schema', () => {
30
+ const line = generateScalarStrictAssertion({ 'x-mjst': { instanceOf: 'Date' } }, 'When')
31
+
32
+ expect(line).toContain('!(input instanceof Date)')
33
+ expect(line).toContain('expected Date')
34
+ })
35
+ })
36
+
37
+ describe('generate-strict-assertion x-mjst primitive', () => {
38
+ it('asserts typeof bigint for a required property', () => {
39
+ const schema = {
40
+ type: 'object' as const,
41
+ properties: { balance: { 'x-mjst': { primitive: 'bigint' } } },
42
+ required: ['balance'],
43
+ }
44
+ const lines = generateObjectStrictAssertion(schema, 'Account').join('\n')
45
+
46
+ expect(lines).toContain('missing required property "balance"')
47
+ expect(lines).toContain('typeof input.balance !== "bigint"')
48
+ expect(lines).toContain('field "balance" must be bigint')
49
+ })
50
+
51
+ it('guards undefined before asserting typeof for an optional bigint property', () => {
52
+ const schema = {
53
+ type: 'object' as const,
54
+ properties: { balance: { 'x-mjst': { primitive: 'bigint' } } },
55
+ }
56
+ const lines = generateObjectStrictAssertion(schema, 'Account').join('\n')
57
+
58
+ expect(lines).toContain('input.balance !== undefined && typeof input.balance !== "bigint"')
59
+ })
60
+
61
+ it('asserts typeof for a top-level bigint schema', () => {
62
+ const line = generateScalarStrictAssertion({ 'x-mjst': { primitive: 'bigint' } }, 'Big')
63
+
64
+ expect(line).toContain('typeof input !== "bigint"')
65
+ expect(line).toContain('expected bigint')
66
+ })
67
+ })
@@ -1,3 +1,4 @@
1
+ import { getMjstInstanceOf, getMjstPrimitive } from '@amritk/helpers/mjst-extension'
1
2
  import { safeAccessor } from '@amritk/helpers/safe-accessor'
2
3
  import {
3
4
  hasEnum,
@@ -134,6 +135,34 @@ const generatePropertyAssertion = (
134
135
  if (!isSchemaObject(propSchema)) return lines
135
136
  if (hasRef(propSchema)) return lines
136
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
+
137
166
  if (hasEnum(propSchema)) {
138
167
  const allowed = JSON.stringify(propSchema.enum)
139
168
  const label = (propSchema.enum as unknown[]).map((v) => JSON.stringify(v)).join(', ')
@@ -202,6 +231,16 @@ export const generateObjectStrictAssertion = (schema: JSONSchema, typeName: stri
202
231
  * Returns null when the schema has no type information to assert on.
203
232
  */
204
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
+
205
244
  if (!isSchemaObject(schema) || !hasType(schema)) return null
206
245
  const t = schema.type as string
207
246
  const wrongType = wrongTypeCondition('input', t)
@@ -791,4 +791,41 @@ describe('generate-validation-expression', () => {
791
791
 
792
792
  expect(result).toContain('? input?.status : undefined')
793
793
  })
794
+
795
+ it('checks instanceof and coerces a required x-mjst Date field', () => {
796
+ const schema = { 'x-mjst': { instanceOf: 'Date' } }
797
+ const result = generateValidationExpression('createdAt', schema, '{}', true)
798
+
799
+ expect(result).toContain('input?.createdAt instanceof Date')
800
+ expect(result).toContain('new Date(input?.createdAt as string | number | Date)')
801
+ })
802
+
803
+ it('checks instanceof and coerces an optional x-mjst Date field', () => {
804
+ const schema = { 'x-mjst': { instanceOf: 'Date' } }
805
+ const result = generateValidationExpression('createdAt', schema, 'undefined', false)
806
+
807
+ expect(result).toContain('input?.createdAt instanceof Date')
808
+ expect(result).toContain('? input?.createdAt : (input?.createdAt !== undefined ? new Date')
809
+ })
810
+
811
+ it('falls back to the default for an unknown instanceOf with no coercion', () => {
812
+ const schema = { 'x-mjst': { instanceOf: 'CustomThing' } }
813
+ const result = generateValidationExpression('value', schema, '{}', true)
814
+
815
+ expect(result).toBe('input?.value instanceof CustomThing ? input?.value : {}')
816
+ })
817
+
818
+ it('checks typeof bigint for a required x-mjst primitive field', () => {
819
+ const schema = { 'x-mjst': { primitive: 'bigint' } }
820
+ const result = generateValidationExpression('balance', schema, '0n', true)
821
+
822
+ expect(result).toBe('typeof input?.balance === "bigint" ? input?.balance : 0n')
823
+ })
824
+
825
+ it('checks typeof bigint for an optional x-mjst primitive field', () => {
826
+ const schema = { 'x-mjst': { primitive: 'bigint' } }
827
+ const result = generateValidationExpression('balance', schema, '0n', false)
828
+
829
+ expect(result).toBe('typeof input?.balance === "bigint" ? input?.balance : undefined')
830
+ })
794
831
  })
@@ -1,3 +1,4 @@
1
+ import { getMjstInstanceOf, getMjstPrimitive } from '@amritk/helpers/mjst-extension'
1
2
  import { resolveRef } from '@amritk/helpers/resolve-ref'
2
3
  import { safeAccessor } from '@amritk/helpers/safe-accessor'
3
4
  import {
@@ -34,6 +35,17 @@ import { generateEnumCheck } from './generate-enum-check'
34
35
  import { generateNonDiscriminatedUnionValidation } from './generate-non-discriminated-union-validation'
35
36
  import { generateSchemaChecks } from './generate-schema-checks'
36
37
 
38
+ /**
39
+ * Coercion expression for an `x-mjst` instanceOf value, when one is known.
40
+ * `Date` can be reconstructed from the common JSON encodings (ISO string or
41
+ * epoch number); other classes have no safe generic coercion, so we return null
42
+ * and the caller falls back to the default.
43
+ */
44
+ const getInstanceCoercion = (accessor: string, instanceOf: string): string | null => {
45
+ if (instanceOf === 'Date') return `new Date(${accessor} as string | number | Date)`
46
+ return null
47
+ }
48
+
37
49
  /**
38
50
  * Generates a type coercion expression for converting a value to the expected type.
39
51
  */
@@ -85,6 +97,34 @@ export const generateValidationExpression = (
85
97
  return isRequired ? `${accessor} ?? ${defaultValue}` : accessor
86
98
  }
87
99
 
100
+ // Handle x-mjst instanceOf (e.g. Date): the value must be an instance of the
101
+ // named class. Invalid values are coerced when a coercer is known, otherwise
102
+ // they fall back to the default (required) or undefined (optional).
103
+ const instanceOf = getMjstInstanceOf(schema)
104
+ if (instanceOf) {
105
+ const valid = `${accessor} instanceof ${instanceOf}`
106
+ const coercion = getInstanceCoercion(accessor, instanceOf)
107
+
108
+ if (isRequired) {
109
+ return coercion
110
+ ? `${valid} ? ${accessor} : (${accessor} !== undefined ? ${coercion} : ${defaultValue})`
111
+ : `${valid} ? ${accessor} : ${defaultValue}`
112
+ }
113
+ return coercion
114
+ ? `${valid} ? ${accessor} : (${accessor} !== undefined ? ${coercion} : undefined)`
115
+ : `${valid} ? ${accessor} : undefined`
116
+ }
117
+
118
+ // Handle x-mjst primitive (e.g. bigint): validate with typeof. We do not
119
+ // coerce — BigInt() throws on invalid input, which a pure coercion expression
120
+ // cannot guard — so invalid values fall back to the default (required) or
121
+ // undefined (optional).
122
+ const primitive = getMjstPrimitive(schema)
123
+ if (primitive) {
124
+ const valid = `typeof ${accessor} === "${primitive}"`
125
+ return isRequired ? `${valid} ? ${accessor} : ${defaultValue}` : `${valid} ? ${accessor} : undefined`
126
+ }
127
+
88
128
  // Handle $ref - resolve and validate against the referenced schema
89
129
  if (hasRef(schema) && rootSchema) {
90
130
  const ref = schema.$ref
@@ -132,4 +132,8 @@ describe('get-default-value', () => {
132
132
  it('handles empty oneOf array and falls back', () => {
133
133
  expect(getDefaultValue({ oneOf: [], type: 'boolean' })).toBe('false')
134
134
  })
135
+
136
+ it('returns 0n for an x-mjst bigint schema', () => {
137
+ expect(getDefaultValue({ 'x-mjst': { primitive: 'bigint' } })).toBe('0n')
138
+ })
135
139
  })
@@ -1,3 +1,4 @@
1
+ import { getMjstPrimitive } from '@amritk/helpers/mjst-extension'
1
2
  import {
2
3
  hasAllOf,
3
4
  hasAnyOf,
@@ -60,6 +61,11 @@ export const getDefaultValue = (schema: JSONSchema): string => {
60
61
  }
61
62
  }
62
63
 
64
+ // x-mjst bigint has no native JSON type but a sensible zero default.
65
+ if (getMjstPrimitive(schema) === 'bigint') {
66
+ return '0n'
67
+ }
68
+
63
69
  if (!hasType(schema)) {
64
70
  return 'undefined'
65
71
  }