@oscarpalmer/atoms 0.180.0 → 0.182.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/dist/array/find.d.mts +42 -1
- package/dist/array/find.mjs +5 -1
- package/dist/array/get.mjs +2 -2
- package/dist/array/index.d.mts +3 -3
- package/dist/array/index.mjs +3 -3
- package/dist/index.d.mts +238 -25
- package/dist/index.mjs +242 -19
- package/dist/internal/array/find.d.mts +4 -3
- package/dist/internal/array/find.mjs +5 -2
- package/dist/internal/array/index-of.d.mts +42 -1
- package/dist/internal/array/index-of.mjs +5 -1
- package/dist/internal/math/aggregate.mjs +2 -2
- package/dist/internal/result.mjs +2 -2
- package/dist/internal/string.d.mts +5 -3
- package/dist/internal/string.mjs +14 -5
- package/dist/internal/value/equal.mjs +2 -2
- package/dist/internal/value/handlers.mjs +2 -2
- package/dist/kalas.d.mts +61 -0
- package/dist/kalas.mjs +93 -0
- package/dist/string/case.mjs +10 -4
- package/dist/string/normalize.d.mts +55 -0
- package/dist/string/normalize.mjs +93 -0
- package/dist/value/index.d.mts +2 -1
- package/dist/value/index.mjs +2 -1
- package/dist/value/merge.d.mts +13 -0
- package/dist/value/merge.mjs +3 -1
- package/dist/value/shake.d.mts +7 -0
- package/dist/value/shake.mjs +16 -0
- package/package.json +1 -1
- package/src/array/exists.ts +1 -1
- package/src/array/find.ts +58 -0
- package/src/array/get.ts +2 -2
- package/src/index.ts +3 -0
- package/src/internal/array/find.ts +24 -4
- package/src/internal/array/index-of.ts +59 -1
- package/src/internal/math/aggregate.ts +2 -2
- package/src/internal/result.ts +6 -3
- package/src/internal/string.ts +26 -8
- package/src/internal/value/equal.ts +2 -2
- package/src/internal/value/handlers.ts +2 -2
- package/src/kalas.ts +167 -0
- package/src/string/case.ts +20 -4
- package/src/string/normalize.ts +169 -0
- package/src/value/index.ts +1 -0
- package/src/value/merge.ts +17 -1
- package/src/value/shake.ts +36 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {NumericalValues, PlainObject} from '../../models';
|
|
2
|
-
import {
|
|
2
|
+
import {isNonNumber} from '../is';
|
|
3
3
|
|
|
4
4
|
// #region Types
|
|
5
5
|
|
|
@@ -40,7 +40,7 @@ export function aggregate(type: AggregationType, array: unknown[], key: unknown)
|
|
|
40
40
|
|
|
41
41
|
const value = callback == null ? item : callback(item as never, index, array);
|
|
42
42
|
|
|
43
|
-
if (
|
|
43
|
+
if (isNonNumber(value)) {
|
|
44
44
|
continue;
|
|
45
45
|
}
|
|
46
46
|
|
package/src/internal/result.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import type {PlainObject} from '../models';
|
|
1
2
|
import type {Err, ExtendedErr, Ok, Result} from '../result/models';
|
|
2
|
-
import {
|
|
3
|
+
import {isNonPlainObject} from './is';
|
|
3
4
|
|
|
4
5
|
// #region Functions
|
|
5
6
|
|
|
6
7
|
function _isResult(value: unknown, okValue: boolean): value is Result<unknown, unknown> {
|
|
7
|
-
if (
|
|
8
|
+
if (isNonPlainObject(value)) {
|
|
8
9
|
return false;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
return
|
|
12
|
+
return (
|
|
13
|
+
(value as PlainObject).ok === okValue && (okValue ? PROPERTY_VALUE : PROPERTY_ERROR) in value
|
|
14
|
+
);
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
/**
|
package/src/internal/string.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import {compact} from './array/compact';
|
|
2
|
-
|
|
3
1
|
// #region Functions
|
|
4
2
|
|
|
5
3
|
/**
|
|
@@ -36,15 +34,35 @@ export function ignoreKey(key: string): boolean {
|
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
/**
|
|
39
|
-
* Join an array of values into a string
|
|
40
|
-
*
|
|
37
|
+
* Join an array of values into a string _(while ignoring empty values)_
|
|
38
|
+
*
|
|
39
|
+
* _(`null`, `undefined`, and any values that become whitespace-only strings are considered empty)_
|
|
40
|
+
* @param array Array of values
|
|
41
41
|
* @param delimiter Delimiter to use between values
|
|
42
42
|
* @returns Joined string
|
|
43
43
|
*/
|
|
44
|
-
export function join(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
export function join(array: unknown[], delimiter?: string): string {
|
|
45
|
+
if (!Array.isArray(array)) {
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const {length} = array;
|
|
50
|
+
|
|
51
|
+
if (length === 0) {
|
|
52
|
+
return '';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const values: string[] = [];
|
|
56
|
+
|
|
57
|
+
for (let index = 0; index < length; index += 1) {
|
|
58
|
+
const item = getString(array[index]);
|
|
59
|
+
|
|
60
|
+
if (item.trim().length > 0) {
|
|
61
|
+
values.push(item);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return values.join(typeof delimiter === 'string' ? delimiter : '');
|
|
48
66
|
}
|
|
49
67
|
|
|
50
68
|
function tryCallback<T, U>(value: T, callback: (value: T) => U): U {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {ArrayOrPlainObject, Constructor, PlainObject, TypedArray} from '../../models';
|
|
2
|
-
import {isPlainObject, isPrimitive, isTypedArray} from '../is';
|
|
2
|
+
import {isNonPlainObject, isPlainObject, isPrimitive, isTypedArray} from '../is';
|
|
3
3
|
import {getCompareHandlers} from './handlers';
|
|
4
4
|
|
|
5
5
|
// #region Types
|
|
@@ -377,7 +377,7 @@ function getEqualOptions(input?: boolean | EqualOptions): Options {
|
|
|
377
377
|
return options;
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
-
if (
|
|
380
|
+
if (isNonPlainObject(input)) {
|
|
381
381
|
return options;
|
|
382
382
|
}
|
|
383
383
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {Constructor, GenericCallback} from '../../models';
|
|
2
|
-
import {
|
|
2
|
+
import {isNonConstructor} from '../is';
|
|
3
3
|
|
|
4
4
|
type Options = {
|
|
5
5
|
callback: GenericCallback;
|
|
@@ -47,7 +47,7 @@ function getHandlers(owner: GenericCallback, options: Options) {
|
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
register(constructor: Constructor, handler?: string | GenericCallback) {
|
|
50
|
-
if (
|
|
50
|
+
if (isNonConstructor(constructor) || handler === owner) {
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
|
package/src/kalas.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {noop} from './internal/function/misc';
|
|
2
|
+
import type {GenericCallback} from './models';
|
|
3
|
+
|
|
4
|
+
// #region Types
|
|
5
|
+
|
|
6
|
+
class Events<Map extends Record<string, GenericCallback>> {
|
|
7
|
+
readonly #kalas: Kalas<Map>;
|
|
8
|
+
|
|
9
|
+
constructor(kalas: Kalas<Map>) {
|
|
10
|
+
this.#kalas = kalas;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Subscribe to an event with a callback
|
|
15
|
+
* @param event Event name
|
|
16
|
+
* @param callback Callback function
|
|
17
|
+
* @returns Unsubscriber function
|
|
18
|
+
*/
|
|
19
|
+
subscribe<Event extends keyof Map>(event: Event, callback: Map[Event]): Unsubscriber {
|
|
20
|
+
return this.#kalas.subscribe(event, callback);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Unsubscribe from an event with a callback _(or all callbacks, if no callback is provided)_
|
|
25
|
+
* @param event Event name
|
|
26
|
+
* @param callback Callback function
|
|
27
|
+
* @returns Unsubscriber function
|
|
28
|
+
*/
|
|
29
|
+
unsubscribe<Event extends keyof Map>(event: Event, callback?: Map[Event]): void {
|
|
30
|
+
return this.#kalas.unsubscribe(event, callback);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class Kalas<Map extends Record<string, GenericCallback>> {
|
|
35
|
+
readonly #names: Set<keyof Map>;
|
|
36
|
+
|
|
37
|
+
readonly #subscribers = new Map<keyof Map, Set<Map[keyof Map]>>();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Events interface for subscribing and unsubscribing to events
|
|
41
|
+
*/
|
|
42
|
+
declare readonly events: Events<Map>;
|
|
43
|
+
|
|
44
|
+
constructor(names: (keyof Map)[]) {
|
|
45
|
+
this.#names = new Set(names);
|
|
46
|
+
|
|
47
|
+
Object.defineProperty(this, 'events', {
|
|
48
|
+
value: new Events(this),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Remove all event subscribers
|
|
54
|
+
*/
|
|
55
|
+
clear(): void {
|
|
56
|
+
this.#subscribers.clear();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Emit an event with parameters
|
|
61
|
+
* @param event Event name
|
|
62
|
+
* @param parameters Event parameters
|
|
63
|
+
*/
|
|
64
|
+
emit<Event extends keyof Map>(event: Event, ...parameters: Parameters<Map[Event]>) {
|
|
65
|
+
const subscribers = this.#subscribers.get(event);
|
|
66
|
+
|
|
67
|
+
if (subscribers == null) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const callback of subscribers) {
|
|
72
|
+
callback(...parameters);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Subscribe to an event with a callback
|
|
78
|
+
* @param event Event name
|
|
79
|
+
* @param callback Callback function
|
|
80
|
+
* @returns Unsubscriber function
|
|
81
|
+
*/
|
|
82
|
+
subscribe<Event extends keyof Map>(event: Event, callback: Map[Event]): Unsubscriber {
|
|
83
|
+
if (!this.#names.has(event) || typeof callback !== 'function') {
|
|
84
|
+
return noop;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let subscribers = this.#subscribers.get(event);
|
|
88
|
+
|
|
89
|
+
if (subscribers == null) {
|
|
90
|
+
subscribers = new Set();
|
|
91
|
+
|
|
92
|
+
this.#subscribers.set(event, subscribers);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
subscribers.add(callback);
|
|
96
|
+
|
|
97
|
+
return () => {
|
|
98
|
+
subscribers?.delete(callback);
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Unsubscribe from an event with a callback _(or all callbacks, if no callback is provided)_
|
|
104
|
+
* @param event Event name
|
|
105
|
+
* @param callback Callback function
|
|
106
|
+
*/
|
|
107
|
+
unsubscribe<Event extends keyof Map>(event: Event, callback?: Map[Event]): void {
|
|
108
|
+
if (!this.#names.has(event) || (callback != null ? typeof callback !== 'function' : false)) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const subscribers = this.#subscribers.get(event);
|
|
113
|
+
|
|
114
|
+
if (subscribers == null) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (callback == null) {
|
|
119
|
+
subscribers.clear();
|
|
120
|
+
} else {
|
|
121
|
+
subscribers.delete(callback);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (callback == null || subscribers.size === 0) {
|
|
125
|
+
this.#subscribers.delete(event);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export type Unsubscriber = () => void;
|
|
131
|
+
|
|
132
|
+
// #endregion
|
|
133
|
+
|
|
134
|
+
// #region Functions
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Create a Kalas _(party)_ for named events
|
|
138
|
+
* @param names Event names
|
|
139
|
+
* @returns Kalas instance
|
|
140
|
+
*/
|
|
141
|
+
export function kalas<Events extends Record<string, GenericCallback>>(
|
|
142
|
+
names: (keyof Events)[],
|
|
143
|
+
): Kalas<Events> {
|
|
144
|
+
if (
|
|
145
|
+
!Array.isArray(names) ||
|
|
146
|
+
names.length === 0 ||
|
|
147
|
+
!names.every(name => typeof name === 'string')
|
|
148
|
+
) {
|
|
149
|
+
throw new Error(MESSAGE);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return new Kalas<Events>(names);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// #endregion
|
|
156
|
+
|
|
157
|
+
// #region Variables
|
|
158
|
+
|
|
159
|
+
const MESSAGE = 'Kalas requires an array of event names.';
|
|
160
|
+
|
|
161
|
+
// #endregion
|
|
162
|
+
|
|
163
|
+
// #region Exports
|
|
164
|
+
|
|
165
|
+
export {type Events, type Kalas};
|
|
166
|
+
|
|
167
|
+
// #endregion
|
package/src/string/case.ts
CHANGED
|
@@ -58,7 +58,13 @@ export function kebabCase(value: string): string {
|
|
|
58
58
|
* @returns Lower-cased string
|
|
59
59
|
*/
|
|
60
60
|
export function lowerCase(value: string): string {
|
|
61
|
-
|
|
61
|
+
if (typeof value !== 'string') {
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
memoizedLowerCase ??= memoize(v => v.toLocaleLowerCase());
|
|
66
|
+
|
|
67
|
+
return memoizedLowerCase.run(value);
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
/**
|
|
@@ -85,12 +91,12 @@ export function snakeCase(value: string): string {
|
|
|
85
91
|
* @returns Title-cased string
|
|
86
92
|
*/
|
|
87
93
|
export function titleCase(value: string): string {
|
|
88
|
-
if (typeof value !== 'string') {
|
|
94
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
89
95
|
return '';
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
memoizedTitleCase ??= memoize(v =>
|
|
93
|
-
v.length <
|
|
99
|
+
v.length < 2 ? capitalize(v) : join(words(v).map(capitalize), ' '),
|
|
94
100
|
);
|
|
95
101
|
|
|
96
102
|
return memoizedTitleCase.run(value);
|
|
@@ -167,7 +173,13 @@ function toCaseCallback(this: Options, value: string): string {
|
|
|
167
173
|
* @returns Upper-cased string
|
|
168
174
|
*/
|
|
169
175
|
export function upperCase(value: string): string {
|
|
170
|
-
|
|
176
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
177
|
+
return '';
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
memoizedUpperCase ??= memoize(v => v.toLocaleUpperCase());
|
|
181
|
+
|
|
182
|
+
return memoizedUpperCase.run(value);
|
|
171
183
|
}
|
|
172
184
|
|
|
173
185
|
// #endregion
|
|
@@ -207,6 +219,10 @@ const delimiters: Record<Case, string> = {
|
|
|
207
219
|
|
|
208
220
|
let memoizedCapitalize: Memoized<(value: string) => string>;
|
|
209
221
|
|
|
222
|
+
let memoizedLowerCase: Memoized<(value: string) => string>;
|
|
223
|
+
|
|
210
224
|
let memoizedTitleCase: Memoized<(value: string) => string>;
|
|
211
225
|
|
|
226
|
+
let memoizedUpperCase: Memoized<(value: string) => string>;
|
|
227
|
+
|
|
212
228
|
// #endregion
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import {memoize, type Memoized} from '../function/memoize';
|
|
2
|
+
import {isPlainObject} from '../internal/is';
|
|
3
|
+
import {lowerCase} from './case';
|
|
4
|
+
|
|
5
|
+
// #region Types
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for normalizing a string
|
|
9
|
+
*/
|
|
10
|
+
export type NormalizeOptions = {
|
|
11
|
+
/**
|
|
12
|
+
* Remove diacritical marks from the string? _(defaults to `true`)_
|
|
13
|
+
*/
|
|
14
|
+
deburr?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Convert the string to lower case? _(defaults to `true`)_
|
|
17
|
+
*/
|
|
18
|
+
lowerCase?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Trim the string? _(defaults to `true`)_
|
|
21
|
+
*/
|
|
22
|
+
trim?: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* String normalizer function
|
|
27
|
+
*/
|
|
28
|
+
export type Normalizer = {
|
|
29
|
+
/**
|
|
30
|
+
* Normalize a string
|
|
31
|
+
* @param value String to normalize
|
|
32
|
+
* @returns Normalized string
|
|
33
|
+
*/
|
|
34
|
+
(value: string): string;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type Options = Required<NormalizeOptions>;
|
|
38
|
+
|
|
39
|
+
// #endregion
|
|
40
|
+
|
|
41
|
+
// #region Functions
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Deburr a string, removing diacritical marks
|
|
45
|
+
* @param value String to deburr
|
|
46
|
+
* @returns Deburred string
|
|
47
|
+
*/
|
|
48
|
+
export function deburr(value: string): string {
|
|
49
|
+
if (typeof value !== 'string') {
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
deburrMemoizer ??= memoize(value => {
|
|
54
|
+
let deburred = value.normalize(DEBURR_NORMALIZATION).replace(DEBURR_PATTERN_SIMPLE, '');
|
|
55
|
+
|
|
56
|
+
deburred = deburred.replace(
|
|
57
|
+
DEBURR_PATTERN_CHARACTERS,
|
|
58
|
+
(_, character) => DEBURR_CHARACTERS[character as keyof typeof DEBURR_CHARACTERS],
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return deburred;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return deburrMemoizer.run(value);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getNormalizeOptions(input?: NormalizeOptions): Options {
|
|
68
|
+
const options = isPlainObject(input) ? input : {};
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
deburr: options.deburr !== false,
|
|
72
|
+
lowerCase: options.lowerCase !== false,
|
|
73
|
+
trim: options.trim !== false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Initialize a string normalizer
|
|
79
|
+
* @param options Normalization options
|
|
80
|
+
* @returns Normalizer function
|
|
81
|
+
*/
|
|
82
|
+
export function initializeNormalizer(options?: NormalizeOptions): Normalizer {
|
|
83
|
+
const normalization = getNormalizeOptions(options);
|
|
84
|
+
|
|
85
|
+
return (value: string) => normalizeString(value, normalization);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Normalize a string
|
|
90
|
+
*
|
|
91
|
+
* By default, the string will be trimmed, deburred, and then lowercased
|
|
92
|
+
* @param value String to normalize
|
|
93
|
+
* @param options Normalization options
|
|
94
|
+
* @returns Normalized string
|
|
95
|
+
*/
|
|
96
|
+
export function normalize(value: string, options?: NormalizeOptions): string {
|
|
97
|
+
return normalizeString(value, getNormalizeOptions(options));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
normalize.initialize = initializeNormalizer;
|
|
101
|
+
|
|
102
|
+
function normalizeString(value: string, options: Options): string {
|
|
103
|
+
if (typeof value !== 'string') {
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let result = value;
|
|
108
|
+
|
|
109
|
+
if (options.trim) {
|
|
110
|
+
result = result.trim();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (options.deburr) {
|
|
114
|
+
result = deburr(result);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (options.lowerCase) {
|
|
118
|
+
result = lowerCase(result);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// #endregion
|
|
125
|
+
|
|
126
|
+
// #region Variables
|
|
127
|
+
|
|
128
|
+
const DEBURR_CHARACTERS = {
|
|
129
|
+
Æ: 'AE',
|
|
130
|
+
æ: 'ae',
|
|
131
|
+
Ð: 'D',
|
|
132
|
+
ð: 'd',
|
|
133
|
+
Đ: 'D',
|
|
134
|
+
đ: 'd',
|
|
135
|
+
Ħ: 'H',
|
|
136
|
+
ħ: 'h',
|
|
137
|
+
IJ: 'IJ',
|
|
138
|
+
ij: 'ij',
|
|
139
|
+
İ: 'I',
|
|
140
|
+
ı: 'i',
|
|
141
|
+
ĸ: 'k',
|
|
142
|
+
Ŀ: 'L',
|
|
143
|
+
ŀ: 'l',
|
|
144
|
+
Ł: 'L',
|
|
145
|
+
ł: 'l',
|
|
146
|
+
Ŋ: 'N',
|
|
147
|
+
ŋ: 'n',
|
|
148
|
+
ʼn: "'n",
|
|
149
|
+
Œ: 'OE',
|
|
150
|
+
œ: 'oe',
|
|
151
|
+
Ø: 'O',
|
|
152
|
+
ø: 'o',
|
|
153
|
+
ſ: 's',
|
|
154
|
+
ß: 'ss',
|
|
155
|
+
Þ: 'TH',
|
|
156
|
+
þ: 'th',
|
|
157
|
+
Ŧ: 'T',
|
|
158
|
+
ŧ: 't',
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const DEBURR_NORMALIZATION = 'NFD';
|
|
162
|
+
|
|
163
|
+
const DEBURR_PATTERN_CHARACTERS = new RegExp(`(${Object.keys(DEBURR_CHARACTERS).join('|')})`, 'g');
|
|
164
|
+
|
|
165
|
+
const DEBURR_PATTERN_SIMPLE = /[\u0300-\u036f]/g;
|
|
166
|
+
|
|
167
|
+
let deburrMemoizer: Memoized<typeof deburr>;
|
|
168
|
+
|
|
169
|
+
// #endregion
|
package/src/value/index.ts
CHANGED
package/src/value/merge.ts
CHANGED
|
@@ -8,16 +8,29 @@ import type {ArrayOrPlainObject, NestedPartial, PlainObject} from '../models';
|
|
|
8
8
|
* Options for merging values
|
|
9
9
|
*/
|
|
10
10
|
export type MergeOptions = {
|
|
11
|
+
/**
|
|
12
|
+
* Assign values to the first array or object instead of creating a new one?
|
|
13
|
+
*/
|
|
14
|
+
assignValues?: boolean;
|
|
11
15
|
/**
|
|
12
16
|
* Key _(or key epxressions)_ for values that should be replaced
|
|
17
|
+
*
|
|
13
18
|
* ```ts
|
|
14
19
|
* merge([{items: [1, 2, 3]}, {items: [99]}]); // {items: [99]}
|
|
15
20
|
* ```
|
|
16
21
|
*/
|
|
17
22
|
replaceableObjects?: string | RegExp | Array<string | RegExp>;
|
|
23
|
+
/**
|
|
24
|
+
* Skip nullable values when merging objects?
|
|
25
|
+
*
|
|
26
|
+
* ```ts
|
|
27
|
+
* merge({a: 1, b: 2}, {b: null, c: 3}, {d: null}); // {a: 1, b: 2, c: 3}
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
18
30
|
skipNullableAny?: boolean;
|
|
19
31
|
/**
|
|
20
32
|
* Skip nullable values when merging arrays?
|
|
33
|
+
*
|
|
21
34
|
* ```ts
|
|
22
35
|
* merge([1, 2, 3], [null, null, 99]); // [1, 2, 99]
|
|
23
36
|
* ```
|
|
@@ -35,6 +48,7 @@ export type Merger<Model extends ArrayOrPlainObject = ArrayOrPlainObject> = (
|
|
|
35
48
|
) => Model;
|
|
36
49
|
|
|
37
50
|
type Options = {
|
|
51
|
+
assignValues: boolean;
|
|
38
52
|
replaceableObjects: ReplaceableObjectsCallback | undefined;
|
|
39
53
|
skipNullableAny: boolean;
|
|
40
54
|
skipNullableInArrays: boolean;
|
|
@@ -48,6 +62,7 @@ type ReplaceableObjectsCallback = (name: string) => boolean;
|
|
|
48
62
|
|
|
49
63
|
function getMergeOptions(options?: MergeOptions): Options {
|
|
50
64
|
const actual: Options = {
|
|
65
|
+
assignValues: false,
|
|
51
66
|
replaceableObjects: undefined,
|
|
52
67
|
skipNullableAny: false,
|
|
53
68
|
skipNullableInArrays: false,
|
|
@@ -59,6 +74,7 @@ function getMergeOptions(options?: MergeOptions): Options {
|
|
|
59
74
|
|
|
60
75
|
actual.replaceableObjects = getReplaceableObjects(options.replaceableObjects);
|
|
61
76
|
|
|
77
|
+
actual.assignValues = options.assignValues === true;
|
|
62
78
|
actual.skipNullableAny = options.skipNullableAny === true;
|
|
63
79
|
actual.skipNullableInArrays = options.skipNullableInArrays === true;
|
|
64
80
|
|
|
@@ -132,7 +148,7 @@ function mergeObjects(
|
|
|
132
148
|
): ArrayOrPlainObject {
|
|
133
149
|
const {length} = values;
|
|
134
150
|
const isArray = values.every(Array.isArray);
|
|
135
|
-
const merged = (isArray ? [] : {}) as PlainObject;
|
|
151
|
+
const merged = (options.assignValues ? values[0] : isArray ? [] : {}) as PlainObject;
|
|
136
152
|
|
|
137
153
|
for (let outerIndex = 0; outerIndex < length; outerIndex += 1) {
|
|
138
154
|
const item = values[outerIndex] as PlainObject;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {isNonPlainObject} from '../is';
|
|
2
|
+
import type {PlainObject} from '../models';
|
|
3
|
+
|
|
4
|
+
// #region Types
|
|
5
|
+
|
|
6
|
+
export type Shaken<Value extends PlainObject> = {
|
|
7
|
+
[Key in keyof Value]: Value[Key] extends undefined ? never : Value[Key];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// #endregion
|
|
11
|
+
|
|
12
|
+
// #region Functions
|
|
13
|
+
|
|
14
|
+
export function shake<Value extends PlainObject>(value: Value): Shaken<Value> {
|
|
15
|
+
const shaken: PlainObject = {};
|
|
16
|
+
|
|
17
|
+
if (isNonPlainObject(value)) {
|
|
18
|
+
return shaken as Shaken<Value>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const keys = Object.keys(value) as (keyof Value)[];
|
|
22
|
+
const {length} = keys;
|
|
23
|
+
|
|
24
|
+
for (let index = 0; index < length; index += 1) {
|
|
25
|
+
const key = keys[index];
|
|
26
|
+
const val = value[key];
|
|
27
|
+
|
|
28
|
+
if (val !== undefined) {
|
|
29
|
+
shaken[key] = val;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return shaken as Shaken<Value>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// #endregion
|