@develia/commons 0.4.26 → 0.6.1
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/dist/array.d.ts +10 -0
- package/dist/array.d.ts.map +1 -1
- package/dist/array.js +18 -0
- package/dist/array.js.map +1 -1
- package/dist/async-pool-executor.d.ts +3 -5
- package/dist/async-pool-executor.d.ts.map +1 -1
- package/dist/async-pool-executor.js +9 -9
- package/dist/async-pool-executor.js.map +1 -1
- package/dist/browser/form-utilities.d.ts +0 -2
- package/dist/browser/form-utilities.d.ts.map +1 -1
- package/dist/browser/form-utilities.js +3 -23
- package/dist/browser/form-utilities.js.map +1 -1
- package/dist/browser/geo-location.js +3 -3
- package/dist/browser/geo-location.js.map +1 -1
- package/dist/browser/native-bridge.d.ts +1 -1
- package/dist/browser/native-bridge.d.ts.map +1 -1
- package/dist/browser/native-bridge.js +2 -2
- package/dist/browser/native-bridge.js.map +1 -1
- package/dist/cancellable-promise.d.ts +8 -2
- package/dist/cancellable-promise.d.ts.map +1 -1
- package/dist/cancellable-promise.js +9 -3
- package/dist/cancellable-promise.js.map +1 -1
- package/dist/clean-url-search-params.js +3 -3
- package/dist/clean-url-search-params.js.map +1 -1
- package/dist/collections/from.d.ts +16 -5
- package/dist/collections/from.d.ts.map +1 -1
- package/dist/collections/from.js +69 -38
- package/dist/collections/from.js.map +1 -1
- package/dist/draft.d.ts +2 -2
- package/dist/draft.d.ts.map +1 -1
- package/dist/draft.js +2 -2
- package/dist/draft.js.map +1 -1
- package/dist/functions.d.ts +2 -2
- package/dist/functions.d.ts.map +1 -1
- package/dist/functions.js +1 -1
- package/dist/functions.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/math.d.ts +14 -5
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +16 -5
- package/dist/math.js.map +1 -1
- package/dist/parse.d.ts +62 -44
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +95 -59
- package/dist/parse.js.map +1 -1
- package/dist/range.d.ts +2 -10
- package/dist/range.d.ts.map +1 -1
- package/dist/range.js +0 -12
- package/dist/range.js.map +1 -1
- package/dist/stopwatch.d.ts +2 -2
- package/dist/stopwatch.d.ts.map +1 -1
- package/dist/stopwatch.js +9 -9
- package/dist/stopwatch.js.map +1 -1
- package/dist/string.d.ts +15 -0
- package/dist/string.d.ts.map +1 -1
- package/dist/string.js +28 -3
- package/dist/string.js.map +1 -1
- package/dist/timespan.d.ts +10 -15
- package/dist/timespan.d.ts.map +1 -1
- package/dist/timespan.js +10 -15
- package/dist/timespan.js.map +1 -1
- package/dist/triggers.d.ts +6 -15
- package/dist/triggers.d.ts.map +1 -1
- package/dist/triggers.js +8 -22
- package/dist/triggers.js.map +1 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities.d.ts +7 -6
- package/dist/utilities.d.ts.map +1 -1
- package/dist/utilities.js +19 -20
- package/dist/utilities.js.map +1 -1
- package/dist/uuid.d.ts +73 -0
- package/dist/uuid.d.ts.map +1 -0
- package/dist/uuid.js +129 -0
- package/dist/uuid.js.map +1 -0
- package/package.json +5 -1
- package/src/array.ts +19 -0
- package/src/async-pool-executor.ts +9 -9
- package/src/browser/form-utilities.ts +3 -32
- package/src/browser/geo-location.ts +3 -3
- package/src/browser/index.ts +0 -0
- package/src/browser/native-bridge.ts +2 -2
- package/src/cancellable-promise.ts +9 -3
- package/src/clean-url-search-params.ts +3 -3
- package/src/collections/cache-dictionary.ts +0 -0
- package/src/collections/default-map.ts +0 -0
- package/src/collections/default-weak-map.ts +0 -0
- package/src/collections/from.ts +70 -38
- package/src/collections/index.ts +0 -0
- package/src/draft.ts +3 -3
- package/src/event-bus.ts +0 -0
- package/src/functions.ts +3 -3
- package/src/index.ts +2 -1
- package/src/key-value-pair.ts +0 -0
- package/src/lazy.ts +0 -0
- package/src/math.ts +17 -5
- package/src/order.ts +0 -0
- package/src/parse.ts +108 -66
- package/src/patch.ts +0 -0
- package/src/range.ts +2 -16
- package/src/stopwatch.ts +9 -9
- package/src/string.ts +33 -3
- package/src/timer.ts +0 -0
- package/src/timespan.ts +10 -15
- package/src/triggers.ts +10 -24
- package/src/type-code.ts +0 -0
- package/src/type.ts +0 -0
- package/src/types.ts +0 -1
- package/src/utilities.ts +22 -25
- package/src/uuid.ts +153 -0
|
@@ -7,12 +7,12 @@ function isRecordParams(params: unknown): params is Record<string, any> {
|
|
|
7
7
|
typeof (params as any)[Symbol.iterator] !== 'function';
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
function
|
|
10
|
+
function appendNonNullishValues(params: URLSearchParams, key: string, value: any): void {
|
|
11
11
|
if (value === null || value === undefined) return;
|
|
12
12
|
|
|
13
13
|
if (Array.isArray(value)) {
|
|
14
14
|
for (const item of value) {
|
|
15
|
-
|
|
15
|
+
appendNonNullishValues(params, key, item);
|
|
16
16
|
}
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
@@ -31,7 +31,7 @@ export default class CleanURLSearchParams extends URLSearchParams {
|
|
|
31
31
|
|
|
32
32
|
// Filtrar `null` y `undefined` antes de añadirlos a URLSearchParams
|
|
33
33
|
for (const [key, value] of Object.entries(params)) {
|
|
34
|
-
|
|
34
|
+
appendNonNullishValues(this, key, value);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/collections/from.ts
CHANGED
|
@@ -485,7 +485,7 @@ export class From<T> implements Iterable<T> {
|
|
|
485
485
|
array.sort((a, b) => {
|
|
486
486
|
const aValue = mapper(a);
|
|
487
487
|
const bValue = mapper(b);
|
|
488
|
-
return aValue > bValue ? 1 :
|
|
488
|
+
return aValue > bValue ? -1 : aValue < bValue ? 1 : 0;
|
|
489
489
|
});
|
|
490
490
|
} else {
|
|
491
491
|
throw new Error("invalid order argument");
|
|
@@ -713,11 +713,11 @@ export class From<T> implements Iterable<T> {
|
|
|
713
713
|
|
|
714
714
|
|
|
715
715
|
/**
|
|
716
|
-
*
|
|
716
|
+
* The elements of this sequence followed by those of the other, duplicates included, as LINQ's Concat.
|
|
717
717
|
* @param {Iterable<T>} other - The other sequence.
|
|
718
718
|
* @returns {From<T>} A new From instance.
|
|
719
719
|
*/
|
|
720
|
-
public
|
|
720
|
+
public concat(other: Iterable<T>): From<T> {
|
|
721
721
|
const self = this;
|
|
722
722
|
return From.fn<T>(function* () {
|
|
723
723
|
yield* self;
|
|
@@ -726,7 +726,19 @@ export class From<T> implements Iterable<T> {
|
|
|
726
726
|
}
|
|
727
727
|
|
|
728
728
|
/**
|
|
729
|
-
*
|
|
729
|
+
* The set union, as LINQ's Union: the elements of this sequence and then those of the other, each one once (the
|
|
730
|
+
* first time it appears), compared as distinct() does.
|
|
731
|
+
* @param {Iterable<T>} other - The other sequence.
|
|
732
|
+
* @param {EqualityComparer<T>} [equalityComparer] - Optional equality comparer; shallowEqual when not given.
|
|
733
|
+
* @returns {From<T>} A new From instance.
|
|
734
|
+
*/
|
|
735
|
+
public union(other: Iterable<T>, equalityComparer?: EqualityComparer<T>): From<T> {
|
|
736
|
+
return this.concat(other).distinct(equalityComparer);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Correlates the elements of two sequences based on matching keys: one result per matching pair, so an element
|
|
741
|
+
* that matches several elements of the other sequence gives one result for each.
|
|
730
742
|
* @template T2, R, R2
|
|
731
743
|
* @param {Iterable<T2>} other - The other sequence.
|
|
732
744
|
* @param {UnaryFunction<T, R>} thisKeySelector - Key selector for this sequence.
|
|
@@ -738,18 +750,20 @@ export class From<T> implements Iterable<T> {
|
|
|
738
750
|
|
|
739
751
|
const self = this;
|
|
740
752
|
return From.fn<R2>(() => {
|
|
741
|
-
const otherByKey =
|
|
742
|
-
|
|
743
|
-
|
|
753
|
+
const otherByKey = groupItemsByKey(other, otherKeySelector);
|
|
754
|
+
const results: R2[] = [];
|
|
755
|
+
for (const item of self) {
|
|
756
|
+
for (const otherItem of otherByKey.get(thisKeySelector(item)) ?? []) {
|
|
757
|
+
results.push(resultSelector(item, otherItem));
|
|
758
|
+
}
|
|
744
759
|
}
|
|
745
|
-
return
|
|
746
|
-
.filter(item => otherByKey.has(thisKeySelector(item)))
|
|
747
|
-
.map(item => resultSelector(item, otherByKey.get(thisKeySelector(item))!));
|
|
760
|
+
return results;
|
|
748
761
|
});
|
|
749
762
|
}
|
|
750
763
|
|
|
751
764
|
/**
|
|
752
|
-
* Performs a left join on two sequences
|
|
765
|
+
* Performs a left join on two sequences: one result per matching pair, and one with `undefined` for each element of
|
|
766
|
+
* this sequence that matches none.
|
|
753
767
|
* @template U, K, R
|
|
754
768
|
* @param {Iterable<U>} other - The other sequence.
|
|
755
769
|
* @param {UnaryFunction<T, K>} thisKeySelector - Key selector for this sequence.
|
|
@@ -761,11 +775,19 @@ export class From<T> implements Iterable<T> {
|
|
|
761
775
|
|
|
762
776
|
const self = this;
|
|
763
777
|
return From.fn<R>(() => {
|
|
764
|
-
const otherByKey =
|
|
765
|
-
|
|
766
|
-
|
|
778
|
+
const otherByKey = groupItemsByKey(other, otherKeySelector);
|
|
779
|
+
const results: R[] = [];
|
|
780
|
+
for (const item of self) {
|
|
781
|
+
const matches = otherByKey.get(thisKeySelector(item));
|
|
782
|
+
if (matches === undefined) {
|
|
783
|
+
results.push(resultSelector(item, undefined));
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
for (const otherItem of matches) {
|
|
787
|
+
results.push(resultSelector(item, otherItem));
|
|
788
|
+
}
|
|
767
789
|
}
|
|
768
|
-
return
|
|
790
|
+
return results;
|
|
769
791
|
});
|
|
770
792
|
}
|
|
771
793
|
|
|
@@ -783,15 +805,8 @@ export class From<T> implements Iterable<T> {
|
|
|
783
805
|
|
|
784
806
|
const self = this;
|
|
785
807
|
return From.fn<R>(() => {
|
|
786
|
-
const
|
|
787
|
-
|
|
788
|
-
const key = otherKeySelector(item);
|
|
789
|
-
if (!otherByKeys.has(key)) {
|
|
790
|
-
otherByKeys.set(key, []);
|
|
791
|
-
}
|
|
792
|
-
otherByKeys.get(key)!.push(item);
|
|
793
|
-
}
|
|
794
|
-
return Array.from(self).map(item => resultSelector(item, otherByKeys.get(thisKeySelector(item)) || []));
|
|
808
|
+
const otherByKey = groupItemsByKey(other, otherKeySelector);
|
|
809
|
+
return Array.from(self).map(item => resultSelector(item, otherByKey.get(thisKeySelector(item)) ?? []));
|
|
795
810
|
});
|
|
796
811
|
}
|
|
797
812
|
|
|
@@ -808,21 +823,15 @@ export class From<T> implements Iterable<T> {
|
|
|
808
823
|
|
|
809
824
|
const self = this;
|
|
810
825
|
return From.fn<R>(() => {
|
|
811
|
-
const
|
|
812
|
-
|
|
813
|
-
const key = thisKeySelector(item);
|
|
814
|
-
if (!thisByKeys.has(key)) {
|
|
815
|
-
thisByKeys.set(key, []);
|
|
816
|
-
}
|
|
817
|
-
thisByKeys.get(key)!.push(item);
|
|
818
|
-
}
|
|
819
|
-
return Array.from(other).map(item => resultSelector(thisByKeys.get(otherKeySelector(item)) || [], item));
|
|
826
|
+
const thisByKey = groupItemsByKey(self, thisKeySelector);
|
|
827
|
+
return Array.from(other).map(item => resultSelector(thisByKey.get(otherKeySelector(item)) ?? [], item));
|
|
820
828
|
});
|
|
821
829
|
}
|
|
822
830
|
|
|
823
831
|
|
|
824
832
|
/**
|
|
825
|
-
* Performs a right join on two sequences
|
|
833
|
+
* Performs a right join on two sequences: one result per matching pair, and one with `undefined` for each element of
|
|
834
|
+
* the other sequence that matches none.
|
|
826
835
|
* @template U, K, R
|
|
827
836
|
* @param {Iterable<U>} other - The other sequence.
|
|
828
837
|
* @param {UnaryFunction<T, K>} thisKeySelector - Key selector for this sequence.
|
|
@@ -834,16 +843,39 @@ export class From<T> implements Iterable<T> {
|
|
|
834
843
|
|
|
835
844
|
const self = this;
|
|
836
845
|
return From.fn<R>(() => {
|
|
837
|
-
const thisByKey =
|
|
838
|
-
|
|
839
|
-
|
|
846
|
+
const thisByKey = groupItemsByKey(self, thisKeySelector);
|
|
847
|
+
const results: R[] = [];
|
|
848
|
+
for (const otherItem of other) {
|
|
849
|
+
const matches = thisByKey.get(otherKeySelector(otherItem));
|
|
850
|
+
if (matches === undefined) {
|
|
851
|
+
results.push(resultSelector(undefined, otherItem));
|
|
852
|
+
continue;
|
|
853
|
+
}
|
|
854
|
+
for (const item of matches) {
|
|
855
|
+
results.push(resultSelector(item, otherItem));
|
|
856
|
+
}
|
|
840
857
|
}
|
|
841
|
-
return
|
|
858
|
+
return results;
|
|
842
859
|
});
|
|
843
860
|
}
|
|
844
861
|
|
|
845
862
|
}
|
|
846
863
|
|
|
864
|
+
/** The items of a sequence in lists by their key, in their order, for the joins. */
|
|
865
|
+
function groupItemsByKey<TItem, TKey>(items: Iterable<TItem>, keySelector: UnaryFunction<TItem, TKey>): Map<TKey, TItem[]> {
|
|
866
|
+
const itemsByKey = new Map<TKey, TItem[]>();
|
|
867
|
+
for (const item of items) {
|
|
868
|
+
const key = keySelector(item);
|
|
869
|
+
const group = itemsByKey.get(key);
|
|
870
|
+
if (group === undefined) {
|
|
871
|
+
itemsByKey.set(key, [item]);
|
|
872
|
+
} else {
|
|
873
|
+
group.push(item);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
return itemsByKey;
|
|
877
|
+
}
|
|
878
|
+
|
|
847
879
|
/**
|
|
848
880
|
* Represents a group of elements that have a common key.
|
|
849
881
|
* @template TKey, T
|
package/src/collections/index.ts
CHANGED
|
File without changes
|
package/src/draft.ts
CHANGED
|
@@ -39,7 +39,7 @@ type DraftMethods<T> = {
|
|
|
39
39
|
*
|
|
40
40
|
* @returns Array of modified property keys (does not recurse into children).
|
|
41
41
|
*/
|
|
42
|
-
|
|
42
|
+
getModifiedProps(): (keyof T)[];
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* Manually mark (or unmark) a property as modified.
|
|
@@ -155,7 +155,7 @@ function deepDraft(value: any, parentLink?: ParentLink): any {
|
|
|
155
155
|
/**
|
|
156
156
|
* Create a draft proxy over `original`. The proxy exposes the same properties
|
|
157
157
|
* as the original (with nested objects wrapped as child drafts) plus the
|
|
158
|
-
* control methods `commit`, `rollback`, `isModified`, `
|
|
158
|
+
* control methods `commit`, `rollback`, `isModified`, `getModifiedProps` and
|
|
159
159
|
* `setModified`.
|
|
160
160
|
*
|
|
161
161
|
* Mutations on the draft do not affect the original until `commit()` is called.
|
|
@@ -249,7 +249,7 @@ export default function draft<T extends object>(
|
|
|
249
249
|
return key === undefined ? touched.size > 0 : touched.has(key);
|
|
250
250
|
},
|
|
251
251
|
|
|
252
|
-
|
|
252
|
+
getModifiedProps() {
|
|
253
253
|
return [...touched] as (keyof T)[];
|
|
254
254
|
},
|
|
255
255
|
|
package/src/event-bus.ts
CHANGED
|
File without changes
|
package/src/functions.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface ThrottleOptions {
|
|
|
17
17
|
* const refresh = throttle(loadData, 250);
|
|
18
18
|
* refresh();
|
|
19
19
|
*
|
|
20
|
-
* if (refresh.
|
|
20
|
+
* if (refresh.isPending()) {
|
|
21
21
|
* refresh.flush();
|
|
22
22
|
* }
|
|
23
23
|
* ```
|
|
@@ -31,7 +31,7 @@ export type DeferredFunction<F extends AnyFunction> = ((
|
|
|
31
31
|
/** Execute the scheduled trailing call immediately, when one exists. */
|
|
32
32
|
flush(): ReturnType<F> | undefined;
|
|
33
33
|
/** Return true while a trailing call is scheduled. */
|
|
34
|
-
|
|
34
|
+
isPending(): boolean;
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
/**
|
|
@@ -300,7 +300,7 @@ export function throttle<F extends AnyFunction>(
|
|
|
300
300
|
return result;
|
|
301
301
|
};
|
|
302
302
|
|
|
303
|
-
throttled.
|
|
303
|
+
throttled.isPending = (): boolean => timer !== undefined;
|
|
304
304
|
|
|
305
305
|
return throttled;
|
|
306
306
|
}
|
package/src/index.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
export * from './types.js';
|
|
5
5
|
export {default as Type} from './type.js';
|
|
6
6
|
export {default as TypeCode} from './type-code.js';
|
|
7
|
+
export {default as Uuid} from './uuid.js';
|
|
7
8
|
|
|
8
9
|
// ─── Utilities ───────────────────────────────────────
|
|
9
10
|
export * from './utilities.js';
|
|
@@ -41,7 +42,7 @@ export {default as draft} from './draft.js';
|
|
|
41
42
|
// ─── Web ─────────────────────────────────────────────
|
|
42
43
|
export {default as CleanURLSearchParams} from './clean-url-search-params.js';
|
|
43
44
|
/** @deprecated */
|
|
44
|
-
export {ajaxSubmit,
|
|
45
|
+
export {ajaxSubmit, submitForm, formToObject} from './browser/index.js';
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
|
package/src/key-value-pair.ts
CHANGED
|
File without changes
|
package/src/lazy.ts
CHANGED
|
File without changes
|
package/src/math.ts
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Linearly interpolates a
|
|
2
|
+
* Linearly interpolates between two numbers: `a` for `t` 0, `b` for `t` 1, and beyond them outside that range.
|
|
3
3
|
*
|
|
4
|
-
* @param {number}
|
|
4
|
+
* @param {number} a - The value at `t` 0.
|
|
5
|
+
* @param {number} b - The value at `t` 1.
|
|
6
|
+
* @param {number} t - The interpolation factor.
|
|
7
|
+
* @return {number} - The interpolated value.
|
|
8
|
+
*/
|
|
9
|
+
export function lerp(a: number, b: number, t: number): number {
|
|
10
|
+
return a + (b - a) * t;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Maps a number from one range to another, keeping its proportion (`remap(5, 0, 10, 0, 100)` is 50).
|
|
15
|
+
*
|
|
16
|
+
* @param {number} n - The number to map.
|
|
5
17
|
* @param {number} inMin - The minimum value of the input range.
|
|
6
18
|
* @param {number} inMax - The maximum value of the input range.
|
|
7
19
|
* @param {number} outMin - The minimum value of the output range.
|
|
8
20
|
* @param {number} outMax - The maximum value of the output range.
|
|
9
|
-
*
|
|
10
|
-
* @
|
|
21
|
+
* @return {number} - The number in the output range.
|
|
22
|
+
* @throws {Error} When the input range is empty (`inMin === inMax`).
|
|
11
23
|
*/
|
|
12
|
-
export function
|
|
24
|
+
export function remap(n: number, inMin: number, inMax: number, outMin: number, outMax: number): number {
|
|
13
25
|
if (inMax === inMin) {
|
|
14
26
|
throw new Error("Input range cannot be zero");
|
|
15
27
|
}
|
package/src/order.ts
CHANGED
|
File without changes
|
package/src/parse.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// parse.ts
|
|
2
2
|
/**
|
|
3
|
-
* Options for {@link parseBoolean}.
|
|
3
|
+
* Options for {@link tryParseBoolean} and {@link parseBoolean}.
|
|
4
4
|
*/
|
|
5
5
|
export interface ParseBooleanOptions {
|
|
6
6
|
/**
|
|
@@ -19,7 +19,7 @@ export interface ParseBooleanOptions {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Options for {@link parseInteger}.
|
|
22
|
+
* Options for {@link tryParseInteger} and {@link parseInteger}.
|
|
23
23
|
*/
|
|
24
24
|
export interface ParseIntegerOptions {
|
|
25
25
|
/**
|
|
@@ -37,7 +37,7 @@ export interface ParseIntegerOptions {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Options for {@link parseDecimal}.
|
|
40
|
+
* Options for {@link tryParseDecimal} and {@link parseDecimal}.
|
|
41
41
|
*/
|
|
42
42
|
export interface ParseDecimalOptions {
|
|
43
43
|
/**
|
|
@@ -75,64 +75,78 @@ function isValidInteger(value: string, radix: number): boolean {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
// ============================================
|
|
78
|
-
// parseInteger
|
|
78
|
+
// tryParseInteger / parseInteger
|
|
79
79
|
// ============================================
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
82
|
* Safely parses a value into an integer.
|
|
83
|
-
* Returns `
|
|
83
|
+
* Returns `undefined` if the value cannot be parsed.
|
|
84
84
|
*
|
|
85
|
-
* - `null` or `undefined` → `
|
|
85
|
+
* - `null` or `undefined` → `undefined`
|
|
86
86
|
* - `number` → returned as-is (floats are truncated)
|
|
87
87
|
* - `string` → parsed with the given options
|
|
88
88
|
*
|
|
89
89
|
* @param value - The value to parse.
|
|
90
90
|
* @param options - Optional parsing configuration.
|
|
91
|
-
* @returns The parsed integer, or `
|
|
91
|
+
* @returns The parsed integer, or `undefined` on failure.
|
|
92
92
|
*
|
|
93
93
|
* @example
|
|
94
94
|
* ```ts
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
95
|
+
* tryParseInteger(42) // 42
|
|
96
|
+
* tryParseInteger(3.7) // 3
|
|
97
|
+
* tryParseInteger(null) // undefined
|
|
98
|
+
* tryParseInteger(undefined) // undefined
|
|
99
|
+
* tryParseInteger("42") // 42
|
|
100
|
+
* tryParseInteger("1.234.567", { thousandsSeparator: "." }) // 1234567
|
|
101
|
+
* tryParseInteger("FF", { radix: 16 }) // 255
|
|
102
|
+
* tryParseInteger("abc") // undefined
|
|
103
103
|
* ```
|
|
104
104
|
*/
|
|
105
|
-
export function
|
|
105
|
+
export function tryParseInteger(
|
|
106
106
|
value: string | number | null | undefined,
|
|
107
107
|
options: ParseIntegerOptions = {}
|
|
108
|
-
): number |
|
|
109
|
-
if (value === null || value === undefined) return
|
|
108
|
+
): number | undefined {
|
|
109
|
+
if (value === null || value === undefined) return undefined;
|
|
110
110
|
|
|
111
111
|
if (typeof value === "number") {
|
|
112
|
-
return Number.isFinite(value) ? Math.trunc(value) :
|
|
112
|
+
return Number.isFinite(value) ? Math.trunc(value) : undefined;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
const { radix = 10, thousandsSeparator } = options;
|
|
116
116
|
|
|
117
117
|
const cleaned = stripThousands(value.trim(), thousandsSeparator);
|
|
118
118
|
|
|
119
|
-
if (cleaned === "") return
|
|
120
|
-
if (!isValidInteger(cleaned, radix)) return
|
|
119
|
+
if (cleaned === "") return undefined;
|
|
120
|
+
if (!isValidInteger(cleaned, radix)) return undefined;
|
|
121
121
|
|
|
122
122
|
const parsed = Number.parseInt(cleaned, radix);
|
|
123
123
|
|
|
124
|
-
return Number.isNaN(parsed) ?
|
|
124
|
+
return Number.isNaN(parsed) ? undefined : parsed;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Parses a value into an integer as {@link tryParseInteger} does.
|
|
129
|
+
*
|
|
130
|
+
* @throws {SyntaxError} If the value cannot be parsed.
|
|
131
|
+
*/
|
|
132
|
+
export function parseInteger(value: string | number, options: ParseIntegerOptions = {}): number {
|
|
133
|
+
const parsed = tryParseInteger(value, options);
|
|
134
|
+
if (parsed === undefined) {
|
|
135
|
+
throw new SyntaxError(`Invalid integer "${value}".`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return parsed;
|
|
125
139
|
}
|
|
126
140
|
|
|
127
141
|
// ============================================
|
|
128
|
-
// parseDecimal
|
|
142
|
+
// tryParseDecimal / parseDecimal
|
|
129
143
|
// ============================================
|
|
130
144
|
|
|
131
145
|
/**
|
|
132
146
|
* Safely parses a value into a floating-point number.
|
|
133
|
-
* Returns `
|
|
147
|
+
* Returns `undefined` if the value cannot be parsed.
|
|
134
148
|
*
|
|
135
|
-
* - `null` or `undefined` → `
|
|
149
|
+
* - `null` or `undefined` → `undefined`
|
|
136
150
|
* - `number` → returned as-is (if finite)
|
|
137
151
|
* - `string` → parsed with the given options
|
|
138
152
|
*
|
|
@@ -141,50 +155,64 @@ export function parseInteger(
|
|
|
141
155
|
*
|
|
142
156
|
* @param value - The value to parse.
|
|
143
157
|
* @param options - Optional parsing configuration.
|
|
144
|
-
* @returns The parsed float, or `
|
|
158
|
+
* @returns The parsed float, or `undefined` on failure.
|
|
145
159
|
*
|
|
146
160
|
* @example
|
|
147
161
|
* ```ts
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
162
|
+
* tryParseDecimal(3.14) // 3.14
|
|
163
|
+
* tryParseDecimal(null) // undefined
|
|
164
|
+
* tryParseDecimal(undefined) // undefined
|
|
165
|
+
* tryParseDecimal("3.14") // 3.14
|
|
166
|
+
* tryParseDecimal("3,14", { decimalSeparator: "," }) // 3.14
|
|
167
|
+
* tryParseDecimal("1.234,56", { decimalSeparator: ",", thousandsSeparator: "." }) // 1234.56
|
|
168
|
+
* tryParseDecimal("abc") // undefined
|
|
155
169
|
* ```
|
|
156
170
|
*/
|
|
157
|
-
export function
|
|
171
|
+
export function tryParseDecimal(
|
|
158
172
|
value: string | number | null | undefined,
|
|
159
173
|
options: ParseDecimalOptions = {}
|
|
160
|
-
): number |
|
|
161
|
-
if (value === null || value === undefined) return
|
|
174
|
+
): number | undefined {
|
|
175
|
+
if (value === null || value === undefined) return undefined;
|
|
162
176
|
|
|
163
177
|
if (typeof value === "number") {
|
|
164
|
-
return Number.isFinite(value) ? value :
|
|
178
|
+
return Number.isFinite(value) ? value : undefined;
|
|
165
179
|
}
|
|
166
180
|
|
|
167
181
|
const { decimalSeparator = ".", thousandsSeparator } = options;
|
|
168
182
|
|
|
169
183
|
let cleaned = stripThousands(value.trim(), thousandsSeparator);
|
|
170
184
|
|
|
171
|
-
if (cleaned === "") return
|
|
185
|
+
if (cleaned === "") return undefined;
|
|
172
186
|
|
|
173
187
|
if (decimalSeparator === ",") {
|
|
174
188
|
const commaCount = (cleaned.match(/,/g) || []).length;
|
|
175
|
-
if (commaCount > 1) return
|
|
189
|
+
if (commaCount > 1) return undefined;
|
|
176
190
|
cleaned = cleaned.replace(",", ".");
|
|
177
191
|
}
|
|
178
192
|
|
|
179
|
-
if (!/^[+-]?\d+(\.\d+)?$/.test(cleaned)) return
|
|
193
|
+
if (!/^[+-]?\d+(\.\d+)?$/.test(cleaned)) return undefined;
|
|
180
194
|
|
|
181
195
|
const parsed = Number.parseFloat(cleaned);
|
|
182
196
|
|
|
183
|
-
return Number.isNaN(parsed) || !Number.isFinite(parsed) ?
|
|
197
|
+
return Number.isNaN(parsed) || !Number.isFinite(parsed) ? undefined : parsed;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Parses a value into a decimal number as {@link tryParseDecimal} does.
|
|
202
|
+
*
|
|
203
|
+
* @throws {SyntaxError} If the value cannot be parsed.
|
|
204
|
+
*/
|
|
205
|
+
export function parseDecimal(value: string | number, options: ParseDecimalOptions = {}): number {
|
|
206
|
+
const parsed = tryParseDecimal(value, options);
|
|
207
|
+
if (parsed === undefined) {
|
|
208
|
+
throw new SyntaxError(`Invalid decimal number "${value}".`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return parsed;
|
|
184
212
|
}
|
|
185
213
|
|
|
186
214
|
// ============================================
|
|
187
|
-
// parseBoolean
|
|
215
|
+
// tryParseBoolean / parseBoolean
|
|
188
216
|
// ============================================
|
|
189
217
|
|
|
190
218
|
const DEFAULT_TRUTHY = ["true", "1", "yes", "si", "sí", "on"];
|
|
@@ -192,9 +220,9 @@ const DEFAULT_FALSY = ["false", "0", "no", "off"];
|
|
|
192
220
|
|
|
193
221
|
/**
|
|
194
222
|
* Safely parses a value into a boolean.
|
|
195
|
-
* Returns `
|
|
223
|
+
* Returns `undefined` if the value cannot be interpreted as boolean.
|
|
196
224
|
*
|
|
197
|
-
* - `null` or `undefined` → `
|
|
225
|
+
* - `null` or `undefined` → `undefined`
|
|
198
226
|
* - `boolean` → returned as-is
|
|
199
227
|
* - `number` → `0` is `false`, any other finite number is `true`
|
|
200
228
|
* - `string` → matched case-insensitively against known truthy/falsy values
|
|
@@ -204,43 +232,43 @@ const DEFAULT_FALSY = ["false", "0", "no", "off"];
|
|
|
204
232
|
*
|
|
205
233
|
* @param value - The value to parse.
|
|
206
234
|
* @param options - Optional parsing configuration.
|
|
207
|
-
* @returns The parsed boolean, or `
|
|
235
|
+
* @returns The parsed boolean, or `undefined` on failure.
|
|
208
236
|
*
|
|
209
237
|
* @example
|
|
210
238
|
* ```ts
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
239
|
+
* tryParseBoolean(true) // true
|
|
240
|
+
* tryParseBoolean(false) // false
|
|
241
|
+
* tryParseBoolean(1) // true
|
|
242
|
+
* tryParseBoolean(0) // false
|
|
243
|
+
* tryParseBoolean(null) // undefined
|
|
244
|
+
* tryParseBoolean(undefined) // undefined
|
|
245
|
+
* tryParseBoolean("yes") // true
|
|
246
|
+
* tryParseBoolean("no") // false
|
|
247
|
+
* tryParseBoolean("sí") // true
|
|
248
|
+
* tryParseBoolean("TRUE") // true
|
|
249
|
+
* tryParseBoolean("oui") // undefined
|
|
250
|
+
* tryParseBoolean("oui", { extraTruthy: ["oui"] }) // true
|
|
251
|
+
* tryParseBoolean("nein", { extraFalsy: ["nein"] }) // false
|
|
252
|
+
* tryParseBoolean("whatever") // undefined
|
|
225
253
|
* ```
|
|
226
254
|
*/
|
|
227
|
-
export function
|
|
255
|
+
export function tryParseBoolean(
|
|
228
256
|
value: string | number | boolean | null | undefined,
|
|
229
257
|
options: ParseBooleanOptions = {}
|
|
230
|
-
): boolean |
|
|
231
|
-
if (value === null || value === undefined) return
|
|
258
|
+
): boolean | undefined {
|
|
259
|
+
if (value === null || value === undefined) return undefined;
|
|
232
260
|
|
|
233
261
|
if (typeof value === "boolean") return value;
|
|
234
262
|
|
|
235
263
|
if (typeof value === "number") {
|
|
236
|
-
return Number.isFinite(value) ? value !== 0 :
|
|
264
|
+
return Number.isFinite(value) ? value !== 0 : undefined;
|
|
237
265
|
}
|
|
238
266
|
|
|
239
267
|
const { extraTruthy = [], extraFalsy = [] } = options;
|
|
240
268
|
|
|
241
269
|
const normalized = value.trim().toLowerCase();
|
|
242
270
|
|
|
243
|
-
if (normalized === "") return
|
|
271
|
+
if (normalized === "") return undefined;
|
|
244
272
|
|
|
245
273
|
const truthy = [...DEFAULT_TRUTHY, ...extraTruthy.map((s) => s.toLowerCase())];
|
|
246
274
|
const falsy = [...DEFAULT_FALSY, ...extraFalsy.map((s) => s.toLowerCase())];
|
|
@@ -248,5 +276,19 @@ export function parseBoolean(
|
|
|
248
276
|
if (truthy.includes(normalized)) return true;
|
|
249
277
|
if (falsy.includes(normalized)) return false;
|
|
250
278
|
|
|
251
|
-
return
|
|
252
|
-
}
|
|
279
|
+
return undefined;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Parses a value into a boolean as {@link tryParseBoolean} does.
|
|
284
|
+
*
|
|
285
|
+
* @throws {SyntaxError} If the value cannot be parsed.
|
|
286
|
+
*/
|
|
287
|
+
export function parseBoolean(value: string | number | boolean, options: ParseBooleanOptions = {}): boolean {
|
|
288
|
+
const parsed = tryParseBoolean(value, options);
|
|
289
|
+
if (parsed === undefined) {
|
|
290
|
+
throw new SyntaxError(`Invalid boolean "${value}".`);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return parsed;
|
|
294
|
+
}
|
package/src/patch.ts
CHANGED
|
File without changes
|