@carecard/validate 3.18.0 → 3.20.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 (36) hide show
  1. package/.agents/skills/carecard-workspace-standards/SKILL.md +49 -20
  2. package/.agents/skills/github-pr-create-update/SKILL.md +22 -1
  3. package/.agents/skills/github-pr-merge-cleanup/SKILL.md +22 -1
  4. package/.agents/skills/logged-in-user-profile-page/SKILL.md +22 -1
  5. package/.agents/skills/pkg-publish/SKILL.md +22 -1
  6. package/.agents/skills/pkg-validate-coding-standards-and-best-practices/SKILL.md +47 -9
  7. package/.agents/skills/pkg-validate-validation-library/SKILL.md +45 -14
  8. package/.agents/skills/software-design-patterns-and-clean-code/SKILL.md +23 -3
  9. package/.codex/AGENTS.md +41 -10
  10. package/.github/workflows/auto-draft-pr.yml +173 -151
  11. package/.github/workflows/ci.yml +35 -32
  12. package/.husky/pre-commit +4 -4
  13. package/.prettierrc.js +10 -9
  14. package/AGENTS.md +19 -0
  15. package/eslint.config.mjs +60 -8
  16. package/index.d.ts +108 -107
  17. package/index.js +6 -6
  18. package/lib/validate.js +262 -158
  19. package/lib/validateNewUserRoleRequest.js +86 -60
  20. package/lib/validateProperties.js +326 -326
  21. package/lib/validateWhitelistProperties.js +182 -142
  22. package/lint-staged.config.mjs +36 -0
  23. package/package.json +66 -60
  24. package/readme.md +22 -1
  25. package/scripts/canonicalTestCommand.test.mjs +32 -0
  26. package/scripts/packageTaskRunner.audit.mjs +37 -0
  27. package/scripts/packageTaskRunner.test.mjs +50 -72
  28. package/scripts/runPackageTask.mjs +103 -58
  29. package/scripts/testOrder/randomizeTestOrder.cjs +35 -25
  30. package/scripts/testOrder/randomizeTestOrder.test.mjs +19 -19
  31. package/scripts/testOrder/testOrderPolicy.audit.mjs +54 -0
  32. package/scripts/testParallel/parallelTestPolicy.audit.mjs +63 -0
  33. package/scripts/testParallel/runIndexedMochaTests.cjs +45 -43
  34. package/scripts/testParallel/runIndexedMochaTests.test.mjs +13 -7
  35. package/scripts/testOrder/testOrderPolicy.test.mjs +0 -48
  36. package/scripts/testParallel/parallelTestPolicy.test.mjs +0 -43
package/lib/validate.js CHANGED
@@ -1,279 +1,383 @@
1
1
  const isImageUrl = imageUrl => {
2
- if (imageUrl === undefined || typeof imageUrl !== 'string' || imageUrl.length === 0 || imageUrl.length > 2048) return false;
2
+ if (
3
+ imageUrl === undefined ||
4
+ typeof imageUrl !== 'string' ||
5
+ imageUrl.length === 0 ||
6
+ imageUrl.length > 2048
7
+ ) {
8
+ return false;
9
+ }
3
10
 
4
- const imageUrlRegex = /^[a-zA-Z0-9-_./]+$/;
5
- return imageUrlRegex.test(imageUrl);
11
+ const imageUrlRegex = /^[a-zA-Z0-9-_./]+$/;
12
+ return imageUrlRegex.test(imageUrl);
6
13
  };
7
14
 
8
15
  const isInteger = number => {
9
- return Number.isInteger(number);
16
+ return Number.isInteger(number);
10
17
  };
11
18
 
19
+ // Pattern: Predicate - reports whether a bounded string contains a JSON object or array.
12
20
  const isValidJsonString = str => {
13
- if (str === undefined || typeof str !== 'string' || str.length === 0 || str.length > 10000) return false;
21
+ if (str === undefined || typeof str !== 'string' || str.length === 0 || str.length > 10000) {
22
+ return false;
23
+ }
14
24
 
15
- try {
16
- const json = JSON.parse(str);
17
- return typeof json === 'object' && json !== null;
18
- } catch (error) {
19
- if (!(error instanceof SyntaxError)) throw error;
20
- return false;
21
- }
25
+ try {
26
+ const json = JSON.parse(str);
27
+ return typeof json === 'object' && json !== null;
28
+ } catch {
29
+ return false;
30
+ }
22
31
  };
