@pawells/typescript-common 2.1.5 → 2.1.6
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 +22 -1
- package/dist/array/index.d.ts +1 -0
- package/dist/array/index.d.ts.map +1 -1
- package/dist/array/index.js +1 -0
- package/dist/array/iterators.d.ts +40 -0
- package/dist/array/iterators.d.ts.map +1 -0
- package/dist/array/iterators.js +54 -0
- package/dist/asserts/generic.d.ts +1 -1
- package/dist/asserts/generic.d.ts.map +1 -1
- package/dist/asserts/generic.js +8 -2
- package/dist/asserts/utils.d.ts.map +1 -1
- package/dist/asserts/utils.js +2 -3
- package/dist/enum/index.d.ts +1 -1
- package/dist/enum/index.d.ts.map +1 -1
- package/dist/enum/index.js +1 -1
- package/dist/function/memoize.d.ts +13 -0
- package/dist/function/memoize.d.ts.map +1 -1
- package/dist/function/memoize.js +13 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/json.sanitization.d.ts +14 -0
- package/dist/json.sanitization.d.ts.map +1 -0
- package/dist/json.sanitization.js +37 -0
- package/dist/object/clone.d.ts +6 -0
- package/dist/object/clone.d.ts.map +1 -1
- package/dist/object/clone.js +7 -1
- package/dist/object/filter-cached.d.ts +0 -18
- package/dist/object/filter-cached.d.ts.map +1 -1
- package/dist/object/filter-cached.js +0 -18
- package/dist/object/filter.d.ts.map +1 -1
- package/dist/object/filter.js +10 -1
- package/dist/object/hash.js +2 -2
- package/dist/object/index.d.ts +1 -1
- package/dist/object/index.d.ts.map +1 -1
- package/dist/object/object-flatten.js +4 -0
- package/dist/object/property-paths.d.ts +2 -0
- package/dist/object/property-paths.d.ts.map +1 -1
- package/dist/object/property-paths.js +2 -0
- package/dist/object/security-utils.d.ts.map +1 -1
- package/dist/object/security-utils.js +8 -1
- package/dist/object/sort-keys.d.ts +14 -0
- package/dist/object/sort-keys.d.ts.map +1 -1
- package/dist/object/sort-keys.js +14 -0
- package/dist/object/types.d.ts +0 -102
- package/dist/object/types.d.ts.map +1 -1
- package/dist/string/assert.d.ts +19 -0
- package/dist/string/assert.d.ts.map +1 -1
- package/dist/string/assert.js +19 -0
- package/dist/time/elapsed-time/elapsed-time.d.ts +7 -7
- package/dist/time/elapsed-time/elapsed-time.js +25 -25
- package/dist/time/index.d.ts +1 -3
- package/dist/time/index.d.ts.map +1 -1
- package/dist/time/index.js +0 -3
- package/dist/time/stopwatch/stopwatch.d.ts +18 -0
- package/dist/time/stopwatch/stopwatch.d.ts.map +1 -1
- package/dist/time/stopwatch/stopwatch.js +23 -0
- package/dist/zod-util.d.ts +145 -0
- package/dist/zod-util.d.ts.map +1 -0
- package/dist/zod-util.js +126 -0
- package/package.json +65 -58
|
@@ -48,11 +48,18 @@ const /**
|
|
|
48
48
|
* anchored to prevent catastrophic backtracking.
|
|
49
49
|
*/
|
|
50
50
|
const PATH_TRAVERSAL_PATTERNS = [
|
|
51
|
+
/\.\./, // ASCII parent directory (..)
|
|
52
|
+
/\//, // ASCII solidus (forward slash)
|
|
51
53
|
/%2e%2e/i, // URL encoded ..
|
|
54
|
+
/%2f/i, // URL encoded solidus
|
|
52
55
|
/%252e%252e/i, // Double URL encoded ..
|
|
56
|
+
/%252f/i, // Double URL encoded solidus
|
|
57
|
+
/../, // Fullwidth parent directory (U+FF0E U+FF0E)
|
|
58
|
+
///, // Fullwidth solidus (U+FF0F)
|
|
59
|
+
/∕/, // Division slash (U+2215)
|
|
53
60
|
new RegExp(String.fromCharCode(0)), // Null byte injection
|
|
54
61
|
/%00/i, // URL encoded null byte
|
|
55
|
-
new RegExp('[
|
|
62
|
+
new RegExp('[]'), // Unicode BOM, reversed BOM, and invalid characters
|
|
56
63
|
];
|
|
57
64
|
/**
|
|
58
65
|
* Validates if a property key is safe to use (not dangerous for prototype pollution)
|
|
@@ -22,5 +22,19 @@
|
|
|
22
22
|
* // Result: { active: true, age: 30, email: 'john@example.com', name: 'John' }
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
|
+
/**
|
|
26
|
+
* Sorts the enumerable keys of an object in ascending order.
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* - Sorts only enumerable keys; non-enumerable properties are preserved in-place
|
|
30
|
+
* - Symbol keys are not sorted (enumerable symbols appear in creation order)
|
|
31
|
+
* - Returns a new object with sorted enumerable keys and all non-enumerable properties
|
|
32
|
+
*
|
|
33
|
+
* @param object - The object to sort
|
|
34
|
+
* @returns A new object with sorted enumerable keys
|
|
35
|
+
* @example
|
|
36
|
+
* const obj = { z: 1, a: 2, m: 3 };
|
|
37
|
+
* ObjectSortKeys(obj); // { a: 2, m: 3, z: 1 }
|
|
38
|
+
*/
|
|
25
39
|
export declare function ObjectSortKeys<T extends Record<string, unknown>>(object: T): T;
|
|
26
40
|
//# sourceMappingURL=sort-keys.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort-keys.d.ts","sourceRoot":"","sources":["../../src/object/sort-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAuC9E"}
|
|
1
|
+
{"version":3,"file":"sort-keys.d.ts","sourceRoot":"","sources":["../../src/object/sort-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAuC9E"}
|
package/dist/object/sort-keys.js
CHANGED
|
@@ -22,6 +22,20 @@
|
|
|
22
22
|
* // Result: { active: true, age: 30, email: 'john@example.com', name: 'John' }
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
|
+
/**
|
|
26
|
+
* Sorts the enumerable keys of an object in ascending order.
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* - Sorts only enumerable keys; non-enumerable properties are preserved in-place
|
|
30
|
+
* - Symbol keys are not sorted (enumerable symbols appear in creation order)
|
|
31
|
+
* - Returns a new object with sorted enumerable keys and all non-enumerable properties
|
|
32
|
+
*
|
|
33
|
+
* @param object - The object to sort
|
|
34
|
+
* @returns A new object with sorted enumerable keys
|
|
35
|
+
* @example
|
|
36
|
+
* const obj = { z: 1, a: 2, m: 3 };
|
|
37
|
+
* ObjectSortKeys(obj); // { a: 2, m: 3, z: 1 }
|
|
38
|
+
*/
|
|
25
39
|
export function ObjectSortKeys(object) {
|
|
26
40
|
if (!object || typeof object !== 'object' || Array.isArray(object)) {
|
|
27
41
|
return object;
|
package/dist/object/types.d.ts
CHANGED
|
@@ -1,105 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Omits properties from B that are not in A.
|
|
3
|
-
*
|
|
4
|
-
* @template A - Base type.
|
|
5
|
-
* @template B - Type to filter.
|
|
6
|
-
*
|
|
7
|
-
* @remarks
|
|
8
|
-
* Currently exported but not used by public API functions. Reserved for future use
|
|
9
|
-
* as an extension point for constrained object transformations or validation scenarios.
|
|
10
|
-
*/
|
|
11
|
-
export type TObjectOmitExtraProperties<A, B> = {
|
|
12
|
-
[K in keyof B]: K extends A ? B[K] : never;
|
|
13
|
-
};
|
|
14
|
-
/**
|
|
15
|
-
* Extracts the property keys of an object type.
|
|
16
|
-
*
|
|
17
|
-
* @template O - The object type.
|
|
18
|
-
*
|
|
19
|
-
* @remarks
|
|
20
|
-
* Currently exported but not used by public API functions. Reserved for future use
|
|
21
|
-
* as a generic property introspection utility or type constraint.
|
|
22
|
-
*/
|
|
23
|
-
export type TObjectProperties<O extends object> = keyof O;
|
|
24
|
-
/**
|
|
25
|
-
* Extracts property keys of a specific type from an object.
|
|
26
|
-
*
|
|
27
|
-
* @template O - Object type.
|
|
28
|
-
* @template PropertyType - The type to match.
|
|
29
|
-
*
|
|
30
|
-
* @remarks
|
|
31
|
-
* Currently exported but not used by public API functions. Reserved for future use
|
|
32
|
-
* in type-filtered property transformations or validations (e.g., filtering all
|
|
33
|
-
* string properties, all optional properties, or all array properties).
|
|
34
|
-
*/
|
|
35
|
-
export type TObjectPropertiesOfType<O extends object, PropertyType> = keyof {
|
|
36
|
-
[K in keyof O as O[K] extends PropertyType ? K : never]: unknown;
|
|
37
|
-
};
|
|
38
|
-
/**
|
|
39
|
-
* Omits properties of a specific type from an object.
|
|
40
|
-
*
|
|
41
|
-
* @template O - Object type.
|
|
42
|
-
* @template PropertyType - The type to omit.
|
|
43
|
-
*
|
|
44
|
-
* @remarks
|
|
45
|
-
* Currently exported but not used by public API functions. Reserved for future use
|
|
46
|
-
* in scenarios requiring conditional property exclusion based on value type
|
|
47
|
-
* (e.g., extracting only non-array properties, or excluding optional properties).
|
|
48
|
-
*/
|
|
49
|
-
export type TObjectOmitPropertiesOfType<O extends object, PropertyType> = {
|
|
50
|
-
[K in keyof O as O[K] extends PropertyType ? never : K]: O[K];
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Represents the union of all property values in an object.
|
|
54
|
-
*
|
|
55
|
-
* @template T - Object type.
|
|
56
|
-
*
|
|
57
|
-
* @remarks
|
|
58
|
-
* Currently exported but not used by public API functions. Reserved for future use
|
|
59
|
-
* in generic object value introspection or validation scenarios.
|
|
60
|
-
*/
|
|
61
|
-
export type TObjectPropertyType<T extends object> = T[keyof T];
|
|
62
|
-
/**
|
|
63
|
-
* Extracts properties shared between two object types.
|
|
64
|
-
*
|
|
65
|
-
* @template A - First object type.
|
|
66
|
-
* @template B - Second object type.
|
|
67
|
-
*
|
|
68
|
-
* @remarks
|
|
69
|
-
* Currently exported but not used by public API functions. Reserved for future use
|
|
70
|
-
* in scenarios requiring intersection of object types or common property extraction
|
|
71
|
-
* for schema validation or type merging operations.
|
|
72
|
-
*/
|
|
73
|
-
export type TObjectSharedProperties<A extends object, B extends object> = {
|
|
74
|
-
[K in keyof A & keyof B]: K extends keyof A ? A[K] : never;
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Extracts keys of array properties from an object type.
|
|
78
|
-
*
|
|
79
|
-
* @template T - Object type.
|
|
80
|
-
*
|
|
81
|
-
* @remarks
|
|
82
|
-
* Currently exported but not used by public API functions. Reserved for future use
|
|
83
|
-
* in scenarios requiring filtering of array-typed properties, such as validating
|
|
84
|
-
* array field schemas or transforming only array properties in an object.
|
|
85
|
-
*/
|
|
86
|
-
export type TObjectArrayProperties<T extends object> = {
|
|
87
|
-
[K in keyof T]: T[K] extends Array<unknown> ? K : never;
|
|
88
|
-
}[keyof T];
|
|
89
|
-
/**
|
|
90
|
-
* Generates nested dot-notation keys for an object type.
|
|
91
|
-
*
|
|
92
|
-
* @template ObjectType - The object type to generate keys for.
|
|
93
|
-
*
|
|
94
|
-
* @remarks
|
|
95
|
-
* Currently exported but not used by public API functions. Reserved for future use
|
|
96
|
-
* in scenarios requiring type-safe nested property access, such as advanced path
|
|
97
|
-
* navigation utilities or deep property validation frameworks that benefit from
|
|
98
|
-
* compile-time validation of dot-notation paths.
|
|
99
|
-
*/
|
|
100
|
-
export type TObjectNestedKeyOf<ObjectType extends object> = {
|
|
101
|
-
[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object ? `${Key}` | `${Key}.${TObjectNestedKeyOf<ObjectType[Key]>}` : `${Key}`;
|
|
102
|
-
}[keyof ObjectType & (string | number)];
|
|
103
1
|
/**
|
|
104
2
|
* Options for object filtering behavior.
|
|
105
3
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/object/types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/object/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACpC,4HAA4H;IAC5H,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,8EAA8E;IAC9E,sBAAsB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7C,iHAAiH;IACjH,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IAC1C,qGAAqG;IACrG,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,4HAA4H;IAC5H,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,8EAA8E;IAC9E,sBAAsB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7C,iHAAiH;IACjH,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,0FAA0F;IAC1F,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,MAAM,2BAA2B,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtI;;;GAGG;AACH,MAAM,MAAM,2BAA2B,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAE7J;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;AAE9E;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM,EAAE,OAAO,SAAS,MAAM,GAAG,MAAM,IAAI,CACjG,KAAK,EAAE,MAAM,KACT,OAAO,CAAC;AAEb;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;AAElF;;;;;;GAMG;AACH,MAAM,MAAM,yBAAyB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;AAE3F;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CACrF,GAAG,EAAE,CAAC,EACN,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,KACP,OAAO,CAAC;AAEb;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CACrF,GAAG,EAAE,CAAC,EACN,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,KACP,OAAO,CAAC"}
|
package/dist/string/assert.d.ts
CHANGED
|
@@ -102,5 +102,24 @@ export declare function AssertStringNotEmpty(value: unknown, exception?: IAssert
|
|
|
102
102
|
* AssertStringMatches("user2@example.com", emailPattern); // Uses cached pattern
|
|
103
103
|
* ```
|
|
104
104
|
*/
|
|
105
|
+
/**
|
|
106
|
+
* Asserts that the provided value matches the specified regular expression pattern.
|
|
107
|
+
*
|
|
108
|
+
* Uses an LRU cache to store compiled RegExp objects for repeated pattern matching,
|
|
109
|
+
* improving performance for long-running processes with dynamic regex patterns.
|
|
110
|
+
*
|
|
111
|
+
* @remarks
|
|
112
|
+
* - Cache size: 100 entries
|
|
113
|
+
* - Cache is LRU-evicted (least recently used entry is removed when size is exceeded)
|
|
114
|
+
* - When to expect cache behavior: dynamic regex patterns with long-running processes
|
|
115
|
+
*
|
|
116
|
+
* @param value - The string to test against the pattern
|
|
117
|
+
* @param regex - The regular expression pattern to match
|
|
118
|
+
* @param exception - Optional exception configuration
|
|
119
|
+
* @throws StringError if the value does not match the pattern
|
|
120
|
+
* @example
|
|
121
|
+
* AssertStringMatches('test@example.com', /^[^@]+@[^@]+\.[^@]+$/); // passes
|
|
122
|
+
* AssertStringMatches('invalid-email', /^[^@]+@[^@]+\.[^@]+$/); // throws
|
|
123
|
+
*/
|
|
105
124
|
export declare function AssertStringMatches(value: string, regex: RegExp, exception?: IAssertException): void;
|
|
106
125
|
//# sourceMappingURL=assert.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../src/string/assert.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA8CnD;;;;;;;;;;GAUG;AACH,qBAAa,WAAY,SAAQ,WAAW;gBAC/B,OAAO,CAAC,EAAE,MAAM;CAG5B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAE,gBAAqB,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAGtG;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAE,gBAAqB,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAY9G;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,gBAAqB,GAAG,IAAI,CAsBxG"}
|
|
1
|
+
{"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../src/string/assert.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA8CnD;;;;;;;;;;GAUG;AACH,qBAAa,WAAY,SAAQ,WAAW;gBAC/B,OAAO,CAAC,EAAE,MAAM;CAG5B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAE,gBAAqB,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAGtG;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,GAAE,gBAAqB,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAY9G;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,gBAAqB,GAAG,IAAI,CAsBxG"}
|
package/dist/string/assert.js
CHANGED
|
@@ -159,6 +159,25 @@ export function AssertStringNotEmpty(value, exception = {}) {
|
|
|
159
159
|
* AssertStringMatches("user2@example.com", emailPattern); // Uses cached pattern
|
|
160
160
|
* ```
|
|
161
161
|
*/
|
|
162
|
+
/**
|
|
163
|
+
* Asserts that the provided value matches the specified regular expression pattern.
|
|
164
|
+
*
|
|
165
|
+
* Uses an LRU cache to store compiled RegExp objects for repeated pattern matching,
|
|
166
|
+
* improving performance for long-running processes with dynamic regex patterns.
|
|
167
|
+
*
|
|
168
|
+
* @remarks
|
|
169
|
+
* - Cache size: 100 entries
|
|
170
|
+
* - Cache is LRU-evicted (least recently used entry is removed when size is exceeded)
|
|
171
|
+
* - When to expect cache behavior: dynamic regex patterns with long-running processes
|
|
172
|
+
*
|
|
173
|
+
* @param value - The string to test against the pattern
|
|
174
|
+
* @param regex - The regular expression pattern to match
|
|
175
|
+
* @param exception - Optional exception configuration
|
|
176
|
+
* @throws StringError if the value does not match the pattern
|
|
177
|
+
* @example
|
|
178
|
+
* AssertStringMatches('test@example.com', /^[^@]+@[^@]+\.[^@]+$/); // passes
|
|
179
|
+
* AssertStringMatches('invalid-email', /^[^@]+@[^@]+\.[^@]+$/); // throws
|
|
180
|
+
*/
|
|
162
181
|
export function AssertStringMatches(value, regex, exception = {}) {
|
|
163
182
|
SetExceptionClass(exception, StringError);
|
|
164
183
|
AssertString(value, exception); // Ensure value is a string before matching
|
|
@@ -61,7 +61,7 @@ export declare class ElapsedTime {
|
|
|
61
61
|
* console.log(elapsed.TotalHours); // 26
|
|
62
62
|
* ```
|
|
63
63
|
*/
|
|
64
|
-
private
|
|
64
|
+
private _calculateTimeValues;
|
|
65
65
|
/**
|
|
66
66
|
* Get a cached property value, computing and caching it if necessary.
|
|
67
67
|
* For stopped/paused instances (where TotalMilliseconds doesn't change),
|
|
@@ -313,7 +313,7 @@ export declare class ElapsedTime {
|
|
|
313
313
|
* elapsed2.Format('LONG'); // "2 hours 2 minutes 2 seconds" (all plural)
|
|
314
314
|
* ```
|
|
315
315
|
*/
|
|
316
|
-
private
|
|
316
|
+
private _formatLong;
|
|
317
317
|
/**
|
|
318
318
|
* Format the elapsed time using the token-based formatting system.
|
|
319
319
|
* This is the main formatting engine that handles all predefined formats
|
|
@@ -335,7 +335,7 @@ export declare class ElapsedTime {
|
|
|
335
335
|
* // Called automatically by Format() method for most format types
|
|
336
336
|
* ```
|
|
337
337
|
*/
|
|
338
|
-
private
|
|
338
|
+
private _formatUsingTokens;
|
|
339
339
|
/**
|
|
340
340
|
* Format time units for TIME and TIME_WITH_SECONDS formats
|
|
341
341
|
* These formats use special formatting with colons for displaying time (e.g., "1:30:45")
|
|
@@ -344,7 +344,7 @@ export declare class ElapsedTime {
|
|
|
344
344
|
* @returns Formatted time string with colons (e.g., "1:30:45")
|
|
345
345
|
* @private
|
|
346
346
|
*/
|
|
347
|
-
private static
|
|
347
|
+
private static _formatTimeUnits;
|
|
348
348
|
/**
|
|
349
349
|
* Format units for standard (non-time) formats
|
|
350
350
|
* Handles different formatting styles including CONCISE, SHORT, MEDIUM, LONG, and custom formats
|
|
@@ -355,7 +355,7 @@ export declare class ElapsedTime {
|
|
|
355
355
|
* @returns Formatted time string according to the specified format style
|
|
356
356
|
* @private
|
|
357
357
|
*/
|
|
358
|
-
private static
|
|
358
|
+
private static _formatStandardUnits;
|
|
359
359
|
/**
|
|
360
360
|
* Filter and limit time units based on formatting options.
|
|
361
361
|
* Applies showZeroValues and maxUnits options to determine which
|
|
@@ -374,7 +374,7 @@ export declare class ElapsedTime {
|
|
|
374
374
|
* // All zero values -> ensures at least "0 seconds" is shown
|
|
375
375
|
* ```
|
|
376
376
|
*/
|
|
377
|
-
private static
|
|
377
|
+
private static _filterAndLimitUnits;
|
|
378
378
|
/**
|
|
379
379
|
* Apply negative value formatting based on user preferences.
|
|
380
380
|
* Wraps or modifies the formatted time string to indicate negative durations
|
|
@@ -394,7 +394,7 @@ export declare class ElapsedTime {
|
|
|
394
394
|
* // Empty: "1h 30m" -> "1h 30m" (no change)
|
|
395
395
|
* ```
|
|
396
396
|
*/
|
|
397
|
-
private static
|
|
397
|
+
private static _applyNegativeFormatting;
|
|
398
398
|
}
|
|
399
399
|
/**
|
|
400
400
|
* Formats elapsed time using the specified configuration.
|
|
@@ -78,7 +78,7 @@ export class ElapsedTime {
|
|
|
78
78
|
* console.log(elapsed.TotalHours); // 26
|
|
79
79
|
* ```
|
|
80
80
|
*/
|
|
81
|
-
|
|
81
|
+
_calculateTimeValues() {
|
|
82
82
|
if (this._valuesCalculated)
|
|
83
83
|
return;
|
|
84
84
|
this._totalSeconds = Math.floor(this._totalMilliseconds / MS_PER_SECOND);
|
|
@@ -119,7 +119,7 @@ export class ElapsedTime {
|
|
|
119
119
|
*/
|
|
120
120
|
get Weeks() {
|
|
121
121
|
return this._getCachedProperty('weeks', () => {
|
|
122
|
-
this.
|
|
122
|
+
this._calculateTimeValues();
|
|
123
123
|
return this._weeks;
|
|
124
124
|
});
|
|
125
125
|
}
|
|
@@ -128,7 +128,7 @@ export class ElapsedTime {
|
|
|
128
128
|
*/
|
|
129
129
|
get Days() {
|
|
130
130
|
return this._getCachedProperty('days', () => {
|
|
131
|
-
this.
|
|
131
|
+
this._calculateTimeValues();
|
|
132
132
|
return this._days;
|
|
133
133
|
});
|
|
134
134
|
}
|
|
@@ -137,7 +137,7 @@ export class ElapsedTime {
|
|
|
137
137
|
*/
|
|
138
138
|
get TotalDays() {
|
|
139
139
|
return this._getCachedProperty('totalDays', () => {
|
|
140
|
-
this.
|
|
140
|
+
this._calculateTimeValues();
|
|
141
141
|
return this._totalDays;
|
|
142
142
|
});
|
|
143
143
|
}
|
|
@@ -146,7 +146,7 @@ export class ElapsedTime {
|
|
|
146
146
|
*/
|
|
147
147
|
get Hours() {
|
|
148
148
|
return this._getCachedProperty('hours', () => {
|
|
149
|
-
this.
|
|
149
|
+
this._calculateTimeValues();
|
|
150
150
|
return this._hours;
|
|
151
151
|
});
|
|
152
152
|
}
|
|
@@ -166,7 +166,7 @@ export class ElapsedTime {
|
|
|
166
166
|
*/
|
|
167
167
|
get TotalHours() {
|
|
168
168
|
return this._getCachedProperty('totalHours', () => {
|
|
169
|
-
this.
|
|
169
|
+
this._calculateTimeValues();
|
|
170
170
|
return this._totalHours;
|
|
171
171
|
});
|
|
172
172
|
}
|
|
@@ -183,7 +183,7 @@ export class ElapsedTime {
|
|
|
183
183
|
*/
|
|
184
184
|
get Minutes() {
|
|
185
185
|
return this._getCachedProperty('minutes', () => {
|
|
186
|
-
this.
|
|
186
|
+
this._calculateTimeValues();
|
|
187
187
|
return this._minutes;
|
|
188
188
|
});
|
|
189
189
|
}
|
|
@@ -200,7 +200,7 @@ export class ElapsedTime {
|
|
|
200
200
|
*/
|
|
201
201
|
get TotalMinutes() {
|
|
202
202
|
return this._getCachedProperty('totalMinutes', () => {
|
|
203
|
-
this.
|
|
203
|
+
this._calculateTimeValues();
|
|
204
204
|
return this._totalMinutes;
|
|
205
205
|
});
|
|
206
206
|
}
|
|
@@ -217,7 +217,7 @@ export class ElapsedTime {
|
|
|
217
217
|
*/
|
|
218
218
|
get Seconds() {
|
|
219
219
|
return this._getCachedProperty('seconds', () => {
|
|
220
|
-
this.
|
|
220
|
+
this._calculateTimeValues();
|
|
221
221
|
return this._seconds;
|
|
222
222
|
});
|
|
223
223
|
}
|
|
@@ -234,7 +234,7 @@ export class ElapsedTime {
|
|
|
234
234
|
*/
|
|
235
235
|
get TotalSeconds() {
|
|
236
236
|
return this._getCachedProperty('totalSeconds', () => {
|
|
237
|
-
this.
|
|
237
|
+
this._calculateTimeValues();
|
|
238
238
|
return this._totalSeconds;
|
|
239
239
|
});
|
|
240
240
|
}
|
|
@@ -251,7 +251,7 @@ export class ElapsedTime {
|
|
|
251
251
|
*/
|
|
252
252
|
get Milliseconds() {
|
|
253
253
|
return this._getCachedProperty('milliseconds', () => {
|
|
254
|
-
this.
|
|
254
|
+
this._calculateTimeValues();
|
|
255
255
|
return this._milliseconds;
|
|
256
256
|
});
|
|
257
257
|
}
|
|
@@ -417,7 +417,7 @@ export class ElapsedTime {
|
|
|
417
417
|
*/
|
|
418
418
|
Format(format = 'concise', options = {}) {
|
|
419
419
|
// Ensure all time values are calculated
|
|
420
|
-
this.
|
|
420
|
+
this._calculateTimeValues();
|
|
421
421
|
let resolvedOptions = { ...options };
|
|
422
422
|
// Handle predefined formats
|
|
423
423
|
let formatKey = '';
|
|
@@ -431,9 +431,9 @@ export class ElapsedTime {
|
|
|
431
431
|
const appliedOptions = ApplyDefaultOptions(resolvedOptions);
|
|
432
432
|
// Special case for LONG format which needs pluralization
|
|
433
433
|
if (formatKey === 'long') {
|
|
434
|
-
return this.
|
|
434
|
+
return this._formatLong(appliedOptions);
|
|
435
435
|
}
|
|
436
|
-
return this.
|
|
436
|
+
return this._formatUsingTokens(appliedOptions, formatKey, options);
|
|
437
437
|
}
|
|
438
438
|
/**
|
|
439
439
|
* Special formatter for LONG format with proper pluralization.
|
|
@@ -454,7 +454,7 @@ export class ElapsedTime {
|
|
|
454
454
|
* elapsed2.Format('LONG'); // "2 hours 2 minutes 2 seconds" (all plural)
|
|
455
455
|
* ```
|
|
456
456
|
*/
|
|
457
|
-
|
|
457
|
+
_formatLong(options) {
|
|
458
458
|
const parts = [];
|
|
459
459
|
// Process each time unit in order of significance
|
|
460
460
|
if (this._weeks > 0 || options.showZeroValues) {
|
|
@@ -486,7 +486,7 @@ export class ElapsedTime {
|
|
|
486
486
|
const formatted = parts.join(' ');
|
|
487
487
|
// Apply negative formatting
|
|
488
488
|
if (this.IsNegative) {
|
|
489
|
-
return ElapsedTime.
|
|
489
|
+
return ElapsedTime._applyNegativeFormatting(formatted, options);
|
|
490
490
|
}
|
|
491
491
|
return formatted;
|
|
492
492
|
}
|
|
@@ -511,7 +511,7 @@ export class ElapsedTime {
|
|
|
511
511
|
* // Called automatically by Format() method for most format types
|
|
512
512
|
* ```
|
|
513
513
|
*/
|
|
514
|
-
|
|
514
|
+
_formatUsingTokens(options, formatKey = '', originalOptions = {}) {
|
|
515
515
|
// Define all available time units
|
|
516
516
|
const units = [
|
|
517
517
|
{ unit: 'week', value: this.Weeks },
|
|
@@ -522,7 +522,7 @@ export class ElapsedTime {
|
|
|
522
522
|
{ unit: 'millisecond', value: this.Milliseconds },
|
|
523
523
|
];
|
|
524
524
|
// Filter and limit units based on options
|
|
525
|
-
const filteredUnits = ElapsedTime.
|
|
525
|
+
const filteredUnits = ElapsedTime._filterAndLimitUnits(units, options);
|
|
526
526
|
const unitLabels = options.unitLabels ?? DEFAULT_UNIT_LABELS.medium;
|
|
527
527
|
// Determine if custom labels were explicitly provided by the user (not from format defaults)
|
|
528
528
|
const hasCustomLabels = originalOptions.unitLabels !== undefined;
|
|
@@ -532,13 +532,13 @@ export class ElapsedTime {
|
|
|
532
532
|
let formatted;
|
|
533
533
|
const isTimeFormat = formatKey === 'time' || formatKey === 'timeWithSeconds';
|
|
534
534
|
if (isTimeFormat) {
|
|
535
|
-
formatted = ElapsedTime.
|
|
535
|
+
formatted = ElapsedTime._formatTimeUnits(filteredUnits, unitLabels);
|
|
536
536
|
}
|
|
537
537
|
else {
|
|
538
538
|
// Handle different format types
|
|
539
|
-
formatted = ElapsedTime.
|
|
539
|
+
formatted = ElapsedTime._formatStandardUnits(filteredUnits, unitLabels, formatKey, hasCustomLabels);
|
|
540
540
|
}
|
|
541
|
-
return this.IsNegative ? ElapsedTime.
|
|
541
|
+
return this.IsNegative ? ElapsedTime._applyNegativeFormatting(formatted, options) : formatted;
|
|
542
542
|
}
|
|
543
543
|
/**
|
|
544
544
|
* Format time units for TIME and TIME_WITH_SECONDS formats
|
|
@@ -548,7 +548,7 @@ export class ElapsedTime {
|
|
|
548
548
|
* @returns Formatted time string with colons (e.g., "1:30:45")
|
|
549
549
|
* @private
|
|
550
550
|
*/
|
|
551
|
-
static
|
|
551
|
+
static _formatTimeUnits(units, unitLabels) {
|
|
552
552
|
return units.map(({ unit, value: _value }) => {
|
|
553
553
|
const labelFunc = unitLabels[unit];
|
|
554
554
|
if (!labelFunc)
|
|
@@ -566,7 +566,7 @@ export class ElapsedTime {
|
|
|
566
566
|
* @returns Formatted time string according to the specified format style
|
|
567
567
|
* @private
|
|
568
568
|
*/
|
|
569
|
-
static
|
|
569
|
+
static _formatStandardUnits(units, unitLabels, formatKey = '', hasCustomLabels = false) {
|
|
570
570
|
// Function-based labels: invoke each label function with the value (e.g. pluralization)
|
|
571
571
|
if (Object.values(unitLabels).some((label) => typeof label === 'function')) {
|
|
572
572
|
return units.map(({ unit, value }) => {
|
|
@@ -626,7 +626,7 @@ export class ElapsedTime {
|
|
|
626
626
|
* // All zero values -> ensures at least "0 seconds" is shown
|
|
627
627
|
* ```
|
|
628
628
|
*/
|
|
629
|
-
static
|
|
629
|
+
static _filterAndLimitUnits(units, options) {
|
|
630
630
|
// Filter out zero values if not showing them
|
|
631
631
|
let filteredUnits = options.showZeroValues ? units : units.filter((item) => item.value > 0);
|
|
632
632
|
// Handle the case where all values are zero
|
|
@@ -659,7 +659,7 @@ export class ElapsedTime {
|
|
|
659
659
|
* // Empty: "1h 30m" -> "1h 30m" (no change)
|
|
660
660
|
* ```
|
|
661
661
|
*/
|
|
662
|
-
static
|
|
662
|
+
static _applyNegativeFormatting(output, options) {
|
|
663
663
|
switch (options.negativeValueFormat) {
|
|
664
664
|
case 'NegativeSign':
|
|
665
665
|
return `-${output}`;
|
package/dist/time/index.d.ts
CHANGED
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
* @module time
|
|
9
9
|
*/
|
|
10
10
|
export * from './elapsed-time/elapsed-time.js';
|
|
11
|
-
export
|
|
12
|
-
export * from './elapsed-time/constants.js';
|
|
13
|
-
export * from './elapsed-time/utils.js';
|
|
11
|
+
export type { ITimeUnitValue, ITimeElapsedFormatOptions, TTimeElapsedFormats, TTimeUnit, IUnitLabelMap, } from './elapsed-time/types.js';
|
|
14
12
|
export * from './stopwatch/stopwatch.js';
|
|
15
13
|
export * from './stopwatch/entry.js';
|
|
16
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/time/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/time/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/time/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,gCAAgC,CAAC;AAC/C,YAAY,EACX,cAAc,EACd,yBAAyB,EACzB,mBAAmB,EACnB,SAAS,EACT,aAAa,GACb,MAAM,yBAAyB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC"}
|
package/dist/time/index.js
CHANGED
|
@@ -8,8 +8,5 @@
|
|
|
8
8
|
* @module time
|
|
9
9
|
*/
|
|
10
10
|
export * from './elapsed-time/elapsed-time.js';
|
|
11
|
-
export * from './elapsed-time/types.js';
|
|
12
|
-
export * from './elapsed-time/constants.js';
|
|
13
|
-
export * from './elapsed-time/utils.js';
|
|
14
11
|
export * from './stopwatch/stopwatch.js';
|
|
15
12
|
export * from './stopwatch/entry.js';
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
import { ElapsedTime } from '../elapsed-time/elapsed-time.js';
|
|
2
2
|
import { StopwatchEntry } from './entry.js';
|
|
3
|
+
import { SimpleError } from '../../asserts/errors.js';
|
|
4
|
+
/**
|
|
5
|
+
* Error thrown by Stopwatch when an invalid operation is attempted.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const sw = new Stopwatch();
|
|
10
|
+
* sw.Start();
|
|
11
|
+
* sw.Stop();
|
|
12
|
+
* sw.Resume(); // Throws StopwatchError
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare class StopwatchError extends SimpleError {
|
|
16
|
+
/**
|
|
17
|
+
* @param message - Description of the stopwatch state error
|
|
18
|
+
*/
|
|
19
|
+
constructor(message: string);
|
|
20
|
+
}
|
|
3
21
|
/**
|
|
4
22
|
* Represents a stopwatch for measuring time intervals.
|
|
5
23
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stopwatch.d.ts","sourceRoot":"","sources":["../../../src/time/stopwatch/stopwatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"stopwatch.d.ts","sourceRoot":"","sources":["../../../src/time/stopwatch/stopwatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,WAAW;IAC9C;;OAEG;gBACS,OAAO,EAAE,MAAM;CAG3B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,qBAAa,SAAS;IACrB,OAAO,CAAC,MAAM,CAAwB;IAEtC,OAAO,CAAC,SAAS,CAAuB;IAExC,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;;;;;;;;;OAYG;gBACS,gBAAgB,UAAQ;IAMpC;;;;OAIG;IACH,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,IAAW,OAAO,IAAI,OAAO,CAE5B;IAED;;;;;OAKG;IACH,IAAW,KAAK,IAAI,cAAc,GAAG,SAAS,CAE7C;IAED;;;;;OAKG;IACH,IAAW,MAAM,IAAI,cAAc,GAAG,SAAS,CAE9C;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,IAAW,OAAO,IAAI,WAAW,CAUhC;IAED;;;;;OAKG;IACH,IAAW,KAAK,IAAI,cAAc,EAAE,CAEnC;IAED;;OAEG;IACH,IAAW,OAAO,IAAI,cAAc,EAAE,CAErC;IAED;;;OAGG;IACH,IAAW,QAAQ,IAAI,MAAM,GAAG,IAAI,CAEnC;IAED;;;;;;;;;;;;;;;;OAgBG;IACI,KAAK,IAAI,cAAc,GAAG,SAAS;IAU1C;;;;;;;;;;;;;;;;;;;;OAoBG;IACI,IAAI,IAAI,cAAc,GAAG,SAAS;IAmBzC;;;;;;;;;;;;;;;;;;;OAmBG;IACI,KAAK,IAAI,cAAc,GAAG,IAAI;IAQrC;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACI,MAAM,IAAI,cAAc,GAAG,IAAI;IActC;;;;;;;;;;;;;;;;OAgBG;IACI,KAAK,IAAI,cAAc;IAW9B;;;;;;;;;;;;;;;;;;OAkBG;IACI,GAAG,IAAI,WAAW;IAUzB;;;;;;;;;;;;;;;OAeG;IACI,KAAK,IAAI,IAAI;CAKpB"}
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { ElapsedTime } from '../elapsed-time/elapsed-time.js';
|
|
2
2
|
import { StopwatchEntry } from './entry.js';
|
|
3
|
+
import { SimpleError } from '../../asserts/errors.js';
|
|
4
|
+
/**
|
|
5
|
+
* Error thrown by Stopwatch when an invalid operation is attempted.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const sw = new Stopwatch();
|
|
10
|
+
* sw.Start();
|
|
11
|
+
* sw.Stop();
|
|
12
|
+
* sw.Resume(); // Throws StopwatchError
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export class StopwatchError extends SimpleError {
|
|
16
|
+
/**
|
|
17
|
+
* @param message - Description of the stopwatch state error
|
|
18
|
+
*/
|
|
19
|
+
constructor(message) {
|
|
20
|
+
super(message);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
3
23
|
/**
|
|
4
24
|
* Represents a stopwatch for measuring time intervals.
|
|
5
25
|
*
|
|
@@ -256,6 +276,9 @@ export class Stopwatch {
|
|
|
256
276
|
* ```
|
|
257
277
|
*/
|
|
258
278
|
Resume() {
|
|
279
|
+
if (this._stopped) {
|
|
280
|
+
throw new StopwatchError('Cannot resume after stopwatch has been stopped');
|
|
281
|
+
}
|
|
259
282
|
if (this._pausedAt === null)
|
|
260
283
|
return null;
|
|
261
284
|
const current = Date.now();
|