@memberjunction/global 2.67.0 → 2.69.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/DeepDiff.d.ts +22 -0
- package/dist/DeepDiff.d.ts.map +1 -1
- package/dist/DeepDiff.js +31 -3
- package/dist/DeepDiff.js.map +1 -1
- package/dist/JSONValidator.d.ts +158 -0
- package/dist/JSONValidator.d.ts.map +1 -0
- package/dist/JSONValidator.js +402 -0
- package/dist/JSONValidator.js.map +1 -0
- package/dist/ValidationTypes.d.ts +36 -0
- package/dist/ValidationTypes.d.ts.map +1 -0
- package/dist/ValidationTypes.js +43 -0
- package/dist/ValidationTypes.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +208 -3
package/dist/DeepDiff.d.ts
CHANGED
|
@@ -34,6 +34,20 @@
|
|
|
34
34
|
* // Added: hobbies[1]
|
|
35
35
|
* // Added "gaming"
|
|
36
36
|
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // With treatNullAsUndefined option
|
|
41
|
+
* const differ = new DeepDiffer({ treatNullAsUndefined: true });
|
|
42
|
+
* const diff = differ.diff(
|
|
43
|
+
* { name: null, status: 'active', oldProp: 'value' },
|
|
44
|
+
* { name: 'John', status: null, newProp: 'value' }
|
|
45
|
+
* );
|
|
46
|
+
* // name: shows as Added (not Modified)
|
|
47
|
+
* // status: shows as Removed (not Modified)
|
|
48
|
+
* // oldProp: shows as Removed
|
|
49
|
+
* // newProp: shows as Added
|
|
50
|
+
* ```
|
|
37
51
|
*/
|
|
38
52
|
/**
|
|
39
53
|
* Types of changes that can occur in a deep diff operation
|
|
@@ -113,6 +127,14 @@ export interface DeepDiffConfig {
|
|
|
113
127
|
* @default true
|
|
114
128
|
*/
|
|
115
129
|
includeArrayIndices: boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Whether to treat null values as equivalent to undefined.
|
|
132
|
+
* When true, transitions between null and undefined are not considered changes,
|
|
133
|
+
* and null values in the old object are treated as "not present" for new values.
|
|
134
|
+
* Useful for APIs where null and undefined are used interchangeably.
|
|
135
|
+
* @default false
|
|
136
|
+
*/
|
|
137
|
+
treatNullAsUndefined: boolean;
|
|
116
138
|
/**
|
|
117
139
|
* Custom value formatter for the formatted output.
|
|
118
140
|
* Allows customization of how values are displayed.
|
package/dist/DeepDiff.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeepDiff.d.ts","sourceRoot":"","sources":["../src/DeepDiff.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"DeepDiff.d.ts","sourceRoot":"","sources":["../src/DeepDiff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAIH;;GAEG;AACH,oBAAY,cAAc;IACtB,wCAAwC;IACxC,KAAK,UAAU;IACf,gDAAgD;IAChD,OAAO,YAAY;IACnB,yDAAyD;IACzD,QAAQ,aAAa;IACrB,uEAAuE;IACvE,SAAS,cAAc;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,IAAI,EAAE,cAAc,CAAC;IACrB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,oDAAoD;IACpD,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,oCAAoC;IACpC,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,wCAAwC;IACxC,OAAO,EAAE;QACL,kDAAkD;QAClD,KAAK,EAAE,MAAM,CAAC;QACd,oDAAoD;QACpD,OAAO,EAAE,MAAM,CAAC;QAChB,qDAAqD;QACrD,QAAQ,EAAE,MAAM,CAAC;QACjB,uEAAuE;QACvE,SAAS,EAAE,MAAM,CAAC;QAClB,qCAAqC;QACrC,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B;;;;OAIG;IACH,gBAAgB,EAAE,OAAO,CAAC;IAE1B;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,mBAAmB,EAAE,OAAO,CAAC;IAE7B;;;;;;OAMG;IACH,oBAAoB,EAAE,OAAO,CAAC;IAE9B;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACzD;AAED;;;;;GAKG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,MAAM,CAAiB;IAE/B;;;OAGG;gBACS,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC;IAW5C;;;;;;;;;;;;;;;OAeG;IACI,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,cAAc;IAkC9D;;;OAGG;IACI,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;IAI1D;;;OAGG;IACH,OAAO,CAAC,YAAY;IAqEpB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAkDlB;;;OAGG;IACH,OAAO,CAAC,WAAW;IA0BnB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAUrB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA6B3B;;;OAGG;IACH,OAAO,CAAC,UAAU;CAsCrB"}
|
package/dist/DeepDiff.js
CHANGED
|
@@ -35,6 +35,20 @@
|
|
|
35
35
|
* // Added: hobbies[1]
|
|
36
36
|
* // Added "gaming"
|
|
37
37
|
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* // With treatNullAsUndefined option
|
|
42
|
+
* const differ = new DeepDiffer({ treatNullAsUndefined: true });
|
|
43
|
+
* const diff = differ.diff(
|
|
44
|
+
* { name: null, status: 'active', oldProp: 'value' },
|
|
45
|
+
* { name: 'John', status: null, newProp: 'value' }
|
|
46
|
+
* );
|
|
47
|
+
* // name: shows as Added (not Modified)
|
|
48
|
+
* // status: shows as Removed (not Modified)
|
|
49
|
+
* // oldProp: shows as Removed
|
|
50
|
+
* // newProp: shows as Added
|
|
51
|
+
* ```
|
|
38
52
|
*/
|
|
39
53
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
40
54
|
if (k2 === undefined) k2 = k;
|
|
@@ -93,6 +107,7 @@ class DeepDiffer {
|
|
|
93
107
|
maxDepth: 10,
|
|
94
108
|
maxStringLength: 100,
|
|
95
109
|
includeArrayIndices: true,
|
|
110
|
+
treatNullAsUndefined: false,
|
|
96
111
|
...config
|
|
97
112
|
};
|
|
98
113
|
}
|
|
@@ -151,8 +166,21 @@ class DeepDiffer {
|
|
|
151
166
|
return;
|
|
152
167
|
}
|
|
153
168
|
const pathStr = path.join('.');
|
|
169
|
+
// Helper to check if a value is effectively undefined (includes null if treatNullAsUndefined is true)
|
|
170
|
+
const isEffectivelyUndefined = (value) => {
|
|
171
|
+
return value === undefined || (this.config.treatNullAsUndefined && value === null);
|
|
172
|
+
};
|
|
173
|
+
// Helper to check if values are effectively equal
|
|
174
|
+
const areEffectivelyEqual = (val1, val2) => {
|
|
175
|
+
if (val1 === val2)
|
|
176
|
+
return true;
|
|
177
|
+
if (this.config.treatNullAsUndefined && isEffectivelyUndefined(val1) && isEffectivelyUndefined(val2)) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
};
|
|
154
182
|
// Handle different cases
|
|
155
|
-
if (oldValue
|
|
183
|
+
if (areEffectivelyEqual(oldValue, newValue)) {
|
|
156
184
|
if (this.config.includeUnchanged) {
|
|
157
185
|
changes.push({
|
|
158
186
|
path: pathStr || 'root',
|
|
@@ -163,7 +191,7 @@ class DeepDiffer {
|
|
|
163
191
|
});
|
|
164
192
|
}
|
|
165
193
|
}
|
|
166
|
-
else if (oldValue
|
|
194
|
+
else if (isEffectivelyUndefined(oldValue) && !isEffectivelyUndefined(newValue)) {
|
|
167
195
|
changes.push({
|
|
168
196
|
path: pathStr || 'root',
|
|
169
197
|
type: DiffChangeType.Added,
|
|
@@ -171,7 +199,7 @@ class DeepDiffer {
|
|
|
171
199
|
description: this.describeValue(newValue, 'Added')
|
|
172
200
|
});
|
|
173
201
|
}
|
|
174
|
-
else if (oldValue
|
|
202
|
+
else if (!isEffectivelyUndefined(oldValue) && isEffectivelyUndefined(newValue)) {
|
|
175
203
|
changes.push({
|
|
176
204
|
path: pathStr || 'root',
|
|
177
205
|
type: DiffChangeType.Removed,
|
package/dist/DeepDiff.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeepDiff.js","sourceRoot":"","sources":["../src/DeepDiff.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"DeepDiff.js","sourceRoot":"","sources":["../src/DeepDiff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview JSON validation utility with support for flexible validation rules.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a lightweight JSON validator that supports special field
|
|
5
|
+
* suffixes and validation rules for validating objects against example templates.
|
|
6
|
+
* It's designed to be simpler and more flexible than formal JSON Schema validation.
|
|
7
|
+
*
|
|
8
|
+
* ## Validation Syntax
|
|
9
|
+
*
|
|
10
|
+
* Field names can include validation rules using these patterns:
|
|
11
|
+
* - `fieldName?` - Optional field
|
|
12
|
+
* - `fieldName*` - Required field with any content (wildcard)
|
|
13
|
+
* - `fieldName:rule` - Field with validation rule
|
|
14
|
+
* - `fieldName:rule1:rule2` - Field with multiple validation rules
|
|
15
|
+
* - `fieldName:rule?` - Optional field with validation rule
|
|
16
|
+
*
|
|
17
|
+
* ## Supported Validation Rules
|
|
18
|
+
*
|
|
19
|
+
* **Array Length:**
|
|
20
|
+
* - `[N+]` - Array with at least N elements
|
|
21
|
+
* - `[N-M]` - Array with between N and M elements
|
|
22
|
+
* - `[=N]` - Array with exactly N elements
|
|
23
|
+
*
|
|
24
|
+
* **Type Checking:**
|
|
25
|
+
* - `string` - Must be a string
|
|
26
|
+
* - `number` - Must be a number
|
|
27
|
+
* - `boolean` - Must be a boolean
|
|
28
|
+
* - `object` - Must be an object (not array)
|
|
29
|
+
* - `array` - Must be an array
|
|
30
|
+
*
|
|
31
|
+
* **Value Constraints:**
|
|
32
|
+
* - `!empty` - Non-empty string, array, or object
|
|
33
|
+
*
|
|
34
|
+
* @module @memberjunction/global
|
|
35
|
+
* @author MemberJunction.com
|
|
36
|
+
* @since 3.0.0
|
|
37
|
+
*/
|
|
38
|
+
import { ValidationResult } from './ValidationTypes';
|
|
39
|
+
/**
|
|
40
|
+
* Lightweight JSON validator with flexible validation rules.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const validator = new JSONValidator();
|
|
45
|
+
*
|
|
46
|
+
* const template = {
|
|
47
|
+
* "name": "John Doe", // Required field
|
|
48
|
+
* "email?": "user@example.com", // Optional field
|
|
49
|
+
* "settings*": {}, // Required, any content
|
|
50
|
+
* "tags:[1+]": ["tag1"], // Array with 1+ items
|
|
51
|
+
* "age:number": 25 // Must be number
|
|
52
|
+
* };
|
|
53
|
+
*
|
|
54
|
+
* const data = {
|
|
55
|
+
* name: "Jane Smith",
|
|
56
|
+
* tags: ["work", "urgent"],
|
|
57
|
+
* age: 30
|
|
58
|
+
* };
|
|
59
|
+
*
|
|
60
|
+
* const result = validator.validate(data, template);
|
|
61
|
+
* if (result.Success) {
|
|
62
|
+
* console.log('Validation passed!');
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare class JSONValidator {
|
|
67
|
+
/**
|
|
68
|
+
* Validates an object against a template with validation rules.
|
|
69
|
+
*
|
|
70
|
+
* @param data - The data object to validate
|
|
71
|
+
* @param template - The template object with validation rules
|
|
72
|
+
* @param path - The current path in the object hierarchy (used internally)
|
|
73
|
+
* @returns ValidationResult with Success flag and any validation errors
|
|
74
|
+
*/
|
|
75
|
+
validate(data: unknown, template: unknown, path?: string): ValidationResult;
|
|
76
|
+
/**
|
|
77
|
+
* Validates an object against a template recursively.
|
|
78
|
+
*
|
|
79
|
+
* @private
|
|
80
|
+
*/
|
|
81
|
+
private validateObject;
|
|
82
|
+
/**
|
|
83
|
+
* Parses a field key to extract the field name and validation rules.
|
|
84
|
+
*
|
|
85
|
+
* @private
|
|
86
|
+
*/
|
|
87
|
+
private parseFieldKey;
|
|
88
|
+
/**
|
|
89
|
+
* Parses validation rules from a string, handling special cases like array syntax.
|
|
90
|
+
*
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
private parseValidationRules;
|
|
94
|
+
/**
|
|
95
|
+
* Applies validation rules to a field value.
|
|
96
|
+
*
|
|
97
|
+
* @private
|
|
98
|
+
*/
|
|
99
|
+
private applyValidationRules;
|
|
100
|
+
/**
|
|
101
|
+
* Validates array length constraints.
|
|
102
|
+
*
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
private validateArrayLength;
|
|
106
|
+
/**
|
|
107
|
+
* Validates type constraints.
|
|
108
|
+
*
|
|
109
|
+
* @private
|
|
110
|
+
*/
|
|
111
|
+
private validateType;
|
|
112
|
+
/**
|
|
113
|
+
* Validates non-empty constraint.
|
|
114
|
+
*
|
|
115
|
+
* @private
|
|
116
|
+
*/
|
|
117
|
+
private validateNonEmpty;
|
|
118
|
+
/**
|
|
119
|
+
* Validates an object against a JSON schema string.
|
|
120
|
+
* Convenience method that parses the schema and validates.
|
|
121
|
+
*
|
|
122
|
+
* @param data - The data to validate
|
|
123
|
+
* @param schemaJson - JSON string containing the validation schema
|
|
124
|
+
* @returns ValidationResult with Success flag and any validation errors
|
|
125
|
+
*/
|
|
126
|
+
validateAgainstSchema(data: unknown, schemaJson: string): ValidationResult;
|
|
127
|
+
/**
|
|
128
|
+
* Cleans validation syntax from JSON object keys.
|
|
129
|
+
*
|
|
130
|
+
* This method recursively processes a JSON object and removes validation
|
|
131
|
+
* syntax markers (?, *, :rules) from all object keys. This is useful when
|
|
132
|
+
* AI models mistakenly include our validation syntax in their responses.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* interface MyData {
|
|
137
|
+
* name: string;
|
|
138
|
+
* items: string[];
|
|
139
|
+
* config: { enabled: boolean };
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* const dirtyJson = {
|
|
143
|
+
* "name?": "John",
|
|
144
|
+
* "items:[1+]": ["a", "b"],
|
|
145
|
+
* "config*": { "enabled?": true }
|
|
146
|
+
* };
|
|
147
|
+
*
|
|
148
|
+
* const cleanJson = validator.cleanValidationSyntax<MyData>(dirtyJson);
|
|
149
|
+
* // Result is typed as MyData
|
|
150
|
+
* ```
|
|
151
|
+
*
|
|
152
|
+
* @template T - The expected type of the cleaned data
|
|
153
|
+
* @param data - The JSON data to clean
|
|
154
|
+
* @returns A new object with cleaned keys, typed as T
|
|
155
|
+
*/
|
|
156
|
+
cleanValidationSyntax<T>(data: unknown): T;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=JSONValidator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JSONValidator.d.ts","sourceRoot":"","sources":["../src/JSONValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAE,gBAAgB,EAA4C,MAAM,mBAAmB,CAAC;AA0B/F;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,aAAa;IACtB;;;;;;;OAOG;IACI,QAAQ,CACX,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,OAAO,EACjB,IAAI,GAAE,MAAW,GAClB,gBAAgB;IASnB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IA4EtB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAsCrB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IA6B5B;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAgC5B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IA6D3B;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAsCpB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IA0BxB;;;;;;;OAOG;IACI,qBAAqB,CACxB,IAAI,EAAE,OAAO,EACb,UAAU,EAAE,MAAM,GACnB,gBAAgB;IAmBnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACI,qBAAqB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC;CAiCpD"}
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview JSON validation utility with support for flexible validation rules.
|
|
4
|
+
*
|
|
5
|
+
* This module provides a lightweight JSON validator that supports special field
|
|
6
|
+
* suffixes and validation rules for validating objects against example templates.
|
|
7
|
+
* It's designed to be simpler and more flexible than formal JSON Schema validation.
|
|
8
|
+
*
|
|
9
|
+
* ## Validation Syntax
|
|
10
|
+
*
|
|
11
|
+
* Field names can include validation rules using these patterns:
|
|
12
|
+
* - `fieldName?` - Optional field
|
|
13
|
+
* - `fieldName*` - Required field with any content (wildcard)
|
|
14
|
+
* - `fieldName:rule` - Field with validation rule
|
|
15
|
+
* - `fieldName:rule1:rule2` - Field with multiple validation rules
|
|
16
|
+
* - `fieldName:rule?` - Optional field with validation rule
|
|
17
|
+
*
|
|
18
|
+
* ## Supported Validation Rules
|
|
19
|
+
*
|
|
20
|
+
* **Array Length:**
|
|
21
|
+
* - `[N+]` - Array with at least N elements
|
|
22
|
+
* - `[N-M]` - Array with between N and M elements
|
|
23
|
+
* - `[=N]` - Array with exactly N elements
|
|
24
|
+
*
|
|
25
|
+
* **Type Checking:**
|
|
26
|
+
* - `string` - Must be a string
|
|
27
|
+
* - `number` - Must be a number
|
|
28
|
+
* - `boolean` - Must be a boolean
|
|
29
|
+
* - `object` - Must be an object (not array)
|
|
30
|
+
* - `array` - Must be an array
|
|
31
|
+
*
|
|
32
|
+
* **Value Constraints:**
|
|
33
|
+
* - `!empty` - Non-empty string, array, or object
|
|
34
|
+
*
|
|
35
|
+
* @module @memberjunction/global
|
|
36
|
+
* @author MemberJunction.com
|
|
37
|
+
* @since 3.0.0
|
|
38
|
+
*/
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.JSONValidator = void 0;
|
|
41
|
+
const ValidationTypes_1 = require("./ValidationTypes");
|
|
42
|
+
/**
|
|
43
|
+
* Lightweight JSON validator with flexible validation rules.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const validator = new JSONValidator();
|
|
48
|
+
*
|
|
49
|
+
* const template = {
|
|
50
|
+
* "name": "John Doe", // Required field
|
|
51
|
+
* "email?": "user@example.com", // Optional field
|
|
52
|
+
* "settings*": {}, // Required, any content
|
|
53
|
+
* "tags:[1+]": ["tag1"], // Array with 1+ items
|
|
54
|
+
* "age:number": 25 // Must be number
|
|
55
|
+
* };
|
|
56
|
+
*
|
|
57
|
+
* const data = {
|
|
58
|
+
* name: "Jane Smith",
|
|
59
|
+
* tags: ["work", "urgent"],
|
|
60
|
+
* age: 30
|
|
61
|
+
* };
|
|
62
|
+
*
|
|
63
|
+
* const result = validator.validate(data, template);
|
|
64
|
+
* if (result.Success) {
|
|
65
|
+
* console.log('Validation passed!');
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
class JSONValidator {
|
|
70
|
+
/**
|
|
71
|
+
* Validates an object against a template with validation rules.
|
|
72
|
+
*
|
|
73
|
+
* @param data - The data object to validate
|
|
74
|
+
* @param template - The template object with validation rules
|
|
75
|
+
* @param path - The current path in the object hierarchy (used internally)
|
|
76
|
+
* @returns ValidationResult with Success flag and any validation errors
|
|
77
|
+
*/
|
|
78
|
+
validate(data, template, path = '') {
|
|
79
|
+
const errors = this.validateObject(data, template, path);
|
|
80
|
+
return {
|
|
81
|
+
Success: errors.length === 0,
|
|
82
|
+
Errors: errors
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Validates an object against a template recursively.
|
|
87
|
+
*
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
validateObject(data, template, path = '') {
|
|
91
|
+
const errors = [];
|
|
92
|
+
// If template is not an object, we don't validate structure
|
|
93
|
+
if (typeof template !== 'object' || template === null || Array.isArray(template)) {
|
|
94
|
+
return errors;
|
|
95
|
+
}
|
|
96
|
+
// Data must be an object if template is an object
|
|
97
|
+
if (typeof data !== 'object' || data === null || Array.isArray(data)) {
|
|
98
|
+
errors.push(new ValidationTypes_1.ValidationErrorInfo(path || 'root', `Expected object but got ${Array.isArray(data) ? 'array' : typeof data}`, data, ValidationTypes_1.ValidationErrorType.Failure));
|
|
99
|
+
return errors;
|
|
100
|
+
}
|
|
101
|
+
const dataObj = data;
|
|
102
|
+
const templateObj = template;
|
|
103
|
+
// Check each field in the template
|
|
104
|
+
for (const [templateKey, templateValue] of Object.entries(templateObj)) {
|
|
105
|
+
const parsed = this.parseFieldKey(templateKey);
|
|
106
|
+
const fieldPath = path ? `${path}.${parsed.fieldName}` : parsed.fieldName;
|
|
107
|
+
// Check if required field exists
|
|
108
|
+
if (!parsed.isOptional && !parsed.isWildcard && !(parsed.fieldName in dataObj)) {
|
|
109
|
+
errors.push(new ValidationTypes_1.ValidationErrorInfo(fieldPath, `Required field '${parsed.fieldName}' is missing`, undefined, ValidationTypes_1.ValidationErrorType.Failure));
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
// If field exists, validate it
|
|
113
|
+
if (parsed.fieldName in dataObj) {
|
|
114
|
+
const fieldValue = dataObj[parsed.fieldName];
|
|
115
|
+
// Skip validation for wildcard fields
|
|
116
|
+
if (parsed.isWildcard) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
// Apply validation rules
|
|
120
|
+
if (parsed.validationRules.length > 0) {
|
|
121
|
+
const ruleErrors = this.applyValidationRules(fieldValue, parsed.validationRules, fieldPath);
|
|
122
|
+
errors.push(...ruleErrors);
|
|
123
|
+
}
|
|
124
|
+
// Recursively validate nested objects (unless validation failed)
|
|
125
|
+
if (errors.filter(e => e.Source === fieldPath).length === 0) {
|
|
126
|
+
const nestedErrors = this.validateObject(fieldValue, templateValue, fieldPath);
|
|
127
|
+
errors.push(...nestedErrors);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return errors;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Parses a field key to extract the field name and validation rules.
|
|
135
|
+
*
|
|
136
|
+
* @private
|
|
137
|
+
*/
|
|
138
|
+
parseFieldKey(key) {
|
|
139
|
+
let workingKey = key.trim();
|
|
140
|
+
let isOptional = false;
|
|
141
|
+
let isWildcard = false;
|
|
142
|
+
const validationRules = [];
|
|
143
|
+
// Check for optional suffix (?)
|
|
144
|
+
if (workingKey.endsWith('?')) {
|
|
145
|
+
isOptional = true;
|
|
146
|
+
workingKey = workingKey.slice(0, -1);
|
|
147
|
+
}
|
|
148
|
+
// Check for wildcard suffix (*)
|
|
149
|
+
else if (workingKey.endsWith('*')) {
|
|
150
|
+
isWildcard = true;
|
|
151
|
+
workingKey = workingKey.slice(0, -1);
|
|
152
|
+
}
|
|
153
|
+
// Parse validation rules (everything after first :)
|
|
154
|
+
const colonIndex = workingKey.indexOf(':');
|
|
155
|
+
let fieldName = workingKey;
|
|
156
|
+
if (colonIndex !== -1) {
|
|
157
|
+
fieldName = workingKey.substring(0, colonIndex);
|
|
158
|
+
const rulesString = workingKey.substring(colonIndex + 1);
|
|
159
|
+
// Split by : but handle array syntax [N+] specially
|
|
160
|
+
const rules = this.parseValidationRules(rulesString);
|
|
161
|
+
validationRules.push(...rules);
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
fieldName,
|
|
165
|
+
isOptional,
|
|
166
|
+
isWildcard,
|
|
167
|
+
validationRules
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Parses validation rules from a string, handling special cases like array syntax.
|
|
172
|
+
*
|
|
173
|
+
* @private
|
|
174
|
+
*/
|
|
175
|
+
parseValidationRules(rulesString) {
|
|
176
|
+
const rules = [];
|
|
177
|
+
let currentRule = '';
|
|
178
|
+
let inBrackets = false;
|
|
179
|
+
for (const char of rulesString) {
|
|
180
|
+
if (char === '[') {
|
|
181
|
+
inBrackets = true;
|
|
182
|
+
currentRule += char;
|
|
183
|
+
}
|
|
184
|
+
else if (char === ']') {
|
|
185
|
+
inBrackets = false;
|
|
186
|
+
currentRule += char;
|
|
187
|
+
}
|
|
188
|
+
else if (char === ':' && !inBrackets) {
|
|
189
|
+
if (currentRule) {
|
|
190
|
+
rules.push(currentRule);
|
|
191
|
+
currentRule = '';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
currentRule += char;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (currentRule) {
|
|
199
|
+
rules.push(currentRule);
|
|
200
|
+
}
|
|
201
|
+
return rules;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Applies validation rules to a field value.
|
|
205
|
+
*
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
applyValidationRules(value, rules, fieldPath) {
|
|
209
|
+
const errors = [];
|
|
210
|
+
for (const rule of rules) {
|
|
211
|
+
// Array length validation
|
|
212
|
+
if (rule.startsWith('[') && rule.endsWith(']')) {
|
|
213
|
+
const lengthErrors = this.validateArrayLength(value, rule, fieldPath);
|
|
214
|
+
errors.push(...lengthErrors);
|
|
215
|
+
}
|
|
216
|
+
// Type validation
|
|
217
|
+
else if (['string', 'number', 'boolean', 'object', 'array'].includes(rule)) {
|
|
218
|
+
const typeError = this.validateType(value, rule, fieldPath);
|
|
219
|
+
if (typeError) {
|
|
220
|
+
errors.push(typeError);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Non-empty validation
|
|
224
|
+
else if (rule === '!empty') {
|
|
225
|
+
const emptyError = this.validateNonEmpty(value, fieldPath);
|
|
226
|
+
if (emptyError) {
|
|
227
|
+
errors.push(emptyError);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return errors;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Validates array length constraints.
|
|
235
|
+
*
|
|
236
|
+
* @private
|
|
237
|
+
*/
|
|
238
|
+
validateArrayLength(value, rule, fieldPath) {
|
|
239
|
+
const errors = [];
|
|
240
|
+
if (!Array.isArray(value)) {
|
|
241
|
+
errors.push(new ValidationTypes_1.ValidationErrorInfo(fieldPath, `Array length validation requires an array, but got ${typeof value}`, value, ValidationTypes_1.ValidationErrorType.Failure));
|
|
242
|
+
return errors;
|
|
243
|
+
}
|
|
244
|
+
const arrayLength = value.length;
|
|
245
|
+
const constraint = rule.slice(1, -1); // Remove [ and ]
|
|
246
|
+
// Parse the constraint
|
|
247
|
+
if (constraint.endsWith('+')) {
|
|
248
|
+
// Minimum length: [N+]
|
|
249
|
+
const min = parseInt(constraint.slice(0, -1), 10);
|
|
250
|
+
if (arrayLength < min) {
|
|
251
|
+
errors.push(new ValidationTypes_1.ValidationErrorInfo(fieldPath, `Array must have at least ${min} element${min > 1 ? 's' : ''}, but has ${arrayLength}`, value, ValidationTypes_1.ValidationErrorType.Failure));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else if (constraint.includes('-')) {
|
|
255
|
+
// Range: [N-M]
|
|
256
|
+
const [minStr, maxStr] = constraint.split('-');
|
|
257
|
+
const min = parseInt(minStr, 10);
|
|
258
|
+
const max = parseInt(maxStr, 10);
|
|
259
|
+
if (arrayLength < min || arrayLength > max) {
|
|
260
|
+
errors.push(new ValidationTypes_1.ValidationErrorInfo(fieldPath, `Array must have between ${min} and ${max} elements, but has ${arrayLength}`, value, ValidationTypes_1.ValidationErrorType.Failure));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else if (constraint.startsWith('=')) {
|
|
264
|
+
// Exact: [=N]
|
|
265
|
+
const exact = parseInt(constraint.slice(1), 10);
|
|
266
|
+
if (arrayLength !== exact) {
|
|
267
|
+
errors.push(new ValidationTypes_1.ValidationErrorInfo(fieldPath, `Array must have exactly ${exact} element${exact > 1 ? 's' : ''}, but has ${arrayLength}`, value, ValidationTypes_1.ValidationErrorType.Failure));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return errors;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Validates type constraints.
|
|
274
|
+
*
|
|
275
|
+
* @private
|
|
276
|
+
*/
|
|
277
|
+
validateType(value, expectedType, fieldPath) {
|
|
278
|
+
const actualType = Array.isArray(value) ? 'array' : typeof value;
|
|
279
|
+
let isValid = false;
|
|
280
|
+
switch (expectedType) {
|
|
281
|
+
case 'string':
|
|
282
|
+
isValid = typeof value === 'string';
|
|
283
|
+
break;
|
|
284
|
+
case 'number':
|
|
285
|
+
isValid = typeof value === 'number' && !isNaN(value);
|
|
286
|
+
break;
|
|
287
|
+
case 'boolean':
|
|
288
|
+
isValid = typeof value === 'boolean';
|
|
289
|
+
break;
|
|
290
|
+
case 'object':
|
|
291
|
+
isValid = typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
292
|
+
break;
|
|
293
|
+
case 'array':
|
|
294
|
+
isValid = Array.isArray(value);
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
if (!isValid) {
|
|
298
|
+
return new ValidationTypes_1.ValidationErrorInfo(fieldPath, `Expected ${expectedType} but got ${actualType}`, value, ValidationTypes_1.ValidationErrorType.Failure);
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Validates non-empty constraint.
|
|
304
|
+
*
|
|
305
|
+
* @private
|
|
306
|
+
*/
|
|
307
|
+
validateNonEmpty(value, fieldPath) {
|
|
308
|
+
let isEmpty = false;
|
|
309
|
+
if (typeof value === 'string') {
|
|
310
|
+
isEmpty = value.trim().length === 0;
|
|
311
|
+
}
|
|
312
|
+
else if (Array.isArray(value)) {
|
|
313
|
+
isEmpty = value.length === 0;
|
|
314
|
+
}
|
|
315
|
+
else if (typeof value === 'object' && value !== null) {
|
|
316
|
+
isEmpty = Object.keys(value).length === 0;
|
|
317
|
+
}
|
|
318
|
+
if (isEmpty) {
|
|
319
|
+
return new ValidationTypes_1.ValidationErrorInfo(fieldPath, `Field must not be empty`, value, ValidationTypes_1.ValidationErrorType.Failure);
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Validates an object against a JSON schema string.
|
|
325
|
+
* Convenience method that parses the schema and validates.
|
|
326
|
+
*
|
|
327
|
+
* @param data - The data to validate
|
|
328
|
+
* @param schemaJson - JSON string containing the validation schema
|
|
329
|
+
* @returns ValidationResult with Success flag and any validation errors
|
|
330
|
+
*/
|
|
331
|
+
validateAgainstSchema(data, schemaJson) {
|
|
332
|
+
try {
|
|
333
|
+
const schema = JSON.parse(schemaJson);
|
|
334
|
+
return this.validate(data, schema);
|
|
335
|
+
}
|
|
336
|
+
catch (parseError) {
|
|
337
|
+
return {
|
|
338
|
+
Success: false,
|
|
339
|
+
Errors: [
|
|
340
|
+
new ValidationTypes_1.ValidationErrorInfo('schema', `Invalid JSON schema: ${parseError.message}`, schemaJson, ValidationTypes_1.ValidationErrorType.Failure)
|
|
341
|
+
]
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Cleans validation syntax from JSON object keys.
|
|
347
|
+
*
|
|
348
|
+
* This method recursively processes a JSON object and removes validation
|
|
349
|
+
* syntax markers (?, *, :rules) from all object keys. This is useful when
|
|
350
|
+
* AI models mistakenly include our validation syntax in their responses.
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* interface MyData {
|
|
355
|
+
* name: string;
|
|
356
|
+
* items: string[];
|
|
357
|
+
* config: { enabled: boolean };
|
|
358
|
+
* }
|
|
359
|
+
*
|
|
360
|
+
* const dirtyJson = {
|
|
361
|
+
* "name?": "John",
|
|
362
|
+
* "items:[1+]": ["a", "b"],
|
|
363
|
+
* "config*": { "enabled?": true }
|
|
364
|
+
* };
|
|
365
|
+
*
|
|
366
|
+
* const cleanJson = validator.cleanValidationSyntax<MyData>(dirtyJson);
|
|
367
|
+
* // Result is typed as MyData
|
|
368
|
+
* ```
|
|
369
|
+
*
|
|
370
|
+
* @template T - The expected type of the cleaned data
|
|
371
|
+
* @param data - The JSON data to clean
|
|
372
|
+
* @returns A new object with cleaned keys, typed as T
|
|
373
|
+
*/
|
|
374
|
+
cleanValidationSyntax(data) {
|
|
375
|
+
// Handle non-objects
|
|
376
|
+
if (data === null || data === undefined) {
|
|
377
|
+
return data;
|
|
378
|
+
}
|
|
379
|
+
if (Array.isArray(data)) {
|
|
380
|
+
// Recursively clean array elements
|
|
381
|
+
return data.map(item => this.cleanValidationSyntax(item));
|
|
382
|
+
}
|
|
383
|
+
if (typeof data !== 'object') {
|
|
384
|
+
// Primitive values pass through unchanged
|
|
385
|
+
return data;
|
|
386
|
+
}
|
|
387
|
+
// Process object
|
|
388
|
+
const cleaned = {};
|
|
389
|
+
const dataObj = data;
|
|
390
|
+
for (const [key, value] of Object.entries(dataObj)) {
|
|
391
|
+
// Parse the key to extract the clean field name
|
|
392
|
+
const parsed = this.parseFieldKey(key);
|
|
393
|
+
// Recursively clean the value
|
|
394
|
+
const cleanedValue = this.cleanValidationSyntax(value);
|
|
395
|
+
// Use the clean field name as the key
|
|
396
|
+
cleaned[parsed.fieldName] = cleanedValue;
|
|
397
|
+
}
|
|
398
|
+
return cleaned;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
exports.JSONValidator = JSONValidator;
|
|
402
|
+
//# sourceMappingURL=JSONValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JSONValidator.js","sourceRoot":"","sources":["../src/JSONValidator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview General-purpose validation types for use across MemberJunction
|
|
3
|
+
*
|
|
4
|
+
* These types provide a standard way to represent validation results and errors
|
|
5
|
+
* throughout the framework, independent of any specific validation implementation.
|
|
6
|
+
*
|
|
7
|
+
* @module @memberjunction/global
|
|
8
|
+
* @author MemberJunction.com
|
|
9
|
+
* @since 2.68.0
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Enumeration of validation error types
|
|
13
|
+
*/
|
|
14
|
+
export declare const ValidationErrorType: {
|
|
15
|
+
readonly Failure: "Failure";
|
|
16
|
+
readonly Warning: "Warning";
|
|
17
|
+
};
|
|
18
|
+
export type ValidationErrorType = typeof ValidationErrorType[keyof typeof ValidationErrorType];
|
|
19
|
+
/**
|
|
20
|
+
* Information about a single validation error
|
|
21
|
+
*/
|
|
22
|
+
export declare class ValidationErrorInfo {
|
|
23
|
+
Source: string;
|
|
24
|
+
Message: string;
|
|
25
|
+
Value: any;
|
|
26
|
+
Type: ValidationErrorType;
|
|
27
|
+
constructor(Source: string, Message: string, Value: any, Type?: ValidationErrorType);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Result of a validation operation
|
|
31
|
+
*/
|
|
32
|
+
export declare class ValidationResult {
|
|
33
|
+
Success: boolean;
|
|
34
|
+
Errors: ValidationErrorInfo[];
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=ValidationTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ValidationTypes.d.ts","sourceRoot":"","sources":["../src/ValidationTypes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;CAGtB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAC,MAAM,OAAO,mBAAmB,CAAC,CAAC;AAE/F;;GAEG;AACH,qBAAa,mBAAmB;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,GAAG,CAAC;IACX,IAAI,EAAE,mBAAmB,CAAC;gBAEd,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,GAAE,mBAAiD;CAMnH;AAED;;GAEG;AACH,qBAAa,gBAAgB;IACzB,OAAO,EAAE,OAAO,CAAS;IACzB,MAAM,EAAE,mBAAmB,EAAE,CAAM;CACtC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview General-purpose validation types for use across MemberJunction
|
|
4
|
+
*
|
|
5
|
+
* These types provide a standard way to represent validation results and errors
|
|
6
|
+
* throughout the framework, independent of any specific validation implementation.
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/global
|
|
9
|
+
* @author MemberJunction.com
|
|
10
|
+
* @since 2.68.0
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.ValidationResult = exports.ValidationErrorInfo = exports.ValidationErrorType = void 0;
|
|
14
|
+
/**
|
|
15
|
+
* Enumeration of validation error types
|
|
16
|
+
*/
|
|
17
|
+
exports.ValidationErrorType = {
|
|
18
|
+
Failure: 'Failure',
|
|
19
|
+
Warning: 'Warning',
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Information about a single validation error
|
|
23
|
+
*/
|
|
24
|
+
class ValidationErrorInfo {
|
|
25
|
+
constructor(Source, Message, Value, Type = exports.ValidationErrorType.Failure) {
|
|
26
|
+
this.Source = Source;
|
|
27
|
+
this.Message = Message;
|
|
28
|
+
this.Value = Value;
|
|
29
|
+
this.Type = Type;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.ValidationErrorInfo = ValidationErrorInfo;
|
|
33
|
+
/**
|
|
34
|
+
* Result of a validation operation
|
|
35
|
+
*/
|
|
36
|
+
class ValidationResult {
|
|
37
|
+
constructor() {
|
|
38
|
+
this.Success = false;
|
|
39
|
+
this.Errors = [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.ValidationResult = ValidationResult;
|
|
43
|
+
//# sourceMappingURL=ValidationTypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ValidationTypes.js","sourceRoot":"","sources":["../src/ValidationTypes.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEH;;GAEG;AACU,QAAA,mBAAmB,GAAG;IAC/B,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACZ,CAAC;AAIX;;GAEG;AACH,MAAa,mBAAmB;IAM5B,YAAY,MAAc,EAAE,OAAe,EAAE,KAAU,EAAE,OAA4B,2BAAmB,CAAC,OAAO;QAC5G,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;CACJ;AAZD,kDAYC;AAED;;GAEG;AACH,MAAa,gBAAgB;IAA7B;QACI,YAAO,GAAY,KAAK,CAAC;QACzB,WAAM,GAA0B,EAAE,CAAC;IACvC,CAAC;CAAA;AAHD,4CAGC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export * from './BaseSingleton';
|
|
|
6
6
|
export * from './DeepDiff';
|
|
7
7
|
export * from './ClassUtils';
|
|
8
8
|
export * from './util/PatternUtils';
|
|
9
|
+
export * from './ValidationTypes';
|
|
10
|
+
export * from './JSONValidator';
|
|
9
11
|
export * from './Global';
|
|
10
12
|
export * from './RegisterClass';
|
|
11
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAChE,cAAc,aAAa,CAAA;AAC3B,cAAc,QAAQ,CAAA;AACtB,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAA;AACjC,cAAc,iBAAiB,CAAA;AAG/B,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,8 @@ __exportStar(require("./BaseSingleton"), exports);
|
|
|
26
26
|
__exportStar(require("./DeepDiff"), exports);
|
|
27
27
|
__exportStar(require("./ClassUtils"), exports);
|
|
28
28
|
__exportStar(require("./util/PatternUtils"), exports);
|
|
29
|
+
__exportStar(require("./ValidationTypes"), exports);
|
|
30
|
+
__exportStar(require("./JSONValidator"), exports);
|
|
29
31
|
// Export the main classes
|
|
30
32
|
__exportStar(require("./Global"), exports);
|
|
31
33
|
__exportStar(require("./RegisterClass"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,iCAAiC;AACjC,+CAAgE;AAAvD,4GAAA,YAAY,OAAA;AAAE,iHAAA,iBAAiB,OAAA;AACxC,8CAA2B;AAC3B,yCAAsB;AACtB,gDAA6B;AAC7B,kDAA+B;AAC/B,6CAA0B;AAC1B,+CAA4B;AAC5B,sDAAoC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,iCAAiC;AACjC,+CAAgE;AAAvD,4GAAA,YAAY,OAAA;AAAE,iHAAA,iBAAiB,OAAA;AACxC,8CAA2B;AAC3B,yCAAsB;AACtB,gDAA6B;AAC7B,kDAA+B;AAC/B,6CAA0B;AAC1B,+CAA4B;AAC5B,sDAAoC;AACpC,oDAAiC;AACjC,kDAA+B;AAE/B,0BAA0B;AAC1B,2CAAwB;AACxB,kDAA+B"}
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -18,6 +18,7 @@ The `@memberjunction/global` library serves as the foundation for cross-componen
|
|
|
18
18
|
- **Object Caching** - In-memory object cache for application lifetime
|
|
19
19
|
- **Class Reflection Utilities** - Runtime class hierarchy inspection and analysis
|
|
20
20
|
- **Deep Diff Engine** - Comprehensive object comparison and change tracking
|
|
21
|
+
- **JSON Validator** - Lightweight JSON validation with flexible rules and special syntax
|
|
21
22
|
- **Utility Functions** - Common string manipulation, JSON parsing (including recursive nested JSON parsing), pattern matching, and formatting utilities
|
|
22
23
|
|
|
23
24
|
## Core Components
|
|
@@ -211,9 +212,10 @@ import { DeepDiffer, DiffChangeType } from '@memberjunction/global';
|
|
|
211
212
|
|
|
212
213
|
// Create a differ instance
|
|
213
214
|
const differ = new DeepDiffer({
|
|
214
|
-
includeUnchanged: false,
|
|
215
|
-
maxDepth: 10,
|
|
216
|
-
maxStringLength: 100
|
|
215
|
+
includeUnchanged: false, // Don't track unchanged values
|
|
216
|
+
maxDepth: 10, // Maximum recursion depth
|
|
217
|
+
maxStringLength: 100, // Truncate long strings
|
|
218
|
+
treatNullAsUndefined: false // Treat null and undefined as distinct (default: false)
|
|
217
219
|
});
|
|
218
220
|
|
|
219
221
|
// Compare two objects
|
|
@@ -255,6 +257,209 @@ const modifications = result.changes.filter(c => c.type === DiffChangeType.Modif
|
|
|
255
257
|
differ.updateConfig({ includeUnchanged: true });
|
|
256
258
|
```
|
|
257
259
|
|
|
260
|
+
#### Treating null as undefined
|
|
261
|
+
|
|
262
|
+
When working with APIs or databases where `null` and `undefined` are used interchangeably, you can enable the `treatNullAsUndefined` option:
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
const differ = new DeepDiffer({ treatNullAsUndefined: true });
|
|
266
|
+
|
|
267
|
+
const oldData = {
|
|
268
|
+
name: null,
|
|
269
|
+
status: 'active',
|
|
270
|
+
oldProp: 'value'
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const newData = {
|
|
274
|
+
name: 'John', // Will show as "Added" instead of "Modified"
|
|
275
|
+
status: null, // Will show as "Removed" instead of "Modified"
|
|
276
|
+
newProp: 'value'
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const result = differ.diff(oldData, newData);
|
|
280
|
+
// With treatNullAsUndefined: true
|
|
281
|
+
// - name: Added (not Modified, since null is treated as non-existent)
|
|
282
|
+
// - status: Removed (not Modified, since null is treated as non-existent)
|
|
283
|
+
// - oldProp: Removed
|
|
284
|
+
// - newProp: Added
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### JSON Validator
|
|
288
|
+
|
|
289
|
+
Lightweight JSON validation with flexible validation rules and special field suffixes.
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { JSONValidator } from '@memberjunction/global';
|
|
293
|
+
|
|
294
|
+
// Create validator instance
|
|
295
|
+
const validator = new JSONValidator();
|
|
296
|
+
|
|
297
|
+
// Define validation template with rules
|
|
298
|
+
const template = {
|
|
299
|
+
name: "John Doe", // Required field
|
|
300
|
+
email?: "user@example.com", // Optional field
|
|
301
|
+
settings*: {}, // Required, any content allowed
|
|
302
|
+
tags:[1+]: ["tag1"], // Array with at least 1 item
|
|
303
|
+
age:number: 25, // Must be a number
|
|
304
|
+
username:string:!empty: "johndoe", // Non-empty string
|
|
305
|
+
items:array:[2-5]?: ["A", "B"] // Optional array with 2-5 items
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// Validate data against template
|
|
309
|
+
const data = {
|
|
310
|
+
name: "Jane Smith",
|
|
311
|
+
tags: ["work", "urgent"],
|
|
312
|
+
age: 30,
|
|
313
|
+
username: "jsmith"
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const result = validator.validate(data, template);
|
|
317
|
+
if (result.Success) {
|
|
318
|
+
console.log('Validation passed!');
|
|
319
|
+
} else {
|
|
320
|
+
result.Errors.forEach(error => {
|
|
321
|
+
console.log(`${error.Source}: ${error.Message}`);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
#### Validation Syntax
|
|
327
|
+
|
|
328
|
+
**Field Suffixes:**
|
|
329
|
+
- `?` - Optional field (e.g., `email?`)
|
|
330
|
+
- `*` - Required field with any content/structure (e.g., `payload*`)
|
|
331
|
+
|
|
332
|
+
**Validation Rules (using `:` delimiter):**
|
|
333
|
+
- **Array Length:**
|
|
334
|
+
- `[N+]` - At least N elements (e.g., `tags:[1+]`)
|
|
335
|
+
- `[N-M]` - Between N and M elements (e.g., `items:[2-5]`)
|
|
336
|
+
- `[=N]` - Exactly N elements (e.g., `coordinates:[=2]`)
|
|
337
|
+
|
|
338
|
+
- **Type Checking:**
|
|
339
|
+
- `string` - Must be a string
|
|
340
|
+
- `number` - Must be a number (NaN fails validation)
|
|
341
|
+
- `boolean` - Must be a boolean
|
|
342
|
+
- `object` - Must be an object (not array or null)
|
|
343
|
+
- `array` - Must be an array
|
|
344
|
+
|
|
345
|
+
- **Value Constraints:**
|
|
346
|
+
- `!empty` - Non-empty string, array, or object
|
|
347
|
+
|
|
348
|
+
**Combining Rules:**
|
|
349
|
+
Multiple validation rules can be combined with `:` delimiter:
|
|
350
|
+
```typescript
|
|
351
|
+
{
|
|
352
|
+
// Array of strings with 2+ items
|
|
353
|
+
"tags:array:[2+]": ["important", "urgent"],
|
|
354
|
+
|
|
355
|
+
// Non-empty string
|
|
356
|
+
"username:string:!empty": "johndoe",
|
|
357
|
+
|
|
358
|
+
// Optional number
|
|
359
|
+
"score:number?": 85,
|
|
360
|
+
|
|
361
|
+
// Optional array with 1-3 items
|
|
362
|
+
"options:array:[1-3]?": ["A", "B"]
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
#### Nested Object Validation
|
|
367
|
+
|
|
368
|
+
The validator recursively validates nested objects:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
const template = {
|
|
372
|
+
user: {
|
|
373
|
+
id:number: 123,
|
|
374
|
+
name:string:!empty: "John",
|
|
375
|
+
roles:array:[1+]: ["admin"]
|
|
376
|
+
},
|
|
377
|
+
settings?: {
|
|
378
|
+
theme: "dark",
|
|
379
|
+
notifications:boolean: true
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
#### Cleaning Validation Syntax
|
|
385
|
+
|
|
386
|
+
The validator can clean validation syntax from JSON objects that may have been returned by AI systems:
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
// AI might return JSON with validation syntax in keys
|
|
390
|
+
const aiResponse = {
|
|
391
|
+
"name?": "John Doe",
|
|
392
|
+
"email:string": "john@example.com",
|
|
393
|
+
"tags:[2+]": ["work", "urgent"],
|
|
394
|
+
"settings*": { theme: "dark" },
|
|
395
|
+
"score:number:!empty": 85
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// Clean the validation syntax
|
|
399
|
+
const cleaned = validator.cleanValidationSyntax<any>(aiResponse);
|
|
400
|
+
// Returns:
|
|
401
|
+
// {
|
|
402
|
+
// "name": "John Doe",
|
|
403
|
+
// "email": "john@example.com",
|
|
404
|
+
// "tags": ["work", "urgent"],
|
|
405
|
+
// "settings": { theme: "dark" },
|
|
406
|
+
// "score": 85
|
|
407
|
+
// }
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
The `cleanValidationSyntax` method:
|
|
411
|
+
- Recursively processes all object keys
|
|
412
|
+
- Removes validation suffixes (`?`, `*`)
|
|
413
|
+
- Removes validation rules (`:type`, `:[N+]`, `:!empty`, etc.)
|
|
414
|
+
- Preserves the original values unchanged
|
|
415
|
+
- Handles nested objects and arrays
|
|
416
|
+
- Returns a new object with cleaned keys
|
|
417
|
+
|
|
418
|
+
#### Convenience Methods
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
// Validate against JSON string
|
|
422
|
+
const schemaJson = '{"name": "string", "age:number": 0}';
|
|
423
|
+
const result = validator.validateAgainstSchema(data, schemaJson);
|
|
424
|
+
|
|
425
|
+
// Integration with MemberJunction ValidationResult
|
|
426
|
+
// Returns standard ValidationResult with ValidationErrorInfo[]
|
|
427
|
+
// Compatible with existing MJ validation patterns
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
#### Use Cases
|
|
431
|
+
|
|
432
|
+
1. **API Response Validation:**
|
|
433
|
+
```typescript
|
|
434
|
+
const apiResponseTemplate = {
|
|
435
|
+
status:string: "success",
|
|
436
|
+
data*: {}, // Any data structure allowed
|
|
437
|
+
errors:array?: []
|
|
438
|
+
};
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
2. **Configuration Validation:**
|
|
442
|
+
```typescript
|
|
443
|
+
const configTemplate = {
|
|
444
|
+
apiUrl:string:!empty: "https://api.example.com",
|
|
445
|
+
timeout:number: 5000,
|
|
446
|
+
retries:number: 3,
|
|
447
|
+
features:array:[1+]: ["logging"]
|
|
448
|
+
};
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
3. **Form Data Validation:**
|
|
452
|
+
```typescript
|
|
453
|
+
const formTemplate = {
|
|
454
|
+
username:string:!empty: "user",
|
|
455
|
+
email:string: "user@example.com",
|
|
456
|
+
age:number?: 25,
|
|
457
|
+
preferences:object?: {
|
|
458
|
+
notifications:boolean: true
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
```
|
|
462
|
+
|
|
258
463
|
## Event Types
|
|
259
464
|
|
|
260
465
|
The library provides predefined event types for common scenarios:
|