@strictly/base 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/.eslintrc.cjs +26 -0
- package/.out/errors/not_implemented.d.ts +3 -0
- package/.out/errors/not_implemented.js +5 -0
- package/.out/errors/unexpected_implementation.d.ts +3 -0
- package/.out/errors/unexpected_implementation.js +5 -0
- package/.out/errors/unreachable.d.ts +3 -0
- package/.out/errors/unreachable.js +6 -0
- package/.out/index.d.ts +20 -0
- package/.out/index.js +20 -0
- package/.out/test/index.d.ts +1 -0
- package/.out/test/index.js +1 -0
- package/.out/test/vitest/expect.d.ts +4 -0
- package/.out/test/vitest/expect.js +13 -0
- package/.out/tsconfig.json +16 -0
- package/.out/tsconfig.tsbuildinfo +1 -0
- package/.out/tsup.config.d.ts +3 -0
- package/.out/tsup.config.js +12 -0
- package/.out/types/element_of_array.d.ts +1 -0
- package/.out/types/element_of_array.js +1 -0
- package/.out/types/extract_generics.d.ts +2 -0
- package/.out/types/extract_generics.js +1 -0
- package/.out/types/is_field_optional.d.ts +1 -0
- package/.out/types/is_field_optional.js +1 -0
- package/.out/types/is_field_readonly.d.ts +8 -0
- package/.out/types/is_field_readonly.js +2 -0
- package/.out/types/maybe.d.ts +3 -0
- package/.out/types/maybe.js +1 -0
- package/.out/types/printable_of.d.ts +1 -0
- package/.out/types/printable_of.js +1 -0
- package/.out/types/required_of_record.d.ts +3 -0
- package/.out/types/required_of_record.js +1 -0
- package/.out/types/specs/element_of_array.tests.d.ts +1 -0
- package/.out/types/specs/element_of_array.tests.js +6 -0
- package/.out/types/specs/is_field_readonly.tests.d.ts +1 -0
- package/.out/types/specs/is_field_readonly.tests.js +9 -0
- package/.out/types/specs/printable_of.tests.d.ts +1 -0
- package/.out/types/specs/printable_of.tests.js +6 -0
- package/.out/types/specs/required_of_record.tests.d.ts +1 -0
- package/.out/types/specs/required_of_record.tests.js +12 -0
- package/.out/types/specs/string_key_of.tests.d.ts +1 -0
- package/.out/types/specs/string_key_of.tests.js +10 -0
- package/.out/types/string_key_of.d.ts +1 -0
- package/.out/types/string_key_of.js +1 -0
- package/.out/util/array.d.ts +1 -0
- package/.out/util/array.js +8 -0
- package/.out/util/cache.d.ts +13 -0
- package/.out/util/cache.js +42 -0
- package/.out/util/delay.d.ts +12 -0
- package/.out/util/delay.js +32 -0
- package/.out/util/format.d.ts +2 -0
- package/.out/util/format.js +11 -0
- package/.out/util/json.d.ts +1 -0
- package/.out/util/json.js +11 -0
- package/.out/util/poll.d.ts +8 -0
- package/.out/util/poll.js +23 -0
- package/.out/util/preconditions.d.ts +11 -0
- package/.out/util/preconditions.js +43 -0
- package/.out/util/promises.d.ts +1 -0
- package/.out/util/promises.js +11 -0
- package/.out/util/record.d.ts +10 -0
- package/.out/util/record.js +64 -0
- package/.out/util/specs/cache.tests.d.ts +1 -0
- package/.out/util/specs/cache.tests.js +49 -0
- package/.out/util/specs/format.tests.d.ts +1 -0
- package/.out/util/specs/format.tests.js +67 -0
- package/.out/util/specs/poll.tests.d.ts +1 -0
- package/.out/util/specs/poll.tests.js +47 -0
- package/.out/vitest.workspace.d.ts +2 -0
- package/.out/vitest.workspace.js +7 -0
- package/.turbo/turbo-build.log +18 -0
- package/.turbo/turbo-check-types.log +3 -0
- package/.turbo/turbo-release$colon$exports.log +3 -0
- package/README.md +3 -0
- package/dist/index.cjs +387 -0
- package/dist/index.d.cts +109 -0
- package/dist/index.d.ts +109 -0
- package/dist/index.js +328 -0
- package/errors/not_implemented.ts +5 -0
- package/errors/unexpected_implementation.ts +5 -0
- package/errors/unreachable.ts +6 -0
- package/index.ts +20 -0
- package/package.exports.json +18 -0
- package/package.json +50 -0
- package/test/index.ts +1 -0
- package/test/vitest/expect.ts +16 -0
- package/tsconfig.build.json +11 -0
- package/tsconfig.json +16 -0
- package/tsup.config.ts +16 -0
- package/types/element_of_array.ts +1 -0
- package/types/extract_generics.ts +2 -0
- package/types/is_field_optional.ts +5 -0
- package/types/is_field_readonly.ts +8 -0
- package/types/maybe.ts +5 -0
- package/types/printable_of.ts +1 -0
- package/types/required_of_record.ts +4 -0
- package/types/specs/element_of_array.tests.ts +9 -0
- package/types/specs/is_field_readonly.tests.ts +15 -0
- package/types/specs/printable_of.tests.ts +8 -0
- package/types/specs/required_of_record.tests.ts +16 -0
- package/types/specs/string_key_of.tests.ts +16 -0
- package/types/string_key_of.ts +1 -0
- package/util/array.ts +12 -0
- package/util/cache.ts +52 -0
- package/util/delay.ts +36 -0
- package/util/format.ts +23 -0
- package/util/json.ts +10 -0
- package/util/poll.ts +40 -0
- package/util/preconditions.ts +83 -0
- package/util/promises.ts +11 -0
- package/util/record.ts +133 -0
- package/util/specs/cache.tests.ts +68 -0
- package/util/specs/format.tests.ts +70 -0
- package/util/specs/poll.tests.ts +75 -0
- package/vitest.workspace.ts +11 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
// errors/not_implemented.ts
|
|
2
|
+
var NotImplementedError = class extends Error {
|
|
3
|
+
constructor(name) {
|
|
4
|
+
super(`${name} not implemented`);
|
|
5
|
+
}
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// errors/unexpected_implementation.ts
|
|
9
|
+
var UnexpectedImplementationError = class extends Error {
|
|
10
|
+
constructor(impl) {
|
|
11
|
+
super(impl);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// errors/unreachable.ts
|
|
16
|
+
var UnreachableError = class extends Error {
|
|
17
|
+
constructor(v) {
|
|
18
|
+
super(`Unreachable value received: ${v}`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// test/vitest/expect.ts
|
|
23
|
+
function expectEquals(v1, v2) {
|
|
24
|
+
expect(v1).toEqual(v2);
|
|
25
|
+
}
|
|
26
|
+
function expectTruthy(b) {
|
|
27
|
+
expect(b).toBeTruthy();
|
|
28
|
+
}
|
|
29
|
+
function expectDefined(v) {
|
|
30
|
+
expect(v).toBeDefined();
|
|
31
|
+
}
|
|
32
|
+
function expectDefinedAndReturn(v) {
|
|
33
|
+
expectDefined(v);
|
|
34
|
+
return v;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// util/array.ts
|
|
38
|
+
async function asyncReduce(arr, reducer, initial) {
|
|
39
|
+
let acc = initial;
|
|
40
|
+
for (let i = 0; i < arr.length; i++) {
|
|
41
|
+
const v = arr[i];
|
|
42
|
+
acc = await reducer(acc, v, i);
|
|
43
|
+
}
|
|
44
|
+
return acc;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// util/cache.ts
|
|
48
|
+
var Cache = class {
|
|
49
|
+
constructor(valueFactory) {
|
|
50
|
+
this.valueFactory = valueFactory;
|
|
51
|
+
}
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
cache = /* @__PURE__ */ new Map();
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
+
retrieveFinalMap(...args) {
|
|
56
|
+
return args.slice(0, -1).reduce(function(cache, key) {
|
|
57
|
+
let map2 = cache.get(key);
|
|
58
|
+
if (map2 == null) {
|
|
59
|
+
map2 = /* @__PURE__ */ new Map();
|
|
60
|
+
cache.set(key, map2);
|
|
61
|
+
}
|
|
62
|
+
return map2;
|
|
63
|
+
}, this.cache);
|
|
64
|
+
}
|
|
65
|
+
retrieve(...args) {
|
|
66
|
+
const finalKey = args[args.length - 1];
|
|
67
|
+
const finalMap = this.retrieveFinalMap(...args);
|
|
68
|
+
if (!finalMap.has(finalKey)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return [finalMap.get(finalKey)];
|
|
72
|
+
}
|
|
73
|
+
retrieveOrCreate(...args) {
|
|
74
|
+
const finalKey = args[args.length - 1];
|
|
75
|
+
const finalMap = this.retrieveFinalMap(...args);
|
|
76
|
+
if (finalMap == null || !finalMap.has(finalKey)) {
|
|
77
|
+
const value = this.valueFactory(...args);
|
|
78
|
+
finalMap.set(finalKey, value);
|
|
79
|
+
}
|
|
80
|
+
return finalMap.get(finalKey);
|
|
81
|
+
}
|
|
82
|
+
clear(...args) {
|
|
83
|
+
const finalKey = args[args.length - 1];
|
|
84
|
+
const finalMap = this.retrieveFinalMap(...args);
|
|
85
|
+
finalMap.delete(finalKey);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// util/delay.ts
|
|
90
|
+
function createDelay(millis) {
|
|
91
|
+
return function() {
|
|
92
|
+
return delay(millis);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function createWarmupDelay(coldMillis, warmMillis) {
|
|
96
|
+
let warmup;
|
|
97
|
+
return function() {
|
|
98
|
+
if (warmup != null) {
|
|
99
|
+
return warmup.then(function() {
|
|
100
|
+
return delay(warmMillis);
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
warmup = delay(coldMillis);
|
|
104
|
+
return warmup;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function delay(millis) {
|
|
109
|
+
return new Promise(function(resolve) {
|
|
110
|
+
setTimeout(resolve, millis);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
var secondDelay = createDelay(1e3);
|
|
114
|
+
|
|
115
|
+
// util/format.ts
|
|
116
|
+
function format(message, ...args) {
|
|
117
|
+
let index = 0;
|
|
118
|
+
return message.replaceAll(/{(\d*)}/g, function(_substring, indexString) {
|
|
119
|
+
let argIndex = parseInt(indexString);
|
|
120
|
+
if (Number.isNaN(argIndex)) {
|
|
121
|
+
argIndex = index;
|
|
122
|
+
index++;
|
|
123
|
+
}
|
|
124
|
+
return JSON.stringify(args[argIndex]);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// util/json.ts
|
|
129
|
+
function errorHandlingJsonParse(json, errorHandler) {
|
|
130
|
+
try {
|
|
131
|
+
return JSON.parse(json);
|
|
132
|
+
} catch (e) {
|
|
133
|
+
errorHandler?.(e);
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// util/poll.ts
|
|
139
|
+
function constantPollInterval(delay2) {
|
|
140
|
+
return function() {
|
|
141
|
+
return delay2;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async function poll(f, {
|
|
145
|
+
pollInterval = constantPollInterval(200),
|
|
146
|
+
retries = 3
|
|
147
|
+
} = {}) {
|
|
148
|
+
let retriesRemaining = retries;
|
|
149
|
+
while (retriesRemaining > 0) {
|
|
150
|
+
await delay(pollInterval(retriesRemaining));
|
|
151
|
+
retriesRemaining--;
|
|
152
|
+
const v = await f();
|
|
153
|
+
if (v != null) {
|
|
154
|
+
return v;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// util/preconditions.ts
|
|
161
|
+
var PreconditionFailedError = class extends Error {
|
|
162
|
+
constructor(message, ...args) {
|
|
163
|
+
super(format(message, ...args));
|
|
164
|
+
this.name = "PreconditionFailedError";
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
function assertExistsAndReturn(t, message, ...args) {
|
|
168
|
+
assertExists(t, message, ...args);
|
|
169
|
+
return t;
|
|
170
|
+
}
|
|
171
|
+
function assertExists(v, message, ...args) {
|
|
172
|
+
if (v == null) {
|
|
173
|
+
throw new PreconditionFailedError(message, ...args);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function assertEqual(a, b, message = "{} != {}", arg1 = a, arg2 = b, ...args) {
|
|
177
|
+
if (a !== b) {
|
|
178
|
+
throw new PreconditionFailedError(
|
|
179
|
+
message,
|
|
180
|
+
arg1,
|
|
181
|
+
arg2,
|
|
182
|
+
...args
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function assertState(condition, message, ...args) {
|
|
187
|
+
if (!condition) {
|
|
188
|
+
throw new PreconditionFailedError(message, ...args);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function assertIs(v, condition, message, ...args) {
|
|
192
|
+
if (!condition(v)) {
|
|
193
|
+
throw new PreconditionFailedError(message, ...args);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function checkUnary(t, message, ...args) {
|
|
197
|
+
if (t.length !== 1) {
|
|
198
|
+
throw new PreconditionFailedError(message, ...args);
|
|
199
|
+
}
|
|
200
|
+
return t[0];
|
|
201
|
+
}
|
|
202
|
+
function checkValidNumber(n, message, ...args) {
|
|
203
|
+
if (isNaN(n) || !isFinite(n)) {
|
|
204
|
+
throw new PreconditionFailedError(message, ...args);
|
|
205
|
+
}
|
|
206
|
+
return n;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// util/promises.ts
|
|
210
|
+
function callAsPromise(f) {
|
|
211
|
+
return new Promise(function(resolve, reject) {
|
|
212
|
+
f(function(e) {
|
|
213
|
+
if (e == null) {
|
|
214
|
+
resolve();
|
|
215
|
+
}
|
|
216
|
+
reject(e);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// util/record.ts
|
|
222
|
+
function reverse(obj) {
|
|
223
|
+
return Object.keys(obj).reduce((acc, stringKey) => {
|
|
224
|
+
const key = stringKey;
|
|
225
|
+
const value = obj[key];
|
|
226
|
+
acc[value] = key;
|
|
227
|
+
return acc;
|
|
228
|
+
}, {});
|
|
229
|
+
}
|
|
230
|
+
function rollup(...records) {
|
|
231
|
+
return records.slice(1).reduce((acc, record) => {
|
|
232
|
+
Object.keys(record).forEach((key) => {
|
|
233
|
+
const k = key;
|
|
234
|
+
acc[k] = acc[k] ?? record[k];
|
|
235
|
+
});
|
|
236
|
+
return acc;
|
|
237
|
+
}, records[0]);
|
|
238
|
+
}
|
|
239
|
+
function union(r1, r2) {
|
|
240
|
+
return {
|
|
241
|
+
...r1,
|
|
242
|
+
...r2
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function map(r, f) {
|
|
246
|
+
return Object.entries(r).reduce(
|
|
247
|
+
function(acc, [
|
|
248
|
+
k,
|
|
249
|
+
v
|
|
250
|
+
]) {
|
|
251
|
+
const typedKey = k;
|
|
252
|
+
acc[typedKey] = f(typedKey, v);
|
|
253
|
+
return acc;
|
|
254
|
+
},
|
|
255
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
256
|
+
{}
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
function reduce(r, f, a) {
|
|
260
|
+
return Object.entries(r).reduce(
|
|
261
|
+
function(acc, [
|
|
262
|
+
k,
|
|
263
|
+
v
|
|
264
|
+
]) {
|
|
265
|
+
const typedKey = k;
|
|
266
|
+
return f(acc, typedKey, v);
|
|
267
|
+
},
|
|
268
|
+
a
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
function forEach(r, f) {
|
|
272
|
+
return Object.entries(r).forEach(
|
|
273
|
+
function([
|
|
274
|
+
k,
|
|
275
|
+
v
|
|
276
|
+
]) {
|
|
277
|
+
return f(k, v);
|
|
278
|
+
}
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
function toArray(r) {
|
|
282
|
+
return reduce(
|
|
283
|
+
r,
|
|
284
|
+
function(acc, k, v) {
|
|
285
|
+
acc.push([
|
|
286
|
+
k,
|
|
287
|
+
v
|
|
288
|
+
]);
|
|
289
|
+
return acc;
|
|
290
|
+
},
|
|
291
|
+
[]
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
export {
|
|
295
|
+
Cache,
|
|
296
|
+
NotImplementedError,
|
|
297
|
+
PreconditionFailedError,
|
|
298
|
+
UnexpectedImplementationError,
|
|
299
|
+
UnreachableError,
|
|
300
|
+
assertEqual,
|
|
301
|
+
assertExists,
|
|
302
|
+
assertExistsAndReturn,
|
|
303
|
+
assertIs,
|
|
304
|
+
assertState,
|
|
305
|
+
asyncReduce,
|
|
306
|
+
callAsPromise,
|
|
307
|
+
checkUnary,
|
|
308
|
+
checkValidNumber,
|
|
309
|
+
constantPollInterval,
|
|
310
|
+
createDelay,
|
|
311
|
+
createWarmupDelay,
|
|
312
|
+
delay,
|
|
313
|
+
errorHandlingJsonParse,
|
|
314
|
+
expectDefined,
|
|
315
|
+
expectDefinedAndReturn,
|
|
316
|
+
expectEquals,
|
|
317
|
+
expectTruthy,
|
|
318
|
+
forEach,
|
|
319
|
+
format,
|
|
320
|
+
map,
|
|
321
|
+
poll,
|
|
322
|
+
reduce,
|
|
323
|
+
reverse,
|
|
324
|
+
rollup,
|
|
325
|
+
secondDelay,
|
|
326
|
+
toArray,
|
|
327
|
+
union
|
|
328
|
+
};
|
package/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export * from './errors/not_implemented'
|
|
2
|
+
export * from './errors/unexpected_implementation'
|
|
3
|
+
export * from './errors/unreachable'
|
|
4
|
+
export * from './test'
|
|
5
|
+
export * from './types/element_of_array'
|
|
6
|
+
export * from './types/extract_generics'
|
|
7
|
+
export * from './types/is_field_readonly'
|
|
8
|
+
export * from './types/maybe'
|
|
9
|
+
export * from './types/printable_of'
|
|
10
|
+
export * from './types/required_of_record'
|
|
11
|
+
export * from './types/string_key_of'
|
|
12
|
+
export * from './util/array'
|
|
13
|
+
export * from './util/cache'
|
|
14
|
+
export * from './util/delay'
|
|
15
|
+
export * from './util/format'
|
|
16
|
+
export * from './util/json'
|
|
17
|
+
export * from './util/poll'
|
|
18
|
+
export * from './util/preconditions'
|
|
19
|
+
export * from './util/promises'
|
|
20
|
+
export * from './util/record'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"exports": {
|
|
3
|
+
".": {
|
|
4
|
+
"import": {
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
|
|
7
|
+
"default": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"require": {
|
|
10
|
+
"types": "./dist/index.d.cts",
|
|
11
|
+
|
|
12
|
+
"default": "./dist/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts"
|
|
18
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "Chris <chris.glover@gmail.com> (@madmaw)",
|
|
3
|
+
"devDependencies": {
|
|
4
|
+
"@strictly/support-vite": "*",
|
|
5
|
+
"json": "^11.0.0"
|
|
6
|
+
},
|
|
7
|
+
"homepage": "https://madmaw.github.io/de/base",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"react",
|
|
10
|
+
"state management",
|
|
11
|
+
"types"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"name": "@strictly/base",
|
|
15
|
+
"packageManager": "yarn@1.22.22",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"directory": "packages/base",
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/madmaw/de.git"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"check-types": "tsc",
|
|
27
|
+
"clean": "del-cli dist",
|
|
28
|
+
"lint": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint . --max-warnings=0",
|
|
29
|
+
"lint:fix": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint . --fix",
|
|
30
|
+
"release:exports": "json -f package.json -f package.exports.json --merge > package.release.json",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"test:watch": "vitest"
|
|
33
|
+
},
|
|
34
|
+
"type": "module",
|
|
35
|
+
"version": "0.0.1",
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"import": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"default": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"require": {
|
|
43
|
+
"types": "./dist/index.d.cts",
|
|
44
|
+
"default": "./dist/index.cjs"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"main": "./dist/index.js",
|
|
49
|
+
"types": "./dist/index.d.ts"
|
|
50
|
+
}
|
package/test/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './vitest/expect'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function expectEquals<V1, V2 extends V1>(v1: V1, v2: V2): asserts v1 is V2 {
|
|
2
|
+
expect(v1).toEqual(v2)
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function expectTruthy(b: boolean): asserts b is true {
|
|
6
|
+
expect(b).toBeTruthy()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function expectDefined<V>(v: V): asserts v is NonNullable<V> {
|
|
10
|
+
expect(v).toBeDefined()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function expectDefinedAndReturn<V>(v: V): NonNullable<V> {
|
|
14
|
+
expectDefined(v)
|
|
15
|
+
return v
|
|
16
|
+
}
|
package/tsconfig.json
ADDED
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineConfig,
|
|
3
|
+
type Options,
|
|
4
|
+
} from 'tsup'
|
|
5
|
+
|
|
6
|
+
export default defineConfig((options: Options) => ({
|
|
7
|
+
entry: ['index.ts'],
|
|
8
|
+
tsconfig: './tsconfig.build.json',
|
|
9
|
+
clean: false,
|
|
10
|
+
dts: true,
|
|
11
|
+
format: [
|
|
12
|
+
'cjs',
|
|
13
|
+
'esm',
|
|
14
|
+
],
|
|
15
|
+
...options,
|
|
16
|
+
}))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ElementOfArray<A> = A extends readonly (infer T)[] ? T : never
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type IsEqual } from 'type-fest'
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4
|
+
export type IsFieldReadonly<R extends Record<string, any>, K extends keyof R> = {
|
|
5
|
+
[P in keyof R]: IsEqual<{ [Q in P]: R[P] }, { readonly [Q in P]: R[P] }>
|
|
6
|
+
}[K]
|
|
7
|
+
|
|
8
|
+
// extends never ? false : true
|
package/types/maybe.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type PrintableOf<T> = Extract<T, string | number>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type IsFieldReadonly } from 'types/is_field_readonly'
|
|
2
|
+
|
|
3
|
+
describe('IsFieldReadonly', function () {
|
|
4
|
+
it('detects readonly', function () {
|
|
5
|
+
type T = IsFieldReadonly<{ readonly a: 1 }, 'a'>
|
|
6
|
+
|
|
7
|
+
expectTypeOf<true>().toEqualTypeOf<T>()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('detects mutable', function () {
|
|
11
|
+
type T = IsFieldReadonly<{ a: 1 }, 'a'>
|
|
12
|
+
|
|
13
|
+
expectTypeOf<false>().toEqualTypeOf<T>()
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type PrintableOf } from 'types/printable_of'
|
|
2
|
+
|
|
3
|
+
describe('PrintableOf', function () {
|
|
4
|
+
it('filters out the non-printable types', function () {
|
|
5
|
+
type T = PrintableOf<string | number | boolean>
|
|
6
|
+
expectTypeOf<T>().toEqualTypeOf<string | number>()
|
|
7
|
+
})
|
|
8
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type RequiredOfRecord } from 'types/required_of_record'
|
|
2
|
+
|
|
3
|
+
describe('RequiredOfRecord', function () {
|
|
4
|
+
it('works on empty record', function () {
|
|
5
|
+
expectTypeOf<RequiredOfRecord<{}>>().toEqualTypeOf<{}>()
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
it('removes all optional types', function () {
|
|
9
|
+
expectTypeOf<RequiredOfRecord<{ a?: 1, b?: true, c?: 'a' }>>().toEqualTypeOf<{}>()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('leaves all mandatory types alone', function () {
|
|
13
|
+
type T = { a: 1, b: true, c: 'a' }
|
|
14
|
+
expectTypeOf<RequiredOfRecord<T>>().toEqualTypeOf<T>()
|
|
15
|
+
})
|
|
16
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type StringKeyOf } from 'types/string_key_of'
|
|
2
|
+
|
|
3
|
+
const s = Symbol()
|
|
4
|
+
type S = typeof s
|
|
5
|
+
|
|
6
|
+
describe('PrintableOf', function () {
|
|
7
|
+
it('filters out the non-string keys', function () {
|
|
8
|
+
type T = StringKeyOf<Record<string | number | symbol, unknown>>
|
|
9
|
+
expectTypeOf<T>().toEqualTypeOf<string>()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('filters out the non-string literal keys', function () {
|
|
13
|
+
type T = StringKeyOf<Record<'a' | 'b' | 1 | 2 | S, unknown>>
|
|
14
|
+
expectTypeOf<T>().toEqualTypeOf<'a' | 'b'>()
|
|
15
|
+
})
|
|
16
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type StringKeyOf<T> = Exclude<keyof T, number | symbol>
|
package/util/array.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export async function asyncReduce<T, Acc>(
|
|
2
|
+
arr: readonly T[],
|
|
3
|
+
reducer: (acc: Acc, v: T, index: number) => Promise<Acc>,
|
|
4
|
+
initial: Acc,
|
|
5
|
+
): Promise<Acc> {
|
|
6
|
+
let acc = initial
|
|
7
|
+
for (let i = 0; i < arr.length; i++) {
|
|
8
|
+
const v = arr[i]
|
|
9
|
+
acc = await reducer(acc, v, i)
|
|
10
|
+
}
|
|
11
|
+
return acc
|
|
12
|
+
}
|
package/util/cache.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type Maybe } from 'types/maybe'
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4
|
+
export type CacheValueFactory<A extends any[], V> = {
|
|
5
|
+
(...args: A): V,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
export class Cache<A extends any[], V> {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
private readonly cache: Map<any, V> = new Map()
|
|
12
|
+
|
|
13
|
+
constructor(private readonly valueFactory: CacheValueFactory<A, V>) {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
private retrieveFinalMap(...args: A): Map<any, V> {
|
|
18
|
+
return args.slice(0, -1).reduce(function (cache, key) {
|
|
19
|
+
let map = cache.get(key)
|
|
20
|
+
if (map == null) {
|
|
21
|
+
map = new Map()
|
|
22
|
+
cache.set(key, map)
|
|
23
|
+
}
|
|
24
|
+
return map
|
|
25
|
+
}, this.cache)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
retrieve(...args: A): Maybe<V> {
|
|
29
|
+
const finalKey = args[args.length - 1]
|
|
30
|
+
const finalMap = this.retrieveFinalMap(...args)
|
|
31
|
+
if (!finalMap.has(finalKey)) {
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
return [finalMap.get(finalKey)!]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
retrieveOrCreate(...args: A): V {
|
|
38
|
+
const finalKey = args[args.length - 1]
|
|
39
|
+
const finalMap = this.retrieveFinalMap(...args)
|
|
40
|
+
if (finalMap == null || !finalMap.has(finalKey)) {
|
|
41
|
+
const value = this.valueFactory(...args)
|
|
42
|
+
finalMap.set(finalKey, value)
|
|
43
|
+
}
|
|
44
|
+
return finalMap.get(finalKey)!
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
clear(...args: A) {
|
|
48
|
+
const finalKey = args[args.length - 1]
|
|
49
|
+
const finalMap = this.retrieveFinalMap(...args)
|
|
50
|
+
finalMap.delete(finalKey)
|
|
51
|
+
}
|
|
52
|
+
}
|