@rainbow-o23/n1 1.0.49 → 1.0.50

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.
Files changed (38) hide show
  1. package/README.md +44 -6
  2. package/index.cjs +641 -78
  3. package/index.d.ts +1 -0
  4. package/index.js +598 -54
  5. package/lib/pipeline/index.d.ts +2 -1
  6. package/lib/pipeline/step-helpers-utils.d.ts +28 -3
  7. package/lib/pipeline/step-helpers-value-operator.d.ts +34 -0
  8. package/lib/pipeline/step-helpers.d.ts +9 -23
  9. package/lib/pipeline/types.d.ts +1 -0
  10. package/lib/pipeline/value-operators/action-types.d.ts +18 -0
  11. package/lib/pipeline/value-operators/index.d.ts +8 -0
  12. package/lib/pipeline/value-operators/test-any-actions.d.ts +10 -0
  13. package/lib/pipeline/value-operators/test-decimal-actions.d.ts +25 -0
  14. package/lib/pipeline/value-operators/test-string-actions.d.ts +2 -0
  15. package/lib/pipeline/value-operators/testers.d.ts +36 -0
  16. package/lib/pipeline/value-operators/transform-decimal-actions.d.ts +21 -0
  17. package/lib/pipeline/value-operators/transform-string-actions.d.ts +10 -0
  18. package/lib/pipeline/value-operators/transformers.d.ts +31 -0
  19. package/package.json +25 -3
  20. package/rollup.config.base.js +1 -2
  21. package/src/index.ts +3 -0
  22. package/src/lib/pipeline/index.ts +2 -1
  23. package/src/lib/pipeline/step-helpers-utils.ts +105 -29
  24. package/src/lib/pipeline/step-helpers-value-operator.ts +307 -0
  25. package/src/lib/pipeline/step-helpers.ts +24 -50
  26. package/src/lib/pipeline/types.ts +7 -0
  27. package/src/lib/pipeline/value-operators/action-types.ts +8 -0
  28. package/src/lib/pipeline/value-operators/index.ts +10 -0
  29. package/src/lib/pipeline/value-operators/test-any-actions.ts +58 -0
  30. package/src/lib/pipeline/value-operators/test-decimal-actions.ts +85 -0
  31. package/src/lib/pipeline/value-operators/test-string-actions.ts +15 -0
  32. package/src/lib/pipeline/value-operators/testers.ts +59 -0
  33. package/src/lib/pipeline/value-operators/transform-decimal-actions.ts +88 -0
  34. package/src/lib/pipeline/value-operators/transform-string-actions.ts +49 -0
  35. package/src/lib/pipeline/value-operators/transformers.ts +34 -0
  36. package/test/value-test.test.ts +55 -0
  37. /package/lib/{pipeline/envs.d.ts → envs.d.ts} +0 -0
  38. /package/src/lib/{pipeline/envs.ts → envs.ts} +0 -0