23
32
 
24
33
  const isValidIntegerString = str => {
25
- if (str === undefined || typeof str !== 'string' || str.length === 0 || str.length > 20) return false;
26
- return /^\d+$/.test(str);
34
+ if (str === undefined || typeof str !== 'string' || str.length === 0 || str.length > 20) {
35
+ return false;
36
+ }
37
+ return /^\d+$/.test(str);
27
38
  };
28
39
 
29
40
  const isValidUuidString = str => {
30
- if (str === undefined || typeof str !== 'string' || str.length === 0) return false;
31
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
32
- return uuidRegex.test(str);
41
+ if (str === undefined || typeof str !== 'string' || str.length === 0) {
42
+ return false;
43
+ }
44
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
45
+ return uuidRegex.test(str);
33
46
  };
34
47
 
35
48
  const isCcIdString = str => {
36
- if (typeof str !== 'string') return false;
37
- return /^[a-z0-9]{8}$/.test(str);
49
+ if (typeof str !== 'string') {
50
+ return false;
51
+ }
52
+ return /^[a-z0-9]{8}$/.test(str);
38
53
  };
39
54
 
40
55
  const isCharactersString = str => {
41
- if (str === undefined || typeof str !== 'string' || str.length === 0 || str.length > 1000) return false;
42
- return /^[\da-zA-Z _-]+$/.test(str);
56
+ if (str === undefined || typeof str !== 'string' || str.length === 0 || str.length > 1000) {
57
+ return false;
58
+ }
59
+ return /^[\da-zA-Z _-]+$/.test(str);
43
60
  };
44
61
 
