@kravc/schema 2.7.5 → 2.8.0-alpha.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 (170) hide show
  1. package/README.md +19 -14
  2. package/dist/CredentialFactory.d.ts +345 -0
  3. package/dist/CredentialFactory.d.ts.map +1 -0
  4. package/dist/CredentialFactory.js +381 -0
  5. package/dist/CredentialFactory.js.map +1 -0
  6. package/dist/Schema.d.ts +448 -0
  7. package/dist/Schema.d.ts.map +1 -0
  8. package/dist/Schema.js +506 -0
  9. package/dist/Schema.js.map +1 -0
  10. package/dist/ValidationError.d.ts +70 -0
  11. package/dist/ValidationError.d.ts.map +1 -0
  12. package/dist/ValidationError.js +78 -0
  13. package/dist/ValidationError.js.map +1 -0
  14. package/dist/Validator.d.ts +483 -0
  15. package/dist/Validator.d.ts.map +1 -0
  16. package/dist/Validator.js +570 -0
  17. package/dist/Validator.js.map +1 -0
  18. package/dist/helpers/JsonSchema.d.ts +99 -0
  19. package/dist/helpers/JsonSchema.d.ts.map +1 -0
  20. package/dist/helpers/JsonSchema.js +3 -0
  21. package/dist/helpers/JsonSchema.js.map +1 -0
  22. package/dist/helpers/cleanupAttributes.d.ts +34 -0
  23. package/dist/helpers/cleanupAttributes.d.ts.map +1 -0
  24. package/dist/helpers/cleanupAttributes.js +113 -0
  25. package/dist/helpers/cleanupAttributes.js.map +1 -0
  26. package/dist/helpers/cleanupNulls.d.ts +27 -0
  27. package/dist/helpers/cleanupNulls.d.ts.map +1 -0
  28. package/dist/helpers/cleanupNulls.js +96 -0
  29. package/dist/helpers/cleanupNulls.js.map +1 -0
  30. package/dist/helpers/getReferenceIds.d.ts +169 -0
  31. package/dist/helpers/getReferenceIds.d.ts.map +1 -0
  32. package/dist/helpers/getReferenceIds.js +241 -0
  33. package/dist/helpers/getReferenceIds.js.map +1 -0
  34. package/dist/helpers/got.d.ts +60 -0
  35. package/dist/helpers/got.d.ts.map +1 -0
  36. package/dist/helpers/got.js +72 -0
  37. package/dist/helpers/got.js.map +1 -0
  38. package/dist/helpers/mapObjectProperties.d.ts +150 -0
  39. package/dist/helpers/mapObjectProperties.d.ts.map +1 -0
  40. package/dist/helpers/mapObjectProperties.js +229 -0
  41. package/dist/helpers/mapObjectProperties.js.map +1 -0
  42. package/dist/helpers/normalizeAttributes.d.ts +213 -0
  43. package/dist/helpers/normalizeAttributes.d.ts.map +1 -0
  44. package/dist/helpers/normalizeAttributes.js +243 -0
  45. package/dist/helpers/normalizeAttributes.js.map +1 -0
  46. package/dist/helpers/normalizeProperties.d.ts +168 -0
  47. package/dist/helpers/normalizeProperties.d.ts.map +1 -0
  48. package/dist/helpers/normalizeProperties.js +223 -0
  49. package/dist/helpers/normalizeProperties.js.map +1 -0
  50. package/dist/helpers/normalizeRequired.d.ts +159 -0
  51. package/dist/helpers/normalizeRequired.d.ts.map +1 -0
  52. package/dist/helpers/normalizeRequired.js +206 -0
  53. package/dist/helpers/normalizeRequired.js.map +1 -0
  54. package/dist/helpers/normalizeType.d.ts +81 -0
  55. package/dist/helpers/normalizeType.d.ts.map +1 -0
  56. package/dist/helpers/normalizeType.js +210 -0
  57. package/dist/helpers/normalizeType.js.map +1 -0
  58. package/dist/helpers/nullifyEmptyValues.d.ts +139 -0
  59. package/dist/helpers/nullifyEmptyValues.d.ts.map +1 -0
  60. package/dist/helpers/nullifyEmptyValues.js +191 -0
  61. package/dist/helpers/nullifyEmptyValues.js.map +1 -0
  62. package/dist/helpers/removeRequiredAndDefault.d.ts +106 -0
  63. package/dist/helpers/removeRequiredAndDefault.d.ts.map +1 -0
  64. package/dist/helpers/removeRequiredAndDefault.js +138 -0
  65. package/dist/helpers/removeRequiredAndDefault.js.map +1 -0
  66. package/dist/helpers/validateId.d.ts +39 -0
  67. package/dist/helpers/validateId.d.ts.map +1 -0
  68. package/dist/helpers/validateId.js +51 -0
  69. package/dist/helpers/validateId.js.map +1 -0
  70. package/dist/index.d.ts +7 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +17 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/ld/documentLoader.d.ts +8 -0
  75. package/dist/ld/documentLoader.d.ts.map +1 -0
  76. package/dist/ld/documentLoader.js +24 -0
  77. package/dist/ld/documentLoader.js.map +1 -0
  78. package/dist/ld/getLinkedDataAttributeType.d.ts +10 -0
  79. package/dist/ld/getLinkedDataAttributeType.d.ts.map +1 -0
  80. package/dist/ld/getLinkedDataAttributeType.js +32 -0
  81. package/dist/ld/getLinkedDataAttributeType.js.map +1 -0
  82. package/dist/ld/getLinkedDataContext.d.ts +19 -0
  83. package/dist/ld/getLinkedDataContext.d.ts.map +1 -0
  84. package/dist/ld/getLinkedDataContext.js +50 -0
  85. package/dist/ld/getLinkedDataContext.js.map +1 -0
  86. package/eslint.config.mjs +32 -52
  87. package/examples/credentials/createAccountCredential.ts +27 -0
  88. package/examples/credentials/createMineSweeperScoreCredential.ts +115 -0
  89. package/examples/index.ts +7 -0
  90. package/examples/schemas/FavoriteItemSchema.ts +27 -0
  91. package/examples/{Preferences.yaml → schemas/Preferences.yaml} +2 -0
  92. package/examples/schemas/PreferencesSchema.ts +29 -0
  93. package/examples/schemas/ProfileSchema.ts +91 -0
  94. package/examples/schemas/Status.yaml +3 -0
  95. package/examples/schemas/StatusSchema.ts +12 -0
  96. package/jest.config.mjs +5 -0
  97. package/package.json +28 -21
  98. package/src/CredentialFactory.ts +392 -0
  99. package/src/Schema.ts +583 -0
  100. package/src/ValidationError.ts +90 -0
  101. package/src/Validator.ts +603 -0
  102. package/src/__tests__/CredentialFactory.test.ts +588 -0
  103. package/src/__tests__/Schema.test.ts +371 -0
  104. package/src/__tests__/ValidationError.test.ts +235 -0
  105. package/src/__tests__/Validator.test.ts +787 -0
  106. package/src/helpers/JsonSchema.ts +119 -0
  107. package/src/helpers/__tests__/cleanupAttributes.test.ts +943 -0
  108. package/src/helpers/__tests__/cleanupNulls.test.ts +772 -0
  109. package/src/helpers/__tests__/getReferenceIds.test.ts +975 -0
  110. package/src/helpers/__tests__/got.test.ts +193 -0
  111. package/src/helpers/__tests__/mapObjectProperties.test.ts +1126 -0
  112. package/src/helpers/__tests__/normalizeAttributes.test.ts +1435 -0
  113. package/src/helpers/__tests__/normalizeProperties.test.ts +727 -0
  114. package/src/helpers/__tests__/normalizeRequired.test.ts +669 -0
  115. package/src/helpers/__tests__/normalizeType.test.ts +772 -0
  116. package/src/helpers/__tests__/nullifyEmptyValues.test.ts +735 -0
  117. package/src/helpers/__tests__/removeRequiredAndDefault.test.ts +734 -0
  118. package/src/helpers/__tests__/validateId.test.ts +118 -0
  119. package/src/helpers/cleanupAttributes.ts +151 -0
  120. package/src/helpers/cleanupNulls.ts +106 -0
  121. package/src/helpers/getReferenceIds.ts +273 -0
  122. package/src/helpers/got.ts +73 -0
  123. package/src/helpers/mapObjectProperties.ts +272 -0
  124. package/src/helpers/normalizeAttributes.ts +247 -0
  125. package/src/helpers/normalizeProperties.ts +249 -0
  126. package/src/helpers/normalizeRequired.ts +233 -0
  127. package/src/helpers/normalizeType.ts +235 -0
  128. package/src/helpers/nullifyEmptyValues.ts +207 -0
  129. package/src/helpers/removeRequiredAndDefault.ts +151 -0
  130. package/src/helpers/validateId.ts +53 -0
  131. package/src/index.ts +13 -0
  132. package/src/ld/__tests__/documentLoader.test.ts +57 -0
  133. package/src/ld/__tests__/getLinkedDataAttributeType.test.ts +212 -0
  134. package/src/ld/__tests__/getLinkedDataContext.test.ts +378 -0
  135. package/src/ld/documentLoader.ts +28 -0
  136. package/src/ld/getLinkedDataAttributeType.ts +46 -0
  137. package/src/ld/getLinkedDataContext.ts +80 -0
  138. package/tsconfig.json +27 -0
  139. package/types/credentials-context.d.ts +14 -0
  140. package/types/security-context.d.ts +6 -0
  141. package/examples/Status.yaml +0 -3
  142. package/examples/createAccountCredential.js +0 -27
  143. package/examples/createMineSweeperScoreCredential.js +0 -63
  144. package/examples/index.js +0 -9
  145. package/src/CredentialFactory.js +0 -67
  146. package/src/CredentialFactory.spec.js +0 -131
  147. package/src/Schema.js +0 -104
  148. package/src/Schema.spec.js +0 -172
  149. package/src/ValidationError.js +0 -31
  150. package/src/Validator.js +0 -128
  151. package/src/Validator.spec.js +0 -355
  152. package/src/helpers/cleanupAttributes.js +0 -71
  153. package/src/helpers/cleanupNulls.js +0 -42
  154. package/src/helpers/getReferenceIds.js +0 -71
  155. package/src/helpers/mapObject.js +0 -65
  156. package/src/helpers/normalizeAttributes.js +0 -28
  157. package/src/helpers/normalizeProperties.js +0 -61
  158. package/src/helpers/normalizeRequired.js +0 -37
  159. package/src/helpers/normalizeType.js +0 -41
  160. package/src/helpers/nullifyEmptyValues.js +0 -57
  161. package/src/helpers/removeRequiredAndDefault.js +0 -30
  162. package/src/helpers/validateId.js +0 -19
  163. package/src/index.d.ts +0 -25
  164. package/src/index.js +0 -8
  165. package/src/ld/documentLoader.js +0 -25
  166. package/src/ld/documentLoader.spec.js +0 -12
  167. package/src/ld/getLinkedDataContext.js +0 -63
  168. package/src/ld/getLinkedDataType.js +0 -38
  169. /package/examples/{FavoriteItem.yaml → schemas/FavoriteItem.yaml} +0 -0
  170. /package/examples/{Profile.yaml → schemas/Profile.yaml} +0 -0
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const lodash_1 = require("lodash");
7
+ const normalizeType_1 = __importDefault(require("./normalizeType"));
8
+ const mapObjectProperties_1 = __importDefault(require("./mapObjectProperties"));
9
+ /**
10
+ * Normalizes object attribute values based on a JSON Schema definition.
11
+ *
12
+ * ## Intent
13
+ *
14
+ * This function ensures that object properties conform to their schema definitions by:
15
+ * 1. Setting default values for properties that are undefined (but not null)
16
+ * 2. Normalizing existing values to match their schema-defined types (e.g., converting
17
+ * string "123" to number 123, or string "true" to boolean true)
18
+ *
19
+ * The function operates recursively, processing nested objects, arrays, and referenced
20
+ * schemas ($ref) to ensure all properties throughout the object tree are normalized
21
+ * according to their respective schema definitions.
22
+ *
23
+ * This is particularly useful in data processing pipelines where data may come from
24
+ * external sources (forms, APIs, databases) with inconsistent types, but needs to be
25
+ * normalized before validation or further processing.
26
+ *
27
+ * ## Use Cases
28
+ *
29
+ * 1. **Form data processing**: HTML forms submit all values as strings. This function
30
+ * converts them to their expected types (numbers, booleans) based on schema definitions
31
+ * and fills in default values for missing fields.
32
+ *
33
+ * 2. **API response normalization**: When consuming APIs that return loosely-typed data
34
+ * (e.g., numbers as strings, booleans as strings), this function ensures values match
35
+ * the expected schema types before validation or business logic processing.
36
+ *
37
+ * 3. **Configuration object initialization**: Setting default values and normalizing types
38
+ * for configuration objects based on their schema definitions, ensuring consistent
39
+ * structure and types throughout the application.
40
+ *
41
+ * 4. **Data migration and transformation**: Normalizing data structures during migration
42
+ * or transformation processes where source data may have inconsistent types but target
43
+ * schema requires specific types.
44
+ *
45
+ * 5. **Pre-validation normalization**: Preparing objects for schema validation by ensuring
46
+ * types are correct and defaults are applied, reducing validation errors and improving
47
+ * data quality.
48
+ *
49
+ * ## Behavior
50
+ *
51
+ * - **Default values**: Properties that are `undefined` will be set to their schema-defined
52
+ * default value (if one exists). Properties that are `null` are left as `null` and will
53
+ * not receive default values. Default values are also normalized according to their type
54
+ * (e.g., a default string "123" with type "number" will be converted to the number 123).
55
+ *
56
+ * - **Type normalization**: Properties with existing values (including default values that
57
+ * were just set) are normalized to match their schema type using `normalizeType`. This
58
+ * includes converting strings to numbers/booleans where appropriate, while preserving the
59
+ * original value if conversion is not possible.
60
+ *
61
+ * - **Recursive processing**: The function processes nested objects, arrays, and schema
62
+ * references ($ref) recursively, ensuring all nested properties are normalized.
63
+ *
64
+ * - **Non-destructive**: The function mutates the input object in place. If you need to
65
+ * preserve the original, create a deep copy before calling this function.
66
+ *
67
+ * ## Examples
68
+ *
69
+ * ### Basic Usage: Default Values and Type Normalization
70
+ * ```typescript
71
+ * import Schema from './Schema';
72
+ * import normalizeAttributes from './normalizeAttributes';
73
+ *
74
+ * const schema = new Schema({
75
+ * name: { type: 'string', default: 'Anonymous' },
76
+ * age: { type: 'number' },
77
+ * isActive: { type: 'boolean', default: false }
78
+ * }, 'user-schema');
79
+ *
80
+ * const user = {
81
+ * age: '25' // string that should be a number
82
+ * };
83
+ *
84
+ * normalizeAttributes(user, schema.jsonSchema, {});
85
+ *
86
+ * // Result:
87
+ * // {
88
+ * // name: 'Anonymous', // default value applied
89
+ * // age: 25, // string converted to number
90
+ * // isActive: false // default value applied
91
+ * // }
92
+ * ```
93
+ *
94
+ * ### Nested Objects
95
+ * ```typescript
96
+ * const schema = new Schema({
97
+ * address: {
98
+ * type: 'object',
99
+ * properties: {
100
+ * street: { type: 'string', default: 'Unknown' },
101
+ * zipCode: { type: 'number' }
102
+ * }
103
+ * }
104
+ * }, 'profile-schema');
105
+ *
106
+ * const profile = {
107
+ * address: {
108
+ * zipCode: '12345' // string that should be a number
109
+ * }
110
+ * };
111
+ *
112
+ * normalizeAttributes(profile, schema.jsonSchema, {});
113
+ *
114
+ * // Result:
115
+ * // {
116
+ * // address: {
117
+ * // street: 'Unknown', // default value applied
118
+ * // zipCode: 12345 // string converted to number
119
+ * // }
120
+ * // }
121
+ * ```
122
+ *
123
+ * ### Arrays with Schema References
124
+ * ```typescript
125
+ * const itemSchema = new Schema({
126
+ * id: { type: 'number' },
127
+ * name: { type: 'string', default: 'Unnamed' }
128
+ * }, 'item-schema');
129
+ *
130
+ * const schema = new Schema({
131
+ * items: {
132
+ * type: 'array',
133
+ * items: { $ref: 'item-schema' }
134
+ * }
135
+ * }, 'collection-schema');
136
+ *
137
+ * const collection = {
138
+ * items: [
139
+ * { id: '1' }, // id is a string, should be number
140
+ * { id: '2', name: 'Item 2' }
141
+ * ]
142
+ * };
143
+ *
144
+ * const schemasMap = {
145
+ * 'item-schema': itemSchema.jsonSchema
146
+ * };
147
+ *
148
+ * normalizeAttributes(collection, schema.jsonSchema, schemasMap);
149
+ *
150
+ * // Result:
151
+ * // {
152
+ * // items: [
153
+ * // { id: 1, name: 'Unnamed' }, // id normalized, default name applied
154
+ * // { id: 2, name: 'Item 2' } // id normalized, existing name preserved
155
+ * // ]
156
+ * // }
157
+ * ```
158
+ *
159
+ * ### Boolean Normalization
160
+ * ```typescript
161
+ * const schema = new Schema({
162
+ * enabled: { type: 'boolean', default: false },
163
+ * verified: { type: 'boolean' }
164
+ * }, 'settings-schema');
165
+ *
166
+ * const settings = {
167
+ * verified: 'yes' // string that should be boolean
168
+ * };
169
+ *
170
+ * normalizeAttributes(settings, schema.jsonSchema, {});
171
+ *
172
+ * // Result:
173
+ * // {
174
+ * // enabled: false, // default value applied
175
+ * // verified: true // string "yes" converted to boolean true
176
+ * // }
177
+ * ```
178
+ *
179
+ * ### Handling Null Values
180
+ * ```typescript
181
+ * const schema = new Schema({
182
+ * optionalField: { type: 'string', default: 'default-value' }
183
+ * }, 'test-schema');
184
+ *
185
+ * const obj1 = {}; // undefined → default applied
186
+ * const obj2 = { optionalField: null }; // null → no default applied
187
+ *
188
+ * normalizeAttributes(obj1, schema.jsonSchema, {});
189
+ * normalizeAttributes(obj2, schema.jsonSchema, {});
190
+ *
191
+ * // obj1: { optionalField: 'default-value' }
192
+ * // obj2: { optionalField: null } // null preserved, default not applied
193
+ * ```
194
+ *
195
+ * ### Default Value Normalization
196
+ * ```typescript
197
+ * const schema = new Schema({
198
+ * count: { type: 'number', default: '42' }, // default is string, type is number
199
+ * enabled: { type: 'boolean', default: 'true' } // default is string, type is boolean
200
+ * }, 'config-schema');
201
+ *
202
+ * const config = {};
203
+ *
204
+ * normalizeAttributes(config, schema.jsonSchema, {});
205
+ *
206
+ * // Result:
207
+ * // {
208
+ * // count: 42, // default string "42" normalized to number
209
+ * // enabled: true // default string "true" normalized to boolean
210
+ * // }
211
+ * ```
212
+ *
213
+ * @param object - The target object to normalize (mutated in place)
214
+ * @param jsonSchema - The JSON Schema definition describing the object structure
215
+ * @param jsonSchemasMap - Map of schema IDs to schema definitions, used for resolving $ref references
216
+ * @returns void (mutates the input object)
217
+ */
218
+ const normalizeAttributes = (object, jsonSchema, jsonSchemasMap) => {
219
+ /** Callback to normalize value based on property type defined in schema */
220
+ const callback = (propertyName, propertySchema, object) => {
221
+ let value = object[propertyName];
222
+ const type = (0, lodash_1.get)(propertySchema, 'type');
223
+ const defaultValue = (0, lodash_1.get)(propertySchema, 'default');
224
+ const hasValue = !(0, lodash_1.isUndefined)(value);
225
+ const hasDefaultValue = !(0, lodash_1.isUndefined)(defaultValue);
226
+ const shouldSetDefaultValue = hasDefaultValue && !hasValue;
227
+ // Set default value if property is undefined and default exists
228
+ if (shouldSetDefaultValue) {
229
+ object[propertyName] = defaultValue;
230
+ value = defaultValue; // Update value reference for normalization
231
+ }
232
+ const hasType = !!type;
233
+ const hasValueAfterDefault = !(0, lodash_1.isUndefined)(value);
234
+ const shouldNormalizeValue = hasType && hasValueAfterDefault;
235
+ // Normalize the current value (original or default) if type is defined
236
+ if (shouldNormalizeValue) {
237
+ object[propertyName] = (0, normalizeType_1.default)(type, value);
238
+ }
239
+ };
240
+ (0, mapObjectProperties_1.default)(object, jsonSchema, jsonSchemasMap, callback);
241
+ };
242
+ exports.default = normalizeAttributes;
243
+ //# sourceMappingURL=normalizeAttributes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalizeAttributes.js","sourceRoot":"","sources":["../../src/helpers/normalizeAttributes.ts"],"names":[],"mappings":";;;;;AAAA,mCAA0C;AAE1C,oEAA4C;AAC5C,gFAAwD;AAGxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgNG;AACH,MAAM,mBAAmB,GAAG,CAAC,MAAoB,EAAE,UAAsB,EAAE,cAA8B,EAAE,EAAE;IAC3G,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,CAAC,YAAoB,EAAE,cAA8B,EAAE,MAAoB,EAAE,EAAE;QAC9F,IAAI,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;QAEjC,MAAM,IAAI,GAAG,IAAA,YAAG,EAAC,cAAc,EAAE,MAAM,CAAC,CAAC;QACzC,MAAM,YAAY,GAAG,IAAA,YAAG,EAAC,cAAc,EAAE,SAAS,CAAC,CAAC;QAEpD,MAAM,QAAQ,GAAG,CAAC,IAAA,oBAAW,EAAC,KAAK,CAAC,CAAC;QACrC,MAAM,eAAe,GAAG,CAAC,IAAA,oBAAW,EAAC,YAAY,CAAC,CAAC;QACnD,MAAM,qBAAqB,GAAG,eAAe,IAAI,CAAC,QAAQ,CAAC;QAE3D,gEAAgE;QAChE,IAAI,qBAAqB,EAAE,CAAC;YAC1B,MAAM,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC;YACpC,KAAK,GAAG,YAAY,CAAC,CAAC,2CAA2C;QACnE,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC;QACvB,MAAM,oBAAoB,GAAG,CAAC,IAAA,oBAAW,EAAC,KAAK,CAAC,CAAC;QACjD,MAAM,oBAAoB,GAAG,OAAO,IAAI,oBAAoB,CAAC;QAE7D,uEAAuE;QACvE,IAAI,oBAAoB,EAAE,CAAC;YACzB,MAAM,CAAC,YAAY,CAAC,GAAG,IAAA,uBAAa,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC;IAEF,IAAA,6BAAmB,EAAC,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC;AACpE,CAAC,CAAC;AAEF,kBAAe,mBAAmB,CAAC"}
@@ -0,0 +1,168 @@
1
+ import type { EnumSchema, PropertiesSchema } from './JsonSchema';
2
+ /**
3
+ * Normalizes JSON schema properties by ensuring all properties have an explicit `type` attribute.
4
+ *
5
+ * **Intent:**
6
+ * This function transforms schemas that may have implicit or missing type information into
7
+ * fully normalized schemas with explicit types. It recursively processes nested structures
8
+ * (objects and arrays) to ensure type consistency throughout the schema hierarchy.
9
+ *
10
+ * **Use Cases:**
11
+ * - **Schema Validation Preparation**: Ensures schemas are ready for validation where type
12
+ * information is required by validators or processing tools
13
+ * - **External Schema Normalization**: Normalizes schemas imported from external sources
14
+ * (e.g., OpenAPI specs, YAML schemas) that may omit type information
15
+ * - **Type Inference**: Automatically infers types from structural hints (e.g., presence of
16
+ * `properties` implies `object`, presence of `items` implies `array`)
17
+ * - **Schema Consistency**: Guarantees consistent schema structure before further processing
18
+ * or transformation
19
+ * - **Default Type Assignment**: Provides sensible defaults (e.g., `string` for primitives)
20
+ * when type cannot be inferred
21
+ *
22
+ * **Behavior:**
23
+ * - **Enum Schemas**: Sets `type` to `'string'` if missing (preserves existing type if present)
24
+ * - **Reference Properties**: Skips `$ref` properties (they don't need type normalization)
25
+ * - **Type Inference Priority** (when type is missing):
26
+ * 1. If property has `properties` → sets `type: 'object'`
27
+ * 2. Else if property has `items` → sets `type: 'array'`
28
+ * 3. Else → sets `type: 'string'` (default)
29
+ * - **Object Properties**:
30
+ * - Infers `type: 'object'` from presence of `properties` (if type not already set)
31
+ * - Creates empty `properties: {}` if `type: 'object'` but no properties exist
32
+ * - Recursively normalizes nested object properties
33
+ * - Note: If both `properties` and `items` exist, `properties` takes precedence
34
+ * - **Array Properties**:
35
+ * - Infers `type: 'array'` from presence of `items` (if type not already set)
36
+ * - Sets default `items: { type: 'string' }` if array has no items
37
+ * - Normalizes item schemas: sets `type: 'object'` if items have `properties` (not undefined)
38
+ * - `properties: null` → treated as having properties (sets type to 'object')
39
+ * - `properties: undefined` → treated as not having properties (no type set)
40
+ * - Empty object `{}` → treated as not having properties (no type set)
41
+ * - Recursively normalizes nested properties within array items
42
+ * - **Primitive Properties**: Sets `type: 'string'` as default when no type, items, or properties exist
43
+ * - **Existing Types**: Never overrides existing type values (even if structure suggests different type)
44
+ * - **Edge Cases**:
45
+ * - Empty schemas (`{}`) are handled gracefully
46
+ * - Properties with conflicting structure (e.g., `type: 'object'` with `items`) are normalized
47
+ * according to the explicit type, ignoring conflicting structural hints
48
+ *
49
+ * **Examples:**
50
+ *
51
+ * @example Enum schema normalization
52
+ * ```typescript
53
+ * const schema: EnumSchema = { enum: ['red', 'green', 'blue'] };
54
+ * normalizeProperties(schema);
55
+ * // Result: { enum: ['red', 'green', 'blue'], type: 'string' }
56
+ * ```
57
+ *
58
+ * @example Object type inference
59
+ * ```typescript
60
+ * const schema: PropertiesSchema = {
61
+ * user: {
62
+ * properties: {
63
+ * name: {}
64
+ * }
65
+ * }
66
+ * };
67
+ * normalizeProperties(schema);
68
+ * // Result:
69
+ * // {
70
+ * // user: {
71
+ * // type: 'object',
72
+ * // properties: {
73
+ * // name: { type: 'string' }
74
+ * // }
75
+ * // }
76
+ * // }
77
+ * ```
78
+ *
79
+ * @example Array type inference
80
+ * ```typescript
81
+ * const schema: PropertiesSchema = {
82
+ * tags: {
83
+ * items: { type: 'string' }
84
+ * }
85
+ * };
86
+ * normalizeProperties(schema);
87
+ * // Result:
88
+ * // {
89
+ * // tags: {
90
+ * // type: 'array',
91
+ * // items: { type: 'string' }
92
+ * // }
93
+ * // }
94
+ * ```
95
+ *
96
+ * @example Complex nested structure
97
+ * ```typescript
98
+ * const schema: PropertiesSchema = {
99
+ * profile: {
100
+ * properties: {
101
+ * name: {},
102
+ * addresses: {
103
+ * items: {
104
+ * properties: {
105
+ * street: {},
106
+ * city: {}
107
+ * }
108
+ * }
109
+ * }
110
+ * }
111
+ * }
112
+ * };
113
+ * normalizeProperties(schema);
114
+ * // Result:
115
+ * // {
116
+ * // profile: {
117
+ * // type: 'object',
118
+ * // properties: {
119
+ * // name: { type: 'string' },
120
+ * // addresses: {
121
+ * // type: 'array',
122
+ * // items: {
123
+ * // type: 'object',
124
+ * // properties: {
125
+ * // street: { type: 'string' },
126
+ * // city: { type: 'string' }
127
+ * // }
128
+ * // }
129
+ * // }
130
+ * // }
131
+ * // }
132
+ * // }
133
+ * ```
134
+ *
135
+ * @example Reference properties are skipped
136
+ * ```typescript
137
+ * const schema: PropertiesSchema = {
138
+ * refField: { $ref: '#/definitions/User' },
139
+ * normalField: {}
140
+ * };
141
+ * normalizeProperties(schema);
142
+ * // Result:
143
+ * // {
144
+ * // refField: { $ref: '#/definitions/User' }, // Unchanged
145
+ * // normalField: { type: 'string' }
146
+ * // }
147
+ * ```
148
+ *
149
+ * @example Default type assignment
150
+ * ```typescript
151
+ * const schema: PropertiesSchema = {
152
+ * title: {},
153
+ * count: { type: 'number' }
154
+ * };
155
+ * normalizeProperties(schema);
156
+ * // Result:
157
+ * // {
158
+ * // title: { type: 'string' }, // Default assigned
159
+ * // count: { type: 'number' } // Existing preserved
160
+ * // }
161
+ * ```
162
+ *
163
+ * @param schema - The schema to normalize (either an EnumSchema or PropertiesSchema)
164
+ * @modifies The schema object is mutated in place with normalized types
165
+ */
166
+ declare const normalizeProperties: (schema: EnumSchema | PropertiesSchema) => void;
167
+ export default normalizeProperties;
168
+ //# sourceMappingURL=normalizeProperties.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalizeProperties.d.ts","sourceRoot":"","sources":["../../src/helpers/normalizeProperties.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAIjB,MAAM,cAAc,CAAC;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmKG;AACH,QAAA,MAAM,mBAAmB,GAAI,QAAQ,UAAU,GAAG,gBAAgB,SAwEjE,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const lodash_1 = require("lodash");
4
+ /**
5
+ * Normalizes JSON schema properties by ensuring all properties have an explicit `type` attribute.
6
+ *
7
+ * **Intent:**
8
+ * This function transforms schemas that may have implicit or missing type information into
9
+ * fully normalized schemas with explicit types. It recursively processes nested structures
10
+ * (objects and arrays) to ensure type consistency throughout the schema hierarchy.
11
+ *
12
+ * **Use Cases:**
13
+ * - **Schema Validation Preparation**: Ensures schemas are ready for validation where type
14
+ * information is required by validators or processing tools
15
+ * - **External Schema Normalization**: Normalizes schemas imported from external sources
16
+ * (e.g., OpenAPI specs, YAML schemas) that may omit type information
17
+ * - **Type Inference**: Automatically infers types from structural hints (e.g., presence of
18
+ * `properties` implies `object`, presence of `items` implies `array`)
19
+ * - **Schema Consistency**: Guarantees consistent schema structure before further processing
20
+ * or transformation
21
+ * - **Default Type Assignment**: Provides sensible defaults (e.g., `string` for primitives)
22
+ * when type cannot be inferred
23
+ *
24
+ * **Behavior:**
25
+ * - **Enum Schemas**: Sets `type` to `'string'` if missing (preserves existing type if present)
26
+ * - **Reference Properties**: Skips `$ref` properties (they don't need type normalization)
27
+ * - **Type Inference Priority** (when type is missing):
28
+ * 1. If property has `properties` → sets `type: 'object'`
29
+ * 2. Else if property has `items` → sets `type: 'array'`
30
+ * 3. Else → sets `type: 'string'` (default)
31
+ * - **Object Properties**:
32
+ * - Infers `type: 'object'` from presence of `properties` (if type not already set)
33
+ * - Creates empty `properties: {}` if `type: 'object'` but no properties exist
34
+ * - Recursively normalizes nested object properties
35
+ * - Note: If both `properties` and `items` exist, `properties` takes precedence
36
+ * - **Array Properties**:
37
+ * - Infers `type: 'array'` from presence of `items` (if type not already set)
38
+ * - Sets default `items: { type: 'string' }` if array has no items
39
+ * - Normalizes item schemas: sets `type: 'object'` if items have `properties` (not undefined)
40
+ * - `properties: null` → treated as having properties (sets type to 'object')
41
+ * - `properties: undefined` → treated as not having properties (no type set)
42
+ * - Empty object `{}` → treated as not having properties (no type set)
43
+ * - Recursively normalizes nested properties within array items
44
+ * - **Primitive Properties**: Sets `type: 'string'` as default when no type, items, or properties exist
45
+ * - **Existing Types**: Never overrides existing type values (even if structure suggests different type)
46
+ * - **Edge Cases**:
47
+ * - Empty schemas (`{}`) are handled gracefully
48
+ * - Properties with conflicting structure (e.g., `type: 'object'` with `items`) are normalized
49
+ * according to the explicit type, ignoring conflicting structural hints
50
+ *
51
+ * **Examples:**
52
+ *
53
+ * @example Enum schema normalization
54
+ * ```typescript
55
+ * const schema: EnumSchema = { enum: ['red', 'green', 'blue'] };
56
+ * normalizeProperties(schema);
57
+ * // Result: { enum: ['red', 'green', 'blue'], type: 'string' }
58
+ * ```
59
+ *
60
+ * @example Object type inference
61
+ * ```typescript
62
+ * const schema: PropertiesSchema = {
63
+ * user: {
64
+ * properties: {
65
+ * name: {}
66
+ * }
67
+ * }
68
+ * };
69
+ * normalizeProperties(schema);
70
+ * // Result:
71
+ * // {
72
+ * // user: {
73
+ * // type: 'object',
74
+ * // properties: {
75
+ * // name: { type: 'string' }
76
+ * // }
77
+ * // }
78
+ * // }
79
+ * ```
80
+ *
81
+ * @example Array type inference
82
+ * ```typescript
83
+ * const schema: PropertiesSchema = {
84
+ * tags: {
85
+ * items: { type: 'string' }
86
+ * }
87
+ * };
88
+ * normalizeProperties(schema);
89
+ * // Result:
90
+ * // {
91
+ * // tags: {
92
+ * // type: 'array',
93
+ * // items: { type: 'string' }
94
+ * // }
95
+ * // }
96
+ * ```
97
+ *
98
+ * @example Complex nested structure
99
+ * ```typescript
100
+ * const schema: PropertiesSchema = {
101
+ * profile: {
102
+ * properties: {
103
+ * name: {},
104
+ * addresses: {
105
+ * items: {
106
+ * properties: {
107
+ * street: {},
108
+ * city: {}
109
+ * }
110
+ * }
111
+ * }
112
+ * }
113
+ * }
114
+ * };
115
+ * normalizeProperties(schema);
116
+ * // Result:
117
+ * // {
118
+ * // profile: {
119
+ * // type: 'object',
120
+ * // properties: {
121
+ * // name: { type: 'string' },
122
+ * // addresses: {
123
+ * // type: 'array',
124
+ * // items: {
125
+ * // type: 'object',
126
+ * // properties: {
127
+ * // street: { type: 'string' },
128
+ * // city: { type: 'string' }
129
+ * // }
130
+ * // }
131
+ * // }
132
+ * // }
133
+ * // }
134
+ * // }
135
+ * ```
136
+ *
137
+ * @example Reference properties are skipped
138
+ * ```typescript
139
+ * const schema: PropertiesSchema = {
140
+ * refField: { $ref: '#/definitions/User' },
141
+ * normalField: {}
142
+ * };
143
+ * normalizeProperties(schema);
144
+ * // Result:
145
+ * // {
146
+ * // refField: { $ref: '#/definitions/User' }, // Unchanged
147
+ * // normalField: { type: 'string' }
148
+ * // }
149
+ * ```
150
+ *
151
+ * @example Default type assignment
152
+ * ```typescript
153
+ * const schema: PropertiesSchema = {
154
+ * title: {},
155
+ * count: { type: 'number' }
156
+ * };
157
+ * normalizeProperties(schema);
158
+ * // Result:
159
+ * // {
160
+ * // title: { type: 'string' }, // Default assigned
161
+ * // count: { type: 'number' } // Existing preserved
162
+ * // }
163
+ * ```
164
+ *
165
+ * @param schema - The schema to normalize (either an EnumSchema or PropertiesSchema)
166
+ * @modifies The schema object is mutated in place with normalized types
167
+ */
168
+ const normalizeProperties = (schema) => {
169
+ const { enum: isEnum } = schema;
170
+ if (isEnum) {
171
+ const enumSchema = schema;
172
+ enumSchema.type = enumSchema.type || 'string';
173
+ return;
174
+ }
175
+ const properties = schema;
176
+ for (const name in properties) {
177
+ const property = properties[name];
178
+ const { $ref: isRef } = property;
179
+ if (isRef) {
180
+ continue;
181
+ }
182
+ const hasType = !!(0, lodash_1.get)(property, 'type');
183
+ const hasItems = !!(0, lodash_1.get)(property, 'items');
184
+ const hasProperties = !!(0, lodash_1.get)(property, 'properties');
185
+ if (!hasType) {
186
+ if (hasProperties) {
187
+ (0, lodash_1.set)(property, 'type', 'object');
188
+ }
189
+ else if (hasItems) {
190
+ (0, lodash_1.set)(property, 'type', 'array');
191
+ }
192
+ else {
193
+ (0, lodash_1.set)(property, 'type', 'string');
194
+ }
195
+ }
196
+ const type = (0, lodash_1.get)(property, 'type');
197
+ const isObject = type === 'object';
198
+ if (isObject) {
199
+ if (!hasProperties) {
200
+ property.properties = {};
201
+ }
202
+ // istanbul ignore next - unreachable defensive code: properties is always set to {} above if missing
203
+ normalizeProperties(property.properties || {});
204
+ }
205
+ const isArray = type === 'array';
206
+ if (isArray) {
207
+ if (hasItems) {
208
+ // istanbul ignore next - unreachable defensive code: if items is undefined, hasItems would be false
209
+ const { items = {} } = property;
210
+ const isItemObject = !(0, lodash_1.isUndefined)(items.properties);
211
+ if (isItemObject) {
212
+ (0, lodash_1.set)(items, 'type', 'object');
213
+ normalizeProperties(items.properties || {});
214
+ }
215
+ }
216
+ else {
217
+ property.items = { type: 'string' };
218
+ }
219
+ }
220
+ }
221
+ };
222
+ exports.default = normalizeProperties;
223
+ //# sourceMappingURL=normalizeProperties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalizeProperties.js","sourceRoot":"","sources":["../../src/helpers/normalizeProperties.ts"],"names":[],"mappings":";;AAAA,mCAA+C;AAU/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmKG;AACH,MAAM,mBAAmB,GAAG,CAAC,MAAqC,EAAE,EAAE;IACpE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAI,MAAqB,CAAC;IAEhD,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,UAAU,GAAI,MAAqB,CAAC;QAC1C,UAAU,CAAC,IAAI,GAAG,UAAU,CAAC,IAAI,IAAI,QAAQ,CAAC;QAE9C,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAI,MAA2B,CAAC;IAEhD,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAElC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAI,QAAoC,CAAC;QAE9D,IAAI,KAAK,EAAE,CAAC;YACV,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,CAAC,IAAA,YAAG,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAA,YAAG,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,aAAa,GAAG,CAAC,CAAC,IAAA,YAAG,EAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAEpD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,aAAa,EAAE,CAAC;gBAClB,IAAA,YAAG,EAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;YAElC,CAAC;iBAAM,IAAI,QAAQ,EAAE,CAAC;gBACpB,IAAA,YAAG,EAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;YAEjC,CAAC;iBAAM,CAAC;gBACN,IAAA,YAAG,EAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;YAElC,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GAAG,IAAA,YAAG,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAEnC,MAAM,QAAQ,GAAG,IAAI,KAAK,QAAQ,CAAC;QAEnC,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,aAAa,EAAE,CAAC;gBAClB,QAAiC,CAAC,UAAU,GAAG,EAAE,CAAC;YACrD,CAAC;YAED,qGAAqG;YACrG,mBAAmB,CAAE,QAAiC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,KAAK,OAAO,CAAC;QAEjC,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,QAAQ,EAAE,CAAC;gBACb,oGAAoG;gBACpG,MAAM,EAAE,KAAK,GAAG,EAAE,EAAE,GAAI,QAAgC,CAAC;gBAEzD,MAAM,YAAY,GAAG,CAAC,IAAA,oBAAW,EAAE,KAA8B,CAAC,UAAU,CAAC,CAAC;gBAE9E,IAAI,YAAY,EAAE,CAAC;oBACjB,IAAA,YAAG,EAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;oBAE7B,mBAAmB,CAAE,KAA8B,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;gBACxE,CAAC;YAEH,CAAC;iBAAM,CAAC;gBACL,QAAgC,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YAE/D,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC,CAAC;AAEF,kBAAe,mBAAmB,CAAC"}