@kravc/schema 2.8.0-alpha.6 → 2.8.0-alpha.8

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 (118) hide show
  1. package/dist/CredentialFactory.d.ts +5 -318
  2. package/dist/CredentialFactory.d.ts.map +1 -1
  3. package/dist/CredentialFactory.js +5 -317
  4. package/dist/CredentialFactory.js.map +1 -1
  5. package/dist/Schema.d.ts +15 -420
  6. package/dist/Schema.d.ts.map +1 -1
  7. package/dist/Schema.js +13 -384
  8. package/dist/Schema.js.map +1 -1
  9. package/dist/ValidationError.d.ts +3 -49
  10. package/dist/ValidationError.d.ts.map +1 -1
  11. package/dist/ValidationError.js +3 -48
  12. package/dist/ValidationError.js.map +1 -1
  13. package/dist/Validator.d.ts +6 -470
  14. package/dist/Validator.d.ts.map +1 -1
  15. package/dist/Validator.js +50 -478
  16. package/dist/Validator.js.map +1 -1
  17. package/dist/helpers/cleanupAttributes.d.ts +3 -32
  18. package/dist/helpers/cleanupAttributes.d.ts.map +1 -1
  19. package/dist/helpers/cleanupAttributes.js +1 -30
  20. package/dist/helpers/cleanupAttributes.js.map +1 -1
  21. package/dist/helpers/cleanupNulls.d.ts +1 -25
  22. package/dist/helpers/cleanupNulls.d.ts.map +1 -1
  23. package/dist/helpers/cleanupNulls.js +2 -61
  24. package/dist/helpers/cleanupNulls.js.map +1 -1
  25. package/dist/helpers/createSchemasMap.d.ts +2 -93
  26. package/dist/helpers/createSchemasMap.d.ts.map +1 -1
  27. package/dist/helpers/createSchemasMap.js +4 -162
  28. package/dist/helpers/createSchemasMap.js.map +1 -1
  29. package/dist/helpers/getReferenceIds.d.ts +1 -165
  30. package/dist/helpers/getReferenceIds.d.ts.map +1 -1
  31. package/dist/helpers/getReferenceIds.js +2 -166
  32. package/dist/helpers/getReferenceIds.js.map +1 -1
  33. package/dist/helpers/got.d.ts +2 -58
  34. package/dist/helpers/got.d.ts.map +1 -1
  35. package/dist/helpers/got.js +1 -57
  36. package/dist/helpers/got.js.map +1 -1
  37. package/dist/helpers/mapObjectProperties.d.ts +2 -144
  38. package/dist/helpers/mapObjectProperties.d.ts.map +1 -1
  39. package/dist/helpers/mapObjectProperties.js +1 -142
  40. package/dist/helpers/mapObjectProperties.js.map +1 -1
  41. package/dist/helpers/normalizeAttributes.d.ts +3 -211
  42. package/dist/helpers/normalizeAttributes.d.ts.map +1 -1
  43. package/dist/helpers/normalizeAttributes.js +1 -209
  44. package/dist/helpers/normalizeAttributes.js.map +1 -1
  45. package/dist/helpers/normalizeProperties.d.ts +1 -165
  46. package/dist/helpers/normalizeProperties.d.ts.map +1 -1
  47. package/dist/helpers/normalizeProperties.js +1 -164
  48. package/dist/helpers/normalizeProperties.js.map +1 -1
  49. package/dist/helpers/normalizeRequired.d.ts +1 -153
  50. package/dist/helpers/normalizeRequired.d.ts.map +1 -1
  51. package/dist/helpers/normalizeRequired.js +0 -151
  52. package/dist/helpers/normalizeRequired.js.map +1 -1
  53. package/dist/helpers/normalizeType.d.ts +1 -77
  54. package/dist/helpers/normalizeType.d.ts.map +1 -1
  55. package/dist/helpers/normalizeType.js +11 -139
  56. package/dist/helpers/normalizeType.js.map +1 -1
  57. package/dist/helpers/nullifyEmptyValues.d.ts +1 -135
  58. package/dist/helpers/nullifyEmptyValues.d.ts.map +1 -1
  59. package/dist/helpers/nullifyEmptyValues.js +13 -143
  60. package/dist/helpers/nullifyEmptyValues.js.map +1 -1
  61. package/dist/helpers/removeRequiredAndDefault.d.ts +2 -102
  62. package/dist/helpers/removeRequiredAndDefault.d.ts.map +1 -1
  63. package/dist/helpers/removeRequiredAndDefault.js +1 -100
  64. package/dist/helpers/removeRequiredAndDefault.js.map +1 -1
  65. package/dist/helpers/validateId.d.ts +1 -36
  66. package/dist/helpers/validateId.d.ts.map +1 -1
  67. package/dist/helpers/validateId.js +1 -36
  68. package/dist/helpers/validateId.js.map +1 -1
  69. package/dist/ld/documentLoader.d.ts +1 -1
  70. package/dist/ld/documentLoader.d.ts.map +1 -1
  71. package/dist/ld/documentLoader.js +1 -1
  72. package/dist/ld/documentLoader.js.map +1 -1
  73. package/dist/ld/getLinkedDataAttributeType.d.ts +1 -1
  74. package/dist/ld/getLinkedDataAttributeType.d.ts.map +1 -1
  75. package/dist/ld/getLinkedDataAttributeType.js +1 -1
  76. package/dist/ld/getLinkedDataAttributeType.js.map +1 -1
  77. package/dist/ld/getLinkedDataContext.d.ts +1 -1
  78. package/dist/ld/getLinkedDataContext.d.ts.map +1 -1
  79. package/dist/ld/getLinkedDataContext.js +1 -1
  80. package/dist/ld/getLinkedDataContext.js.map +1 -1
  81. package/package.json +2 -2
  82. package/src/CredentialFactory.ts +5 -318
  83. package/src/Schema.ts +17 -427
  84. package/src/ValidationError.ts +5 -52
  85. package/src/Validator.ts +19 -483
  86. package/src/__tests__/CredentialFactory.test.ts +1 -1
  87. package/src/__tests__/Schema.test.ts +3 -8
  88. package/src/__tests__/ValidationError.test.ts +4 -2
  89. package/src/__tests__/Validator.test.ts +21 -4
  90. package/src/helpers/__tests__/cleanupAttributes.test.ts +3 -1
  91. package/src/helpers/__tests__/createSchemasMap.test.ts +1 -1
  92. package/src/helpers/__tests__/mapObjectProperties.test.ts +2 -1
  93. package/src/helpers/__tests__/normalizeAttributes.test.ts +4 -2
  94. package/src/helpers/__tests__/normalizeProperties.test.ts +3 -1
  95. package/src/helpers/__tests__/normalizeRequired.test.ts +4 -9
  96. package/src/helpers/__tests__/nullifyEmptyValues.test.ts +43 -12
  97. package/src/helpers/__tests__/removeRequiredAndDefault.test.ts +3 -10
  98. package/src/helpers/cleanupAttributes.ts +6 -44
  99. package/src/helpers/cleanupNulls.ts +2 -63
  100. package/src/helpers/createSchemasMap.ts +4 -163
  101. package/src/helpers/getReferenceIds.ts +2 -173
  102. package/src/helpers/got.ts +3 -59
  103. package/src/helpers/mapObjectProperties.ts +4 -156
  104. package/src/helpers/normalizeAttributes.ts +7 -211
  105. package/src/helpers/normalizeProperties.ts +1 -172
  106. package/src/helpers/normalizeRequired.ts +1 -161
  107. package/src/helpers/normalizeType.ts +11 -139
  108. package/src/helpers/nullifyEmptyValues.ts +10 -145
  109. package/src/helpers/removeRequiredAndDefault.ts +1 -106
  110. package/src/helpers/validateId.ts +1 -36
  111. package/src/ld/documentLoader.ts +1 -1
  112. package/src/ld/getLinkedDataAttributeType.ts +1 -1
  113. package/src/ld/getLinkedDataContext.ts +1 -1
  114. package/src/{helpers/JsonSchema.ts → types.d.ts} +12 -16
  115. package/dist/helpers/JsonSchema.d.ts +0 -99
  116. package/dist/helpers/JsonSchema.d.ts.map +0 -1
  117. package/dist/helpers/JsonSchema.js +0 -3
  118. package/dist/helpers/JsonSchema.js.map +0 -1