45
62
  const isStreetString = str => {
46
- if (typeof str !== 'string' || str.trim().length === 0 || str.length > 1000) {
47
- return false;
48
- }
49
- const value = str.trim();
50
- const streetRegex = /^(?![,_-])[0-9a-zA-Z\s,./#-]+$/;
51
- return streetRegex.test(value);
63
+ if (typeof str !== 'string' || str.trim().length === 0 || str.length > 1000) {
64
+ return false;
65
+ }
66
+ const value = str.trim();
67
+ const streetRegex = /^(?![,_-])[0-9a-zA-Z\s,./#-]+$/;
68
+ return streetRegex.test(value);
52
69
  };
53
70
 
54
71
  const isNameString = str => {
55
- if (typeof str !== 'string' || str.length === 0 || str.length > 1000) {
56
- return false;
57
- }
58
- return /^[A-Za-z][0-9a-zA-Z-_.,'() ]+$/.test(str.trim());
72
+ if (typeof str !== 'string' || str.length === 0 || str.length > 1000) {
73
+ return false;
74
+ }
75
+ return /^[A-Za-z][0-9a-zA-Z-_.,'() ]+$/.test(str.trim());
59
76
  };
60
77
 
61
78
  const isSafeSearchString = str => {
62
- if (typeof str !== 'string' || str.length === 0) return false;
63
- return /^[A-Za-z][0-9a-zA-Z\-_.,'()@ ]{1,100}$/.test(str.trim());
79
+ if (typeof str !== 'string' || str.length === 0) {
80
+ return false;
81
+ }
82
+ return /^[A-Za-z][0-9a-zA-Z\-_.,'()@ ]{1,100}$/.test(str.trim());
64
83
  };
65
84
 
66
85
  const isEmailString = email => {
67
- if (typeof email !== 'string' || email.length === 0 || email.length > 320) {
68
- return false;
69
- }
70
- // Simplified safe email regex
71
- const regExpEmail =
72
- /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-zA-Z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/;
73
- return regExpEmail.test(email);
86
+ if (typeof email !== 'string' || email.length === 0 || email.length > 320) {
87
+ return false;
88
+ }
89
+ // Simplified safe email regex
90
+ const regExpEmail =
91
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-zA-Z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/;
92
+ return regExpEmail.test(email);
74
93
  };
75
94
 
76
95
  const isJwtString = jwt => {
77
- if (typeof jwt !== 'string' || jwt.length === 0 || jwt.length > 8192 || jwt.trim() === '') return false;
78
- const jwtRegex = /^eyJ[a-zA-Z0-9-_.]+$/;
79
- return jwtRegex.test(jwt);
96
+ if (typeof jwt !== 'string' || jwt.length === 0 || jwt.length > 8192 || jwt.trim() === '') {
97
+ return false;
98
+ }
99
+ const jwtRegex = /^eyJ[a-zA-Z0-9-_.]+$/;
100
+ return jwtRegex.test(jwt);
80
101
  };
81
102
 
82
103
  const isPasswordString = password => {
83
- if (typeof password !== 'string' || password.length === 0 || password.length > 128) return false;
84
- const regExPassword = /^(?=.*[a-zA-Z0-9])(?=.*[!@#$%^&*_-])[a-zA-Z0-9!@#$%^&*_-]{6,32}$/;
85
- return regExPassword.test(String(password));
104
+ if (typeof password !== 'string' || password.length === 0 || password.length > 128) {
105
+ return false;
106
+ }
107
+ const regExPassword = /^(?=.*[a-zA-Z0-9])(?=.*[!@#$%^&*_-])[a-zA-Z0-9!@#$%^&*_-]{6,32}$/;
108
+ return regExPassword.test(String(password));
86
109
  };
87
110
 
88
111
  const isSimplePasswordString = password => {
89
- if (typeof password !== 'string' || password.length === 0 || password.length > 128) return false;
90
- const regExPassword = /^[a-zA-Z0-9!@#$%^&*_-]{6,32}$/;
91
- return regExPassword.test(String(password));
112
+ if (typeof password !== 'string' || password.length === 0 || password.length > 128) {
113
+ return false;
114
+ }
115
+ const regExPassword = /^[a-zA-Z0-9!@#$%^&*_-]{6,32}$/;
116
+ return regExPassword.test(String(password));
92
117
  };
93
118
 
94
119
  const isPasswordStringFailureMessage = password => {
95
- if (!isPasswordString(password)) {
96
- return 'Total 6 to 32 characters, numbers and one of !@#$%^&*_-';
97
- } else {
98
- return null;
99
- }
120
+ if (!isPasswordString(password)) {
121
+ return 'Total 6 to 32 characters, numbers and one of !@#$%^&*_-';
122
+ } else {
123
+ return null;
124
+ }
100
125
  };
101
126
 
102
127
  const isSimplePasswordStringFailureMessage = password => {
103
- if (!isSimplePasswordString(password)) {
104
- return 'Total 6 to 32 characters, numbers or !@#$%^&*_-';
105
- } else {
106
- return null;
107
- }
128
+ if (!isSimplePasswordString(password)) {
129
+ return 'Total 6 to 32 characters, numbers or !@#$%^&*_-';
130
+ } else {
131
+ return null;
132
+ }
108
133
  };
109
134
 
110
135
  const isUsernameString = str => {
111
- if (typeof str !== 'string' || str.length === 0 || str.length > 200) return false;
112
- return /^[0-9a-zA-Z]+$/.test(str);
136
+ if (typeof str !== 'string' || str.length === 0 || str.length > 200) {
137
+ return false;
138
+ }
139
+ return /^[0-9a-zA-Z]+$/.test(str);
113
140
  };
114
141
 
115
142
  function isPhoneNumber(str) {
116
- if (typeof str !== 'string' || str.length === 0 || str.length > 20) return false;
117
- return /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/.test(str);
143
+ if (typeof str !== 'string' || str.length === 0 || str.length > 20) {
144
+ return false;
145
+ }
146
+ return /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/.test(str);
118
147
  }
119
148
 
120
149
  const isUrlSafeString = inputString => {
121
- if (typeof inputString !== 'string' || inputString.length === 0 || inputString.length > 2048 || inputString.trim() === '') return false;
122
- const urlSafeRegex = /^[a-zA-Z0-9-_.]+$/;
123
- return urlSafeRegex.test(inputString);
150
+ if (
151
+ typeof inputString !== 'string' ||
152
+ inputString.length === 0 ||
153
+ inputString.length > 2048 ||
154
+ inputString.trim() === ''
155
+ ) {
156
+ return false;
157
+ }
158
+ const urlSafeRegex = /^[a-zA-Z0-9-_.]+$/;
159
+ return urlSafeRegex.test(inputString);
124
160
  };
125
161
 
126
162
  const isString6To24CharacterLong = password => {
127
- if (typeof password !== 'string' || password.length === 0) return false;
128
- return 6 <= password.length && password.length <= 24;
163
+ if (typeof password !== 'string' || password.length === 0) {
164
+ return false;
165
+ }
166
+ return 6 <= password.length && password.length <= 24;
129
167
  };
130
168
 
131
169
  const isString6To16CharacterLong = password => {
132
- if (typeof password !== 'string' || password.length === 0) return false;
133
- return 6 <= password.length && password.length <= 16;
170
+ if (typeof password !== 'string' || password.length === 0) {
171
+ return false;
172
+ }
173
+ return 6 <= password.length && password.length <= 16;
134
174
  };
135
175
 
136
176
  const isProvinceString = inputString => {
137
- const provinces = ['on', 'qc'];
177
+ const provinces = ['on', 'qc'];
138
178
 
139
- if (isNameString(inputString)) {
140
- return provinces.includes(inputString.toLowerCase().trim());
141
- }
179
+ if (isNameString(inputString)) {
180
+ return provinces.includes(inputString.toLowerCase().trim());
181
+ }
142
182
 
143
- return false;
183
+ return false;
144
184
  };
145
185
 
146
186
  const isBoolValue = inputValue => {
147
- return typeof inputValue === 'boolean' || inputValue === 'true' || inputValue === 'false';
187
+ return typeof inputValue === 'boolean' || inputValue === 'true' || inputValue === 'false';
148
188
  };
149
189
 
150
190
  const isPostalCodeString = inputString => {
151
- const postalCodeRegex = /^(?!.*[DFIOQU])[A-VXY][0-9][A-Z] ?[0-9][A-Z][0-9]$/i;
191
+ const postalCodeRegex = /^(?!.*[DFIOQU])[A-VXY][0-9][A-Z] ?[0-9][A-Z][0-9]$/i;
152
192
 
153
- if (isNameString(inputString)) {
154
- return postalCodeRegex.test(inputString.trim());
155
- }
193
+ if (isNameString(inputString)) {
194
+ return postalCodeRegex.test(inputString.trim());
195
+ }
156
196
 
157
- return false;
197
+ return false;
158
198
  };
159
199
 
160
200
  const isSafeString = str => {
161
- if (typeof str !== 'string' || str.length === 0 || str.length > 10000) return false;
162
- return /^[\da-zA-Z-_.,#*'()[\]: ]+$/.test(str);
201
+ if (typeof str !== 'string' || str.length === 0 || str.length > 10000) {
202
+ return false;
203
+ }
204
+ return /^[\da-zA-Z-_.,#*'()[\]: ]+$/.test(str);
163
205
  };
164
206
 
165
207
  const isTextString = str => {
166
- return typeof str === 'string' && str.length > 0 && str.length <= 10000;
208
+ return typeof str === 'string' && str.length > 0 && str.length <= 10000;
167
209
  };
168
210
 
169
211
  const isInStringArray = (StringArray, inputString) => {
170
- if (isNameString(inputString)) {
171
- return StringArray.includes(inputString.toLowerCase().trim());
172
- }
212
+ if (isNameString(inputString)) {
213
+ return StringArray.includes(inputString.toLowerCase().trim());
214
+ }
173
215
 
174
- return false;
216
+ return false;
175
217
  };
176
218
 
177
219
  const isUserRoleRequestStatusString = inputString => {
178
- const statuses = ['pending', 'approved', 'rejected', 'cancelled', 'expired', 'hidden', 'on_hold', 'in_progress', 'info_needed'];
179
- return isInStringArray(statuses, inputString);
220
+ const statuses = [
221
+ 'pending',
222
+ 'approved',
223
+ 'rejected',
224
+ 'cancelled',
225
+ 'expired',
226
+ 'hidden',
227
+ 'on_hold',
228
+ 'in_progress',
229
+ 'info_needed',
230
+ ];
231
+ return isInStringArray(statuses, inputString);
180
232
  };
181
233
 
182
234
  const isUserRoleRequestRoleString = inputString => {
183
- const roles = ['student', 'intern', 'volunteer'];
184
- return typeof inputString === 'string' && roles.includes(inputString.trim().toLowerCase());
235
+ const roles = ['student', 'intern', 'volunteer'];
236
+ return typeof inputString === 'string' && roles.includes(inputString.trim().toLowerCase());
185
237
  };
186
238
 
187
239
  const isCountryCodeString = str => {
188
- if (typeof str !== 'string' || str.length === 0 || str.length > 4) return false;
240
+ if (typeof str !== 'string' || str.length === 0 || str.length > 4) {
241
+ return false;
242
+ }
189
243
 
190
- const countryCodeRegex = /^\+[1-9][0-9]{0,2}$/;
244
+ const countryCodeRegex = /^\+[1-9][0-9]{0,2}$/;
191
245
 
192
- return countryCodeRegex.test(str);
246
+ return countryCodeRegex.test(str);
193
247
  };
194
248
 
195
249
  const isValidDomainName = domain => {
196
- if (typeof domain !== 'string' || domain.length === 0 || domain.length > 253) return false;
250
+ if (typeof domain !== 'string' || domain.length === 0 || domain.length > 253) {
251
+ return false;
252
+ }
253
+
254
+ const domainRegex =
255
+ /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/i;
256
+ return domainRegex.test(domain);
257
+ };
197
258
 
198
- const domainRegex = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/i;
199
- return domainRegex.test(domain);
259
+ // Pattern: Pure Function - validates calendar and clock fields without Date.parse normalization.
260
+ const hasValidTimestampFields = match => {
261
+ if (!match) {
262
+ return false;
263
+ }
264
+ const [, year, month, day, hour, minute, second] = match;
265
+ return (
266
+ isValidCalendarDate(Number(year), Number(month), Number(day)) &&
267
+ Number(hour) <= 23 &&
268
+ Number(minute) <= 59 &&
269
+ Number(second) <= 59
270
+ );
200
271
  };
201
272
 
273
+ // Pattern: Pure Function - validates the numeric UTC offset carried by a timestamp.
274
+ const hasValidTimestampOffset = match => {
275
+ const zone = match?.[7];
276
+ return zone === 'Z' || (Number(match?.[8]) <= 23 && Number(match?.[9]) <= 59);
277
+ };
278
+
279
+ // Pattern: Predicate - accepts only real ISO timestamps with an explicit time zone.
202
280
  const isValidTimestampzString = str => {
203
- if (typeof str !== 'string' || str.length === 0 || str.length > 64) return false;
204
- // ISO 8601 for UTC or with Offset: 2023-10-27T10:00:00Z or 2023-10-27T10:00:00+02:00
205
- const timestampzRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
206
- return timestampzRegex.test(str) && !isNaN(Date.parse(str));
281
+ if (typeof str !== 'string' || str.length === 0 || str.length > 64) {
282
+ return false;
283
+ }
284
+ // ISO 8601 for UTC or with Offset: 2023-10-27T10:00:00Z or 2023-10-27T10:00:00+02:00
285
+ const timestampzRegex =
286
+ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(Z|[+-](\d{2}):(\d{2}))$/;
287
+ const match = str.match(timestampzRegex);
288
+ return hasValidTimestampFields(match) && hasValidTimestampOffset(match);
207
289
  };
208
290
 
291
+ // Pattern: Predicate - accepts only real ISO local timestamps without a time zone.
209
292
  const isValidTimestampString = str => {
210
- if (typeof str !== 'string' || str.length === 0 || str.length > 64) return false;
211
- // ISO 8601 without time zone: 2023-10-27T10:00:00 or 2023-10-27T10:00:00.123
212
- const timestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$/;
213
- return timestampRegex.test(str) && !isNaN(Date.parse(str));
293
+ if (typeof str !== 'string' || str.length === 0 || str.length > 64) {
294
+ return false;
295
+ }
296
+ // ISO 8601 without time zone: 2023-10-27T10:00:00 or 2023-10-27T10:00:00.123
297
+ const timestampRegex = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?$/;
298
+ return hasValidTimestampFields(str.match(timestampRegex));
214
299
  };
215
300
 
216
- const isValidDateString = str => {
217
- if (typeof str !== 'string' || str.length === 0 || str.length > 10) return false;
301
+ // Pattern: Pure Function - validates Gregorian date fields without runtime date coercion.
302
+ function isValidCalendarDate(year, month, day) {
303
+ if (year < 1 || month < 1 || month > 12 || day < 1) {
304
+ return false;
305
+ }
306
+ const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
307
+ const monthLengths = [31, leapYear ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
308
+ return day <= monthLengths[month - 1];
309
+ }
218
310
 
219
- const dateRegex = /^(\d{4})-(\d{2})-(\d{2})$/;
220
- const match = str.match(dateRegex);
221
- if (!match) return false;
311
+ // Pattern: Predicate - accepts only real Gregorian dates in YYYY-MM-DD form.
312
+ const isValidDateString = str => {
313
+ if (typeof str !== 'string' || str.length === 0 || str.length > 10) {
314
+ return false;
315
+ }
222
316
 
223
- const year = Number(match[1]);
224
- const month = Number(match[2]);
225
- const day = Number(match[3]);
226
- const date = new Date(Date.UTC(year, month - 1, day));
317
+ const dateRegex = /^(\d{4})-(\d{2})-(\d{2})$/;
318
+ const match = str.match(dateRegex);
319
+ if (!match) {
320
+ return false;
321
+ }
227
322
 
228
- return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
323
+ const year = Number(match[1]);
324
+ const month = Number(match[2]);
325
+ const day = Number(match[3]);
326
+ return isValidCalendarDate(year, month, day);
229
327
  };
230
328
 
231
329
  const isValidUrl = url => {
232
- if (typeof url !== 'string' || url.length === 0 || url.length > 2048) return false;
233
- if (!URL.canParse(url)) return false;
330
+ if (typeof url !== 'string' || url.length === 0 || url.length > 2048) {
331
+ return false;
332
+ }
333
+ if (!URL.canParse(url)) {
334
+ return false;
335
+ }
234
336
 
235
- const parsedUrl = new URL(url);
236
- return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:';
337
+ const parsedUrl = new URL(url);
338
+ return parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:';
237
339
  };
238
340
  const isValidArrayOfStrings = arr => {
239
- if (!Array.isArray(arr)) return false;
240
- return arr.every(isSafeString);
341
+ if (!Array.isArray(arr)) {
342
+ return false;
343
+ }
344
+ return arr.every(isSafeString);
241
345
  };
242
346
  module.exports = {
243
- isImageUrl,
244
- isInteger,
245
- isValidJsonString,
246
- isValidIntegerString,
247
- isValidUuidString,
248
- isCcIdString,
249
- isCharactersString,
250
- isStreetString,
251
- isNameString,
252
- isSafeSearchString,
253
- isEmailString,
254
- isJwtString,
255
- isPasswordString,
256
- isSimplePasswordString,
257
- isPasswordStringFailureMessage,
258
- isSimplePasswordStringFailureMessage,
259
- isUsernameString,
260
- isPhoneNumber,
261
- isUrlSafeString,
262
- isString6To24CharacterLong,
263
- isString6To16CharacterLong,
264
- isProvinceString,
265
- isBoolValue,
266
- isPostalCodeString,
267
- isSafeString,
268
- isTextString,
269
- isInStringArray,
270
- isUserRoleRequestStatusString,
271
- isUserRoleRequestRoleString,
272
- isCountryCodeString,
273
- isValidDomainName,
274
- isValidTimestampzString,
275
- isValidTimestampString,
276
- isValidDateString,
277
- isValidUrl,
278
- isValidArrayOfStrings,
347
+ isImageUrl,
348
+ isInteger,
349
+ isValidJsonString,
350
+ isValidIntegerString,
351
+ isValidUuidString,
352
+ isCcIdString,
353
+ isCharactersString,
354
+ isStreetString,
355
+ isNameString,
356
+ isSafeSearchString,
357
+ isEmailString,
358
+ isJwtString,
359
+ isPasswordString,
360
+ isSimplePasswordString,
361
+ isPasswordStringFailureMessage,
362
+ isSimplePasswordStringFailureMessage,
363
+ isUsernameString,
364
+ isPhoneNumber,
365
+ isUrlSafeString,
366
+ isString6To24CharacterLong,
367
+ isString6To16CharacterLong,
368
+ isProvinceString,
369
+ isBoolValue,
370
+ isPostalCodeString,
371
+ isSafeString,
372
+ isTextString,
373
+ isInStringArray,
374
+ isUserRoleRequestStatusString,
375
+ isUserRoleRequestRoleString,
376
+ isCountryCodeString,
377
+ isValidDomainName,
378
+ isValidTimestampzString,
379
+ isValidTimestampString,
380
+ isValidDateString,
381
+ isValidUrl,
382
+ isValidArrayOfStrings,
279
383
  };