vest-utils 1.5.0 → 2.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.
Files changed (157) hide show
  1. package/README.md +7 -2
  2. package/dist/chunk-CLMFDpHK.mjs +18 -0
  3. package/dist/exports/minifyObject.cjs +114 -0
  4. package/dist/exports/minifyObject.cjs.map +1 -0
  5. package/dist/exports/minifyObject.mjs +113 -0
  6. package/dist/exports/minifyObject.mjs.map +1 -0
  7. package/dist/exports/standardSchemaSpec.cjs +0 -0
  8. package/dist/exports/standardSchemaSpec.mjs +1 -0
  9. package/dist/isEmpty-BBxAFjjm.mjs +103 -0
  10. package/dist/isEmpty-BBxAFjjm.mjs.map +1 -0
  11. package/dist/isEmpty-BuEa-96Q.cjs +235 -0
  12. package/dist/isEmpty-BuEa-96Q.cjs.map +1 -0
  13. package/dist/vest-utils.cjs +510 -0
  14. package/dist/vest-utils.cjs.map +1 -0
  15. package/dist/vest-utils.mjs +421 -0
  16. package/dist/vest-utils.mjs.map +1 -0
  17. package/minifyObject/package.json +12 -8
  18. package/package.json +43 -58
  19. package/src/Brand.ts +9 -0
  20. package/src/IO.ts +2 -0
  21. package/src/Predicates.ts +13 -0
  22. package/src/Result.ts +121 -0
  23. package/src/SimpleStateMachine.ts +157 -0
  24. package/src/StringObject.ts +6 -0
  25. package/src/__tests__/Architecture.test.ts +69 -0
  26. package/src/__tests__/Predicates.test.ts +118 -0
  27. package/src/__tests__/Result.test.ts +284 -0
  28. package/src/__tests__/SimpleStateMachine.test.ts +425 -0
  29. package/src/__tests__/StringObject.test.ts +18 -0
  30. package/src/__tests__/asArray.test.ts +14 -0
  31. package/src/__tests__/bindNot.test.ts +39 -0
  32. package/src/__tests__/bus.test.ts +135 -0
  33. package/src/__tests__/cache.test.ts +139 -0
  34. package/src/__tests__/callEach.test.ts +20 -0
  35. package/src/__tests__/defaultTo.test.ts +52 -0
  36. package/src/__tests__/deferThrow.test.ts +26 -0
  37. package/src/__tests__/either.test.ts +17 -0
  38. package/src/__tests__/freezeAssign.test.ts +24 -0
  39. package/src/__tests__/greaterThan.test.ts +68 -0
  40. package/src/__tests__/invariant.test.ts +47 -0
  41. package/src/__tests__/isArray.test.ts +16 -0
  42. package/src/__tests__/isBoolean.test.ts +16 -0
  43. package/src/__tests__/isEmpty.test.ts +55 -0
  44. package/src/__tests__/isEmptySet.test.ts +22 -0
  45. package/src/__tests__/isNull.test.ts +26 -0
  46. package/src/__tests__/isNumeric.test.ts +27 -0
  47. package/src/__tests__/isPositive.test.ts +38 -0
  48. package/src/__tests__/isPromise.test.ts +17 -0
  49. package/src/__tests__/isString.test.ts +13 -0
  50. package/src/__tests__/isUndefined.test.ts +27 -0
  51. package/src/__tests__/isUnsafeKey.test.ts +22 -0
  52. package/src/__tests__/lengthEquals.test.ts +58 -0
  53. package/src/__tests__/longerThan.test.ts +58 -0
  54. package/src/__tests__/mapFirst.test.ts +31 -0
  55. package/src/__tests__/nonnullish.test.ts +25 -0
  56. package/src/__tests__/noop.test.ts +12 -0
  57. package/src/__tests__/numberEquals.test.ts +67 -0
  58. package/src/__tests__/optionalFunctionValue.test.ts +29 -0
  59. package/src/__tests__/seq.test.ts +29 -0
  60. package/src/__tests__/text.test.ts +41 -0
  61. package/src/__tests__/tinyState.test.ts +68 -0
  62. package/src/__tests__/toNumber.test.ts +39 -0
  63. package/src/__tests__/vest-utils.test.ts +13 -0
  64. package/src/__tests__/withCatch.test.ts +17 -0
  65. package/src/__tests__/withResolvers.test.ts +45 -0
  66. package/src/asArray.ts +3 -0
  67. package/src/assign.ts +1 -0
  68. package/src/bindNot.ts +3 -0
  69. package/src/bus.ts +52 -0
  70. package/src/cache.ts +68 -0
  71. package/src/callEach.ts +5 -0
  72. package/src/defaultTo.ts +9 -0
  73. package/src/deferThrow.ts +7 -0
  74. package/src/dynamicValue.ts +9 -0
  75. package/src/either.ts +3 -0
  76. package/src/exports/__tests__/minifyObject.security.test.ts +65 -0
  77. package/src/exports/__tests__/minifyObject.test.ts +281 -0
  78. package/src/exports/minifyObject.ts +198 -0
  79. package/src/exports/standardSchemaSpec.ts +70 -0
  80. package/src/freezeAssign.ts +5 -0
  81. package/src/globals.d.ts +3 -0
  82. package/src/greaterThan.ts +8 -0
  83. package/src/hasOwnProperty.ts +9 -0
  84. package/src/invariant.ts +19 -0
  85. package/src/isArrayValue.ts +11 -0
  86. package/src/isBooleanValue.ts +3 -0
  87. package/src/isEmpty.ts +18 -0
  88. package/src/isEmptySet.ts +15 -0
  89. package/src/isFunction.ts +5 -0
  90. package/src/isNull.ts +7 -0
  91. package/src/isNullish.ts +10 -0
  92. package/src/isNumeric.ts +11 -0
  93. package/src/isPositive.ts +5 -0
  94. package/src/isPromise.ts +5 -0
  95. package/src/isStringValue.ts +3 -0
  96. package/src/isUndefined.ts +7 -0
  97. package/src/isUnsafeKey.ts +3 -0
  98. package/src/lengthEquals.ts +11 -0
  99. package/src/longerThan.ts +8 -0
  100. package/src/mapFirst.ts +25 -0
  101. package/src/nonnullish.ts +9 -0
  102. package/src/noop.ts +1 -0
  103. package/src/numberEquals.ts +11 -0
  104. package/src/seq.ts +16 -0
  105. package/src/text.ts +20 -0
  106. package/src/tinyState.ts +28 -0
  107. package/src/toNumber.ts +11 -0
  108. package/src/utilityTypes.ts +25 -0
  109. package/src/valueIsObject.ts +5 -0
  110. package/src/vest-utils.ts +73 -0
  111. package/src/withCatch.ts +11 -0
  112. package/src/withResolvers.ts +33 -0
  113. package/standardSchemaSpec/package.json +14 -0
  114. package/types/{minifyObject.d.ts → exports/minifyObject.d.cts} +4 -2
  115. package/types/exports/minifyObject.d.cts.map +1 -0
  116. package/types/exports/minifyObject.d.mts +7 -0
  117. package/types/exports/minifyObject.d.mts.map +1 -0
  118. package/types/exports/standardSchemaSpec.d.cts +59 -0
  119. package/types/exports/standardSchemaSpec.d.cts.map +1 -0
  120. package/types/exports/standardSchemaSpec.d.mts +59 -0
  121. package/types/exports/standardSchemaSpec.d.mts.map +1 -0
  122. package/types/vest-utils.d.cts +296 -0
  123. package/types/vest-utils.d.cts.map +1 -0
  124. package/types/vest-utils.d.mts +295 -0
  125. package/types/vest-utils.d.mts.map +1 -0
  126. package/types/vest-utils.d.ts +245 -143
  127. package/vitest.config.ts +9 -45
  128. package/dist/cjs/minifyObject.development.js +0 -217
  129. package/dist/cjs/minifyObject.development.js.map +0 -1
  130. package/dist/cjs/minifyObject.js +0 -6
  131. package/dist/cjs/minifyObject.production.js +0 -2
  132. package/dist/cjs/minifyObject.production.js.map +0 -1
  133. package/dist/cjs/package.json +0 -1
  134. package/dist/cjs/vest-utils.development.js +0 -378
  135. package/dist/cjs/vest-utils.development.js.map +0 -1
  136. package/dist/cjs/vest-utils.js +0 -6
  137. package/dist/cjs/vest-utils.production.js +0 -2
  138. package/dist/cjs/vest-utils.production.js.map +0 -1
  139. package/dist/es/minifyObject.development.js +0 -214
  140. package/dist/es/minifyObject.development.js.map +0 -1
  141. package/dist/es/minifyObject.production.js +0 -2
  142. package/dist/es/minifyObject.production.js.map +0 -1
  143. package/dist/es/package.json +0 -1
  144. package/dist/es/vest-utils.development.js +0 -330
  145. package/dist/es/vest-utils.development.js.map +0 -1
  146. package/dist/es/vest-utils.production.js +0 -2
  147. package/dist/es/vest-utils.production.js.map +0 -1
  148. package/dist/umd/minifyObject.development.js +0 -223
  149. package/dist/umd/minifyObject.development.js.map +0 -1
  150. package/dist/umd/minifyObject.production.js +0 -2
  151. package/dist/umd/minifyObject.production.js.map +0 -1
  152. package/dist/umd/vest-utils.development.js +0 -384
  153. package/dist/umd/vest-utils.development.js.map +0 -1
  154. package/dist/umd/vest-utils.production.js +0 -2
  155. package/dist/umd/vest-utils.production.js.map +0 -1
  156. package/types/minifyObject.d.ts.map +0 -1
  157. package/types/vest-utils.d.ts.map +0 -1
