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