@carecard/validate 3.1.17 → 3.1.19

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.
@@ -58,6 +58,10 @@ function validateProperties(obj = {}) {
58
58
  case 'document_type':
59
59
  case 'documentType':
60
60
  case 'reason':
61
+ case 'entity_type':
62
+ case 'entityType':
63
+ case 'action_type':
64
+ case 'actionType':
61
65
  case 'street':
62
66
  case 'city':
63
67
  case 'state':
@@ -149,6 +153,12 @@ function validateProperties(obj = {}) {
149
153
  case 'userRoleId':
150
154
  case 'phone_number_id':
151
155
  case 'phoneNumberId':
156
+ case 'entity_id':
157
+ case 'entityId':
158
+ case 'changed_by':
159
+ case 'changedBy':
160
+ case 'request_id':
161
+ case 'requestId':
152
162
  if (isValidUuidString(value)) {
153
163
  returnObj[key] = value;
154
164
  }
@@ -165,6 +175,8 @@ function validateProperties(obj = {}) {
165
175
  case 'price':
166
176
  case 'from':
167
177
  case 'number':
178
+ case 'limit':
179
+ case 'offset':
168
180
  if (isValidIntegerString(value)) {
169
181
  returnObj[key] = value;
170
182
  }
@@ -212,6 +224,10 @@ function validateProperties(obj = {}) {
212
224
  break;
213
225
  case 'expires_at':
214
226
  case 'expiresAt':
227
+ case 'start_time':
228
+ case 'startTime':
229
+ case 'end_time':
230
+ case 'endTime':
215
231
  if (isValidTimestampzString(value) || isValidTimestampString(value)) {
216
232
  returnObj[key] = value;
217
233
  }
@@ -18,7 +18,53 @@ const MAX_NESTING_DEPTH = 5;
18
18
  const MAX_KEYS_PER_CALL = 5000;
19
19
 
20
20
  /**
21
- * Splits a dot-notation property path into its segments and validates depth.
21
+ * Returns true if the segment contains a mix of snake_case (underscore) and
22
+ * camelCase (uppercase letter), e.g. `my_mixName`. Such names are ambiguous
23
+ * and are not supported.
24
+ * @param {string} segment
25
+ * @returns {boolean}
26
+ */
27
+ function isMixedCaseSegment(segment) {
28
+ return /_/.test(segment) && /[A-Z]/.test(segment);
29
+ }
30
+
31
+ /**
32
+ * Converts a snake_case identifier to camelCase. Leaves identifiers without
33
+ * underscores unchanged.
34
+ * @param {string} s
35
+ * @returns {string}
36
+ */
37
+ function snakeToCamel(s) {
38
+ return s.replace(/_([a-zA-Z0-9])/g, (_, c) => c.toUpperCase());
39
+ }
40
+
41
+ /**
42
+ * Converts a camelCase identifier to snake_case. Leaves identifiers without
43
+ * uppercase letters unchanged.
44
+ * @param {string} s
45
+ * @returns {string}
46
+ */
47
+ function camelToSnake(s) {
48
+ return s.replace(/[A-Z]/g, c => `_${c.toLowerCase()}`);
49
+ }
50
+
51
+ /**
52
+ * Returns the alternate-case form of the segment:
53
+ * - snake_case -> camelCase
54
+ * - camelCase -> snake_case
55
+ * - otherwise (no `_` and no uppercase) the segment itself.
56
+ * @param {string} segment
57
+ * @returns {string}
58
+ */
59
+ function alternateCase(segment) {
60
+ if (segment.indexOf('_') !== -1) return snakeToCamel(segment);
61
+ if (/[A-Z]/.test(segment)) return camelToSnake(segment);
62
+ return segment;
63
+ }
64
+
65
+ /**
66
+ * Splits a dot-notation property path into its segments and validates depth
67
+ * and per-segment casing (mixed snake/camel segments are rejected).
22
68
  * @param {string} path
23
69
  * @returns {string[]}
24
70
  */
@@ -29,6 +75,13 @@ function splitPath(path) {
29
75
  userMessage: `Property path "${path}" exceeds maximum nesting depth of ${MAX_NESTING_DEPTH}`,
30
76
  });
31
77
  }
78
+ for (const seg of segments) {
79
+ if (isMixedCaseSegment(seg)) {
80
+ throwBadInputError({
81
+ userMessage: `Property path "${path}" has a segment "${seg}" mixing snake_case and camelCase`,
82
+ });
83
+ }
84
+ }
32
85
  return segments;
33
86
  }
34
87
 
@@ -42,16 +95,27 @@ function splitPath(path) {
42
95
  * @returns {{ found: boolean, value: any }}
43
96
  */
44
97
  function readLeaf(obj, segments) {
98
+ // Resolve a segment against the current node, trying its as-written form
99
+ // first and then its alternate snake/camel form. Returns the actual key
100
+ // present in the node, or undefined if neither form exists.
101
+ function resolveKey(node, seg) {
102
+ if (Object.prototype.hasOwnProperty.call(node, seg)) return seg;
103
+ const alt = alternateCase(seg);
104
+ if (alt !== seg && Object.prototype.hasOwnProperty.call(node, alt)) return alt;
105
+ return undefined;
106
+ }
107
+
45
108
  let current = obj;
46
109
  for (let i = 0; i < segments.length - 1; i++) {
47
110
  if (current === null || typeof current !== 'object') return { found: false, value: undefined };
48
- if (!Object.prototype.hasOwnProperty.call(current, segments[i])) return { found: false, value: undefined };
49
- current = current[segments[i]];
111
+ const key = resolveKey(current, segments[i]);
112
+ if (key === undefined) return { found: false, value: undefined };
113
+ current = current[key];
50
114
  }
51
115
  if (current === null || typeof current !== 'object') return { found: false, value: undefined };
52
- const leaf = segments[segments.length - 1];
53
- if (!Object.prototype.hasOwnProperty.call(current, leaf)) return { found: false, value: undefined };
54
- return { found: true, value: current[leaf] };
116
+ const leafKey = resolveKey(current, segments[segments.length - 1]);
117
+ if (leafKey === undefined) return { found: false, value: undefined };
118
+ return { found: true, value: current[leafKey] };
55
119
  }
56
120
 
57
121
  /**
@@ -146,7 +210,7 @@ function validateWhitelistProperties(
146
210
  });
147
211
  }
148
212
 
149
- const requiredPaths = requiredProperties.map(p => ({ raw: p, segments: splitPath(p) }));
213
+ const requiredPaths = (requiredProperties || []).map(p => ({ raw: p, segments: splitPath(p) }));
150
214
  const optionalPaths = optionalProperties.map(p => ({ raw: p, segments: splitPath(p) }));
151
215
 
152
216
  let validatedObject = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carecard/validate",
3
- "version": "3.1.17",
3
+ "version": "3.1.19",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/CareCard-ca/pkg-validate.git"