@spudlabs/guardis 0.4.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 (106) hide show
  1. package/README.md +901 -0
  2. package/esm/mod.d.ts +55 -0
  3. package/esm/mod.d.ts.map +1 -0
  4. package/esm/mod.js +43 -0
  5. package/esm/package.json +3 -0
  6. package/esm/specs/standard-schema-spec.v1.d.ts +56 -0
  7. package/esm/specs/standard-schema-spec.v1.d.ts.map +1 -0
  8. package/esm/specs/standard-schema-spec.v1.js +1 -0
  9. package/esm/src/batch.d.ts +23 -0
  10. package/esm/src/batch.d.ts.map +1 -0
  11. package/esm/src/batch.js +23 -0
  12. package/esm/src/brand.d.ts +62 -0
  13. package/esm/src/brand.d.ts.map +1 -0
  14. package/esm/src/brand.js +9 -0
  15. package/esm/src/context.d.ts +19 -0
  16. package/esm/src/context.d.ts.map +1 -0
  17. package/esm/src/context.js +41 -0
  18. package/esm/src/extend.d.ts +23 -0
  19. package/esm/src/extend.d.ts.map +1 -0
  20. package/esm/src/extend.js +9 -0
  21. package/esm/src/guard.d.ts +288 -0
  22. package/esm/src/guard.d.ts.map +1 -0
  23. package/esm/src/guard.js +631 -0
  24. package/esm/src/helpers/http.helpers.d.ts +3 -0
  25. package/esm/src/helpers/http.helpers.d.ts.map +1 -0
  26. package/esm/src/helpers/http.helpers.js +2 -0
  27. package/esm/src/helpers/strings.helpers.d.ts +18 -0
  28. package/esm/src/helpers/strings.helpers.d.ts.map +1 -0
  29. package/esm/src/helpers/strings.helpers.js +47 -0
  30. package/esm/src/introspect.d.ts +36 -0
  31. package/esm/src/introspect.d.ts.map +1 -0
  32. package/esm/src/introspect.js +25 -0
  33. package/esm/src/modules/async.d.ts +27 -0
  34. package/esm/src/modules/async.d.ts.map +1 -0
  35. package/esm/src/modules/async.js +38 -0
  36. package/esm/src/modules/http.branded.d.ts +42 -0
  37. package/esm/src/modules/http.branded.d.ts.map +1 -0
  38. package/esm/src/modules/http.branded.js +24 -0
  39. package/esm/src/modules/http.d.ts +46 -0
  40. package/esm/src/modules/http.d.ts.map +1 -0
  41. package/esm/src/modules/http.js +59 -0
  42. package/esm/src/modules/strings.branded.d.ts +185 -0
  43. package/esm/src/modules/strings.branded.d.ts.map +1 -0
  44. package/esm/src/modules/strings.branded.js +123 -0
  45. package/esm/src/modules/strings.d.ts +109 -0
  46. package/esm/src/modules/strings.d.ts.map +1 -0
  47. package/esm/src/modules/strings.js +147 -0
  48. package/esm/src/types.d.ts +318 -0
  49. package/esm/src/types.d.ts.map +1 -0
  50. package/esm/src/types.js +1 -0
  51. package/esm/src/utilities.d.ts +95 -0
  52. package/esm/src/utilities.d.ts.map +1 -0
  53. package/esm/src/utilities.js +196 -0
  54. package/package.json +40 -0
  55. package/script/mod.d.ts +55 -0
  56. package/script/mod.d.ts.map +1 -0
  57. package/script/mod.js +83 -0
  58. package/script/package.json +3 -0
  59. package/script/specs/standard-schema-spec.v1.d.ts +56 -0
  60. package/script/specs/standard-schema-spec.v1.d.ts.map +1 -0
  61. package/script/specs/standard-schema-spec.v1.js +2 -0
  62. package/script/src/batch.d.ts +23 -0
  63. package/script/src/batch.d.ts.map +1 -0
  64. package/script/src/batch.js +26 -0
  65. package/script/src/brand.d.ts +62 -0
  66. package/script/src/brand.d.ts.map +1 -0
  67. package/script/src/brand.js +12 -0
  68. package/script/src/context.d.ts +19 -0
  69. package/script/src/context.d.ts.map +1 -0
  70. package/script/src/context.js +45 -0
  71. package/script/src/extend.d.ts +23 -0
  72. package/script/src/extend.d.ts.map +1 -0
  73. package/script/src/extend.js +12 -0
  74. package/script/src/guard.d.ts +288 -0
  75. package/script/src/guard.d.ts.map +1 -0
  76. package/script/src/guard.js +640 -0
  77. package/script/src/helpers/http.helpers.d.ts +3 -0
  78. package/script/src/helpers/http.helpers.d.ts.map +1 -0
  79. package/script/src/helpers/http.helpers.js +5 -0
  80. package/script/src/helpers/strings.helpers.d.ts +18 -0
  81. package/script/src/helpers/strings.helpers.d.ts.map +1 -0
  82. package/script/src/helpers/strings.helpers.js +52 -0
  83. package/script/src/introspect.d.ts +36 -0
  84. package/script/src/introspect.d.ts.map +1 -0
  85. package/script/src/introspect.js +31 -0
  86. package/script/src/modules/async.d.ts +27 -0
  87. package/script/src/modules/async.d.ts.map +1 -0
  88. package/script/src/modules/async.js +41 -0
  89. package/script/src/modules/http.branded.d.ts +42 -0
  90. package/script/src/modules/http.branded.d.ts.map +1 -0
  91. package/script/src/modules/http.branded.js +30 -0
  92. package/script/src/modules/http.d.ts +46 -0
  93. package/script/src/modules/http.d.ts.map +1 -0
  94. package/script/src/modules/http.js +62 -0
  95. package/script/src/modules/strings.branded.d.ts +185 -0
  96. package/script/src/modules/strings.branded.d.ts.map +1 -0
  97. package/script/src/modules/strings.branded.js +126 -0
  98. package/script/src/modules/strings.d.ts +109 -0
  99. package/script/src/modules/strings.d.ts.map +1 -0
  100. package/script/src/modules/strings.js +150 -0
  101. package/script/src/types.d.ts +318 -0
  102. package/script/src/types.d.ts.map +1 -0
  103. package/script/src/types.js +2 -0
  104. package/script/src/utilities.d.ts +95 -0
  105. package/script/src/utilities.d.ts.map +1 -0
  106. package/script/src/utilities.js +207 -0