@@ -0,0 +1,307 @@
1
+ import {StaticImplements} from './types';
2
+ import {
3
+ AllTesters,
4
+ AllTransformers,
5
+ RegisteredValueAction,
6
+ RegisteredValueActionWithParams,
7
+ ValueAction,
8
+ ValueActionFailed,
9
+ ValueActionPassed
10
+ } from './value-operators';
11
+
12
+ interface ValueOperatorBase {
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ $value?: any;
15
+ $allowMoreAction: boolean;
16
+ $actions?: Array<ValueAction>;
17
+ $allowUseDefault: boolean;
18
+ $defaultUsed: boolean;
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ $defaultValue?: any;
21
+ // control
22
+ $allowNoParamFuncCall: boolean;
23
+ }
24
+
25
+ /**
26
+ * function call is allowed for tester and transformer, only when the {@link $allowNoParamFuncCall} is true.
27
+ * and once it is called, set {@link $allowNoParamFuncCall} to false.
28
+ * otherwise, throw exception.
29
+ */
30
+ const applyOperator = (operator: IValueOperator, base: ValueOperatorBase) => {
31
+ if (base.$allowNoParamFuncCall) {
32
+ base.$allowNoParamFuncCall = false;
33
+ return operator;
34
+ } else {
35
+ throw new Error(`Function call is not allowed from: ${operator}.`);
36
+ }
37
+ };
38
+ const NOT_FOUND = Symbol('not found');
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ type ValueActionFind = (operator: IValueOperator, base: ValueOperatorBase, prop: string) => IValueOperator | ((...args: Array<any>) => IValueOperator) | symbol;
41
+ const findValueAction = (actions: Record<string, RegisteredValueAction | RegisteredValueActionWithParams>): ValueActionFind => {
42
+ return (operator: IValueOperator, base: ValueOperatorBase, prop: string) => {
43
+ const tester = actions[prop];
44
+ if (tester == null) {
45
+ return NOT_FOUND;
46
+ }
47
+
48
+ base.$allowUseDefault = true;
49
+ if (base.$actions == null) {
50
+ base.$actions = [];
51
+ }
52
+ if (tester.type === 'func') {
53
+ // push to tester stack
54
+ base.$actions.push(tester.func);
55
+ base.$allowNoParamFuncCall = true;
56
+ return operator;
57
+ } else if (tester.type === 'param') {
58
+ // build a function to accept parameters
59
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
60
+ return (...args: Array<any>) => {
61
+ base.$actions.push(tester.func(...args));
62
+ return operator;
63
+ };
64
+ } else {
65
+ throw new Error(`Unknown tester type: ${tester}.`);
66
+ }
67
+ };
68
+ };
69
+ const findTester = findValueAction(AllTesters);
70
+ const findTransformer = findValueAction(AllTransformers);
71
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
+ type UseDefaultFind = (operator: IValueOperator, base: ValueOperatorBase, prop: string) => ((defaultValue: any) => IValueOperator) | undefined | symbol;
73
+ const findUseDefault: UseDefaultFind = (operator: IValueOperator, base: ValueOperatorBase, prop: string) => {
74
+ if (!base.$allowUseDefault || !['orUseDefault', 'useDefault', 'withDefault', 'orElse', 'else'].includes(prop)) {
75
+ return NOT_FOUND;
76
+ }
77
+ if ((base.$actions == null || base.$actions.length === 0)) {
78
+ // no action defined, use default value directly, no way
79
+ return (void 0);
80
+ }
81
+ base.$allowMoreAction = false;
82
+ base.$allowUseDefault = false;
83
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
+ return (defaultValue: any) => {
85
+ base.$defaultUsed = true;
86
+ base.$defaultValue = defaultValue;
87
+ return operator;
88
+ };
89
+ };
90
+ type ValueFind = (operator: IValueOperator, base: ValueOperatorBase, prop: string) => (<T>() => T) | undefined | symbol;
91
+ const createValueRetrieveFunc = (base: ValueOperatorBase) => {
92
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
93
+ return <T>(): ValueActionPassed<T> | ValueActionFailed<any> => {
94
+ const tested = {test: true, value: base.$value};
95
+ for (const action of (base.$actions ?? [])) {
96
+ const result = action(tested.value);
97
+ if (!result.test) {
98
+ // failed on action proceeding, ignore all tailing actions, and use original value
99
+ tested.test = false;
100
+ tested.value = base.$value;
101
+ break;
102
+ } else {
103
+ // action proceeded successfully
104
+ tested.value = result.value;
105
+ }
106
+ }
107
+ if (tested.test) {
108
+ // all actions proceeded, and value might be transformed, do nothing
109
+ } else if (base.$defaultUsed) {
110
+ // failed on action proceeding, use default value if defined
111
+ // therefore, final result has been treated as success
112
+ tested.test = true;
113
+ tested.value = base.$defaultValue as T;
114
+ } else {
115
+ // failed on acton proceeding, and no default value defined, return value itself
116
+ tested.value = base.$value;
117
+ }
118
+ return tested;
119
+ };
120
+ };
121
+ const findValue: ValueFind = (_operator: IValueOperator, base: ValueOperatorBase, prop: string) => {
122
+ if (prop !== 'value') {
123
+ return NOT_FOUND;
124
+ }
125
+ if ((base.$actions == null || base.$actions.length === 0)) {
126
+ // no action defined, get value directly, no way
127
+ return (void 0);
128
+ }
129
+ // return value anyway, no matter success or failure
130
+ return <T>(): T => createValueRetrieveFunc(base)<T>().value;
131
+ };
132
+ type SuccessCallback = (callback: <T>(value: T) => void) => ({ failure: (callback: <V>(value: V) => void) => void });
133
+ type FailureCallback = (callback: <V>(value: V) => void) => ({ success: (callback: <T>(value: T) => void) => void });
134
+ type SuccessOrFailureCallbackFind = (operator: IValueOperator, base: ValueOperatorBase, prop: string) => SuccessCallback | FailureCallback | undefined | symbol;
135
+ const findSuccessOrFailureCallback: SuccessOrFailureCallbackFind = (_operator: IValueOperator, base: ValueOperatorBase, prop: string) => {
136
+ if (prop !== 'success' && prop !== 'failure') {
137
+ return NOT_FOUND;
138
+ }
139
+ if ((base.$actions == null || base.$actions.length === 0)) {
140
+ // no action defined, get value directly, no way
141
+ return (void 0);
142
+ }
143
+ switch (prop) {
144
+ case 'success':
145
+ return (callback: <T>(value: T) => void) => {
146
+ const tested = createValueRetrieveFunc(base)();
147
+ if (tested.test) {
148
+ callback(tested.value);
149
+ }
150
+ return {
151
+ failure: (callback: <T>(value: T) => void): void => {
152
+ if (!tested.test) {
153
+ callback(tested.value);
154
+ }
155
+ }
156
+ };
157
+ };
158
+ case 'failure':
159
+ return (callback: <V>(value: V) => void) => {
160
+ const tested = createValueRetrieveFunc(base)();
161
+ if (!tested.test) {
162
+ callback(tested.value);
163
+ }
164
+ return {
165
+ success: (callback: <T>(value: T) => void): void => {
166
+ if (tested.test) {
167
+ callback(tested.value);
168
+ }
169
+ }
170
+ };
171
+ };
172
+ default:
173
+ throw new Error(`Unknown callback type: ${prop}.`);
174
+ }
175
+ };
176
+ type OKFind = (operator: IValueOperator, base: ValueOperatorBase, prop: string) => (() => boolean) | symbol;
177
+ const findOK: OKFind = (operator: IValueOperator, base: ValueOperatorBase, prop: string) => {
178
+ if (prop !== 'ok') {
179
+ return NOT_FOUND;
180
+ }
181
+ if ((base.$actions == null || base.$actions.length === 0)) {
182
+ // no action defined, get value directly, no way
183
+ return (void 0);
184
+ }
185
+ return (): boolean => createValueRetrieveFunc(base)().test;
186
+ };
187
+ type PromiseFind = (operator: IValueOperator, base: ValueOperatorBase, prop: string) => (<T>() => Promise<T>) | symbol;
188
+ const findPromise: PromiseFind = (_operator: IValueOperator, base: ValueOperatorBase, prop: string) => {
189
+ if (prop !== 'promise') {
190
+ return NOT_FOUND;
191
+ }
192
+ if ((base.$actions == null || base.$actions.length === 0)) {
193
+ // no action defined, get value directly, no way
194
+ return (void 0);
195
+ }
196
+ return async <T>(): Promise<T> => {
197
+ const tested = createValueRetrieveFunc(base)();
198
+ if (tested.test) {
199
+ return Promise.resolve(tested.value as T);
200
+ } else {
201
+ return Promise.reject(tested.value);
202
+ }
203
+ };
204
+ };
205
+ const getFromOperator = (operator: IValueOperator, base: ValueOperatorBase, prop: string) => {
206
+ // set to false anyway
207
+ base.$allowNoParamFuncCall = false;
208
+ const finds = [
209
+ findTester, findTransformer, findUseDefault,
210
+ findValue, findSuccessOrFailureCallback, findOK, findPromise
211
+ ];
212
+ for (const find of finds) {
213
+ const result = find(operator, base, prop);
214
+ if (result !== NOT_FOUND) {
215
+ return result;
216
+ }
217
+ }
218
+ // not found, return undefined
219
+ return (void 0);
220
+ };
221
+ const createOperator = (base: ValueOperatorBase): IValueOperator => {
222
+ const operatorBase = () => {
223
+ };
224
+ operatorBase.$base = base;
225
+ const operator = new Proxy(operatorBase, {
226
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
227
+ apply(base: typeof operatorBase, _thisArg: any, _argArray: any[]): any {
228
+ return applyOperator(operator, base.$base);
229
+ },
230
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
231
+ get(base: any, p: string, _receiver: any): any {
232
+ return getFromOperator(operator, base.$base, p);
233
+ }
234
+ });
235
+ return operator;
236
+ };
237
+
238
+ export interface FinalValueRetriever {
239
+ value: <T>() => T;
240
+ success: <T>(value: T) => { failure: <V>(value: V) => void };
241
+ failure: <V>(value: V) => { success: <T>(value: T) => void };
242
+ ok: () => boolean;
243
+ // parameter of reject original value
244
+ promise: <T>() => Promise<T>;
245
+ }
246
+
247
+ export interface DefaultValueSetter extends FinalValueRetriever {
248
+ // once, or ignored
249
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
250
+ orUseDefault: (defaultValue: any) => FinalValueRetriever;
251
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
252
+ useDefault: (defaultValue: any) => FinalValueRetriever;
253
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
254
+ withDefault: (defaultValue: any) => FinalValueRetriever;
255
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
256
+ orElse: (defaultValue: any) => FinalValueRetriever;
257
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
258
+ else: (defaultValue: any) => FinalValueRetriever;
259
+ }
260
+
261
+ type ActionType<T> = T extends RegisteredValueAction
262
+ ? (ValueActionsWithDefault & (() => ValueActionsWithDefault))
263
+ : T extends RegisteredValueActionWithParams ? ((...args: Parameters<T['func']>) => ValueActionsWithDefault) : never;
264
+ export type ValueActions =
265
+ & { [K in keyof typeof AllTesters]: ActionType<typeof AllTesters[K]> }
266
+ & { [K in keyof typeof AllTransformers]: ActionType<typeof AllTransformers[K]> };
267
+ export type ValueActionsWithDefault = ValueActions & DefaultValueSetter;
268
+
269
+ export type IValueOperator = ValueActions;
270
+
271
+ export interface IValueOperatorBoostrap {
272
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
273
+ of(value: any): IValueOperator;
274
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
275
+ from(value: any): IValueOperator;
276
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
277
+ with(value: any): IValueOperator;
278
+ }
279
+
280
+ @StaticImplements<IValueOperatorBoostrap>()
281
+ class ValueOperatorBootstrap {
282
+ // noinspection JSUnusedLocalSymbols
283
+ private constructor() {
284
+ // avoid extend
285
+ }
286
+
287
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
288
+ public static of(value: any): IValueOperator {
289
+ return createOperator({
290
+ $value: value,
291
+ $allowMoreAction: true, $allowUseDefault: false, $defaultUsed: false,
292
+ $allowNoParamFuncCall: false
293
+ });
294
+ }
295
+
296
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
297
+ public static from(value: any): IValueOperator {
298
+ return ValueOperatorBootstrap.of(value);
299
+ }
300
+
301
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
302
+ public static with(value: any): IValueOperator {
303
+ return ValueOperatorBootstrap.of(value);
304
+ }
305
+ }
306
+
307
+ export const ValueOperator: IValueOperatorBoostrap = ValueOperatorBootstrap;
@@ -1,21 +1,8 @@
1
1
  import dayjs from 'dayjs';