@@ -0,0 +1,198 @@
1
+ import isUnsafeKey from '../isUnsafeKey';
2
+ import { isArray } from '../isArrayValue';
3
+ import { isEmpty } from '../isEmpty';
4
+ import isFunction from '../isFunction';
5
+ import { isNullish } from '../isNullish';
6
+ import isStringValue from '../isStringValue';
7
+ import { isObject } from '../valueIsObject';
8
+
9
+ // Basic key generator that generates keys like a, b, c, ... aa, ab, ac, ...
10
+ function genMinifiedKey() {
11
+ const chars =
12
+ '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*';
13
+ let index = 0;
14
+
15
+ return function next(): string {
16
+ let code = '';
17
+ let x = index;
18
+
19
+ do {
20
+ code = code + chars[x % chars.length];
21
+ x = Math.floor(x / chars.length);
22
+ } while (x > 0);
23
+ index++;
24
+ return code;
25
+ };
26
+ }
27
+
28
+ export function minifyObject(
29
+ obj: any,
30
+ replacer: MinifyObjectReplacer = v => v,
31
+ ): [any, any] {
32
+ const countMap = new Map<any, number>();
33
+ countOccurrences(obj, countMap, replacer);
34
+ const maps = genMap(countMap);
35
+ const o = minifyObjectImpl(obj, maps.map, replacer);
36
+ // need to reverse the map so that the minified keys are the keys and the original keys are the values
37
+ // and turn it into an object
38
+
39
+ return [o, maps.reverseMap];
40
+ }
41
+
42
+ function genMap(countMap: Map<any, number>) {
43
+ const counts = [];
44
+
45
+ for (const [value, count] of countMap) {
46
+ if (count > 1) {
47
+ counts.push({ value, count });
48
+ }
49
+ }
50
+
51
+ const sorted = counts.sort((a, z) => z.count - a.count);
52
+
53
+ const getKey = genMinifiedKey();
54
+ return sorted.reduce(
55
+ (maps, { value }) => {
56
+ if (!shouldAddToMap(value, maps.keyLength)) {
57
+ return maps;
58
+ }
59
+
60
+ let key;
61
+ do {
62
+ key = getKey();
63
+ } while (countMap.has(key));
64
+ maps.map.set(value, key);
65
+ maps.reverseMap[key] = value;
66
+ maps.keyLength = key.length;
67
+ return maps;
68
+ },
69
+ {
70
+ map: new Map(),
71
+ reverseMap: {},
72
+ keyLength: 1,
73
+ } as {
74
+ map: Map<any, string>;
75
+ reverseMap: Record<string, any>;
76
+ keyLength: number;
77
+ },
78
+ );
79
+ }
80
+
81
+ // This avoids minification if the original key is shorter than or equals the minified key
82
+ function shouldAddToMap(value: any, keyLength: number) {
83
+ return value.toString().length >= keyLength;
84
+ }
85
+
86
+ function addCount(value: any, countMap: Map<any, number>) {
87
+ countMap.set(value, (countMap.get(value) || 0) + 1);
88
+ }
89
+
90
+ function countOccurrences(
91
+ obj: any,
92
+ countMap: Map<any, number>,
93
+ replacer: MinifyObjectReplacer,
94
+ ) {
95
+ for (const key in obj) {
96
+ const value = replacer(obj[key], key);
97
+ if (!shouldMinify(value)) continue;
98
+
99
+ if (!Array.isArray(obj)) {
100
+ addCount(key, countMap);
101
+ }
102
+
103
+ if (isObject(value)) {
104
+ countOccurrences(value, countMap, replacer);
105
+ } else {
106
+ addCount(value, countMap);
107
+ }
108
+ }
109
+ }
110
+
111
+ function isNonSerializable(value: any): boolean {
112
+ return isNullish(value) || isFunction(value) || typeof value === 'symbol';
113
+ }
114
+
115
+ function shouldMinify(value: any): boolean {
116
+ if (isObject(value) && isEmpty(value)) {
117
+ return false;
118
+ }
119
+
120
+ if (isNonSerializable(value)) {
121
+ return false;
122
+ }
123
+
124
+ return true;
125
+ }
126
+
127
+ function minifyObjectImpl(
128
+ obj: any,
129
+ map: Map<any, string>,
130
+ replacer: MinifyObjectReplacer,
131
+ ): any {
132
+ const minifiedObject: any = getRootNode(obj);
133
+
134
+ for (const key in obj) {
135
+ const value = replacer(obj[key], key);
136
+ if (!shouldMinify(value)) continue;
137
+
138
+ let minifiedValue;
139
+ if (isObject(value)) {
140
+ minifiedValue = minifyObjectImpl(value, map, replacer);
141
+ } else {
142
+ minifiedValue = minifyValue(value, map);
143
+ }
144
+
145
+ setValue(minifiedObject, minifiedValue, minifyValue(key, map));
146
+ }
147
+
148
+ return minifiedObject;
149
+ }
150
+
151
+ function minifyValue(value: any, map: Map<any, string>) {
152
+ return map.get(value) ?? value;
153
+ }
154
+
155
+ function expandSingle(value: any, map: Record<string, any>): any {
156
+ if (isStringValue(value)) {
157
+ return map[value] ?? value;
158
+ }
159
+
160
+ return value;
161
+ }
162
+
163
+ export function expandObject(minifiedObj: any, map: Record<string, any>): any {
164
+ const expandedObject: any = getRootNode(minifiedObj);
165
+
166
+ for (const key in minifiedObj) {
167
+ let expandedValue;
168
+ const value = minifiedObj[key];
169
+ if (isObject(value)) {
170
+ expandedValue = expandObject(value, map);
171
+ } else {
172
+ expandedValue = expandSingle(value, map);
173
+ }
174
+
175
+ const expandedKey = expandSingle(key, map);
176
+ setValue(expandedObject, expandedValue, expandedKey);
177
+ }
178
+
179
+ return expandedObject;
180
+ }
181
+
182
+ function setValue(container: any, value: any, key: string) {
183
+ if (isUnsafeKey(key)) {
184
+ return;
185
+ }
186
+
187
+ if (isArray(container)) {
188
+ container.push(value);
189
+ } else {
190
+ container[key] = value;
191
+ }
192
+ }
193
+
194
+ function getRootNode(node: any) {
195
+ return isArray(node) ? [] : {};
196
+ }
197
+
198
+ export type MinifyObjectReplacer = (value: any, key: string) => any;
@@ -0,0 +1,70 @@
1
+ /** The Standard Schema interface. */
2
+ export interface StandardSchemaV1<Input = unknown, Output = Input> {
3
+ /** The Standard Schema properties. */
4
+ readonly '~standard': StandardSchemaV1.Props<Input, Output>;
5
+ }
6
+
7
+ export declare namespace StandardSchemaV1 {
8
+ /** The Standard Schema properties interface. */
9
+ export interface Props<Input = unknown, Output = Input> {
10
+ /** The version number of the standard. */
11
+ readonly version: 1;
12
+ /** The vendor name of the schema library. */
13
+ readonly vendor: string;
14
+ /** Validates unknown input values. */
15
+ readonly validate: (
16
+ value: unknown,
17
+ ) => Result<Output> | Promise<Result<Output>>;
18
+ /** Inferred types associated with the schema. */
19
+ readonly types?: Types<Input, Output> | undefined;
20
+ }
21
+
22
+ /** The result interface of the validate function. */
23
+ export type Result<Output> = SuccessResult<Output> | FailureResult;
24
+
25
+ /** The result interface if validation succeeds. */
26
+ export interface SuccessResult<Output> {
27
+ /** The typed output value. */
28
+ readonly value: Output;
29
+ /** The non-existent issues. */
30
+ readonly issues?: undefined;
31
+ }
32
+
33
+ /** The result interface if validation fails. */
34
+ export interface FailureResult {
35
+ /** The issues of failed validation. */
36
+ readonly issues: ReadonlyArray<Issue>;
37
+ }
38
+
39
+ /** The issue interface of the failure output. */
40
+ export interface Issue {
41
+ /** The error message of the issue. */
42
+ readonly message: string;
43
+ /** The path of the issue, if any. */
44
+ readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
45
+ }
46
+
47
+ /** The path segment interface of the issue. */
48
+ export interface PathSegment {
49
+ /** The key representing a path segment. */
50
+ readonly key: PropertyKey;
51
+ }
52
+
53
+ /** The Standard Schema types interface. */
54
+ export interface Types<Input = unknown, Output = Input> {
55
+ /** The input type of the schema. */
56
+ readonly input: Input;
57
+ /** The output type of the schema. */
58
+ readonly output: Output;
59
+ }
60
+
61
+ /** Infers the input type of a Standard Schema. */
62
+ export type InferInput<Schema extends StandardSchemaV1> = NonNullable<
63
+ Schema['~standard']['types']
64
+ >['input'];
65
+
66
+ /** Infers the output type of a Standard Schema. */
67
+ export type InferOutput<Schema extends StandardSchemaV1> = NonNullable<
68
+ Schema['~standard']['types']
69
+ >['output'];
70
+ }
@@ -0,0 +1,5 @@
1
+ import assign from './assign';
2
+
3
+ export function freezeAssign<T extends object>(...args: Partial<T>[]): T {
4
+ return Object.freeze(assign(...(args as [Partial<T>])));
5
+ }
@@ -0,0 +1,3 @@
1
+ declare const __DEV__: boolean;
2
+ declare const __LIB_VERSION__: string;
3
+ declare const LIBRARY_NAME: string;
@@ -0,0 +1,8 @@
1
+ import { isNumeric } from './isNumeric';
2
+
3
+ export function greaterThan(
4
+ value: number | string,
5
+ gt: number | string,
6
+ ): boolean {
7
+ return isNumeric(value) && isNumeric(gt) && Number(value) > Number(gt);
8
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * A safe hasOwnProperty access
3
+ */
4
+ export default function hasOwnProperty<T>(
5
+ obj: T,
6
+ key: string | number | symbol,
7
+ ): key is keyof T {
8
+ return Object.prototype.hasOwnProperty.call(obj, key);
9
+ }
@@ -0,0 +1,19 @@
1
+ import dynamicValue from './dynamicValue';
2
+ import type { Stringable } from './utilityTypes';
3
+
4
+ export default function invariant(
5
+ condition: any,
6
+
7
+ message?: String | Stringable,
8
+ ): asserts condition {
9
+ if (condition) {
10
+ return;
11
+ }
12
+
13
+ // If message is a string object (rather than string literal)
14
+ // Throw the value directly as a string
15
+ // Alternatively, throw an error with the message
16
+ throw message instanceof String
17
+ ? message.valueOf()
18
+ : new Error(message ? dynamicValue(message) : message);
19
+ }
@@ -0,0 +1,11 @@
1
+ import bindNot from './bindNot';
2
+
3
+ // The module is named "isArrayValue" since it
4
+ // is conflicting with a nested npm dependency.
5
+ // We may need to revisit this in the future.
6
+
7
+ export function isArray(value: unknown): value is Array<unknown> {
8
+ return Boolean(Array.isArray(value));
9
+ }
10
+
11
+ export const isNotArray = bindNot(isArray);
@@ -0,0 +1,3 @@
1
+ export default function isBoolean(value: unknown): value is boolean {
2
+ return !!value === value;
3
+ }
package/src/isEmpty.ts ADDED
@@ -0,0 +1,18 @@
1
+ import bindNot from './bindNot';
2
+ import hasOwnProperty from './hasOwnProperty';
3
+ import { lengthEquals } from './lengthEquals';
4
+ import { isObject } from './valueIsObject';
5
+
6
+ export function isEmpty(value: unknown): boolean {
7
+ if (!value) {
8
+ return true;
9
+ } else if (hasOwnProperty(value, 'length')) {
10
+ return lengthEquals(value as string | unknown[], 0);
11
+ } else if (isObject(value)) {
12
+ return lengthEquals(Object.keys(value as Record<string, unknown>), 0);
13
+ }
14
+
15
+ return false;
16
+ }
17
+
18
+ export const isNotEmpty = bindNot(isEmpty);
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Checks if a given set is empty.
3
+ * @param value value to check
4
+ */
5
+ export function isEmptySet(value: Set<unknown>): boolean {
6
+ return value.size === 0;
7
+ }
8
+
9
+ /**
10
+ * Checks if a given set is NOT empty.
11
+ * @param value value to check
12
+ */
13
+ export function isNotEmptySet(value: Set<unknown>): boolean {
14
+ return value.size > 0;
15
+ }
@@ -0,0 +1,5 @@
1
+ export default function isFunction(
2
+ value: unknown,
3
+ ): value is (...args: unknown[]) => unknown {
4
+ return typeof value === 'function';
5
+ }
package/src/isNull.ts ADDED
@@ -0,0 +1,7 @@
1
+ import bindNot from './bindNot';
2
+
3
+ export function isNull(value: unknown): value is null {
4
+ return value === null;
5
+ }
6
+
7
+ export const isNotNull = bindNot(isNull);
@@ -0,0 +1,10 @@
1
+ import bindNot from './bindNot';
2
+ import { isNull } from './isNull';
3
+ import { isUndefined } from './isUndefined';
4
+ import { Nullish } from './utilityTypes';
5
+
6
+ export function isNullish(value: any): value is Nullish {
7
+ return isNull(value) || isUndefined(value);
8
+ }
9
+
10
+ export const isNotNullish = bindNot(isNullish);
@@ -0,0 +1,11 @@
1
+ import bindNot from './bindNot';
2
+
3
+ export function isNumeric(value: string | number): boolean {
4
+ const str = String(value);
5
+ const num = Number(value);
6
+ const result =
7
+ !isNaN(parseFloat(str)) && !isNaN(Number(value)) && isFinite(num);
8
+ return Boolean(result);
9
+ }
10
+
11
+ export const isNotNumeric = bindNot(isNumeric);
@@ -0,0 +1,5 @@
1
+ import { greaterThan } from './greaterThan';
2
+
3
+ export function isPositive(value: number | string): boolean {
4
+ return greaterThan(value, 0);
5
+ }
@@ -0,0 +1,5 @@
1
+ import isFunction from './isFunction';
2
+
3
+ export default function isPromise(value: any): value is Promise<unknown> {
4
+ return !!value && isFunction(value.then);
5
+ }
@@ -0,0 +1,3 @@
1
+ export default function isStringValue(v: unknown): v is string {
2
+ return String(v) === v;
3
+ }
@@ -0,0 +1,7 @@
1
+ import bindNot from './bindNot';
2
+
3
+ export function isUndefined(value?: unknown): value is undefined {
4
+ return value === undefined;
5
+ }
6
+
7
+ export const isNotUndefined = bindNot(isUndefined);
@@ -0,0 +1,3 @@
1
+ export default function isUnsafeKey(key: string): boolean {
2
+ return key === '__proto__' || key === 'constructor' || key === 'prototype';
3
+ }
@@ -0,0 +1,11 @@
1
+ import bindNot from './bindNot';
2
+ import { numberEquals } from './numberEquals';
3
+
4
+ export function lengthEquals(
5
+ value: string | unknown[],
6
+ arg1: string | number,
7
+ ): boolean {
8
+ return numberEquals(value.length, arg1);
9
+ }
10
+
11
+ export const lengthNotEquals = bindNot(lengthEquals);
@@ -0,0 +1,8 @@
1
+ import { greaterThan } from './greaterThan';
2
+
3
+ export function longerThan(
4
+ value: string | unknown[],
5
+ arg1: string | number,
6
+ ): boolean {
7
+ return greaterThan(value.length, arg1);
8
+ }
@@ -0,0 +1,25 @@
1
+ export default function mapFirst<T>(
2
+ array: T[],
3
+ callback: (
4
+ item: T,
5
+ breakout: (conditional: boolean, value: unknown) => void,
6
+ index: number,
7
+ ) => unknown,
8
+ ): any {
9
+ let broke = false;
10
+ let breakoutValue = null;
11
+ for (let i = 0; i < array.length; i++) {
12
+ callback(array[i], breakout, i);
13
+
14
+ if (broke) {
15
+ return breakoutValue;
16
+ }
17
+ }
18
+
19
+ function breakout(conditional: boolean, value: unknown) {
20
+ if (conditional) {
21
+ broke = true;
22
+ breakoutValue = value;
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,9 @@
1
+ import invariant from './invariant';
2
+ import { isNullish } from './isNullish';
3
+ import { Nullish } from './utilityTypes';
4
+
5
+ export function nonnullish<T>(value: Nullish<T>, error?: string): T {
6
+ invariant(!isNullish(value), error);
7
+
8
+ return value;
9
+ }
package/src/noop.ts ADDED
@@ -0,0 +1 @@
1
+ export function noop() {}
@@ -0,0 +1,11 @@
1
+ import bindNot from './bindNot';
2
+ import { isNumeric } from './isNumeric';
3
+
4
+ export function numberEquals(
5
+ value: string | number,
6
+ eq: string | number,
7
+ ): boolean {
8
+ return isNumeric(value) && isNumeric(eq) && Number(value) === Number(eq);
9
+ }
10
+
11
+ export const numberNotEquals = bindNot(numberEquals);
package/src/seq.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @returns a unique numeric id.
3
+ */
4
+
5
+ import { CB } from './utilityTypes';
6
+
7
+ const seq = genSeq();
8
+
9
+ export default seq;
10
+
11
+ export function genSeq(namespace?: string): CB<string> {
12
+ return (
13
+ (n: number) => () =>
14
+ `${namespace ? namespace + '_' : ''}${n++}`
15
+ )(0);
16
+ }
package/src/text.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { isEmpty } from './isEmpty';
2
+ import { isObject } from './valueIsObject';
3
+
4
+ const regexp = /{([^}]*)}/g;
5
+
6
+ export function text(str: string, ...substitutions: Array<unknown>): string {
7
+ const first = substitutions[0];
8
+
9
+ if (isObject(first)) {
10
+ return str.replace(regexp, (placeholder, key: string) => {
11
+ return `${first[key] ?? placeholder}`;
12
+ });
13
+ }
14
+
15
+ const subs = [...substitutions];
16
+
17
+ return str.replace(regexp, placeholder => {
18
+ return `${isEmpty(subs) ? placeholder : subs.shift()}`;
19
+ });
20
+ }
@@ -0,0 +1,28 @@
1
+ import dynamicValue from './dynamicValue';
2
+ import { DynamicValue } from './utilityTypes';
3
+
4
+ export function createTinyState<S>(
5
+ initialValue: SetValueInput<S>,
6
+ ): TinyState<S> {
7
+ let value: S;
8
+
9
+ resetValue();
10
+
11
+ return () => [value, setValue, resetValue];
12
+
13
+ function setValue(nextValue: SetValueInput<S>) {
14
+ value = dynamicValue(nextValue, value);
15
+ }
16
+
17
+ function resetValue() {
18
+ setValue(dynamicValue(initialValue));
19
+ }
20
+ }
21
+
22
+ export type TinyState<S> = () => [
23
+ value: S,
24
+ setValue: (next: SetValueInput<S>) => void,
25
+ resetValue: () => void,
26
+ ];
27
+
28
+ type SetValueInput<S> = DynamicValue<S, [prev: S]>;
@@ -0,0 +1,11 @@
1
+ import { makeResult, Result } from './Result';
2
+
3
+ export function toNumber(value: any): Result<number, string> {
4
+ const num = Number(value);
5
+
6
+ if (Number.isNaN(num)) {
7
+ return makeResult.Err(`Value "${value}" is not a number`);
8
+ }
9
+
10
+ return makeResult.Ok(num);
11
+ }
@@ -0,0 +1,25 @@
1
+ export type DropFirst<T extends unknown[]> = T extends [unknown, ...infer U]
2
+ ? U
3
+ : never;
4
+
5
+ export type Stringable = string | CB<string>;
6
+
7
+ export type CB<T = any, Args extends TArgs = TArgs> = (...args: Args) => T;
8
+
9
+ export type ValueOf<T> = T[keyof T];
10
+
11
+ export type Nullish<T = void> = Nullable<T> | Maybe<T>;
12
+
13
+ export type Nullable<T> = T | null;
14
+
15
+ export type Maybe<T> = T | undefined;
16
+
17
+ export type OneOrMoreOf<T> = T | T[];
18
+
19
+ export type DynamicValue<T, Args extends TArgs = TArgs> = T | CB<T, Args>;
20
+
21
+ export type BlankValue = Maybe<''>;
22
+
23
+ type TArgs = any[];
24
+
25
+ export type Predicate<T = any> = boolean | ((value: T) => boolean);
@@ -0,0 +1,5 @@
1
+ import { isNullish } from './isNullish';
2
+
3
+ export function isObject(v: any): v is Record<any, any> {
4
+ return typeof v === 'object' && !isNullish(v);
5
+ }