@murky-web/typebuddy 0.1.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 +177 -0
- package/biome/index.ts +6 -0
- package/biome/maybe_promise_rule.grit +15 -0
- package/biome/maybe_rule.grit +11 -0
- package/biome/nullable_rule.grit +3 -0
- package/biome/optional_rule.gritt +8 -0
- package/biome/require-try-catch-async.grit +5 -0
- package/dist/biome.js +7 -0
- package/dist/globals.js +0 -0
- package/dist/index.js +2 -0
- package/dist/maybe_promise_rule.grit +15 -0
- package/dist/maybe_rule.grit +11 -0
- package/dist/nullable_rule.grit +3 -0
- package/dist/optional_rule.gritt +8 -0
- package/dist/oxlint.js +18 -0
- package/dist/require-try-catch-async.grit +5 -0
- package/dist/rules/async_rule.js +58 -0
- package/dist/rules/maybe_promise_rule.js +132 -0
- package/dist/rules/maybe_rule.js +34 -0
- package/dist/rules/nullable_rule.js +35 -0
- package/dist/rules/optional_rule.js +31 -0
- package/dist/type_helper.js +296 -0
- package/globals.ts +60 -0
- package/jsr.json +29 -0
- package/oxlint/index.ts +30 -0
- package/package.json +68 -0
- package/rules/async_rule.ts +98 -0
- package/rules/maybe_promise_rule.ts +247 -0
- package/rules/maybe_rule.ts +57 -0
- package/rules/nullable_rule.ts +59 -0
- package/rules/optional_rule.ts +54 -0
- package/src/index.ts +16 -0
- package/src/type_helper.ts +644 -0
- package/src/types/globals.ts +13 -0
- package/src/types/index.ts +20 -0
- package/src/types/json.ts +22 -0
- package/src/types/maybe.ts +4 -0
- package/src/types/maybe_promise.ts +14 -0
- package/src/types/nullable.ts +8 -0
- package/src/types/optional.ts +15 -0
|
@@ -0,0 +1,644 @@
|
|
|
1
|
+
import type { Maybe } from "./types/maybe.js";
|
|
2
|
+
import type { Nullable } from "./types/nullable.js";
|
|
3
|
+
import type { Optional } from "./types/optional.js";
|
|
4
|
+
import type { Failed, Success } from "./types/maybe_promise.js";
|
|
5
|
+
|
|
6
|
+
type UnknownFunction = (...args: readonly never[]) => unknown;
|
|
7
|
+
const EMPTY_LENGTH = 0;
|
|
8
|
+
const uuidRegex =
|
|
9
|
+
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;
|
|
10
|
+
|
|
11
|
+
const ulidRegex = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/;
|
|
12
|
+
|
|
13
|
+
function cloneDefaultArray(
|
|
14
|
+
defaultValue?: readonly unknown[],
|
|
15
|
+
): unknown[] | undefined {
|
|
16
|
+
if (!defaultValue) {
|
|
17
|
+
return defaultValue;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return [...defaultValue];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Checks if the provided result is a `Success` type.
|
|
25
|
+
*
|
|
26
|
+
* @template T The type of the value contained in the `Success` type.
|
|
27
|
+
* @param {Readonly<Success<T> | Failed>} result The result to check, which can
|
|
28
|
+
* be either a `Success<T>` or `Failed`.
|
|
29
|
+
* @returns {boolean} `true` if the result is a `Success<T>`, `false` if it is a `Failed`.
|
|
30
|
+
* This function acts as a type guard, narrowing the type of `result`
|
|
31
|
+
* to `Success<T>` when the condition is met.
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const result = await someAsyncFunction();
|
|
35
|
+
* if (isSuccess(result)) {
|
|
36
|
+
* return result.value; // TypeScript knows `value` is of type `T`
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
function isSuccess<T>(
|
|
41
|
+
result: Readonly<Success<T> | Failed>,
|
|
42
|
+
): result is Success<T> {
|
|
43
|
+
return !result.isError;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Check if a value is a string.
|
|
48
|
+
* @param {unknown} value - The value to check.
|
|
49
|
+
* @returns {boolean} True if the value is a string.
|
|
50
|
+
*/
|
|
51
|
+
function isString<T extends string>(value: Nullable<T>): value is T;
|
|
52
|
+
function isString(value: unknown): value is string;
|
|
53
|
+
function isString(value: unknown): value is string {
|
|
54
|
+
return typeof value === "string";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Parses the input value as a boolean. Returns false if the value is no string.
|
|
59
|
+
* @param {unknown} value - The value to check.
|
|
60
|
+
* @returns {boolean} True if the value is a string.
|
|
61
|
+
*/
|
|
62
|
+
function isEmptyString(value: unknown): boolean {
|
|
63
|
+
if (!isString(value)) {return false;}
|
|
64
|
+
return value.trim() === "";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Returns true if the value is null.
|
|
69
|
+
* @param {unknown} value - The value to check.
|
|
70
|
+
* @returns {boolean} True if the value is null.
|
|
71
|
+
*/
|
|
72
|
+
function isNull(value: unknown): value is null {
|
|
73
|
+
return value === null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Returns true if the value is undefined.
|
|
78
|
+
* @param {unknown} value - The value to check.
|
|
79
|
+
* @returns {boolean} True if the value is undefined.
|
|
80
|
+
*/
|
|
81
|
+
function isUndefined(value: unknown): value is undefined {
|
|
82
|
+
return typeof value === "undefined";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Checks whether an Optional value is currently in its missing state.
|
|
87
|
+
* @param {Optional<T>} value - The Optional value to check.
|
|
88
|
+
* @returns {boolean} True when the value is undefined.
|
|
89
|
+
*/
|
|
90
|
+
function isOptional<T>(value: Optional<T>): value is undefined {
|
|
91
|
+
return isUndefined(value);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Checks whether a Maybe value is currently in its missing state.
|
|
96
|
+
* @param {Maybe<T>} value - The Maybe value to check.
|
|
97
|
+
* @returns {boolean} True when the value is null.
|
|
98
|
+
*/
|
|
99
|
+
function isMaybe<T>(value: Maybe<T>): value is null {
|
|
100
|
+
return isNull(value);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Checks whether a Nullable value is currently in its missing state.
|
|
105
|
+
* @param {Nullable<T>} value - The Nullable value to check.
|
|
106
|
+
* @returns {boolean} True when the value is null or undefined.
|
|
107
|
+
*/
|
|
108
|
+
function isNullable<T>(value: Nullable<T>): value is null | undefined {
|
|
109
|
+
return isNull(value) || isUndefined(value);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Check if a value is an array.
|
|
114
|
+
* @param {unknown} value - The value to check.
|
|
115
|
+
* @returns {boolean} True if the value is an array.
|
|
116
|
+
*/
|
|
117
|
+
function isArray<T>(value: Nullable<readonly T[]>): value is readonly T[];
|
|
118
|
+
function isArray(value: unknown): value is readonly unknown[];
|
|
119
|
+
function isArray(value: unknown): value is readonly unknown[] {
|
|
120
|
+
return Array.isArray(value);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Check if a value is an empty array.
|
|
125
|
+
* @param {unknown} value - The value to check.
|
|
126
|
+
* @returns {boolean} True if the value is an empty array.
|
|
127
|
+
*/
|
|
128
|
+
function isEmptyArray<T>(value: Nullable<readonly T[]>): value is readonly T[];
|
|
129
|
+
function isEmptyArray(value: unknown): value is readonly unknown[];
|
|
130
|
+
function isEmptyArray(value: unknown): value is readonly unknown[] {
|
|
131
|
+
return Array.isArray(value) && value.length === EMPTY_LENGTH;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* more performant implementation of isArray for large arrays
|
|
136
|
+
* @param {unknown} value - The value to check.
|
|
137
|
+
* @returns {boolean} True if the value is an array.
|
|
138
|
+
*/
|
|
139
|
+
function fastIsArray<T>(value: Nullable<readonly T[]>): value is readonly T[];
|
|
140
|
+
function fastIsArray(value: unknown): value is readonly unknown[];
|
|
141
|
+
function fastIsArray(value: unknown): value is readonly unknown[] {
|
|
142
|
+
return Object.prototype.toString.call(value) === "[object Array]";
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Check if a value is a number.
|
|
147
|
+
* @param {unknown} value - The value to check.
|
|
148
|
+
* @returns {boolean} True if the value is a number.
|
|
149
|
+
*/
|
|
150
|
+
function isNumber<T extends number>(value: Nullable<T>): value is T;
|
|
151
|
+
function isNumber(value: unknown): value is number;
|
|
152
|
+
function isNumber(value: unknown): value is number {
|
|
153
|
+
if (typeof value === "string" && value.trim() === "") {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
return typeof value === "number" && !Number.isNaN(value) && Number.isFinite(value);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Returns true if the value is an object.
|
|
161
|
+
* @param {unknown} value - The value to check.
|
|
162
|
+
* @returns {boolean} True if the value is an object.
|
|
163
|
+
*/
|
|
164
|
+
function isObject<T extends Record<string, unknown>>(
|
|
165
|
+
value: Nullable<T>,
|
|
166
|
+
): value is T;
|
|
167
|
+
function isObject(value: unknown): value is Record<string, unknown>;
|
|
168
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
169
|
+
if (
|
|
170
|
+
typeof value !== "object" ||
|
|
171
|
+
value === null ||
|
|
172
|
+
isArray(value) ||
|
|
173
|
+
Object.prototype.toString.call(value) !== "[object Object]"
|
|
174
|
+
) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const objectValue: object = value;
|
|
179
|
+
return Object.getPrototypeOf(objectValue) === Object.prototype;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Returns true if the value is a boolean.
|
|
184
|
+
* @param {unknown} value - The value to check.
|
|
185
|
+
* @returns {boolean} True if the value is a boolean.
|
|
186
|
+
*/
|
|
187
|
+
function isBoolean<T extends boolean>(value: Nullable<T>): value is T;
|
|
188
|
+
function isBoolean(value: unknown): value is boolean;
|
|
189
|
+
function isBoolean(value: unknown): value is boolean {
|
|
190
|
+
return typeof value === "boolean";
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Returns true if the value is a function.
|
|
195
|
+
* @param {unknown} value - The value to check.
|
|
196
|
+
* @returns {boolean} True if the value is a function.
|
|
197
|
+
*/
|
|
198
|
+
function isFunction<T extends UnknownFunction>(
|
|
199
|
+
value: Nullable<T>,
|
|
200
|
+
): value is T;
|
|
201
|
+
function isFunction(value: unknown): value is UnknownFunction;
|
|
202
|
+
function isFunction(value: unknown): value is UnknownFunction {
|
|
203
|
+
return typeof value === "function";
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Returns true if the value is a promise.
|
|
208
|
+
* @param {unknown} value - The value to check.
|
|
209
|
+
* @returns {boolean} True if the value is a promise.
|
|
210
|
+
*/
|
|
211
|
+
function isPromise<T>(
|
|
212
|
+
value: Nullable<Readonly<PromiseLike<T>>>,
|
|
213
|
+
): value is PromiseLike<T>;
|
|
214
|
+
function isPromise(value: unknown): value is PromiseLike<unknown>;
|
|
215
|
+
function isPromise(value: unknown): value is PromiseLike<unknown> {
|
|
216
|
+
if (typeof value !== "object" || value === null) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return typeof Reflect.get(value, "then") === "function";
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Returns true if the value is an error.
|
|
225
|
+
* @param {unknown} value - The value to check.
|
|
226
|
+
* @returns {boolean} True if the value is an error.
|
|
227
|
+
*/
|
|
228
|
+
function isError<T extends Error>(value: Nullable<T>): value is T;
|
|
229
|
+
function isError(value: unknown): value is Error;
|
|
230
|
+
function isError(value: unknown): value is Error {
|
|
231
|
+
return value instanceof Error;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Returns true if the value is a date.
|
|
236
|
+
* @param {unknown} value - The value to check.
|
|
237
|
+
* @returns {boolean} True if the value is a date.
|
|
238
|
+
*/
|
|
239
|
+
function isDate<T extends Date>(value: Nullable<T>): value is T;
|
|
240
|
+
function isDate(value: unknown): value is Date;
|
|
241
|
+
function isDate(value: unknown): value is Date {
|
|
242
|
+
return value instanceof Date;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Returns true if the value is a RegExp.
|
|
247
|
+
* @param {unknown} value - The value to check.
|
|
248
|
+
* @returns {boolean} True if the value is a RegExp.
|
|
249
|
+
*/
|
|
250
|
+
function isRegExp<T extends RegExp>(value: Nullable<T>): value is T;
|
|
251
|
+
function isRegExp(value: unknown): value is RegExp;
|
|
252
|
+
function isRegExp(value: unknown): value is RegExp {
|
|
253
|
+
return value instanceof RegExp;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Returns true if the value is a symbol.
|
|
258
|
+
* @param {unknown} value - The value to check.
|
|
259
|
+
* @returns {boolean} True if the value is a symbol.
|
|
260
|
+
*/
|
|
261
|
+
function isSymbol<T extends symbol>(value: Nullable<T>): value is T;
|
|
262
|
+
function isSymbol(value: unknown): value is symbol;
|
|
263
|
+
function isSymbol(value: unknown): value is symbol {
|
|
264
|
+
return typeof value === "symbol";
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Check if a value is a plain object.
|
|
269
|
+
* @param {unknown} value - The value to check.
|
|
270
|
+
* @returns {boolean} True if the value is a plain object.
|
|
271
|
+
*/
|
|
272
|
+
function isEmptyObject<T extends Record<string, unknown>>(
|
|
273
|
+
value: Nullable<T>,
|
|
274
|
+
): value is T;
|
|
275
|
+
function isEmptyObject(
|
|
276
|
+
value: unknown,
|
|
277
|
+
): value is Record<string, unknown>;
|
|
278
|
+
function isEmptyObject(
|
|
279
|
+
value: unknown,
|
|
280
|
+
): value is Record<string, unknown> {
|
|
281
|
+
return (
|
|
282
|
+
typeof value === "object" &&
|
|
283
|
+
!isNull(value) &&
|
|
284
|
+
!isUndefined(value) &&
|
|
285
|
+
!isEmptyArray(value) &&
|
|
286
|
+
Object.getPrototypeOf(value) === Object.prototype &&
|
|
287
|
+
Object.keys(value).length === EMPTY_LENGTH
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Check if a value is an instance of a class.
|
|
293
|
+
* @param {unknown} value - The value to check.
|
|
294
|
+
* @param {unknown} constructor - The class constructor to check against.
|
|
295
|
+
* @returns {boolean} True if the value is an instance of the class.
|
|
296
|
+
*/
|
|
297
|
+
function isInstanceOf<T>(
|
|
298
|
+
value: unknown,
|
|
299
|
+
constructor: new (...args: unknown[]) => T,
|
|
300
|
+
): value is T {
|
|
301
|
+
return value instanceof constructor;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Get the keys of an object.
|
|
306
|
+
* @param {unknown} object - The object to get the keys of.
|
|
307
|
+
* @returns {Array} Keys of object.
|
|
308
|
+
*/
|
|
309
|
+
function getKeys<T extends Record<string, unknown>>(
|
|
310
|
+
object: T,
|
|
311
|
+
): (keyof T)[] {
|
|
312
|
+
return Object.keys(object) as (keyof T)[];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Parses the input value as an integer. Returns NaN if the value cannot
|
|
317
|
+
* be parsed.
|
|
318
|
+
* @param {unknown} value - The value to check.
|
|
319
|
+
* @param {Optional<number>} defaultValue - Value gets returned if integer could not
|
|
320
|
+
* be parsed.
|
|
321
|
+
* @returns {number} The parsed integer.
|
|
322
|
+
*/
|
|
323
|
+
function parseInteger(value: unknown): Optional<number>;
|
|
324
|
+
function parseInteger(value: unknown, defaultValue: number): number;
|
|
325
|
+
function parseInteger(
|
|
326
|
+
value: unknown,
|
|
327
|
+
defaultValue?: number,
|
|
328
|
+
): Optional<number> {
|
|
329
|
+
if (isNumber(value)) {
|
|
330
|
+
return Math.floor(value);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (isString(value)) {
|
|
334
|
+
const parsed = Number(value.trim());
|
|
335
|
+
if (Number.isInteger(parsed)) {
|
|
336
|
+
return parsed;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return defaultValue;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Check if a value is an integer.
|
|
344
|
+
* @param {unknown} value - The value to check.
|
|
345
|
+
* @returns {boolean} True if the value is an integer.
|
|
346
|
+
*/
|
|
347
|
+
function isInteger(value: unknown): value is number {
|
|
348
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Check if a value is a float.
|
|
353
|
+
* @param {unknown} value - The value to check.
|
|
354
|
+
* @returns {boolean} True if the value is a float.
|
|
355
|
+
*/
|
|
356
|
+
function isFloat(value: unknown): value is number {
|
|
357
|
+
return (
|
|
358
|
+
typeof value === "number" &&
|
|
359
|
+
!Number.isNaN(value) &&
|
|
360
|
+
!Number.isInteger(value)
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Parses the input value as a float. Returns NaN if the value
|
|
366
|
+
* cannot be parsed.
|
|
367
|
+
* @param {unknown} value - The value to check.
|
|
368
|
+
* @param {Optional<number>} defaultValue - Value gets returned if float could not
|
|
369
|
+
* be parsed.
|
|
370
|
+
* @returns {number} The parsed float.
|
|
371
|
+
*/
|
|
372
|
+
function parseFloat(value: unknown): Optional<number>;
|
|
373
|
+
function parseFloat(value: unknown, defaultValue: number): number;
|
|
374
|
+
function parseFloat(
|
|
375
|
+
value: unknown,
|
|
376
|
+
defaultValue?: number,
|
|
377
|
+
): Optional<number> {
|
|
378
|
+
if (isNumber(value)) {
|
|
379
|
+
return value;
|
|
380
|
+
}
|
|
381
|
+
if (isString(value)) {
|
|
382
|
+
const normalizedValue = value.trim().replace(",", ".");
|
|
383
|
+
const parsed = Number.parseFloat(normalizedValue);
|
|
384
|
+
if (!Number.isNaN(parsed)) {
|
|
385
|
+
return parsed;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return defaultValue;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Parses the input value as a number. Returns NaN if the value cannot be
|
|
392
|
+
* parsed.
|
|
393
|
+
* @param {unknown} value - The value to check.
|
|
394
|
+
* @param {Optional<number>} defaultValue - Value gets returned if number could not
|
|
395
|
+
* be parsed.
|
|
396
|
+
* @returns {number} The parsed number.
|
|
397
|
+
*/
|
|
398
|
+
function parseNumber(value: unknown): Optional<number>;
|
|
399
|
+
function parseNumber(value: unknown, defaultValue: number): number;
|
|
400
|
+
function parseNumber(
|
|
401
|
+
value: unknown,
|
|
402
|
+
defaultValue?: number,
|
|
403
|
+
): Optional<number> {
|
|
404
|
+
if (isNumber(value)) {
|
|
405
|
+
return value;
|
|
406
|
+
}
|
|
407
|
+
if (isString(value)) {
|
|
408
|
+
const normalizedValue = value.trim().replace(",", ".");
|
|
409
|
+
const parsed = Number(normalizedValue);
|
|
410
|
+
if (Number.isFinite(parsed)) {
|
|
411
|
+
return parsed;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return defaultValue;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Parses the input value as a string. Returns an empty string if the
|
|
419
|
+
* value cannot be converted.
|
|
420
|
+
* @param {unknown} value - The value to check.
|
|
421
|
+
* @param {Optional<string>} defaultValue - Value gets returned if string could not
|
|
422
|
+
* be parsed.
|
|
423
|
+
* @returns {string} The parsed string.
|
|
424
|
+
*/
|
|
425
|
+
function parseString(
|
|
426
|
+
value: unknown,
|
|
427
|
+
defaultValue = "",
|
|
428
|
+
): string {
|
|
429
|
+
if (isString(value)) {
|
|
430
|
+
return value;
|
|
431
|
+
}
|
|
432
|
+
if (isNumber(value)) {
|
|
433
|
+
return value.toString();
|
|
434
|
+
}
|
|
435
|
+
if (typeof value === "boolean") {
|
|
436
|
+
return value.toString();
|
|
437
|
+
}
|
|
438
|
+
return defaultValue;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Returns true for values that behave like "empty" application input.
|
|
443
|
+
* @param {unknown} value - The value to check.
|
|
444
|
+
* @returns {boolean} True if the value is nullish, empty string, empty array,
|
|
445
|
+
* false, or a plain object whose values are all empty-like.
|
|
446
|
+
*/
|
|
447
|
+
function isEmptyLike(value: unknown): boolean {
|
|
448
|
+
if (isNull(value) || isUndefined(value)) {
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
if (isString(value)) {
|
|
452
|
+
return isEmptyString(value);
|
|
453
|
+
}
|
|
454
|
+
if (isArray(value)) {
|
|
455
|
+
return value.every((entry) => {return isEmptyLike(entry)});
|
|
456
|
+
}
|
|
457
|
+
if (isBoolean(value)) {
|
|
458
|
+
return !value;
|
|
459
|
+
}
|
|
460
|
+
if (isObject(value)) {
|
|
461
|
+
if (Object.getPrototypeOf(value) !== Object.prototype) {
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
return Object.values(value).every((entry) =>
|
|
465
|
+
{return isEmptyLike(entry)},
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Checks if the provided value contains empty values.
|
|
473
|
+
*
|
|
474
|
+
* This function determines if the given value is either an empty string,
|
|
475
|
+
* an empty object, or a string representation of an empty object.
|
|
476
|
+
*
|
|
477
|
+
* @param {unknown} value - The value to check for emptiness. It can be of any type.
|
|
478
|
+
* @returns {boolean} `true` if the value is an empty string, an empty object, or a string
|
|
479
|
+
* representation of an empty object; otherwise, `false`.
|
|
480
|
+
*/
|
|
481
|
+
function hasEmptyValues(value: unknown): boolean {
|
|
482
|
+
if (isString(value)) {
|
|
483
|
+
try {
|
|
484
|
+
if (isEmptyObject(JSON.parse(value))) {return true;}
|
|
485
|
+
} catch {
|
|
486
|
+
return isEmptyString(value);
|
|
487
|
+
}
|
|
488
|
+
return isEmptyString(value);
|
|
489
|
+
}
|
|
490
|
+
return isEmptyObject(value);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Parses the input value as an array. Returns an empty array if the value
|
|
495
|
+
* cannot be parsed as an array.
|
|
496
|
+
* @param {unknown} value - The value to check.
|
|
497
|
+
* @param {Optional<T[]>} defaultValue - Value gets returned if array could not
|
|
498
|
+
* be parsed.
|
|
499
|
+
* @returns {Optional<T[]>} The parsed array.
|
|
500
|
+
*/
|
|
501
|
+
|
|
502
|
+
function parseArray<T>(value: readonly T[]): T[];
|
|
503
|
+
function parseArray(value: string): string[];
|
|
504
|
+
function parseArray(value: number): number[];
|
|
505
|
+
function parseArray<T extends Record<string, unknown>>(value: T): T[];
|
|
506
|
+
function parseArray<T>(value: unknown, defaultValue: readonly T[]): T[];
|
|
507
|
+
function parseArray(value: unknown): unknown[] | undefined;
|
|
508
|
+
function parseArray(
|
|
509
|
+
value: unknown,
|
|
510
|
+
defaultValue?: readonly unknown[],
|
|
511
|
+
): unknown[] | undefined {
|
|
512
|
+
if (isArray(value)) {
|
|
513
|
+
return [...value];
|
|
514
|
+
}
|
|
515
|
+
if (isString(value)) {
|
|
516
|
+
const parsed = value
|
|
517
|
+
.split(/[,|;\n\t ]+/)
|
|
518
|
+
.map((entry) => {return entry.trim()})
|
|
519
|
+
.filter((entry) => {return entry.length > EMPTY_LENGTH});
|
|
520
|
+
return parsed;
|
|
521
|
+
}
|
|
522
|
+
if (isNumber(value)) {
|
|
523
|
+
return [value];
|
|
524
|
+
}
|
|
525
|
+
if (isEmptyObject(value)) {
|
|
526
|
+
return [value];
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (isNull(value) || isUndefined(value)) {
|
|
530
|
+
return cloneDefaultArray(defaultValue);
|
|
531
|
+
}
|
|
532
|
+
return cloneDefaultArray(defaultValue);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Compares two arrays and returns true if they have at least one common value.
|
|
537
|
+
* @param {readonly T[]} array1 - First array.
|
|
538
|
+
* @param {readonly T[]} array2 - Second array.
|
|
539
|
+
* @returns {boolean} True if the arrays have at least one common value.
|
|
540
|
+
*/
|
|
541
|
+
function arrayContainsCommonValue<T>(
|
|
542
|
+
array1: readonly T[],
|
|
543
|
+
array2: readonly T[],
|
|
544
|
+
): boolean {
|
|
545
|
+
if (!isArray(array1) || !isArray(array2)) {return false;}
|
|
546
|
+
|
|
547
|
+
const valueOccurrences = new Set(array1);
|
|
548
|
+
return array2.some((value) => {return valueOccurrences.has(value)});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Returns true if the input is a UUID string.
|
|
553
|
+
* @param {string} input - The input to check.
|
|
554
|
+
* @returns {boolean} True if the input is a UUID string.
|
|
555
|
+
*/
|
|
556
|
+
function isUuidString(input: unknown): input is string {
|
|
557
|
+
return isString(input) && uuidRegex.test(input);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Returns true if the input is a ULID string.
|
|
562
|
+
* @param {string }input - The input to check.
|
|
563
|
+
* @returns {boolean} True if the input is a ULID string.
|
|
564
|
+
*/
|
|
565
|
+
function isUlidString(input: unknown): input is string {
|
|
566
|
+
return typeof input === "string" && ulidRegex.test(input);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Parses the domain name from a URL.
|
|
571
|
+
* @param {string} url - The URL to parse.
|
|
572
|
+
* @param {Optional<T>} defaultValue - The fallback when parsing fails.
|
|
573
|
+
* @returns {string} The domain name.
|
|
574
|
+
*/
|
|
575
|
+
function parseDomainName(url: string): Optional<string>;
|
|
576
|
+
function parseDomainName(url: string, defaultValue: string): string;
|
|
577
|
+
function parseDomainName(
|
|
578
|
+
url: string,
|
|
579
|
+
defaultValue?: string,
|
|
580
|
+
): Optional<string> {
|
|
581
|
+
const normalizedValue = url.trim();
|
|
582
|
+
if (normalizedValue === "" || normalizedValue.startsWith("/")) {
|
|
583
|
+
return defaultValue;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
let urlCandidate = normalizedValue;
|
|
587
|
+
if (!normalizedValue.includes("://")) {
|
|
588
|
+
urlCandidate = `https://${normalizedValue}`;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
let hostname = "";
|
|
592
|
+
try {
|
|
593
|
+
({ hostname } = new URL(urlCandidate));
|
|
594
|
+
} catch {
|
|
595
|
+
return defaultValue;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const normalizedHostname = hostname.replace(/^www\d?\./i, "");
|
|
599
|
+
const [domainName] = normalizedHostname.split(".");
|
|
600
|
+
if (!domainName) {
|
|
601
|
+
return defaultValue;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
return domainName;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
export {
|
|
608
|
+
arrayContainsCommonValue,
|
|
609
|
+
fastIsArray,
|
|
610
|
+
getKeys,
|
|
611
|
+
hasEmptyValues,
|
|
612
|
+
isArray,
|
|
613
|
+
isBoolean,
|
|
614
|
+
isDate,
|
|
615
|
+
isEmptyArray,
|
|
616
|
+
isEmptyLike,
|
|
617
|
+
isEmptyObject,
|
|
618
|
+
isEmptyString,
|
|
619
|
+
isError,
|
|
620
|
+
isFloat,
|
|
621
|
+
isFunction,
|
|
622
|
+
isInstanceOf,
|
|
623
|
+
isInteger,
|
|
624
|
+
isMaybe,
|
|
625
|
+
isNull,
|
|
626
|
+
isNullable,
|
|
627
|
+
isNumber,
|
|
628
|
+
isObject,
|
|
629
|
+
isOptional,
|
|
630
|
+
isPromise,
|
|
631
|
+
isRegExp,
|
|
632
|
+
isString,
|
|
633
|
+
isSuccess,
|
|
634
|
+
isSymbol,
|
|
635
|
+
isUlidString,
|
|
636
|
+
isUndefined,
|
|
637
|
+
isUuidString,
|
|
638
|
+
parseArray,
|
|
639
|
+
parseDomainName,
|
|
640
|
+
parseFloat,
|
|
641
|
+
parseInteger,
|
|
642
|
+
parseNumber,
|
|
643
|
+
parseString,
|
|
644
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Failed, MaybePromise, Success } from "./maybe_promise.js";
|
|
2
|
+
import type { JsonifiedObject, JsonifiedValue, Stringified } from "./json.js";
|
|
3
|
+
import type { Maybe, ResolveMaybe } from "./maybe.js";
|
|
4
|
+
import type { Nullable, ResolveNullable } from "./nullable.js";
|
|
5
|
+
import type { Optional, ResolveOptional } from "./optional.js";
|
|
6
|
+
|
|
7
|
+
export type {
|
|
8
|
+
Failed,
|
|
9
|
+
JsonifiedObject,
|
|
10
|
+
JsonifiedValue,
|
|
11
|
+
Maybe,
|
|
12
|
+
MaybePromise,
|
|
13
|
+
Nullable,
|
|
14
|
+
Optional,
|
|
15
|
+
ResolveMaybe,
|
|
16
|
+
ResolveNullable,
|
|
17
|
+
ResolveOptional,
|
|
18
|
+
Stringified,
|
|
19
|
+
Success,
|
|
20
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type UnknownFunction = (...args: readonly unknown[]) => unknown;
|
|
2
|
+
|
|
3
|
+
type JsonifiedValue<T> = T extends string | number | null | boolean
|
|
4
|
+
? T
|
|
5
|
+
: T extends { toJSON(): infer R }
|
|
6
|
+
? R
|
|
7
|
+
: T extends undefined | UnknownFunction
|
|
8
|
+
? never
|
|
9
|
+
: T extends object
|
|
10
|
+
? JsonifiedObject<T>
|
|
11
|
+
: never;
|
|
12
|
+
|
|
13
|
+
type JsonifiedObject<T> = {
|
|
14
|
+
[Key in keyof T as [JsonifiedValue<T[Key]>] extends [never]
|
|
15
|
+
? never
|
|
16
|
+
: Key]: JsonifiedValue<T[Key]>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Stringified type for JSON.stringify to return as a string with a source type
|
|
20
|
+
type Stringified<ObjType> = string & { source: ObjType };
|
|
21
|
+
|
|
22
|
+
export type { JsonifiedObject, JsonifiedValue, Stringified };
|