2
- import * as math from 'mathjs';
3
- import {
4
- CatchableError,
5
- Config,
6
- DateTime,
7
- ErrorCodes,
8
- ExposedUncatchableError,
9
- Logger,
10
- UncatchableError
11
- } from '../utils';
12
- import {
13
- PIPELINE_STEP_RETURN_NULL,
14
- PipelineStepErrorOptions,
15
- PipelineStepFile,
16
- PipelineStepFileOptions,
17
- StepHelpersUtils
18
- } from './step-helpers-utils';
2
+ import Decimal from 'decimal.js';
3
+ import {all, create, MathJsInstance} from 'mathjs';
4
+ import {Config, DateTime, ErrorCodes, Logger} from '../utils';
5
+ import {IStepHelpersUtils, PipelineStepErrorOptions, StepHelpersUtils} from './step-helpers-utils';
19
6
 
20
7
  export class PipelineStepDateHelper {
21
8
  private readonly _dateTimeFormat: string;
@@ -37,42 +24,19 @@ export class PipelineStepDateHelper {
37
24
  }
38
25
  }
39
26
 
40
- export type PipelineStepMathHelper = typeof math;
27
+ export type PipelineStepMathHelper = MathJsInstance;
28
+ export type PipelineStepDecimalHelper = (value: Decimal.Value) => Decimal;
41
29
 