package/src/Validator.ts CHANGED
@@ -1,5 +1,5 @@
1
- import ZSchema from 'z-schema';
2
1
  import { keyBy, groupBy } from 'lodash';
2
+ import ZSchema, { type JsonSchema, ValidateError } from 'z-schema';
3
3
 
4
4
  import got from './helpers/got';
5
5
  import Schema from './Schema';
@@ -9,248 +9,14 @@ import ValidationError from './ValidationError';
9
9
  import cleanupAttributes from './helpers/cleanupAttributes';
10
10
  import nullifyEmptyValues from './helpers/nullifyEmptyValues';
11
11
  import normalizeAttributes from './helpers/normalizeAttributes';
12
- import type { TargetObject, JsonSchemasMap } from './helpers/JsonSchema';
13
-
14
- /**
15
- * Validator for validating and normalizing objects against JSON schemas.
16
- *
17
- * **Intent:**
18
- * The Validator class provides a comprehensive solution for validating objects against JSON schemas
19
- * with built-in normalization, cleanup, and error handling capabilities. It serves as the primary
20
- * interface for ensuring data integrity and consistency in applications that work with structured
21
- * data, particularly in API endpoints, data transformation pipelines, and credential systems.
22
- *
23
- * The validator performs several key operations:
24
- * - Validates objects against registered schemas using JSON Schema validation
25
- * - Removes attributes not defined in the schema (cleanup)
26
- * - Normalizes attribute types (e.g., string '1' → boolean true, string '180' → number 180)
27
- * - Handles empty values by optionally nullifying them for non-required fields
28
- * - Provides detailed validation errors with structured error information
29
- *
30
- * **Use Cases:**
31
- *
32
- * 1. **API Request/Response Validation:**
33
- * - Validate incoming API requests against defined schemas
34
- * - Ensure API responses conform to expected structure
35
- * - Clean up extra fields sent by clients
36
- * - Normalize data from query parameters or form submissions
37
- *
38
- * 2. **Data Integration & Third-Party Services:**
39
- * - Integrate with external APIs that send loosely-typed data
40
- * - Normalize data from URLs where types are strings (e.g., 'true', '1', '180')
41
- * - Clean up payloads before sending to third-party services (e.g., Telegram, webhooks)
42
- * - Handle data from systems that don't enforce strict typing
43
- *
44
- * 3. **Credential & Identity Systems:**
45
- * - Validate verifiable credentials against schema definitions
46
- * - Ensure credential subjects conform to expected schemas
47
- * - Normalize credential data from various sources
48
- *
49
- * 4. **Data Transformation Pipelines:**
50
- * - Normalize data types without full validation
51
- * - Clean up data structures before processing
52
- * - Transform data between different formats while maintaining schema compliance
53
- *
54
- * 5. **Form & User Input Processing:**
55
- * - Validate and normalize form submissions
56
- * - Handle empty values gracefully (nullify empty strings for optional fields)
57
- * - Clean up null values from nested objects
58
- *
59
- * **Example - Basic Validation:**
60
- * ```typescript
61
- * const userSchema = new Schema({
62
- * name: { type: 'string', required: true },
63
- * email: { type: 'string', format: 'email', required: true },
64
- * age: { type: 'number', minimum: 0 }
65
- * }, 'User');
66
- *
67
- * const validator = new Validator([userSchema]);
68
- *
69
- * const validUser = validator.validate({
70
- * name: 'John Doe',
71
- * email: 'john@example.com',
72
- * age: 30
73
- * }, 'User');
74
- * // Returns: { name: 'John Doe', email: 'john@example.com', age: 30 }
75
- * ```
76
- *
77
- * **Example - Normalization (String to Type Conversion):**
78
- * ```typescript
79
- * // Useful when receiving data from URLs or forms where types are strings
80
- * const preferencesSchema = new Schema({
81
- * height: { type: 'number' },
82
- * isNotificationEnabled: { type: 'boolean' }
83
- * }, 'Preferences');
84
- *
85
- * const validator = new Validator([preferencesSchema]);
86
- *
87
- * const normalized = validator.validate({
88
- * height: '180', // String '180' → number 180
89
- * isNotificationEnabled: '1' // String '1' → boolean true
90
- * }, 'Preferences');
91
- * // Returns: { height: 180, isNotificationEnabled: true }
92
- * ```
93
- *
94
- * **Example - Cleanup (Remove Extra Attributes):**
95
- * ```typescript
96
- * const profileSchema = new Schema({
97
- * name: { type: 'string', required: true },
98
- * email: { type: 'string', required: true }
99
- * }, 'Profile');
100
- *
101
- * const validator = new Validator([profileSchema]);
102
- *
103
- * const cleaned = validator.validate({
104
- * name: 'John',
105
- * email: 'john@example.com',
106
- * extraField: 'should be removed',
107
- * _internalId: 'should be removed'
108
- * }, 'Profile', false, true);
109
- * // Returns: { name: 'John', email: 'john@example.com' }
110
- * // extraField and _internalId are removed
111
- * ```
112
- *
113
- * **Example - Nullify Empty Values:**
114
- * ```typescript
115
- * const profileSchema = new Schema({
116
- * name: { type: 'string', required: true },
117
- * gender: { enum: ['Male', 'Female', 'Other'] }, // Optional
118
- * mobileNumber: { type: 'string', pattern: '^\\d+$' } // Optional
119
- * }, 'Profile');
120
- *
121
- * const validator = new Validator([profileSchema]);
122
- *
123
- * const result = validator.validate({
124
- * name: 'John',
125
- * gender: '', // Empty string for optional enum
126
- * mobileNumber: '' // Empty string for optional pattern field
127
- * }, 'Profile', true); // shouldNullifyEmptyValues = true
128
- * // Returns: { name: 'John', gender: null, mobileNumber: null }
129
- * // Empty values are converted to null for non-required fields
130
- * ```
131
- *
132
- * **Example - Normalization Only (Without Validation):**
133
- * ```typescript
134
- * const preferencesSchema = new Schema({
135
- * height: { type: 'number' },
136
- * isNotificationEnabled: { type: 'boolean', default: false }
137
- * }, 'Preferences');
138
- *
139
- * const validator = new Validator([preferencesSchema]);
140
- *
141
- * // Normalize without validation - useful for partial data
142
- * const normalized = validator.normalize({
143
- * height: '180'
144
- * }, 'Preferences');
145
- * // Returns: { height: 180, isNotificationEnabled: false }
146
- * // Applies normalization and defaults without validation
147
- * ```
148
- *
149
- * **Example - Error Handling:**
150
- * ```typescript
151
- * const validator = new Validator([userSchema]);
152
- *
153
- * try {
154
- * validator.validate({
155
- * name: '', // Empty required field
156
- * email: 'invalid-email' // Invalid format
157
- * }, 'User');
158
- * } catch (error) {
159
- * if (error instanceof ValidationError) {
160
- * const errorDetails = error.toJSON();
161
- * console.error(errorDetails.schemaId); // 'User'
162
- * console.error(errorDetails.validationErrors);
163
- * // [
164
- * // { path: '#/name', code: 'MIN_LENGTH', message: '...' },
165
- * // { path: '#/email', code: 'INVALID_FORMAT', message: '...' }
166
- * // ]
167
- * }
168
- * }
169
- * ```
170
- *
171
- * **Example - Schema References:**
172
- * ```typescript
173
- * const addressSchema = new Schema({
174
- * street: { type: 'string', required: true },
175
- * city: { type: 'string', required: true }
176
- * }, 'Address');
177
- *
178
- * const userSchema = new Schema({
179
- * name: { type: 'string', required: true },
180
- * address: { $ref: 'Address' }
181
- * }, 'User');
182
- *
183
- * const validator = new Validator([addressSchema, userSchema]);
184
- *
185
- * // Get all schemas referenced by User schema
186
- * const referencedIds = validator.getReferenceIds('User');
187
- * // Returns: ['Address']
188
- * ```
189
- *
190
- * **Example - Multiple Schemas:**
191
- * ```typescript
192
- * const statusSchema = new Schema({ enum: ['ACTIVE', 'INACTIVE'] }, 'Status');
193
- * const profileSchema = new Schema({
194
- * name: { type: 'string', required: true },
195
- * status: { $ref: 'Status' }
196
- * }, 'Profile');
197
- *
198
- * const validator = new Validator([statusSchema, profileSchema]);
199
- *
200
- * const result = validator.validate({
201
- * name: 'John',
202
- * status: 'ACTIVE'
203
- * }, 'Profile');
204
- * ```
205
- */
12
+
13
+ /** Validator for validating and normalizing objects against JSON schemas. */
206
14
  class Validator {
207
15
  private _engine: ZSchema;
208
16
  private _schemasMap: Record<string, Schema>;
209
- private _jsonSchemasMap: JsonSchemasMap;
210
-
211
- /**
212
- * Creates a validator instance for a collection of schemas.
213
- *
214
- * **Intent:** Initialize a validator with a set of schemas that can be used for validation
215
- * and normalization. The constructor validates that all schemas are valid JSON schemas and
216
- * that there are no duplicate schema IDs.
217
- *
218
- * **Use Cases:**
219
- * - Initialize a validator with all schemas needed for an application
220
- * - Set up a validator for a specific domain or module
221
- * - Create validators for different environments (dev, staging, production)
222
- *
223
- * @param schemas - Array of Schema instances to register with this validator.
224
- * All schemas must have unique IDs and valid JSON Schema structure.
225
- * Referenced schemas (via $ref) must be included in this array.
226
- *
227
- * @throws Error if no schemas are provided
228
- * @throws Error if multiple schemas have the same ID
229
- * @throws Error if any schema has invalid JSON Schema structure or missing references
230
- *
231
- * **Example:**
232
- * ```typescript
233
- * const userSchema = new Schema({ name: { type: 'string' } }, 'User');
234
- * const statusSchema = new Schema({ enum: ['ACTIVE', 'INACTIVE'] }, 'Status');
235
- *
236
- * const validator = new Validator([userSchema, statusSchema]);
237
- * ```
238
- *
239
- * **Example - With Schema References:**
240
- * ```typescript
241
- * const addressSchema = new Schema({
242
- * street: { type: 'string' }
243
- * }, 'Address');
244
- *
245
- * const userSchema = new Schema({
246
- * name: { type: 'string' },
247
- * address: { $ref: 'Address' } // References Address schema
248
- * }, 'User');
249
- *
250
- * // Both schemas must be provided
251
- * const validator = new Validator([addressSchema, userSchema]);
252
- * ```
253
- */
17
+ private _jsonSchemasMap: Record<string, JsonSchema>;
18
+
19
+ /** Creates a validator instance for a collection of schemas. */
254
20
  constructor(schemas: Schema[] | undefined) {
255
21
  if (!schemas) {
256
22
  throw new Error('No schemas provided');
@@ -267,18 +33,18 @@ class Validator {
267
33
  }
268
34
  }
269
35
 
270
- this._engine = new ZSchema({
36
+ this._engine = ZSchema.create({
271
37
  reportPathAsArray: false,
272
38
  ignoreUnknownFormats: true,
273
39
  });
274
40
 
275
41
  const jsonSchemas = schemas.map(({ jsonSchema }) => jsonSchema);
276
- const isValid = this._engine.validateSchema(jsonSchemas);
277
-
278
- if (!isValid) {
279
- const { errors } = this._engine.lastReport!;
280
- const errorsJson = JSON.stringify(errors, null, 2);
281
42
 
43
+ try {
44
+ this._engine.validateSchema(jsonSchemas as JsonSchema);
45
+ } catch (error) {
46
+ const details = error instanceof ValidateError && error.details ? error.details : [];
47
+ const errorsJson = JSON.stringify(details, null, 2);
282
48
  throw new Error(`Schemas validation failed, errors: ${errorsJson}`);
283
49
  }
284
50
 
@@ -286,94 +52,7 @@ class Validator {
286
52
  this._jsonSchemasMap = keyBy(jsonSchemas, 'id');
287
53
  }
288
54
 
289
- /**
290
- * Validates, cleans, and normalizes an object against a registered schema.
291
- *
292
- * **Intent:** Perform comprehensive validation and transformation of objects to ensure they
293
- * conform to schema definitions. This method combines validation, attribute cleanup, type
294
- * normalization, and optional empty value handling in a single operation.
295
- *
296
- * **Use Cases:**
297
- * - Validate API request payloads before processing
298
- * - Clean up objects by removing undefined attributes
299
- * - Normalize data types from loosely-typed sources (URLs, forms, external APIs)
300
- * - Handle empty values gracefully for optional fields
301
- * - Prepare data for storage or transmission
302
- *
303
- * **Processing Pipeline:**
304
- * 1. Deep clones the input object
305
- * 2. Optionally removes null values (if `shouldCleanupNulls` is true)
306
- * 3. Removes attributes not defined in the schema
307
- * 4. Normalizes attribute types (string → number/boolean, etc.)
308
- * 5. Validates against JSON Schema
309
- * 6. Optionally nullifies empty values for non-required fields
310
- * 7. Returns validated and normalized object, or throws ValidationError
311
- *
312
- * @param object - The object to validate and normalize
313
- * @param schemaId - The ID of the schema to validate against (must be registered in constructor)
314
- * @param shouldNullifyEmptyValues - If true, converts empty strings to null for non-required
315
- * fields that fail format/pattern/enum validation. Useful for
316
- * handling form submissions where empty fields are sent as ''.
317
- * @param shouldCleanupNulls - If true, removes null values from the object before processing.
318
- * Useful for cleaning up data structures.
319
- *
320
- * @returns The validated, cleaned, and normalized object
321
- *
322
- * @throws Error if schema with `schemaId` is not found
323
- * @throws ValidationError if validation fails (contains detailed error information)
324
- *
325
- * **Example - Basic Validation:**
326
- * ```typescript
327
- * const validator = new Validator([userSchema]);
328
- *
329
- * const result = validator.validate({
330
- * name: 'John',
331
- * email: 'john@example.com'
332
- * }, 'User');
333
- * ```
334
- *
335
- * **Example - With Cleanup:**
336
- * ```typescript
337
- * const result = validator.validate({
338
- * name: 'John',
339
- * extraField: 'removed',
340
- * nullField: null
341
- * }, 'User', false, true);
342
- * // extraField and nullField are removed
343
- * ```
344
- *
345
- * **Example - With Normalization:**
346
- * ```typescript
347
- * const result = validator.validate({
348
- * name: 'John',
349
- * age: '30', // String → number
350
- * isActive: 'true' // String → boolean
351
- * }, 'User');
352
- * // age becomes 30, isActive becomes true
353
- * ```
354
- *
355
- * **Example - Nullify Empty Values:**
356
- * ```typescript
357
- * const result = validator.validate({
358
- * name: 'John',
359
- * optionalEmail: '', // Empty string
360
- * optionalPhone: '' // Empty string
361
- * }, 'User', true);
362
- * // optionalEmail and optionalPhone become null (if not required)
363
- * ```
364
- *
365
- * **Example - Error Handling:**
366
- * ```typescript
367
- * try {
368
- * validator.validate({ name: '' }, 'User');
369
- * } catch (error) {
370
- * if (error instanceof ValidationError) {
371
- * const details = error.toJSON();
372
- * // Access error.schemaId, error.validationErrors, etc.
373
- * }
374
- * }
375
- * ```
376
- */
55
+ /** Validates, cleans, and normalizes an object against a registered schema. */
377
56
  validate(
378
57
  object: TargetObject,
379
58
  schemaId: string,
@@ -411,13 +90,13 @@ class Validator {
411
90
 
412
91
  }
413
92
 
414
- const isValid = this._engine.validate(result, jsonSchema);
93
+ const validationResult = this._engine.validateSafe(result, jsonSchema as JsonSchema);
415
94
 
416
- if (isValid) {
95
+ if (validationResult.valid) {
417
96
  return result;
418
97
  }
419
98
 
420
- const validationErrors = this._engine.getLastErrors();
99
+ const validationErrors = validationResult.err?.details ?? [];
421
100
 
422
101
  if (!shouldNullifyEmptyValues) {
423
102
  throw new ValidationError(schemaId, result, validationErrors);
@@ -434,76 +113,7 @@ class Validator {
434
113
  return nullifiedResult;
435
114
  }
436
115
 
437
- /**
438
- * Normalizes object attributes using a schema without performing validation.
439
- *
440
- * **Intent:** Apply type normalization and default values to an object without the strictness
441
- * of full validation. This is useful when you want to transform data types but don't need
442
- * complete schema compliance, or when working with partial/incomplete data.
443
- *
444
- * **Use Cases:**
445
- * - Normalize data types from loosely-typed sources (URLs, query parameters, forms)
446
- * - Apply default values from schemas to partial objects
447
- * - Transform data before validation in a separate step
448
- * - Prepare data for display or processing without strict validation
449
- * - Handle partial updates where not all fields are present
450
- *
451
- * **What It Does:**
452
- * - Deep clones the input object
453
- * - Normalizes attribute types (string '1' → boolean true, string '180' → number 180)
454
- * - Applies default values from schema definitions
455
- * - Does NOT validate required fields, formats, patterns, or enums
456
- * - Does NOT remove undefined attributes
457
- *
458
- * @param object - The object to normalize
459
- * @param schemaId - The ID of the schema to use for normalization (must be registered)
460
- *
461
- * @returns A new object with normalized types and applied defaults
462
- *
463
- * @throws Error if schema with `schemaId` is not found
464
- *
465
- * **Example - Type Normalization:**
466
- * ```typescript
467
- * const preferencesSchema = new Schema({
468
- * height: { type: 'number' },
469
- * isNotificationEnabled: { type: 'boolean', default: false }
470
- * }, 'Preferences');
471
- *
472
- * const validator = new Validator([preferencesSchema]);
473
- *
474
- * const normalized = validator.normalize({
475
- * height: '180', // String → number
476
- * isNotificationEnabled: '1' // String '1' → boolean true
477
- * }, 'Preferences');
478
- * // Returns: { height: 180, isNotificationEnabled: true }
479
- * ```
480
- *
481
- * **Example - Apply Defaults:**
482
- * ```typescript
483
- * const userSchema = new Schema({
484
- * name: { type: 'string', required: true },
485
- * status: { enum: ['ACTIVE', 'INACTIVE'], default: 'ACTIVE' },
486
- * role: { enum: ['USER', 'ADMIN'], default: 'USER' }
487
- * }, 'User');
488
- *
489
- * const validator = new Validator([userSchema]);
490
- *
491
- * const normalized = validator.normalize({
492
- * name: 'John'
493
- * // status and role are not provided
494
- * }, 'User');
495
- * // Returns: { name: 'John', status: 'ACTIVE', role: 'USER' }
496
- * ```
497
- *
498
- * **Example - Partial Data:**
499
- * ```typescript
500
- * // Useful for partial updates where validation might fail
501
- * const partial = validator.normalize({
502
- * age: '25' // Only updating age, other fields missing
503
- * }, 'User');
504
- * // Normalizes age to number without requiring other fields
505
- * ```
506
- */
116
+ /** Normalizes object attributes using a schema without performing validation. */
507
117
  normalize(object: TargetObject, schemaId: string) {
508
118
  const jsonSchema = got(this._jsonSchemasMap, schemaId, 'Schema "$PATH" not found');
509
119
  const result = JSON.parse(JSON.stringify(object));
@@ -513,86 +123,12 @@ class Validator {
513
123
  return result;
514
124
  }
515
125
 
516
- /**
517
- * Returns a map of all registered schemas by their IDs.
518
- *
519
- * **Intent:** Provide access to all schemas registered with this validator, enabling
520
- * inspection, iteration, or programmatic access to schema definitions.
521
- *
522
- * **Use Cases:**
523
- * - Inspect all available schemas
524
- * - Iterate over schemas for bulk operations
525
- * - Access schema metadata or properties
526
- * - Build UI components that list available schemas
527
- * - Debug schema registration
528
- *
529
- * @returns A record mapping schema IDs to Schema instances
530
- *
531
- * **Example:**
532
- * ```typescript
533
- * const validator = new Validator([userSchema, statusSchema]);
534
- *
535
- * const schemas = validator.schemasMap;
536
- * // { 'User': Schema instance, 'Status': Schema instance }
537
- *
538
- * // Access a specific schema
539
- * const userSchema = schemas['User'];
540
- *
541
- * // Iterate over all schemas
542
- * Object.keys(schemas).forEach(id => {
543
- * console.log(`Schema ${id} is registered`);
544
- * });
545
- * ```
546
- */
126
+ /** Returns a map of all registered schemas by their IDs. */
547
127
  get schemasMap() {
548
128
  return this._schemasMap;
549
129
  }
550
130
 
551
- /**
552
- * Returns the IDs of all schemas referenced by the specified schema.
553
- *
554
- * **Intent:** Discover schema dependencies by finding all schemas referenced via `$ref`
555
- * in a given schema. This is useful for understanding schema relationships and building
556
- * dependency graphs.
557
- *
558
- * **Use Cases:**
559
- * - Build schema dependency graphs
560
- * - Validate that all referenced schemas are available
561
- * - Generate documentation showing schema relationships
562
- * - Determine which schemas need to be loaded together
563
- * - Debug schema reference issues
564
- *
565
- * @param schemaId - The ID of the schema to analyze for references
566
- *
567
- * @returns An array of schema IDs that are referenced by the specified schema
568
- *
569
- * @throws Error if schema with `schemaId` is not found
570
- *
571
- * **Example:**
572
- * ```typescript
573
- * const addressSchema = new Schema({
574
- * street: { type: 'string' }
575
- * }, 'Address');
576
- *
577
- * const userSchema = new Schema({
578
- * name: { type: 'string' },
579
- * address: { $ref: 'Address' },
580
- * status: { $ref: 'Status' }
581
- * }, 'User');
582
- *
583
- * const validator = new Validator([addressSchema, statusSchema, userSchema]);
584
- *
585
- * const references = validator.getReferenceIds('User');
586
- * // Returns: ['Address', 'Status']
587
- * ```
588
- *
589
- * **Example - Nested References:**
590
- * ```typescript
591
- * // If Address schema also references Country schema
592
- * const references = validator.getReferenceIds('User');
593
- * // Returns: ['Address', 'Status', 'Country'] (includes nested references)
594
- * ```
595
- */
131
+ /** Returns the IDs of all schemas referenced by the specified schema. */
596
132
  getReferenceIds(schemaId: string) {
597
133
  const schema = got(this.schemasMap, schemaId, 'Schema "$PATH" not found');
598
134
 
@@ -281,7 +281,7 @@ describe('CredentialFactory', () => {
281
281
  bestRoundTime: 10000
282
282
  };
283
283
 
284
- const credential = await createMineSweeperScoreCredential(
284
+ const credential = createMineSweeperScoreCredential(
285
285
  'did:GAME_ID',
286
286
  'did:PLAYER_ID',
287
287
  playerScore
@@ -1,14 +1,9 @@
1
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
+ /// <reference path="../types.d.ts" />
3
+
1
4
  import { load } from 'js-yaml';
2
5
  import { readFileSync } from 'fs';
3
6
  import { Schema } from '../../src';
4
- import type {
5
- PropertiesSchema,
6
- EnumSchema,
7
- StringPropertySchema,
8
- ArrayPropertySchema,
9
- ObjectPropertySchema,
10
- ObjectSchema
11
- } from '../../src/helpers/JsonSchema';
12
7
 
13
8
  // eslint-disable-next-line jsdoc/require-jsdoc
14
9
  const loadSync = (yamlPath: string): Schema => {
@@ -1,6 +1,8 @@
1
- import ValidationError from '../ValidationError';
1
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
+ /// <reference path="../types.d.ts" />
3
+
2
4
  import type { SchemaErrorDetail } from 'z-schema';
3
- import type { TargetObject } from '../helpers/JsonSchema';
5
+ import ValidationError from '../ValidationError';
4
6
 
5
7
  describe('ValidationError', () => {
6
8
  // eslint-disable-next-line jsdoc/require-jsdoc
@@ -1,10 +1,9 @@
1
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
+ /// <reference path="../types.d.ts" />
3
+
1
4
  import { load } from 'js-yaml';
2
5
  import { readFileSync } from 'fs';
3
6
  import { Schema, Validator, ValidationError } from '../../src';
4
- import type {
5
- PropertiesSchema,
6
- EnumSchema
7
- } from '../../src/helpers/JsonSchema';
8
7
 
9
8
  // eslint-disable-next-line jsdoc/require-jsdoc
10
9
  const loadSync = (yamlPath: string): Schema => {
@@ -387,6 +386,24 @@ describe('Validator', () => {
387
386
  .toThrow('"Profile" validation failed');
388
387
  });
389
388
 
389
+ it('handles validation error without details (falls back to empty array)', () => {
390
+ const validator = new Validator(SCHEMAS);
391
+ const validateSafeSpy = jest.spyOn(
392
+ (validator as { _engine: { validateSafe: (a: unknown, b: unknown) => { valid: boolean; err?: { details?: unknown[] } } } })._engine,
393
+ 'validateSafe'
394
+ ).mockReturnValueOnce({ valid: false, err: {} } as { valid: boolean; err?: { details?: unknown[] } });
395
+
396
+ try {
397
+ validator.validate({ name: 'Test' }, 'Profile', false);
398
+ throw new Error('Expected ValidationError');
399
+ } catch (error) {
400
+ expect(error).toBeInstanceOf(ValidationError);
401
+ expect((error as ValidationError).toJSON().validationErrors).toEqual([]);
402
+ }
403
+
404
+ validateSafeSpy.mockRestore();
405
+ });
406
+
390
407
  it('still throws validation errors for invalid values even when nullifying empty values', () => {
391
408
  const validator = new Validator(SCHEMAS);
392
409
 
@@ -1,5 +1,7 @@
1
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
+ /// <reference path="../../types.d.ts" />
3
+
1
4
  import cleanupAttributes from '../cleanupAttributes';
2
- import type { ObjectSchema } from '../JsonSchema';
3
5
 
4
6
  describe('cleanupAttributes(object, jsonSchema, schemasMap)', () => {
5
7
  describe('enum schema', () => {
@@ -1,6 +1,6 @@
1
1
  import path from 'path';
2
- import createSchemasMap from '../createSchemasMap';
3
2
  import Schema from '../../Schema';
3
+ import createSchemasMap from '../createSchemasMap';
4
4
 
5
5
  describe('createSchemasMap', () => {
6
6
  const examplesSchemasPath = path.join(__dirname, '../../../examples/schemas');
@@ -1,6 +1,7 @@
1
+ import { type JsonSchema } from 'z-schema';
2
+
1
3
  import Schema from '../../Schema';
2
4
  import mapObjectProperties from '../mapObjectProperties';
3
- import type { JsonSchema } from '../JsonSchema';
4
5
 
5
6
  describe('mapObjectProperties(object, jsonSchema, schemasMap, callback)', () => {
6
7
  describe('enum schema', () => {
@@ -1,6 +1,8 @@
1
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
+ /// <reference path="../../types.d.ts" />
3
+
1
4
  import Schema from '../../Schema';
2
5
  import normalizeAttributes from '../normalizeAttributes';
3
- import type { TargetObject } from '../JsonSchema';
4
6
 
5
7
  describe('normalizeAttributes(object, jsonSchema, schemasMap)', () => {
6
8
  describe('default values', () => {
@@ -76,7 +78,7 @@ describe('normalizeAttributes(object, jsonSchema, schemasMap)', () => {
76
78
  it('should normalize default string to number when type is number', () => {
77
79
  const schema = new Schema(
78
80
  {
79
-
81
+
80
82
  count: { type: 'number', default: '42' // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
83
  } as any
82
84
  },