@@ -0,0 +1,631 @@
1
+ /**
2
+ * guard.ts
3
+ * @module
4
+ */
5
+ import { createContext, createStrictContext } from "./context.js";
6
+ import { hasContext, hasName } from "./introspect.js";
7
+ import { doesNotHaveProperty, formatErrorMessage, hasOptionalProperty, hasProperty, includes, keyOf, tupleHas, unionOf, } from "./utilities.js";
8
+ /**
9
+ * Creates a helpers object for use in type guard parsers.
10
+ * When ctx is provided, has/hasOptional pass context for path tracking.
11
+ * When ctx is undefined, they use raw functions (for boolean type guard calls).
12
+ */
13
+ function createHelpers(ctx) {
14
+ return {
15
+ has: (t, k, guard, errorMessage) => hasProperty(t, k, guard, ctx?.pushPath(k), ctx ? errorMessage : undefined),
16
+ hasNot: (t, k, errorMessage) => doesNotHaveProperty(t, k, ctx?.pushPath(k), ctx ? errorMessage : undefined),
17
+ hasOptional: (t, k, guard, errorMessage) => hasOptionalProperty(t, k, guard, ctx?.pushPath(k), ctx ? errorMessage : undefined),
18
+ tupleHas,
19
+ includes,
20
+ keyOf: (k, t, errorMessage) => keyOf(k, t, ctx, ctx ? errorMessage : undefined),
21
+ fail: (message) => {
22
+ if (ctx)
23
+ ctx.addIssue(message);
24
+ return null;
25
+ },
26
+ _ctx: ctx,
27
+ };
28
+ }
29
+ /** Default helpers for boolean type guard calls (no validation context) */
30
+ const defaultHelpers = createHelpers();
31
+ /**
32
+ * Checks if a value is a TypeGuardShape object (plain object, not a function).
33
+ * Uses raw checks instead of isObject/isFunction to avoid temporal dead zone
34
+ * issues — this function is called during createTypeGuard's implementation,
35
+ * which runs before isObject and isFunction are initialized.
36
+ */
37
+ function isTypeGuardShape(value) {
38
+ return typeof value === "object" && value !== null && !Array.isArray(value) &&
39
+ typeof value !== "function";
40
+ }
41
+ function isRecord(value) {
42
+ return typeof value === "object" && value !== null && !Array.isArray(value);
43
+ }
44
+ /** Adds issues from a guard result to the context if not already tracked. */
45
+ function propagateIssues(issues, key, ctx) {
46
+ for (const issue of issues) {
47
+ const alreadyTracked = ctx.issues.some((i) => i.message === issue.message &&
48
+ JSON.stringify(i.path) === JSON.stringify(issue.path));
49
+ if (!alreadyTracked) {
50
+ ctx.issues.push({ message: issue.message, path: issue.path ?? [key] });
51
+ }
52
+ }
53
+ }
54
+ /**
55
+ * Validates a single shape field against its guard.
56
+ * When ctx is provided, issues are pushed to the shared context.
57
+ * When ctx is absent, issues are collected into localIssues.
58
+ */
59
+ function validateField(obj, key, guard, ctx, localIssues, result) {
60
+ const childCtx = ctx?.pushPath(key);
61
+ // Nested shape — recurse
62
+ if (isTypeGuardShape(guard)) {
63
+ const r = validateShape(obj[key], guard, childCtx);
64
+ if ("value" in r) {
65
+ result[key] = r.value;
66
+ }
67
+ else if (!childCtx) {
68
+ localIssues.push(...r.issues);
69
+ }
70
+ return;
71
+ }
72
+ if (typeof guard !== "function")
73
+ return;
74
+ // Context-aware guard (TypeGuard with _.context)
75
+ if (hasContext(guard)) {
76
+ const guardCtx = childCtx ?? createContext([key]);
77
+ const r = guard._.context(obj[key], guardCtx);
78
+ if ("value" in r) {
79
+ result[key] = r.value;
80
+ }
81
+ else if (childCtx) {
82
+ propagateIssues(r.issues, key, ctx);
83
+ }
84
+ else {
85
+ localIssues.push(...r.issues);
86
+ }
87
+ return;
88
+ }
89
+ // Plain boolean guard
90
+ if (guard(obj[key])) {
91
+ result[key] = obj[key];
92
+ return;
93
+ }
94
+ const message = `Validation failed for property "${String(key)}"`;
95
+ if (childCtx) {
96
+ childCtx.addIssue(message);
97
+ }
98
+ else {
99
+ localIssues.push({ message, path: [key] });
100
+ }
101
+ }
102
+ /**
103
+ * Recursively validates a value against a TypeGuardShape.
104
+ * When ctx is provided, issues are pushed to the shared context for path tracking.
105
+ * When ctx is absent, issues are collected locally and returned.
106
+ */
107
+ function validateShape(value, shape, ctx) {
108
+ if (!isRecord(value)) {
109
+ const message = "Expected an object";
110
+ if (!ctx)
111
+ return { issues: [{ message }] };
112
+ ctx.addIssue(message);
113
+ return { issues: ctx.issues };
114
+ }
115
+ const result = {};
116
+ const localIssues = [];
117
+ for (const key of Object.keys(shape)) {
118
+ validateField(value, key, shape[key], ctx, localIssues, result);
119
+ }
120
+ const issues = ctx ? ctx.issues : localIssues;
121
+ return issues.length > 0 ? { issues } : { value: result };
122
+ }
123
+ /**
124
+ * Creates a type guard that strictly checks the type, throwing
125
+ * a TypeError if it fails. Uses strict context for detailed error messages
126
+ * with path information on nested validations.
127
+ * @param parser The parser function to use for validation
128
+ * @param name Optional name of the type guard for error messages
129
+ * @returns A strict type guard that throws on failure
130
+ */
131
+ const createStrictTypeGuard = (parser, name) => {
132
+ return (value, errorMsg) => {
133
+ const ctx = createStrictContext();
134
+ const helpers = createHelpers(ctx);
135
+ const result = parser(value, helpers);
136
+ if (result === null) {
137
+ throw new TypeError(errorMsg ?? formatErrorMessage(value, name));
138
+ }
139
+ return true;
140
+ };
141
+ };
142
+ /**
143
+ * Creates a callback to construct a union type guard from two existing type guards.
144
+ *
145
+ * @template T1 - The type checked by the first type guard.
146
+ * @template T2 - The type checked by the second type guard.
147
+ *
148
+ * @param guard - A type guard function that checks if a value is of type `T1`.
149
+ * @returns A function that takes a second type guard `guardTwo` and returns a new
150
+ * type guard that checks if a value is of type `T1 | T2`.
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const isString = (value: unknown): value is string => typeof value === 'string';
155
+ * const isNumber = (value: unknown): value is number => typeof value === 'number';
156
+ *
157
+ * const isStringOrNumber = createOrTypeGuard(isString)(isNumber);
158
+ *
159
+ * console.log(isStringOrNumber("hello")); // true
160
+ * console.log(isStringOrNumber(42)); // true
161
+ * console.log(isStringOrNumber(false)); // false
162
+ * ```
163
+ */
164
+ const createOrTypeGuard = (guard) => (guardTwo) => {
165
+ // Create a union of the names of the two guards for better error messages, if available.
166
+ const name = hasName(guard) && hasName(guardTwo)
167
+ ? `${guard._.name} | ${guardTwo._.name}`
168
+ : undefined;
169
+ const parser = (v) => {
170
+ if (guard(v) || guardTwo(v))
171
+ return v === null ? true : v;
172
+ return null;
173
+ };
174
+ return name ? createTypeGuard(name, parser) : createTypeGuard(parser);
175
+ };
176
+ /**
177
+ * Creates a notEmpty variant of a type guard that rejects empty values
178
+ * (null, undefined, empty string, empty array, empty object).
179
+ */
180
+ const createNotEmptyTypeGuard = (guard) => {
181
+ const notEmpty = (value) => !isEmpty(value) && guard(value);
182
+ const name = hasName(guard) ? `non-empty ${guard._.name}` : undefined;
183
+ const notEmptyParser = (value) => notEmpty(value) && guard(value) ? value : null;
184
+ const context = (value, ctx) => {
185
+ if (notEmpty(value))
186
+ return { value };
187
+ const message = formatErrorMessage(value, name);
188
+ const path = ctx?.path.length ? [...ctx.path] : undefined;
189
+ return { issues: [path ? { message, path } : { message }] };
190
+ };
191
+ notEmpty._ = {
192
+ name,
193
+ parser: notEmptyParser,
194
+ context,
195
+ };
196
+ notEmpty.strict = createStrictTypeGuard(notEmptyParser, name);
197
+ notEmpty.assert = notEmpty.strict;
198
+ notEmpty.validate = (value) => context(value, createContext());
199
+ const notEmptyOptional = (value) => guard(value) ? notEmpty(value) : isUndefined(value);
200
+ const optionalName = name ? `${name} | undefined` : undefined;
201
+ const optionalParser = (v) => notEmptyOptional(v) ? v : null;
202
+ notEmptyOptional.strict = createStrictTypeGuard(optionalParser, optionalName);
203
+ notEmptyOptional.assert = notEmptyOptional.strict;
204
+ notEmptyOptional.validate = (value) => {
205
+ if (isUndefined(value))
206
+ return { value: value };
207
+ return context(value, createContext());
208
+ };
209
+ notEmptyOptional.or = createOrTypeGuard(notEmptyOptional);
210
+ notEmpty.optional = notEmptyOptional;
211
+ notEmpty.or = createOrTypeGuard(notEmpty);
212
+ return notEmpty;
213
+ };
214
+ export function createTypeGuard(...args) {
215
+ const parserOrShape = args.length === 1 ? args[0] : args[1];
216
+ const name = args.length === 2 ? args[0] : undefined;
217
+ // Convert shape to parser, then continue with normal guard creation
218
+ const parser = isTypeGuardShape(parserOrShape)
219
+ ? (val, helpers) => {
220
+ const ctx = helpers._ctx;
221
+ const result = validateShape(val, parserOrShape, ctx);
222
+ return "value" in result ? result.value : null;
223
+ }
224
+ : parserOrShape;
225
+ /**
226
+ * Internal validation method that accepts a context for path tracking.
227
+ * This is used by nested validations to propagate paths.
228
+ */
229
+ const context = (value, ctx) => {
230
+ const issuesBefore = ctx?.issues.length ?? 0;
231
+ const helpers = createHelpers(ctx);
232
+ const result = parser(value, helpers);
233
+ // If parser returned null and no child issues were added, add this guard's error
234
+ if (result === null && ctx?.issues.length === issuesBefore) {
235
+ ctx.addIssue(formatErrorMessage(value, name));
236
+ }
237
+ // Return accumulated issues if any
238
+ if (ctx && ctx.issues.length > 0) {
239
+ return { issues: ctx.issues };
240
+ }
241
+ if (result !== null) {
242
+ // Special case: isNull parser returns `true` when value is null
243
+ return { value: result === true && value === null ? value : result };
244
+ }
245
+ return { issues: [{ message: formatErrorMessage(value, name) }] };
246
+ };
247
+ const callback = (value) => parser(value, defaultHelpers) !== null;
248
+ callback._ = { name, parser, context };
249
+ /**
250
+ * Creates a new type guard that checks if the value is of type T1 or T2.
251
+ * This is useful for creating unions of types.
252
+ * @param {Function} guard A type guard for T2
253
+ * @returns {Function} A new type guard that checks if the value is of type T1 or T2
254
+ */
255
+ callback.or = createOrTypeGuard(callback);
256
+ function extend(...args) {
257
+ const parserOrShape = args.length === 1 ? args[0] : args[1];
258
+ const extendName = args.length === 2 ? args[0] : undefined;
259
+ // Build a combined parser that first checks the base guard, then the extension
260
+ let combinedParser;
261
+ if (isTypeGuardShape(parserOrShape)) {
262
+ const shapeGuard = createTypeGuard(parserOrShape);
263
+ combinedParser = (v) => callback(v) && shapeGuard(v) ? v : null;
264
+ }
265
+ else {
266
+ combinedParser = (v, h) => callback(v) ? parserOrShape(v, h) : null;
267
+ }
268
+ if (extendName) {
269
+ return createTypeGuard(extendName, combinedParser);
270
+ }
271
+ return createTypeGuard(combinedParser);
272
+ }
273
+ callback.extend = extend;
274
+ /**
275
+ * Returns false if the value fails the "empty" type guard
276
+ * or if it fails the parser.
277
+ * @param {unknown} value
278
+ * @returns
279
+ */
280
+ callback.notEmpty = createNotEmptyTypeGuard(callback);
281
+ /**
282
+ * Returns true if the value is undefined or passes the parser.
283
+ * @param {unknown} value
284
+ * @returns
285
+ */
286
+ const optional = (value) => isUndefined(value) || callback(value);
287
+ optional.strict = createStrictTypeGuard((v, h) => isUndefined(v) ? v : parser(v, h), name ? `${name} | undefined` : undefined);
288
+ optional.assert = optional.strict;
289
+ optional.validate = (value) => isUndefined(value) ? { value } : context(value, createContext());
290
+ optional.or = createOrTypeGuard(optional);
291
+ optional.notEmpty = callback.notEmpty.optional;
292
+ callback.optional = optional;
293
+ /**
294
+ * Throws a TypeError if the type guard fails. Optionally you may define an
295
+ * error message to be included.
296
+ * @param {unknown} value
297
+ * @param {string?} errorMsg Optional
298
+ * @returns
299
+ */
300
+ callback.strict = createStrictTypeGuard(parser, name);
301
+ callback.assert = callback.strict;
302
+ // StandardSchemaV1 compatibility - uses context-aware validation for path tracking
303
+ callback.validate = (value) => context(value, createContext());
304
+ callback["~standard"] = {
305
+ version: 1,
306
+ vendor: "guardis",
307
+ validate: callback.validate,
308
+ };
309
+ // Attach the type to the function for easy access
310
+ return ((t) => t)(callback);
311
+ }
312
+ function isParser(entry) {
313
+ return typeof entry === "function";
314
+ }
315
+ function isNamedParser(entry) {
316
+ return typeof entry === "object" && "parse" in entry && typeof entry.parse === "function";
317
+ }
318
+ /**
319
+ * Converts a ParserEntry (parser function, named parser object, or shape) into a TypeGuard.
320
+ * Shared by `batch` and `extend` to avoid duplicating entry detection logic.
321
+ */
322
+ export function entryToGuard(entry) {
323
+ if (isParser(entry))
324
+ return createTypeGuard(entry);
325
+ if (isNamedParser(entry))
326
+ return createTypeGuard(entry.name, entry.parse);
327
+ return createTypeGuard(entry);
328
+ }
329
+ /**
330
+ * Returns true if input satisfies type boolean.
331
+ * @param {unknown} t
332
+ * @return {boolean}
333
+ */
334
+ export const isBoolean = createTypeGuard("boolean", (t) => typeof t === "boolean" ? t : null);
335
+ /**
336
+ * Returns true if input satisfies type string.
337
+ * @param {unknown} t
338
+ * @return {boolean}
339
+ */
340
+ export const isString = createTypeGuard("string", (t) => typeof t === "string" ? t : null);
341
+ /**
342
+ * Returns true if input satisfies type number. Returns false if `NaN` is passed.
343
+ *
344
+ * While `NaN` is technically a number in JavaScript, it is not a valid value for many applications
345
+ * and will fail if used with common numeric operations.
346
+ *
347
+ * @param {unknown} t
348
+ * @return {boolean}
349
+ */
350
+ export const isNumber = createTypeGuard("number", (t) => typeof t === "number" && !Number.isNaN(t) ? t : null);
351
+ /**
352
+ * Returns true if input satisfies type symbol.
353
+ * @param {unknown} t
354
+ * @return {boolean}
355
+ */
356
+ export const isSymbol = createTypeGuard("symbol", (t) => typeof t === "symbol" ? t : null);
357
+ /**
358
+ * Returns true if input satisfies type binary.
359
+ * @param {unknown} t
360
+ * @return {boolean}
361
+ */
362
+ export const isBinary = createTypeGuard("binary", (t) => t === 1 || t === 0 ? t : null);
363
+ /**
364
+ * Returns true if input satisfies type numeric.
365
+ * @param {unknown} t
366
+ * @return {boolean}
367
+ */
368
+ export const isNumeric = createTypeGuard("numeric", (t) => {
369
+ if (isNumber(t))
370
+ return t;
371
+ if (!/^-?\d*\.?\d+$/.test(t))
372
+ return null;
373
+ const _t = parseInt(t) || parseFloat(t);
374
+ return (!isNaN(_t) && isNumber(_t)) ? t : null;
375
+ });
376
+ /**
377
+ * Returns true if input satisfies type Function.
378
+ * @param {unknown} t
379
+ * @return {boolean}
380
+ */
381
+ export const isFunction = createTypeGuard("function", (t) => typeof t === "function" ? t : null);
382
+ /**
383
+ * Returns true if input satisfies type undefined.
384
+ * @param {unknown} t
385
+ * @return {boolean}
386
+ */
387
+ export const isUndefined = createTypeGuard("undefined", (t) => t === undefined ? t : null);
388
+ /**
389
+ * Returns true if input satisfies type null.
390
+ * @param {unknown} t
391
+ * @return {boolean}
392
+ */
393
+ const isNull = createTypeGuard("null", (t) => (t === null ? true : null));
394
+ /**
395
+ * Returns true if input is a JSON-able primitive date type
396
+ * @param {unknown} t
397
+ * @return {boolean}
398
+ */
399
+ export const isJsonPrimitive = unionOf(isBoolean, isString, isNumber, isNull);
400
+ /**
401
+ * Returns true if input satisfies type object. _BEWARE_ object
402
+ * can apply to many different types, including arrays. This
403
+ * is not as type safe as you might think.
404
+ * @param {unknown} t
405
+ * @return {boolean}
406
+ */
407
+ export const isObject = createTypeGuard("object", (t) => t && typeof t === "object" && !Array.isArray(t) ? t : null);
408
+ /** Returns true if input satisfies type PropertyKey.
409
+ * @param {unknown} t
410
+ * @return {boolean}
411
+ */
412
+ export const isPropertyKey = unionOf(isString, isNumber, isSymbol);
413
+ /**
414
+ * Returns true if input satisfies type object. _BEWARE_ object
415
+ * can apply to many different types, including arrays. This
416
+ * is not as type safe as you might think.
417
+ * @param {unknown} t
418
+ * @return {boolean}
419
+ */
420
+ export const isJsonObject = createTypeGuard("JsonObject", (t) => {
421
+ if (t && typeof t === "object" &&
422
+ Object.getPrototypeOf(t) === Object.prototype) {
423
+ for (const v of Object.values(t)) {
424
+ if (!isJsonValue(v))
425
+ return null;
426
+ }
427
+ return t;
428
+ }
429
+ return null;
430
+ });
431
+ /** Precursor to full isArray guard */
432
+ const _isArray = createTypeGuard("array", (t) => Array.isArray(t) ? t : null);
433
+ /**
434
+ * Returns true if input satisfies type array.
435
+ * @param {unknown} t
436
+ * @return {boolean}
437
+ */
438
+ export const isArray = Object.assign(_isArray, {
439
+ of: (guard) => {
440
+ const guardName = hasName(guard) ? guard._.name : undefined;
441
+ let name = "array";
442
+ if (guardName) {
443
+ name = guardName?.includes(" | ") ? `(${guardName})[]` : `${guardName}[]`;
444
+ }
445
+ return createTypeGuard(name, (v, helpers) => {
446
+ if (!isArray(v))
447
+ return null;
448
+ const ctx = helpers._ctx;
449
+ // If we have a context, use index-aware validation
450
+ if (ctx && hasContext(guard)) {
451
+ for (let i = 0; i < v.length; i++) {
452
+ const childCtx = ctx.pushPath(i);
453
+ const result = guard._.context(v[i], childCtx);
454
+ if (result.issues)
455
+ return null; // issues already added to parent ctx
456
+ }
457
+ return v;
458
+ }
459
+ // Otherwise, use simple boolean check
460
+ return v.every((item) => guard(item)) ? v : null;
461
+ });
462
+ },
463
+ });
464
+ /**
465
+ * Returns true if input satisfies type array.
466
+ * @param {unknown} t
467
+ * @return {boolean}
468
+ */
469
+ export const isJsonArray = createTypeGuard("JsonArray", (t) => Array.isArray(t) ? t : null);
470
+ /**
471
+ * Checks if a given value is a valid JSON value.
472
+ *
473
+ * This type guard leverages helper functions to determine if the provided value is a valid JSON
474
+ * primitive, JSON array, or JSON object. If the value satisfies any of these conditions, it is
475
+ * considered a valid JSON value.
476
+ *
477
+ * @param t - The value to be checked.
478
+ * @returns The value itself if it is a valid JSON value; otherwise, returns null.
479
+ *
480
+ * @remarks
481
+ * - For primitive types, arrays, and objects, the guard confirms conformance with the JSON value standards.
482
+ *
483
+ * @example
484
+ * const value: unknown = getValue();
485
+ * const jsonValue = isJsonValue(value);
486
+ * if (jsonValue !== null) {
487
+ * // Work with the confirmed JSON value.
488
+ * }
489
+ */
490
+ export const isJsonValue = unionOf(isJsonPrimitive, isJsonArray, isJsonObject);
491
+ /**
492
+ * A type guard function that checks if a value is a Date object.
493
+ *
494
+ * @param t - The value to check
495
+ * @returns The original Date object if the value is a Date, otherwise null
496
+ *
497
+ * @example
498
+ * ```typescript
499
+ * const maybeDate: unknown = new Date();
500
+ *
501
+ * if (isDate(maybeDate)) {
502
+ * // maybeDate is now typed as Date
503
+ * console.log(maybeDate.toISOString());
504
+ * }
505
+ * ```
506
+ */
507
+ export const isDate = createTypeGuard("Date", (t) => t instanceof Date ? t : null);
508
+ /**
509
+ * Returns true if input satisfies type null or undefined.
510
+ * @param {unknown} t
511
+ * @return {boolean}
512
+ */
513
+ const isNil = isNull.or(isUndefined);
514
+ const isEmptyRecord = createTypeGuard("{}", (t) => {
515
+ if (t && typeof t === "object" && Object.getPrototypeOf(t) === Object.prototype &&
516
+ Object.keys(t).length === 0) {
517
+ return t;
518
+ }
519
+ return null;
520
+ });
521
+ const isEmptyArray = createTypeGuard("[]", (t) => Array.isArray(t) && t.length === 0 ? t : null);
522
+ const isEmptyString = createTypeGuard('""', (t) => typeof t === "string" ? t === "" ? t : t?.trim?.() === "" ? t : null : null);
523
+ /**
524
+ * Returns true if input is undefined, null, empty string, object with length
525
+ * of 0 or object without enumerable keys.
526
+ *
527
+ * Strings are trimmed when evaluated.
528
+ * @param {unknown} t
529
+ * @return {boolean}
530
+ */
531
+ const isEmpty = isNull
532
+ .or(isUndefined)
533
+ .or(isEmptyString)
534
+ .or(isEmptyArray)
535
+ .or(isEmptyRecord);
536
+ /**
537
+ * Returns true if the value is iterable (has Symbol.iterator). Does not
538
+ * check the type contained within the iterable.
539
+ * @param t
540
+ * @returns
541
+ */
542
+ const isIterable = createTypeGuard("Iterable", (t) => {
543
+ if (typeof t === "object" &&
544
+ !isNil(t) &&
545
+ Symbol.iterator in t &&
546
+ isFunction(t[Symbol.iterator])) {
547
+ return t;
548
+ }
549
+ return null;
550
+ });
551
+ /**
552
+ * Type guard that checks if a value is a tuple (array) of a specific length.
553
+ *
554
+ * A tuple is an array with a fixed number of elements. This function validates
555
+ * that the input is an array and has exactly the specified length.
556
+ *
557
+ * @typeParam N - The expected length of the tuple
558
+ * @param t - The value to check
559
+ * @param length - The expected length of the tuple
560
+ * @returns Type predicate indicating if the value is a tuple of length N
561
+ *
562
+ * @example
563
+ * ```typescript
564
+ * const value: unknown = [1, 2, 3];
565
+ *
566
+ * if (isTuple(value, 3)) {
567
+ * // value is now typed as [unknown, unknown, unknown]
568
+ * console.log(value.length); // 3
569
+ * }
570
+ *
571
+ * // Check for empty tuple
572
+ * if (isTuple([], 0)) {
573
+ * console.log("Empty tuple");
574
+ * }
575
+ * ```
576
+ */
577
+ const isTuple = (t, length) => {
578
+ return Array.isArray(t) && t.length === length;
579
+ };
580
+ /**
581
+ * Strict version of isTuple that throws a TypeError if the value is not a tuple of the specified length.
582
+ * @typeParam N - The expected length of the tuple
583
+ * @param t - The value to check
584
+ * @param length - The expected length of the tuple
585
+ * @param errorMsg - Optional custom error message
586
+ * @returns true if the value is a tuple of the specified length
587
+ * @throws {TypeError} If the value is not a tuple of the specified length
588
+ */
589
+ isTuple.strict = (t, length, errorMsg) => {
590
+ if (!isTuple(t, length)) {
591
+ throw TypeError(errorMsg ?? `Type guard failed. Value is not a tuple of length ${length}.`);
592
+ }
593
+ return true;
594
+ };
595
+ /**
596
+ * Assertion function that throws an error if the value is not a tuple of the specified length.
597
+ * TypeScript will narrow the type to TupleOfLength<N> after this assertion.
598
+ * @typeParam N - The expected length of the tuple
599
+ * @param t - The value to check
600
+ * @param length - The expected length of the tuple
601
+ * @param errorMsg - Optional custom error message
602
+ * @throws {TypeError} If the value is not a tuple of the specified length
603
+ */
604
+ isTuple.assert = isTuple.strict;
605
+ /**
606
+ * Creates a union type guard that checks if a value is a tuple of specified length OR matches another type.
607
+ * @param length - The expected length of the tuple
608
+ * @param guard - The type guard to combine with isTuple
609
+ * @returns A new type guard for TupleOfLength<N> | T2
610
+ */
611
+ isTuple.or = (length, guard) => {
612
+ return createTypeGuard((v) => isTuple(v, length) ? v : guard._.parser(v, defaultHelpers));
613
+ };
614
+ // Define the optional methods for isTuple
615
+ const isTupleOptional = (t, length) => isUndefined(t) || isTuple(t, length);
616
+ isTupleOptional.strict = (t, length, errorMsg) => {
617
+ if (!isTupleOptional(t, length)) {
618
+ throw TypeError(errorMsg ?? `Type guard failed. Value is not a tuple of length ${length} or undefined.`);
619
+ }
620
+ return true;
621
+ };
622
+ isTupleOptional.assert = isTupleOptional.strict;
623
+ /**
624
+ * Optional variant of isTuple that accepts undefined or a tuple of the specified length.
625
+ * @typeParam N - The expected length of the tuple
626
+ * @param t - The value to check
627
+ * @param length - The expected length of the tuple
628
+ * @returns true if the value is undefined or a tuple of the specified length, otherwise false
629
+ */
630
+ isTuple.optional = isTupleOptional;
631
+ export { isEmpty, isIterable, isNil, isNull, isTuple };
@@ -0,0 +1,3 @@
1
+ export declare const IPV4_REGEX: RegExp;
2
+ export declare const IPV6_REGEX: RegExp;
3
+ //# sourceMappingURL=http.helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.helpers.d.ts","sourceRoot":"","sources":["../../../src/src/helpers/http.helpers.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,QAAiD,CAAC;AACzE,eAAO,MAAM,UAAU,QAC6F,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const IPV4_REGEX = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
2
+ export const IPV6_REGEX = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:)*::([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4}$|^::1$|^::$/;
@@ -0,0 +1,18 @@
1
+ export declare function splitToWords(input: string): [] | RegExpMatchArray;
2
+ export declare function capitalizeWord(word: string): string;
3
+ /**
4
+ * Converts a string into PascalCase.
5
+ *
6
+ * @example Usage
7
+ * ```ts
8
+ * import { toPascalCase } from "@std/text/to-pascal-case";
9
+ * import { assertEquals } from "@std/assert";
10
+ *
11
+ * assertEquals(toPascalCase("deno is awesome"), "DenoIsAwesome");
12
+ * ```
13
+ *
14
+ * @param input The string that is going to be converted into PascalCase
15
+ * @returns The string as PascalCase
16
+ */
17
+ export declare function toPascalCase(input: string): string;
18
+ //# sourceMappingURL=strings.helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strings.helpers.d.ts","sourceRoot":"","sources":["../../../src/src/helpers/strings.helpers.ts"],"names":[],"mappings":"AAiCA,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,yBAEzC;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGlD"}