42
- export interface PipelineStepHelpers {
30
+ export interface PipelineStepHelpers extends IStepHelpersUtils {
43
31
  $config?: Config;
44
32
  $logger?: Logger;
45
33
  $date: PipelineStepDateHelper;
46
34
  $math: PipelineStepMathHelper;
47
- $nano: (size?: number) => string;
48
- $ascii: (size?: number) => string;
35
+ $decimal: PipelineStepDecimalHelper;
36
+
49
37
  /** create an exposed uncatchable error*/
50
38
  $error: (options: PipelineStepErrorOptions) => never;
51
39
  $errorCodes: Readonly<Record<string, string>>;
52
- $errors: {
53
- catchable: (options: Omit<PipelineStepErrorOptions, 'status'>) => never;
54
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
- isCatchable: (e: any) => e is CatchableError;
56
- exposed: (options: PipelineStepErrorOptions) => never;
57
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
- isExposed: (e: any) => e is ExposedUncatchableError;
59
- uncatchable: (options: Omit<PipelineStepErrorOptions, 'status'>) => never;
60
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
- isUncatchable: (e: any) => e is UncatchableError;
62
- };
63
- /** create a file */
64
- $file: (options: PipelineStepFileOptions) => PipelineStepFile;
65
- $clearContextData: () => typeof PIPELINE_STEP_RETURN_NULL;
66
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
- isEmpty: (value: any) => boolean;
68
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
- isNotEmpty: (value: any) => boolean;
70
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
- isBlank: (value: any) => boolean;
72
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
73
- isNotBlank: (value: any) => boolean;
74
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
75
- trim: (value: any) => string;
76
40
 
77
41
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
42
  [key: string]: any;
@@ -84,13 +48,15 @@ export const registerToStepHelpers = (helpers: Record<string, any>) => {
84
48
  RegisteredHelpers.helpers = helpers ?? {};
85
49
  };
86
50
 
87
- export const createStepHelpers = (config: Config, logger: Logger): PipelineStepHelpers => {
88
- return {
51
+ const mathjs = create(all, {number: 'BigNumber', precision: 32});
52
+ export const createStepHelpers = (config: Config, logger: Logger): Readonly<PipelineStepHelpers> => {
53
+ const helpers: PipelineStepHelpers = {
89
54
  ...RegisteredHelpers.helpers,
90
55
  $config: config, $logger: logger,
91
56
  // date
92
57
  $date: new PipelineStepDateHelper(config),
93
- $math: math,
58
+ $math: mathjs,
59
+ $decimal: (value: Decimal.Value) => new Decimal(value),
94
60
  // nano
95
61
  $nano: StepHelpersUtils.$nano, $ascii: StepHelpersUtils.$ascii,
96
62
  // errors
@@ -98,12 +64,20 @@ export const createStepHelpers = (config: Config, logger: Logger): PipelineStepH
98
64
  $errorCodes: ErrorCodes,
99
65
  $errors: StepHelpersUtils.$errors,
100
66
  // file
101
- $file: StepHelpersUtils.createFile,
67
+ $file: StepHelpersUtils.$file,
102
68
  // semaphore
103
69
  $clearContextData: StepHelpersUtils.$clearContextData,
104
70
  // utilities
105
71
  isEmpty: StepHelpersUtils.isEmpty, isNotEmpty: StepHelpersUtils.isNotEmpty,
106
72
  isBlank: StepHelpersUtils.isBlank, isNotBlank: StepHelpersUtils.isNotBlank,
107
- trim: StepHelpersUtils.trim
73
+ trim: StepHelpersUtils.trim,
74
+ touch: StepHelpersUtils.touch,
75
+ noop: StepHelpersUtils.noop, asyncNoop: StepHelpersUtils.asyncNoop
108
76
  };
77
+ return new Proxy(helpers, {
78
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
79
+ set(_target: PipelineStepHelpers, _p: string | symbol, _value: any, _receiver: any): boolean {
80
+ return false;
81
+ }
82
+ });
109
83
  };
@@ -0,0 +1,7 @@
1
+ export const StaticImplements = <T>() => {
2
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3
+ return <U extends T>(_constructor: U) => {
4
+ // since only one static method, no need to execute constructor anymore
5
+ // constructor;
6
+ };
7
+ };
@@ -0,0 +1,8 @@
1
+ export type ValueActionPassed<V> = { test: true, value: V };
2
+ export type ValueActionFailed<V> = { test: false, value: V };
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ export type ValueAction<From = any, To = any> = (value?: From) => ValueActionPassed<To> | ValueActionFailed<From>;
5
+ export type RegisteredValueAction = { type: 'func', func: ValueAction }
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ export type RegisteredValueActionWithParams<F = (...args: Array<any>) => ValueAction> = { type: 'param', func: F };
8
+ export const OBJECT_PROTOTYPE = Object.prototype;
@@ -0,0 +1,10 @@
1
+ export * from './action-types';
2
+
3
+ export * from './test-any-actions';
4
+ export * from './test-string-actions';
5
+ export * from './test-decimal-actions';
6
+ export * from './testers';
7
+
8
+ export * from './transform-string-actions';
9
+ export * from './transform-decimal-actions';
10
+ export * from './transformers';
@@ -0,0 +1,58 @@
1
+ import {OBJECT_PROTOTYPE, ValueAction} from './action-types';
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
+ export const isLength = (value: any): boolean => {
5
+ return typeof value === 'number' && value > -1 && value % 1 === 0 && value <= Number.MAX_SAFE_INTEGER;
6
+ };
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ export const isArrayLike = (value: any): boolean => {
9
+ return value != null && typeof value !== 'function' && isLength(value.length);
10
+ };
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ export const isPrototype = (value: any): boolean => {
13
+ const Ctor = value && value.constructor;
14
+ const proto = (typeof Ctor === 'function' && Ctor.prototype) || OBJECT_PROTOTYPE;
15
+
16
+ return value === proto;
17
+ };
18
+
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ export const isNull: ValueAction<any, null | undefined> = (value?: any) => {
21
+ return value == null
22
+ ? {test: true, value: value as null | undefined}
23
+ : {test: false, value};
24
+ };
25
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
+ export const isNotNull: ValueAction<any, NonNullable<any>> = (value?: any) => ({test: !isNull(value).test, value});
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ export const isEmpty: ValueAction = (value?: any) => {
29
+ if (value == null) {
30
+ return {test: true, value: value as null | undefined};
31
+ }
32
+ let length: number | null = null;
33
+ if (isArrayLike(value) && (Array.isArray(value) || typeof value === 'string')) {
34
+ length = value.length;
35
+ } else if (value instanceof Map) {
36
+ length = value.size;
37
+ } else if (value instanceof Set) {
38
+ length = value.size;
39
+ } else if (isPrototype(value)) {
40
+ length = Object.keys(value).length;
41
+ }
42
+ return {test: length === 0, value};
43
+ };
44
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ export const isNotEmpty: ValueAction = (value?: any) => ({test: !isEmpty(value).test, value});
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ export const isBlank: ValueAction<any, null | undefined | string> = (value?: any) => {
48
+ switch (true) {
49
+ case (value == null):
50
+ return {test: true, value: value as null | undefined};
51
+ case (typeof value === 'string' && value.trim().length === 0):
52
+ return {test: true, value: value as string};
53
+ default:
54
+ return {test: false, value};
55
+ }
56
+ };
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ export const isNotBlank: ValueAction = (value?: any) => ({test: !isBlank(value).test, value});
@@ -0,0 +1,85 @@
1
+ import Decimal from 'decimal.js';
2
+ import {ValueAction} from './action-types';
3
+ import {toDecimal} from './transform-decimal-actions';
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ export const isDecimal: ValueAction<any, Decimal> = (value?: any) => {
7
+ const {test, value: decimal} = toDecimal(value);
8
+ return {test, value: test ? decimal : value};
9
+ };
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+ export const isInteger: ValueAction<any, Decimal> = (value?: any) => {
12
+ const {test, value: decimal} = toDecimal(value);
13
+ return (test && decimal.isInteger()) ? {test: true, value: decimal} : {test: false, value};
14
+ };
15
+ export type DecimalInterval = 'closed' | 'c' | 'open' | 'o' | 'left-open' | 'lo' | 'right-open' | 'ro';
16
+ export type DecimalInRangeOptions =
17
+ & { interval?: DecimalInterval }
18
+ & ({ min: Decimal.Value; max?: Decimal.Value; } | { min?: Decimal.Value; max: Decimal.Value; })
19
+ /**
20
+ * @param options.min value of range, might be included or not
21
+ * @param options.max max value of range, might be included or not
22
+ * @param options.interval closed, c -> [min, max]; open, o -> (min, max); left-open, lo -> (min, max]; right-open, ro -> [min, max)
23
+ */
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ export const isInRange = (options: DecimalInRangeOptions): ValueAction<any, Decimal> => {
26
+ const {min, max, interval = 'closed'} = options;
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ return (value?: any) => {
29
+ const {test, value: decimal} = toDecimal(value);
30
+ if (!test) {
31
+ return {test: false, value};
32
+ }
33
+ let pass = false;
34
+ switch (interval) {
35
+ case 'open':
36
+ case 'o':
37
+ pass = (min == null || decimal.gt(min)) && (max == null || decimal.lt(max));
38
+ break;
39
+ case 'left-open':
40
+ case 'lo':
41
+ pass = (min == null || decimal.gt(min)) && (max == null || decimal.lte(max));
42
+ break;
43
+ case 'right-open':
44
+ case 'ro':
45
+ pass = (min == null || decimal.gte(min)) && (max == null || decimal.lt(max));
46
+ break;
47
+ case 'closed':
48
+ case 'c':
49
+ default:
50
+ pass = (min == null || decimal.gte(min)) && (max == null || decimal.lte(max));
51
+ break;
52
+ }
53
+ return pass ? {test: true, value: decimal} : {test: false, value};
54
+ };
55
+ };
56
+ export const isPositive = isInRange({min: 0, interval: 'left-open'});
57
+ export const isNotPositive = isInRange({max: 0});
58
+ export const isNegative = isInRange({max: 0, interval: 'right-open'});
59
+ export const isNotNegative = isInRange({min: 0});
60
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ export const isZero: ValueAction<any, Decimal> = (value?: any) => {
62
+ const {test, value: decimal} = toDecimal(value);
63
+ return (test && decimal.isZero()) ? {test: true, value: decimal} : {test: false, value};
64
+ };
65
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
66
+ export const isNotZero: ValueAction<any, Decimal> = (value?: any) => {
67
+ const {test, value: decimal} = toDecimal(value);
68
+ return (test && !decimal.isZero()) ? {test: true, value: decimal} : {test: false, value};
69
+ };
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ export const isGreaterThan = (compare: Decimal.Value): ValueAction<any, Decimal> => {
72
+ return isInRange({min: compare, interval: 'left-open'});
73
+ };
74
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
75
+ export const isGreaterThanOrEqual = (compare: Decimal.Value): ValueAction<any, Decimal> => {
76
+ return isInRange({min: compare});
77
+ };
78
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
79
+ export const isLessThan = (compare: Decimal.Value): ValueAction<any, Decimal> => {
80
+ return isInRange({max: compare, interval: 'right-open'});
81
+ };
82
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
83
+ export const isLessThanOrEqual = (compare: Decimal.Value): ValueAction<any, Decimal> => {
84
+ return isInRange({max: compare});
85
+ };
@@ -0,0 +1,15 @@
1
+ import {ValueAction} from './action-types';
2
+
3
+ export const regexp = (regexp: RegExp): ValueAction => {
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ return (value?: any) => {
6
+ if (value == null) {
7
+ return {test: false, value};
8
+ }
9
+ const type = typeof value;
10
+ if (['string', 'number', 'bigint'].includes(type)) {
11
+ return {test: regexp.test(value), value};
12
+ }
13
+ return {test: false, value};
14
+ };
15
+ };
@@ -0,0 +1,59 @@
1
+ import {RegisteredValueAction, RegisteredValueActionWithParams} from './action-types';
2
+ import {isBlank, isEmpty, isNotBlank, isNotEmpty, isNotNull, isNull} from './test-any-actions';
3
+ import {
4
+ isDecimal,
5
+ isGreaterThan,
6
+ isGreaterThanOrEqual,
7
+ isInRange,
8
+ isInteger,
9
+ isLessThan,
10
+ isLessThanOrEqual,
11
+ isNegative,
12
+ isNotNegative,
13
+ isNotPositive,
14
+ isNotZero,
15
+ isPositive,
16
+ isZero
17
+ } from './test-decimal-actions';
18
+ import {regexp} from './test-string-actions';
19
+
20
+ const testers = {
21
+ // any
22
+ isNull: {type: 'func', func: isNull} as RegisteredValueAction,
23
+ isNotNull: {type: 'func', func: isNotNull} as RegisteredValueAction,
24
+ isEmpty: {type: 'func', func: isEmpty} as RegisteredValueAction,
25
+ isNotEmpty: {type: 'func', func: isNotEmpty} as RegisteredValueAction,
26
+ isBlank: {type: 'func', func: isBlank} as RegisteredValueAction,
27
+ isNotBlank: {type: 'func', func: isNotBlank} as RegisteredValueAction,
28
+ // string
29
+ regexp: {type: 'param', func: regexp} as RegisteredValueActionWithParams<typeof regexp>,
30
+ regex: {type: 'param', func: regexp} as RegisteredValueActionWithParams<typeof regexp>,
31
+ matches: {type: 'param', func: regexp} as RegisteredValueActionWithParams<typeof regexp>,
32
+ // decimal, return decimal if test pass
33
+ isNumber: {type: 'func', func: isDecimal} as RegisteredValueAction,
34
+ isDecimal: {type: 'func', func: isDecimal} as RegisteredValueAction,
35
+ isInteger: {type: 'func', func: isInteger} as RegisteredValueAction,
36
+ isInt: {type: 'func', func: isInteger} as RegisteredValueAction,
37
+ isPositive: {type: 'func', func: isPositive} as RegisteredValueAction,
38
+ isNotPositive: {type: 'func', func: isNotPositive} as RegisteredValueAction,
39
+ isNegative: {type: 'func', func: isNegative} as RegisteredValueAction,
40
+ isNotNegative: {type: 'func', func: isNotNegative} as RegisteredValueAction,
41
+ isZero: {type: 'func', func: isZero} as RegisteredValueAction,
42
+ isNotZero: {type: 'func', func: isNotZero} as RegisteredValueAction,
43
+ // decimal with params, return decimal if test pass
44
+ isGreaterThan: {type: 'param', func: isGreaterThan} as RegisteredValueActionWithParams<typeof isGreaterThan>,
45
+ gt: {type: 'param', func: isGreaterThan} as RegisteredValueActionWithParams<typeof isGreaterThan>,
46
+ isGreaterThanOrEqual: {
47
+ type: 'param', func: isGreaterThanOrEqual
48
+ } as RegisteredValueActionWithParams<typeof isGreaterThanOrEqual>,
49
+ gte: {type: 'param', func: isGreaterThanOrEqual} as RegisteredValueActionWithParams<typeof isGreaterThanOrEqual>,
50
+ isLessThan: {type: 'param', func: isLessThan} as RegisteredValueActionWithParams<typeof isLessThan>,
51
+ lt: {type: 'param', func: isLessThan} as RegisteredValueActionWithParams<typeof isLessThan>,
52
+ isLessThanOrEqual: {
53
+ type: 'param', func: isLessThanOrEqual
54
+ } as RegisteredValueActionWithParams<typeof isLessThanOrEqual>,
55
+ lte: {type: 'param', func: isLessThanOrEqual} as RegisteredValueActionWithParams<typeof isLessThanOrEqual>,
56
+ isInRange: {type: 'param', func: isInRange} as RegisteredValueActionWithParams<typeof isInRange>,
57
+ within: {type: 'param', func: isInRange} as RegisteredValueActionWithParams<typeof isInRange>
58
+ };
59
+ export const AllTesters: Readonly<typeof testers> = testers;