@aidc-toolkit/utility 0.0.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/.github/workflows/npm-publish.yml +32 -0
- package/.idea/inspectionProfiles/Project_Default.xml +7 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/runConfigurations/Test_all.xml +12 -0
- package/.idea/runConfigurations/Test_character_set.xml +12 -0
- package/.idea/runConfigurations/Test_iteration.xml +12 -0
- package/.idea/runConfigurations/Test_record.xml +12 -0
- package/.idea/runConfigurations/Test_regular_expression.xml +12 -0
- package/.idea/runConfigurations/Test_transformer.xml +12 -0
- package/.idea/runConfigurations/build.xml +12 -0
- package/.idea/runConfigurations/eslint.xml +12 -0
- package/.idea/utility.iml +9 -0
- package/.idea/vcs.xml +6 -0
- package/LICENSE +201 -0
- package/README.md +12 -0
- package/eslint.config.js +15 -0
- package/package.json +42 -0
- package/src/character_set.ts +766 -0
- package/src/index.ts +6 -0
- package/src/iteration.ts +343 -0
- package/src/locale/en/locale_strings.ts +30 -0
- package/src/locale/i18n.ts +8 -0
- package/src/locale/i18next.d.ts +10 -0
- package/src/record.ts +64 -0
- package/src/reg_exp.ts +58 -0
- package/src/string.ts +22 -0
- package/src/transformer.ts +654 -0
- package/test/character_set.test.ts +170 -0
- package/test/iteration.test.ts +282 -0
- package/test/record.test.ts +41 -0
- package/test/reg_exp.test.ts +43 -0
- package/test/transformer.test.ts +143 -0
- package/tsconfig.json +3 -0
- package/typedoc.json +10 -0
package/src/index.ts
ADDED
package/src/iteration.ts
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iteration source type. The underlying source is an iterable or iterator or a callback to an iterable or iterator.
|
|
3
|
+
*/
|
|
4
|
+
export type IterationSource<T> = Iterable<T> | Iterator<T> | (() => (Iterable<T> | Iterator<T>));
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Iteration proxy class for applying a callback for mapping or filtering.
|
|
8
|
+
*/
|
|
9
|
+
class IterationProxy<T, U, V> implements IterableIterator<V> {
|
|
10
|
+
/**
|
|
11
|
+
* Proxied iterable iterator.
|
|
12
|
+
*/
|
|
13
|
+
private readonly _proxiedIterableIterator: IterableIterator<T>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Callback for map or filter.
|
|
17
|
+
*/
|
|
18
|
+
private readonly _callback: (element: T, index: number) => U;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* If true, callback is a predicate for a filter.
|
|
22
|
+
*/
|
|
23
|
+
private readonly _isPredicate: boolean;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Index into proxied iterable iterator.
|
|
27
|
+
*/
|
|
28
|
+
private _index: number;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Constructor.
|
|
32
|
+
*
|
|
33
|
+
* @param proxiedIterableIterator
|
|
34
|
+
* Proxied iterable iterator.
|
|
35
|
+
*
|
|
36
|
+
* @param callback
|
|
37
|
+
* Callback for map or filter.
|
|
38
|
+
*
|
|
39
|
+
* @param isPredicate
|
|
40
|
+
* If true, callback is a predicate for a filter.
|
|
41
|
+
*/
|
|
42
|
+
constructor(proxiedIterableIterator: IterableIterator<T>, callback: (element: T, index: number) => U, isPredicate: boolean) {
|
|
43
|
+
this._proxiedIterableIterator = proxiedIterableIterator;
|
|
44
|
+
this._callback = callback;
|
|
45
|
+
this._isPredicate = isPredicate;
|
|
46
|
+
|
|
47
|
+
this._index = 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* {@link Iterable} interface implementation.
|
|
52
|
+
*
|
|
53
|
+
* @returns
|
|
54
|
+
* Iterable iterator.
|
|
55
|
+
*/
|
|
56
|
+
[Symbol.iterator](): IterableIterator<V> {
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* {@link Iterator} interface implementation.
|
|
62
|
+
*
|
|
63
|
+
* @param args
|
|
64
|
+
* Arguments.
|
|
65
|
+
*
|
|
66
|
+
* @returns
|
|
67
|
+
* Next element or number or total number of elements if none.
|
|
68
|
+
*/
|
|
69
|
+
next(...args: [] | [undefined]): IteratorResult<V, number> {
|
|
70
|
+
let done = false;
|
|
71
|
+
let value: V | undefined;
|
|
72
|
+
|
|
73
|
+
let callbackDone: boolean;
|
|
74
|
+
|
|
75
|
+
do {
|
|
76
|
+
const proxiedNext = this._proxiedIterableIterator.next(...args);
|
|
77
|
+
|
|
78
|
+
if (!(proxiedNext.done ?? false)) {
|
|
79
|
+
const proxiedValue = proxiedNext.value;
|
|
80
|
+
const callbackValue = this._callback(proxiedValue, this._index++);
|
|
81
|
+
|
|
82
|
+
if (!this._isPredicate) {
|
|
83
|
+
// Types U and V are known to be identical.
|
|
84
|
+
value = callbackValue as unknown as V;
|
|
85
|
+
|
|
86
|
+
callbackDone = true;
|
|
87
|
+
} else {
|
|
88
|
+
callbackDone = callbackValue as boolean;
|
|
89
|
+
|
|
90
|
+
if (callbackDone) {
|
|
91
|
+
// Types T and V are known to be identical.
|
|
92
|
+
value = proxiedValue as unknown as V;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
done = true;
|
|
97
|
+
callbackDone = true;
|
|
98
|
+
}
|
|
99
|
+
} while (!callbackDone);
|
|
100
|
+
|
|
101
|
+
return done ?
|
|
102
|
+
{
|
|
103
|
+
done: true,
|
|
104
|
+
value: this._index
|
|
105
|
+
} :
|
|
106
|
+
{
|
|
107
|
+
done: false,
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
109
|
+
value: value!
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Iteration helper. Adds array-like functionality through {@link forEach}, {@link map}, {@link filter}, and
|
|
116
|
+
* {@link reduce} methods. Likely to be refactored as {@link
|
|
117
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator#iterator_helpers | iterator
|
|
118
|
+
* helpers} are more widely deployed.
|
|
119
|
+
*/
|
|
120
|
+
export class IterationHelper<T> implements IterableIterator<T> {
|
|
121
|
+
/**
|
|
122
|
+
* Iteration source.
|
|
123
|
+
*/
|
|
124
|
+
private readonly _iterationSource: IterationSource<T>;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Iterable extracted from iteration source.
|
|
128
|
+
*/
|
|
129
|
+
private _iterable?: Iterable<T>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Iterator extracted from iteration source.
|
|
133
|
+
*/
|
|
134
|
+
private _iterator?: Iterator<T>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Constructor.
|
|
138
|
+
*
|
|
139
|
+
* @param iterationSource
|
|
140
|
+
* Iteration source.
|
|
141
|
+
*/
|
|
142
|
+
private constructor(iterationSource: IterationSource<T>) {
|
|
143
|
+
this._iterationSource = iterationSource;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get an iteration helper from an iteration source. If the iteration source is itself an iteration helper, it is
|
|
148
|
+
* returned verbatim, otherwise a new iteration helper is constructed.
|
|
149
|
+
*
|
|
150
|
+
* @param iterationSource
|
|
151
|
+
* Iteration source.
|
|
152
|
+
*
|
|
153
|
+
* @returns
|
|
154
|
+
* Iteration helper.
|
|
155
|
+
*/
|
|
156
|
+
static from<T>(iterationSource: IterationSource<T>): IterationHelper<T> {
|
|
157
|
+
return iterationSource instanceof IterationHelper ? iterationSource as IterationHelper<T> : new IterationHelper(iterationSource);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get the iteration source.
|
|
162
|
+
*/
|
|
163
|
+
get iterationSource(): IterationSource<T> {
|
|
164
|
+
return this._iterationSource;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get the iteration source as an iterable.
|
|
169
|
+
*
|
|
170
|
+
* @returns
|
|
171
|
+
* Iterable.
|
|
172
|
+
*/
|
|
173
|
+
asIterable(): Iterable<T> {
|
|
174
|
+
if (this._iterable === undefined) {
|
|
175
|
+
const resolvedIterationSource = typeof this.iterationSource === "function" ? this.iterationSource() : this.iterationSource;
|
|
176
|
+
|
|
177
|
+
this._iterable = Symbol.iterator in resolvedIterationSource ?
|
|
178
|
+
resolvedIterationSource :
|
|
179
|
+
{
|
|
180
|
+
[Symbol.iterator](): Iterator<T> {
|
|
181
|
+
return resolvedIterationSource;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return this._iterable;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get the iteration source as an array.
|
|
191
|
+
*
|
|
192
|
+
* @returns
|
|
193
|
+
* Array.
|
|
194
|
+
*/
|
|
195
|
+
asArray(): readonly T[] {
|
|
196
|
+
const iterable = this.asIterable();
|
|
197
|
+
|
|
198
|
+
// Return iterable as array.
|
|
199
|
+
return Array.isArray(iterable) ? iterable as readonly T[] : Array.from(iterable);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get the iteration source as an iterator.
|
|
204
|
+
*
|
|
205
|
+
* @returns
|
|
206
|
+
* Iterator.
|
|
207
|
+
*/
|
|
208
|
+
asIterator(): Iterator<T> {
|
|
209
|
+
if (this._iterator === undefined) {
|
|
210
|
+
this._iterator = this.asIterable()[Symbol.iterator]();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return this._iterator;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get the iteration source as a callback.
|
|
218
|
+
*
|
|
219
|
+
* @returns
|
|
220
|
+
* Callback.
|
|
221
|
+
*/
|
|
222
|
+
asCallback(): () => IterationSource<T> {
|
|
223
|
+
return typeof this._iterationSource === "function" ? this._iterationSource : () => this._iterationSource;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* {@link Iterable} interface implementation.
|
|
228
|
+
*
|
|
229
|
+
* @returns
|
|
230
|
+
* Iterable iterator.
|
|
231
|
+
*/
|
|
232
|
+
[Symbol.iterator](): IterableIterator<T> {
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* {@link Iterator} interface implementation.
|
|
238
|
+
*
|
|
239
|
+
* @param args
|
|
240
|
+
* Arguments.
|
|
241
|
+
*
|
|
242
|
+
* @returns
|
|
243
|
+
* Next element.
|
|
244
|
+
*/
|
|
245
|
+
next(...args: [] | [undefined]): IteratorResult<T, unknown> {
|
|
246
|
+
return this.asIterator().next(...args);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Perform an action for each element in the iteration helper.
|
|
251
|
+
*
|
|
252
|
+
* @param callback
|
|
253
|
+
* Callback that processes the element and its index in the iteration sequence.
|
|
254
|
+
*/
|
|
255
|
+
forEach(callback: (element: T, index: number) => void): void {
|
|
256
|
+
let index = 0;
|
|
257
|
+
|
|
258
|
+
for (const element of this) {
|
|
259
|
+
callback(element, index++);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Map the iteration helper to another iteration helper by performing an action for each element in the iteration
|
|
265
|
+
* helper along the way.
|
|
266
|
+
*
|
|
267
|
+
* @param callback
|
|
268
|
+
* Callback that processes the element and its index in the iteration sequence.
|
|
269
|
+
*
|
|
270
|
+
* @returns
|
|
271
|
+
* Iterable iterator over callback results.
|
|
272
|
+
*/
|
|
273
|
+
map<U>(callback: (element: T, index: number) => U): IterableIterator<U> {
|
|
274
|
+
return new IterationProxy(this, callback, false);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Filter the iteration helper based on the condition specified in a predicate. Each call to `.next()` will iterate
|
|
279
|
+
* as far as necessary until it reaches an element that satisfies the predicate. Care should be taken when working
|
|
280
|
+
* with large iterators and infrequently truthy predicates.
|
|
281
|
+
*
|
|
282
|
+
* @param predicate
|
|
283
|
+
* Predicate that processes the element and its index in the iteration sequence.
|
|
284
|
+
*
|
|
285
|
+
* @returns
|
|
286
|
+
* Iterator iterable over elements that satisfy the predicate.
|
|
287
|
+
*/
|
|
288
|
+
filter(predicate: (element: T, index: number) => boolean): IterableIterator<T> {
|
|
289
|
+
return new IterationProxy(this, predicate, true);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Reduce the iterator to a single value by applying a callback.
|
|
294
|
+
*
|
|
295
|
+
* @param callback
|
|
296
|
+
* Callback that processes the previous return value of the callback, the current value of the iterator, and the
|
|
297
|
+
* current index. The initial value is considered to be the first element in the iteration helper.
|
|
298
|
+
*
|
|
299
|
+
* @returns
|
|
300
|
+
* Reduced value.
|
|
301
|
+
*/
|
|
302
|
+
reduce(callback: (previousValue: T, currentValue: T, currentIndex: number) => T): T;
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Reduce the iterator to a single value by applying a callback.
|
|
306
|
+
*
|
|
307
|
+
* @param callback
|
|
308
|
+
* Callback that processes the previous return value of the callback, the current value of the iterator, and the
|
|
309
|
+
* current index.
|
|
310
|
+
*
|
|
311
|
+
* @param initialValue
|
|
312
|
+
* Initial value, passed as the first previous return value of the callback.
|
|
313
|
+
*
|
|
314
|
+
* @returns
|
|
315
|
+
* Reduced value.
|
|
316
|
+
*/
|
|
317
|
+
reduce(callback: (previousValue: T, currentValue: T, currentIndex: number) => T, initialValue: T): T;
|
|
318
|
+
|
|
319
|
+
reduce<U>(callback: (previousValue: U, currentValue: T, currentIndex: number) => U, initialValue?: U): U {
|
|
320
|
+
let index = 0;
|
|
321
|
+
let result = initialValue;
|
|
322
|
+
|
|
323
|
+
for (const value of this) {
|
|
324
|
+
if (index === 0 && initialValue === undefined) {
|
|
325
|
+
result = value as unknown as U;
|
|
326
|
+
} else {
|
|
327
|
+
// Iteration has occurred at least once so result is of the expected type.
|
|
328
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
329
|
+
result = callback(result!, value, index);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
index++;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (index === 0 && initialValue === undefined) {
|
|
336
|
+
throw new Error("reduce() of empty iterator with no initial value");
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Iteration has occurred at least once so result is of the expected type.
|
|
340
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
341
|
+
return result!;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const localeStrings = {
|
|
2
|
+
Transformer: {
|
|
3
|
+
domainMustBeGreaterThanZero: "Domain {{domain}} must be greater than 0",
|
|
4
|
+
tweakMustBeGreaterThanOrEqualToZero: "Tweak {{tweak}} must be greater than or equal to 0",
|
|
5
|
+
valueMustBeGreaterThanOrEqualToZero: "Value {{startValue}} must be greater than or equal to 0",
|
|
6
|
+
startValueMustBeGreaterThanOrEqualToZero: "Start value {{startValue}} must be greater than or equal to 0",
|
|
7
|
+
valueMustBeLessThan: "Value {{endValue}} must be less than {{domain}}",
|
|
8
|
+
endValueMustBeLessThan: "End value (start value + count - 1) {{endValue}} must be less than {{domain}}"
|
|
9
|
+
},
|
|
10
|
+
RegExpValidator: {
|
|
11
|
+
stringDoesNotMatchPattern: "String {{s}} does not match pattern"
|
|
12
|
+
},
|
|
13
|
+
CharacterSetValidator: {
|
|
14
|
+
stringMustNotBeAllNumeric: "String must not be all numeric",
|
|
15
|
+
lengthMustBeGreaterThanOrEqualTo: "Length {{length}} must be greater than or equal to {{minimumLength}}",
|
|
16
|
+
lengthMustBeLessThanOrEqualTo: "Length {{length}} must be less than or equal to {{maximumLength}}",
|
|
17
|
+
lengthMustBeEqualTo: "Length {{length}} must be equal to {{exactLength}}",
|
|
18
|
+
lengthOfComponentMustBeGreaterThanOrEqualTo: "Length {{length}} of {{component}} must be greater than or equal to {{minimumLength}}",
|
|
19
|
+
lengthOfComponentMustBeLessThanOrEqualTo: "Length {{length}} of {{component}} must be less than or equal to {{maximumLength}}",
|
|
20
|
+
lengthOfComponentMustBeEqualTo: "Length {{length}} of {{component}} must be equal to {{exactLength}}",
|
|
21
|
+
invalidCharacterAtPosition: "Invalid character '{{c}}' at position {{position}}",
|
|
22
|
+
invalidCharacterAtPositionOfComponent: "Invalid character '{{c}}' at position {{position}} of {{component}}",
|
|
23
|
+
exclusionNotSupported: "Exclusion value of {{exclusion}} is not supported",
|
|
24
|
+
invalidTweakWithAllNumericExclusion: "Tweak must not be used with all-numeric exclusion",
|
|
25
|
+
endSequenceValueMustBeLessThanOrEqualTo: "End sequence value (start sequence value + count - 1) must be less than {{domain}}"
|
|
26
|
+
},
|
|
27
|
+
RecordValidator: {
|
|
28
|
+
typeNameKeyNotFound: "{{typeName}} \"{{key}}\" not found"
|
|
29
|
+
}
|
|
30
|
+
} as const;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { i18nAddResourceBundle, i18next } from "@aidc-toolkit/core";
|
|
2
|
+
import { localeStrings as enLocaleStrings } from "./en/locale_strings.js";
|
|
3
|
+
|
|
4
|
+
export const utilityNS = "aidct_utility";
|
|
5
|
+
|
|
6
|
+
i18nAddResourceBundle("en", utilityNS, enLocaleStrings);
|
|
7
|
+
|
|
8
|
+
export default i18next;
|
package/src/record.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import i18next, { utilityNS } from "./locale/i18n.js";
|
|
2
|
+
import type { StringValidator } from "./string.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Record validator. Validation is performed against a record with a string key type and throws an exception if the key
|
|
6
|
+
* is not found.
|
|
7
|
+
*/
|
|
8
|
+
export class RecordValidator<T> implements StringValidator {
|
|
9
|
+
/**
|
|
10
|
+
* Type name for error message.
|
|
11
|
+
*/
|
|
12
|
+
private readonly _typeName: string;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Record in which to look up keys.
|
|
16
|
+
*/
|
|
17
|
+
private readonly _record: Readonly<Record<string, T>>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Constructor.
|
|
21
|
+
*
|
|
22
|
+
* @param typeName
|
|
23
|
+
* Type name for error message.
|
|
24
|
+
*
|
|
25
|
+
* @param record
|
|
26
|
+
* Record in which to look up keys.
|
|
27
|
+
*/
|
|
28
|
+
constructor(typeName: string, record: Readonly<Record<string, T>>) {
|
|
29
|
+
this._typeName = typeName;
|
|
30
|
+
this._record = record;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get the type name.
|
|
35
|
+
*/
|
|
36
|
+
get typeName(): string {
|
|
37
|
+
return this._typeName;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the record.
|
|
42
|
+
*/
|
|
43
|
+
get record(): Readonly<Record<string, T>> {
|
|
44
|
+
return this._record;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Validate a key by looking it up in the record.
|
|
49
|
+
*
|
|
50
|
+
* @param key
|
|
51
|
+
* Record key.
|
|
52
|
+
*
|
|
53
|
+
* @throws RangeError
|
|
54
|
+
*/
|
|
55
|
+
validate(key: string): void {
|
|
56
|
+
if (this.record[key] === undefined) {
|
|
57
|
+
throw new RangeError(i18next.t("RecordValidator.typeNameKeyNotFound", {
|
|
58
|
+
ns: utilityNS,
|
|
59
|
+
typeName: this.typeName,
|
|
60
|
+
key
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/reg_exp.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import i18next, { utilityNS } from "./locale/i18n.js";
|
|
2
|
+
import type { StringValidator } from "./string.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Regular expression validator. The regular expression applies to the full string only if constructed as such. For
|
|
6
|
+
* example, <code>/\d*/</code> (0 or more digits) matches every string, <code>/\d+/</code>
|
|
7
|
+
* (1 or more digits) matches strings with at least one digit, <code>/^\d*$/</code> matches strings that
|
|
8
|
+
* are all digits or empty, and <code>/^\d+$/</code> matches strings that are all digits and not empty.
|
|
9
|
+
*
|
|
10
|
+
* Clients of this class are recommended to override the {@link createErrorMessage} method create a more suitable error
|
|
11
|
+
* message for their use case.
|
|
12
|
+
*/
|
|
13
|
+
export class RegExpValidator implements StringValidator {
|
|
14
|
+
/**
|
|
15
|
+
* Regular expression.
|
|
16
|
+
*/
|
|
17
|
+
private readonly _regExp: RegExp;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Constructor.
|
|
21
|
+
*
|
|
22
|
+
* @param regExp
|
|
23
|
+
* Regular expression. See {@link RegExpValidator | class documentation} for notes.
|
|
24
|
+
*/
|
|
25
|
+
constructor(regExp: RegExp) {
|
|
26
|
+
this._regExp = regExp;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get the regular expression.
|
|
31
|
+
*/
|
|
32
|
+
get regExp(): RegExp {
|
|
33
|
+
return this._regExp;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create an error message for a string. The generic error message is sufficient for many use cases but a more
|
|
38
|
+
* domain-specific error message, possibly including the pattern itself, is often required.
|
|
39
|
+
*
|
|
40
|
+
* @param s
|
|
41
|
+
* String.
|
|
42
|
+
*
|
|
43
|
+
* @returns
|
|
44
|
+
* Error message.
|
|
45
|
+
*/
|
|
46
|
+
protected createErrorMessage(s: string): string {
|
|
47
|
+
return i18next.t("RegExpValidator.stringDoesNotMatchPattern", {
|
|
48
|
+
ns: utilityNS,
|
|
49
|
+
s
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
validate(s: string): void {
|
|
54
|
+
if (!this._regExp.test(s)) {
|
|
55
|
+
throw new RangeError(this.createErrorMessage(s));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/string.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String validation interface. To ensure signature compatibility in implementing classes, string validation is
|
|
3
|
+
* controlled by validation interfaces specific to each validator type.
|
|
4
|
+
*/
|
|
5
|
+
export interface StringValidation {
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* String validator interface.
|
|
10
|
+
*/
|
|
11
|
+
export interface StringValidator {
|
|
12
|
+
/**
|
|
13
|
+
* Validate a string and throw an exception if validation fails.
|
|
14
|
+
*
|
|
15
|
+
* @param s
|
|
16
|
+
* String.
|
|
17
|
+
*
|
|
18
|
+
* @param validation
|
|
19
|
+
* String validation parameters.
|
|
20
|
+
*/
|
|
21
|
+
validate: (s: string, validation?: StringValidation) => void;
|
|
22
|
+
}
|