@gershy/clearing 0.0.6 → 0.0.7
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/cmp/cjs/main.js +293 -357
- package/cmp/mjs/main.js +293 -357
- package/cmp/types/global.d.ts +135 -232
- package/license +15 -0
- package/package.json +7 -3
- package/readme.md +784 -1
package/cmp/cjs/main.js
CHANGED
|
@@ -3,149 +3,113 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const applyClearing = (() => {
|
|
4
4
|
const global = globalThis;
|
|
5
5
|
// Prevent multiple installations...
|
|
6
|
-
const
|
|
6
|
+
const pfx = '@gershy/clearing';
|
|
7
|
+
const memSym = Symbol.for(`${pfx}:mem`);
|
|
7
8
|
if (global[memSym])
|
|
8
9
|
return;
|
|
9
10
|
global[memSym] = true;
|
|
10
|
-
const symNames = [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
11
|
+
const symNames = [
|
|
12
|
+
// <SYMBOLS>
|
|
13
|
+
'add',
|
|
14
|
+
'allArr',
|
|
15
|
+
'allObj',
|
|
16
|
+
'at',
|
|
17
|
+
'assert',
|
|
18
|
+
'base32',
|
|
19
|
+
'base36',
|
|
20
|
+
'base62',
|
|
21
|
+
'base64Std',
|
|
22
|
+
'base64Url',
|
|
23
|
+
'baseline',
|
|
24
|
+
'bind',
|
|
25
|
+
'bits',
|
|
26
|
+
'char',
|
|
27
|
+
'charset',
|
|
28
|
+
'code',
|
|
29
|
+
'count',
|
|
30
|
+
'cut',
|
|
31
|
+
'dive',
|
|
32
|
+
'empty',
|
|
33
|
+
'find',
|
|
34
|
+
'fire',
|
|
35
|
+
'group',
|
|
36
|
+
'has',
|
|
37
|
+
'hasHead',
|
|
38
|
+
'hasTail',
|
|
39
|
+
'indent',
|
|
40
|
+
'int32',
|
|
41
|
+
'int64',
|
|
42
|
+
'isInt',
|
|
43
|
+
'later',
|
|
44
|
+
'limn',
|
|
45
|
+
'lower',
|
|
46
|
+
'map',
|
|
47
|
+
'mapk',
|
|
48
|
+
'merge',
|
|
49
|
+
'mod',
|
|
50
|
+
'padHead',
|
|
51
|
+
'padTail',
|
|
52
|
+
'rem',
|
|
53
|
+
'slash',
|
|
54
|
+
'slice',
|
|
55
|
+
'suppress',
|
|
56
|
+
'toArr',
|
|
57
|
+
'toNum',
|
|
58
|
+
'toObj',
|
|
59
|
+
'toStr',
|
|
60
|
+
'upper'
|
|
61
|
+
// </SYMBOLS>
|
|
62
|
+
];
|
|
63
|
+
const syms = Object.fromEntries(symNames.map(term => [term, Symbol(`${pfx}:${term}`)]));
|
|
64
|
+
const getClsName = i => {
|
|
65
|
+
if (i === null)
|
|
66
|
+
return 'Null';
|
|
67
|
+
if (i === undefined)
|
|
68
|
+
return 'Undef';
|
|
69
|
+
if (i !== i)
|
|
70
|
+
return 'Nan';
|
|
71
|
+
return Object.getPrototypeOf(i)?.constructor.name ?? 'Prototypeless';
|
|
72
|
+
};
|
|
73
|
+
const getCls = i => Object.getPrototypeOf(i)?.constructor ?? null;
|
|
74
|
+
const isCls = (i, C) => {
|
|
75
|
+
// NaN only matches against the NaN primitive (not the Number Form)
|
|
76
|
+
if (i !== i)
|
|
77
|
+
return C !== C;
|
|
78
|
+
// `null` and `undefined` only match to themselves
|
|
79
|
+
if (i == null)
|
|
80
|
+
return i === C;
|
|
81
|
+
// Otherwise strictly check the constructor
|
|
82
|
+
return Object.getPrototypeOf(i).constructor === C;
|
|
83
|
+
};
|
|
84
|
+
const inCls = (i, C) => i instanceof C;
|
|
85
|
+
const skip = undefined;
|
|
86
|
+
Object.assign(global, { ...syms, clearing: { getClsName, getCls, isCls, inCls } });
|
|
87
|
+
const protoDefs = (Cls, def) => {
|
|
88
|
+
let protoVals = [];
|
|
89
|
+
let classVals = [];
|
|
90
|
+
for (const key of Reflect.ownKeys(def)) {
|
|
91
|
+
if (key !== '$' && !isCls(key, Symbol))
|
|
92
|
+
throw Object.assign(Error('invalid proto key'), { Cls, keyClsName: getClsName(key), key });
|
|
93
|
+
if (key !== '$') {
|
|
94
|
+
protoVals.push([key, def[key]]);
|
|
62
95
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
96
|
+
else {
|
|
97
|
+
for (const k of Reflect.ownKeys(def[key])) {
|
|
98
|
+
if (!isCls(k, Symbol))
|
|
99
|
+
throw Object.assign(Error('invalid class key'), { Cls, keyClsName: getClsName(k), key: k });
|
|
100
|
+
classVals.push([k, def[key][k]]);
|
|
101
|
+
}
|
|
67
102
|
}
|
|
68
|
-
},
|
|
69
|
-
// Jsfn
|
|
70
|
-
jsfn: {
|
|
71
|
-
encode: sovereign((dec /* `val` is still not allowed to have cycles! */, opts) => {
|
|
72
|
-
const encodeFn = opts?.encodeFn ?? (fn => fn.toString());
|
|
73
|
-
const hoists = [];
|
|
74
|
-
const serializeObjKey = (key) => {
|
|
75
|
-
if (/^[$_a-zA-Z][$_a-zA-Z]+$/.test(key))
|
|
76
|
-
return key;
|
|
77
|
-
return `'${key.replaceAll(`'`, `\\'`)}'`;
|
|
78
|
-
};
|
|
79
|
-
const serialize = (val) => {
|
|
80
|
-
if (isForm(val, Object) && Object.keys(val).sort().join(',') === 'args,form,hoist' && hasForm(val.form, Function)) {
|
|
81
|
-
const { args, form, hoist } = val;
|
|
82
|
-
hoists.push(hoist);
|
|
83
|
-
return `new ${hoist.split('::').at(-1)}(${args.map(a => serialize(a)).join(', ')})`;
|
|
84
|
-
}
|
|
85
|
-
if (isForm(val, Array))
|
|
86
|
-
return '[' + val.map((v) => serialize(v)).join(',') + ']';
|
|
87
|
-
if (isForm(val, Object))
|
|
88
|
-
return '{' + val[toArr]((v, k) => `${serializeObjKey(k)}:${serialize(v)}`).join(',') + '}';
|
|
89
|
-
if (hasForm(val, Function))
|
|
90
|
-
return encodeFn(val);
|
|
91
|
-
return JSON.stringify(val);
|
|
92
|
-
};
|
|
93
|
-
return {
|
|
94
|
-
// Note `str` is stringified, but it isn't json - it's js, in string representation!!
|
|
95
|
-
// This representation is actually very simple - in order to run the js represented by
|
|
96
|
-
// `str`, all hoists need to be imported in the context
|
|
97
|
-
hoists,
|
|
98
|
-
str: serialize(dec)
|
|
99
|
-
};
|
|
100
|
-
})
|
|
101
|
-
},
|
|
102
|
-
});
|
|
103
|
-
const protoDefs = (Cls, def) => {
|
|
104
|
-
const protoVals = [];
|
|
105
|
-
const classVals = [];
|
|
106
|
-
for (const key of Reflect.ownKeys(def) /* includes symbols!! */) {
|
|
107
|
-
if (!isForm(key, String))
|
|
108
|
-
protoVals.push({ key, val: def[key] });
|
|
109
|
-
else if (key.startsWith('$'))
|
|
110
|
-
classVals.push({ key: key.slice(1), val: def[key] });
|
|
111
|
-
else if (key.endsWith('->'))
|
|
112
|
-
protoVals.push({ key: def[key], val: Cls.prototype[key.slice(0, -2)] });
|
|
113
103
|
}
|
|
114
104
|
// Assign class properties
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// TODO: Note, we don't want to populate the global namespace, *but* we still populate all the
|
|
119
|
-
// symbols keyed by string name on `global` (note the *symbol* is keyed by its *string name* on
|
|
120
|
-
// `global` - i.e., `global['toArr']` results in `Symbol('clearing.toArr')`! This results in
|
|
121
|
-
// many dozens of keys being populated in global namespace... should probably move these
|
|
122
|
-
// symbols to a module import instead :(
|
|
123
|
-
if (Cls === global.constructor)
|
|
124
|
-
for (const entry of protoVals)
|
|
125
|
-
if (isForm(entry.key, String))
|
|
126
|
-
global[entry.key] = skip;
|
|
127
|
-
// Assign proto properties
|
|
128
|
-
Object.defineProperties(Cls.prototype, Object.fromEntries(protoVals
|
|
129
|
-
.map(({ key, val }) => [key, { enumerable: false, writable: true, value: val }])));
|
|
105
|
+
for (const [target, props] of [[Cls, classVals], [Cls.prototype, protoVals]])
|
|
106
|
+
for (const [sym, value] of props)
|
|
107
|
+
Object.defineProperty(target, sym, { enumerable: false, value });
|
|
130
108
|
};
|
|
131
109
|
protoDefs(Object, {
|
|
132
|
-
$stub: Object.freeze({}),
|
|
133
|
-
$plain: obj => obj ? Object.assign(Object.create(null), obj) : Object.create(null),
|
|
134
|
-
'hasOwnProperty->': has,
|
|
135
|
-
*[apart](dive = []) {
|
|
136
|
-
// Breaks apart a "structured" object into a flat list of dive keys paired with values; every
|
|
137
|
-
// value in the original object appears alongside the "dive" (chain of keys to recursively
|
|
138
|
-
// apply) required to dereference it
|
|
139
|
-
for (const [k, val] of this) {
|
|
140
|
-
if (isForm(val, Object))
|
|
141
|
-
yield* val[apart]([...dive, k]);
|
|
142
|
-
else
|
|
143
|
-
yield { dive: [...dive, k], val };
|
|
144
|
-
}
|
|
145
|
-
},
|
|
146
110
|
[at](cmps, def = skip) {
|
|
147
111
|
let ptr = this;
|
|
148
|
-
if (!
|
|
112
|
+
if (!isCls(cmps, Array))
|
|
149
113
|
cmps = [cmps];
|
|
150
114
|
for (const c of cmps) {
|
|
151
115
|
if (ptr[has](c))
|
|
@@ -155,23 +119,29 @@ const applyClearing = (() => {
|
|
|
155
119
|
}
|
|
156
120
|
return ptr;
|
|
157
121
|
},
|
|
158
|
-
[
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
122
|
+
[count]() { let c = 0; for (const k in this)
|
|
123
|
+
c++; return c; },
|
|
124
|
+
[empty]() { for (const k in this)
|
|
125
|
+
return false; return true; },
|
|
126
|
+
[group](fn) {
|
|
127
|
+
// { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10 }.group(n => {
|
|
128
|
+
// if (n < 4) return 'small';
|
|
129
|
+
// if (n < 8) return 'medium';
|
|
130
|
+
// return 'big';
|
|
131
|
+
// });
|
|
132
|
+
// >> { small: { a: 1, b: 2, c: 3 }, medium: { d: 4, e: 5, f: 6, g: 7 }, big: { h: 8, i: 9, j: 10 } }
|
|
133
|
+
const ret = {};
|
|
162
134
|
for (const [k, v] of this) {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
135
|
+
const g = fn(v, k);
|
|
136
|
+
if (g === skip)
|
|
137
|
+
continue;
|
|
138
|
+
if (!ret[has](g))
|
|
139
|
+
ret[g] = {};
|
|
140
|
+
ret[g][k] = v;
|
|
169
141
|
}
|
|
170
|
-
return
|
|
142
|
+
return ret;
|
|
171
143
|
},
|
|
172
|
-
[
|
|
173
|
-
c++; return c; },
|
|
174
|
-
[dive](cmps, def = skip) { return this[at](cmps, def); },
|
|
144
|
+
[has]: Object.prototype.hasOwnProperty,
|
|
175
145
|
[map](fn) {
|
|
176
146
|
const ret = Object.assign({}, this);
|
|
177
147
|
for (const k in ret) {
|
|
@@ -192,44 +162,6 @@ const applyClearing = (() => {
|
|
|
192
162
|
}
|
|
193
163
|
return Object.fromEntries(arr);
|
|
194
164
|
},
|
|
195
|
-
[toArr](fn) {
|
|
196
|
-
const ret = [];
|
|
197
|
-
for (const k in this) {
|
|
198
|
-
const r = fn(this[k], k);
|
|
199
|
-
if (r !== skip)
|
|
200
|
-
ret.push(r);
|
|
201
|
-
}
|
|
202
|
-
return ret;
|
|
203
|
-
},
|
|
204
|
-
[slash](p) {
|
|
205
|
-
const obj = { ...this };
|
|
206
|
-
for (const k of p)
|
|
207
|
-
delete obj[k];
|
|
208
|
-
return obj;
|
|
209
|
-
},
|
|
210
|
-
[slice](p) {
|
|
211
|
-
// >> { a: 1, b: 2, c: 3, d: 4 }.slice([ 'b', 'd' ]);
|
|
212
|
-
// { b: 2, d: 4 }
|
|
213
|
-
return p[toObj](p => this[has](p) ? [p, this[p]] : skip);
|
|
214
|
-
},
|
|
215
|
-
[empty]() { for (const k in this)
|
|
216
|
-
return false; return true; },
|
|
217
|
-
[group](fn) {
|
|
218
|
-
// { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10 }.group(n => {
|
|
219
|
-
// if (n < 4) return 'small';
|
|
220
|
-
// if (n < 8) return 'medium';
|
|
221
|
-
// return 'big';
|
|
222
|
-
// });
|
|
223
|
-
// >> { small: { a: 1, b: 2, c: 3 }, medium: { d: 4, e: 5, f: 6, g: 7 }, big: { h: 8, i: 9, j: 10 } }
|
|
224
|
-
const ret = {};
|
|
225
|
-
for (const [k, v] of this) {
|
|
226
|
-
const t = fn(v, k);
|
|
227
|
-
if (!ret[has](t))
|
|
228
|
-
ret[t] = {};
|
|
229
|
-
ret[t][k] = v;
|
|
230
|
-
}
|
|
231
|
-
return ret;
|
|
232
|
-
},
|
|
233
165
|
[merge](o) {
|
|
234
166
|
for (const [k, v] of o) {
|
|
235
167
|
// `skip` can be passed to remove properties
|
|
@@ -238,46 +170,45 @@ const applyClearing = (() => {
|
|
|
238
170
|
continue;
|
|
239
171
|
}
|
|
240
172
|
// Incoming non-Object properties are simple
|
|
241
|
-
if (!
|
|
173
|
+
if (!isCls(v, Object)) {
|
|
242
174
|
this[k] = v;
|
|
243
175
|
continue;
|
|
244
176
|
}
|
|
245
177
|
// `v` is an Object; existing non-Object replaced with `{}`
|
|
246
|
-
if (!this[has](k) || !
|
|
178
|
+
if (!this[has](k) || !isCls(this[k], Object))
|
|
247
179
|
this[k] = {};
|
|
248
180
|
// And simply recurse!
|
|
249
181
|
this[k][merge](v);
|
|
250
182
|
}
|
|
251
183
|
return this;
|
|
252
184
|
},
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
'includes->': has,
|
|
259
|
-
[has](v) { return this.includes(v); },
|
|
260
|
-
[map](it) {
|
|
261
|
-
const ret = [];
|
|
262
|
-
const len = this.length;
|
|
263
|
-
for (let i = 0; i < len; i++) {
|
|
264
|
-
const r = it(this[i], i);
|
|
265
|
-
if (r !== skip)
|
|
266
|
-
ret.push(r);
|
|
267
|
-
}
|
|
268
|
-
return ret;
|
|
185
|
+
[slash](p) {
|
|
186
|
+
const obj = { ...this };
|
|
187
|
+
for (const k of p)
|
|
188
|
+
delete obj[k];
|
|
189
|
+
return obj;
|
|
269
190
|
},
|
|
270
|
-
[
|
|
271
|
-
|
|
191
|
+
[slice](p) {
|
|
192
|
+
// >> { a: 1, b: 2, c: 3, d: 4 }.slice([ 'b', 'd' ]);
|
|
193
|
+
// { b: 2, d: 4 }
|
|
194
|
+
return p[toObj](p => this[has](p) ? [p, this[p]] : skip);
|
|
195
|
+
},
|
|
196
|
+
[toArr](fn) {
|
|
272
197
|
const ret = [];
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
const r = it(this[i], i);
|
|
198
|
+
for (const k in this) {
|
|
199
|
+
const r = fn(this[k], k);
|
|
276
200
|
if (r !== skip)
|
|
277
201
|
ret.push(r);
|
|
278
202
|
}
|
|
279
|
-
return
|
|
203
|
+
return ret;
|
|
280
204
|
},
|
|
205
|
+
*[Symbol.iterator]() { for (const k in this)
|
|
206
|
+
yield [k, this[k]]; }
|
|
207
|
+
});
|
|
208
|
+
protoDefs(Array, {
|
|
209
|
+
[add](...args) { this.push(...args); return args[0]; },
|
|
210
|
+
[count]() { return this.length; },
|
|
211
|
+
[empty]() { return !this.length; },
|
|
281
212
|
[find](f) {
|
|
282
213
|
const n = this.length;
|
|
283
214
|
for (let i = 0; i < n; i++)
|
|
@@ -285,11 +216,6 @@ const applyClearing = (() => {
|
|
|
285
216
|
return { found: true, val: this[i], ind: i };
|
|
286
217
|
return { found: false, val: null, ind: null };
|
|
287
218
|
},
|
|
288
|
-
[empty]() { return !this.length; },
|
|
289
|
-
[add](...args) { this.push(...args); return args[0]; },
|
|
290
|
-
[rem](val) { const ind = this.indexOf(val); if (ind > -1)
|
|
291
|
-
this.splice(ind, 1); },
|
|
292
|
-
[count]() { return this.length; },
|
|
293
219
|
[group](fn) {
|
|
294
220
|
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ].group(n => {
|
|
295
221
|
// if (n < 4) return 'small';
|
|
@@ -299,56 +225,78 @@ const applyClearing = (() => {
|
|
|
299
225
|
// >> { small: [ 1, 2, 3 ], medium: [ 4, 5, 6, 7 ], big: [ 8, 9, 10 ] }
|
|
300
226
|
const ret = {};
|
|
301
227
|
for (const elem of this) {
|
|
302
|
-
const
|
|
303
|
-
if (
|
|
304
|
-
|
|
305
|
-
ret[
|
|
228
|
+
const g = fn(elem);
|
|
229
|
+
if (g === skip)
|
|
230
|
+
continue;
|
|
231
|
+
if (!ret[has](g))
|
|
232
|
+
ret[g] = [];
|
|
233
|
+
ret[g].push(elem);
|
|
234
|
+
}
|
|
235
|
+
return ret;
|
|
236
|
+
},
|
|
237
|
+
[has]: Array.prototype.includes,
|
|
238
|
+
[map](it) {
|
|
239
|
+
const ret = [];
|
|
240
|
+
const len = this.length;
|
|
241
|
+
for (let i = 0; i < len; i++) {
|
|
242
|
+
const r = it(this[i], i);
|
|
243
|
+
if (r !== skip)
|
|
244
|
+
ret.push(r);
|
|
306
245
|
}
|
|
307
246
|
return ret;
|
|
247
|
+
},
|
|
248
|
+
[rem](val) { const ind = this.indexOf(val); if (ind > -1)
|
|
249
|
+
this.splice(ind, 1); },
|
|
250
|
+
[toObj](it) {
|
|
251
|
+
const ret = [];
|
|
252
|
+
const len = this.length;
|
|
253
|
+
for (let i = 0; i < len; i++) {
|
|
254
|
+
const r = it(this[i], i);
|
|
255
|
+
if (r !== skip)
|
|
256
|
+
ret.push(r);
|
|
257
|
+
}
|
|
258
|
+
return Object.fromEntries(ret);
|
|
308
259
|
}
|
|
309
260
|
});
|
|
310
261
|
protoDefs(String, {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
262
|
+
$: {
|
|
263
|
+
[baseline]: (str, seq = '| ') => {
|
|
264
|
+
return str.split('\n')[map](ln => {
|
|
265
|
+
const ind = ln.indexOf(seq);
|
|
266
|
+
if (ind === -1)
|
|
267
|
+
return skip;
|
|
268
|
+
return ln.slice(ind + seq.length);
|
|
269
|
+
}).join('\n');
|
|
270
|
+
},
|
|
271
|
+
[base32]: '0123456789abcdefghijklmnopqrstuv',
|
|
272
|
+
[base36]: '0123456789abcdefghijklmnopqrstuvwxyz',
|
|
273
|
+
[base62]: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
274
|
+
[base64Url]: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_',
|
|
275
|
+
[base64Std]: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/',
|
|
276
|
+
[charset]: str => {
|
|
277
|
+
const cache = new Map();
|
|
278
|
+
return {
|
|
279
|
+
str,
|
|
280
|
+
size: BigInt(str.length),
|
|
281
|
+
charVal: (c) => {
|
|
282
|
+
if (!cache.has(c)) {
|
|
283
|
+
const ind = str.indexOf(c);
|
|
284
|
+
if (ind < 0)
|
|
285
|
+
throw Error('char outside charset')[mod]({ char: c });
|
|
286
|
+
cache.set(c, BigInt(ind));
|
|
287
|
+
}
|
|
288
|
+
return cache.get(c);
|
|
289
|
+
},
|
|
290
|
+
valChar: (n) => {
|
|
291
|
+
if (n < 0 || n >= str.length)
|
|
292
|
+
throw Error('val outside charset');
|
|
293
|
+
return str[n];
|
|
330
294
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
valChar: (n) => {
|
|
334
|
-
if (n < 0 || n >= str.length)
|
|
335
|
-
throw Error('val outside charset');
|
|
336
|
-
return str[n];
|
|
337
|
-
}
|
|
338
|
-
};
|
|
295
|
+
};
|
|
296
|
+
},
|
|
339
297
|
},
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
$base62: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
343
|
-
$base64: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_',
|
|
344
|
-
$base64Std: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/',
|
|
345
|
-
'includes->': has,
|
|
346
|
-
'startsWith->': hasHead,
|
|
347
|
-
'endsWith->': hasTail,
|
|
348
|
-
'padStart->': padHead,
|
|
349
|
-
'padEnd->': padTail,
|
|
350
|
-
'toUpperCase->': upper,
|
|
351
|
-
'toLowerCase->': lower,
|
|
298
|
+
[code](ind = 0) { return this.charCodeAt(ind); },
|
|
299
|
+
[count]() { return this.length; },
|
|
352
300
|
[cut](delim, cuts = 1) {
|
|
353
301
|
// `cuts` defines # of cuts (resulting array length is `num + 1`)
|
|
354
302
|
const split = this.split(delim, cuts < Infinity ? cuts : skip);
|
|
@@ -360,13 +308,14 @@ const applyClearing = (() => {
|
|
|
360
308
|
? [...split, this.slice(lenConsumed + delim.length)]
|
|
361
309
|
: split;
|
|
362
310
|
},
|
|
363
|
-
[
|
|
364
|
-
[
|
|
311
|
+
[has]: String.prototype.includes,
|
|
312
|
+
[hasHead]: String.prototype.startsWith,
|
|
313
|
+
[hasTail]: String.prototype.endsWith,
|
|
365
314
|
[indent](...args /* amt=2, char=' ' | indentStr=' '.repeat(2) */) {
|
|
366
315
|
if (!this)
|
|
367
316
|
return this; // No-op on empty String (otherwise it would transform a 0-line string to a 1-line string)
|
|
368
317
|
let indentStr;
|
|
369
|
-
if (
|
|
318
|
+
if (isCls(args[0], String)) {
|
|
370
319
|
indentStr = args[0];
|
|
371
320
|
}
|
|
372
321
|
else {
|
|
@@ -375,10 +324,13 @@ const applyClearing = (() => {
|
|
|
375
324
|
}
|
|
376
325
|
return this.split('\n')[map](ln => `${indentStr}${ln}`).join('\n');
|
|
377
326
|
},
|
|
378
|
-
[
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
327
|
+
[lower]: String.prototype.toLowerCase,
|
|
328
|
+
[padHead]: String.prototype.padStart,
|
|
329
|
+
[padTail]: String.prototype.padEnd,
|
|
330
|
+
[toNum](cs = String[base62]) {
|
|
331
|
+
if (isCls(cs, String))
|
|
332
|
+
cs = String[charset](cs);
|
|
333
|
+
const base = cs.size;
|
|
382
334
|
if (base === 1n)
|
|
383
335
|
return this.count();
|
|
384
336
|
let sum = 0n;
|
|
@@ -387,14 +339,15 @@ const applyClearing = (() => {
|
|
|
387
339
|
// Earlier values of `i` represent higher places same as with written numbers further left
|
|
388
340
|
// digits are more significant
|
|
389
341
|
// The value of the place `i` is `ind - 1`
|
|
390
|
-
sum += (base ** BigInt(n - ind - 1)) *
|
|
342
|
+
sum += (base ** BigInt(n - ind - 1)) * cs.charVal(this[ind]);
|
|
391
343
|
return sum;
|
|
392
|
-
}
|
|
344
|
+
},
|
|
345
|
+
[upper]: String.prototype.toUpperCase,
|
|
393
346
|
});
|
|
394
347
|
protoDefs(Number, {
|
|
395
|
-
|
|
396
|
-
$int64: Math.pow(2, 64),
|
|
348
|
+
$: { [int32]: 2 ** 32, [int64]: 2 ** 64 },
|
|
397
349
|
[char]() { return String.fromCharCode(this); },
|
|
350
|
+
[isInt]() { return this === Math.round(this); }, // No bitwise shortcut - it disrupts Infinity
|
|
398
351
|
[toArr](fn) { const arr = new Array(this || 0); for (let i = 0; i < this; i++)
|
|
399
352
|
arr[i] = fn(i); return arr; },
|
|
400
353
|
[toObj](fn) {
|
|
@@ -406,55 +359,67 @@ const applyClearing = (() => {
|
|
|
406
359
|
}
|
|
407
360
|
return Object.fromEntries(ret);
|
|
408
361
|
},
|
|
409
|
-
[toStr](
|
|
362
|
+
[toStr](cs, padLen = 0) {
|
|
410
363
|
// Note that base-1 requires 0 to map to the empty string. This also
|
|
411
364
|
// means that, for `n >= 1`:
|
|
412
365
|
// | (n).encodeStr(singleChr)
|
|
413
366
|
// is always equivalent to
|
|
414
367
|
// | singleChr.repeat(n - 1)
|
|
415
|
-
if (
|
|
416
|
-
|
|
417
|
-
const base =
|
|
368
|
+
if (isCls(cs, String))
|
|
369
|
+
cs = String[charset](cs);
|
|
370
|
+
const base = cs.size;
|
|
418
371
|
if (base === 1n && padLen)
|
|
419
372
|
throw Error(`pad with base-1 encoding`);
|
|
420
373
|
if (this !== this)
|
|
421
|
-
return (base === 1n) ? '' :
|
|
374
|
+
return (base === 1n) ? '' : cs[0].repeat(Math.max(padLen, 1));
|
|
422
375
|
let num = this.constructor === BigInt ? this : BigInt(Math.floor(this));
|
|
423
376
|
const digits = [];
|
|
424
377
|
while (num) {
|
|
425
|
-
digits.push(
|
|
378
|
+
digits.push(cs.valChar(num % base));
|
|
426
379
|
num /= base;
|
|
427
380
|
}
|
|
428
|
-
return digits.reverse().join('')[padHead](padLen,
|
|
381
|
+
return digits.reverse().join('')[padHead](padLen, cs.str[0]);
|
|
429
382
|
},
|
|
430
|
-
[
|
|
431
|
-
*[Symbol.iterator]() { Error.assert({ n: this }, args => args.n.isInteger()); for (let i = 0; i < this; i++)
|
|
383
|
+
*[Symbol.iterator]() { for (let i = 0; i < this; i++)
|
|
432
384
|
yield i; },
|
|
433
385
|
*[bits]() { let n = this >= 0 ? this : -this; while (n) {
|
|
434
386
|
yield n & 1;
|
|
435
387
|
n = n >> 1;
|
|
436
|
-
} }
|
|
437
|
-
[map]: undefined // Prevent `Number(...).map`
|
|
388
|
+
} }
|
|
438
389
|
});
|
|
439
390
|
protoDefs(BigInt, { [toStr]: Number.prototype[toStr] });
|
|
440
391
|
protoDefs(Function, {
|
|
441
|
-
$stub: v => v,
|
|
442
392
|
[bind](...args) { return this.bind(null, ...args); }
|
|
443
393
|
});
|
|
444
394
|
protoDefs(Error, {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
395
|
+
$: {
|
|
396
|
+
[assert]: (args, fn) => {
|
|
397
|
+
if (fn(args))
|
|
398
|
+
return;
|
|
399
|
+
throw Error('assert failed')[mod]({
|
|
400
|
+
fn: `false === (${fn.toString().replace(/[\s]+/, ' ')})(args)`,
|
|
401
|
+
args
|
|
402
|
+
});
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
[fire](props /* { cause, msg, message, ...more } */) { throw this[mod](props); },
|
|
406
|
+
[limn](seen = new Map()) {
|
|
407
|
+
if (seen.has(this))
|
|
408
|
+
return seen.get(this);
|
|
409
|
+
seen.set(this, 'cycle(Error)');
|
|
410
|
+
const { message, stack, cause, ...props } = this;
|
|
411
|
+
return {
|
|
412
|
+
form: getClsName(this),
|
|
413
|
+
msg: message,
|
|
414
|
+
trace: stack?.split('\n').slice(1)[map](v => v.trim() ?? skip) ?? [],
|
|
415
|
+
...props,
|
|
416
|
+
cause: !cause ? null : cause[limn](seen)
|
|
417
|
+
};
|
|
453
418
|
},
|
|
454
419
|
[mod](props = {} /* { cause, msg, message, ...more } */) {
|
|
455
|
-
if (
|
|
420
|
+
if (isCls(props, Function))
|
|
456
421
|
props = props(this.message, this);
|
|
457
|
-
if (
|
|
422
|
+
if (isCls(props, String))
|
|
458
423
|
props = { message: props };
|
|
459
424
|
const { cause = null, msg = null, message = msg ?? this.message, ...moreProps } = props;
|
|
460
425
|
// - Assign `cause` to transfer props like fs "code" props, etc. - watch out, `cause` may be
|
|
@@ -462,56 +427,47 @@ const applyClearing = (() => {
|
|
|
462
427
|
// - Assign `moreProps` to transfer any other properties
|
|
463
428
|
// - Add `message` prop
|
|
464
429
|
// - Only add `cause` prop if `cause` is non-null
|
|
465
|
-
return Object.assign(this,
|
|
430
|
+
return Object.assign(this, inCls(cause, Error) ? cause : {}, moreProps, cause ? { message, cause } : { message });
|
|
466
431
|
},
|
|
467
|
-
[fire](props /* { cause, msg, message, ...more } */) { throw this[mod](props); },
|
|
468
432
|
[suppress]() {
|
|
469
433
|
this[Symbol.for('clearing.err.suppressed')] = true;
|
|
470
434
|
if (this.cause) {
|
|
471
|
-
const causes =
|
|
435
|
+
const causes = inCls(this.cause, Error) ? [this.cause] : this.cause;
|
|
472
436
|
for (const err of causes)
|
|
473
437
|
err[suppress]();
|
|
474
438
|
}
|
|
475
439
|
return this;
|
|
476
|
-
},
|
|
477
|
-
[limn](seen = new Map()) {
|
|
478
|
-
if (seen.has(this))
|
|
479
|
-
return seen.get(this);
|
|
480
|
-
seen.set(this, 'cycle(Error)');
|
|
481
|
-
const { message, stack, cause, ...props } = this;
|
|
482
|
-
return {
|
|
483
|
-
form: getFormName(this),
|
|
484
|
-
msg: message,
|
|
485
|
-
trace: stack?.split('\n').slice(1)[map](v => v.trim() ?? skip) ?? [],
|
|
486
|
-
...props,
|
|
487
|
-
cause: !cause ? null : cause[limn](seen)
|
|
488
|
-
};
|
|
489
440
|
}
|
|
490
441
|
});
|
|
491
442
|
protoDefs(Promise, {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
});
|
|
443
|
+
$: {
|
|
444
|
+
[allArr]: Promise.all,
|
|
445
|
+
[allObj]: (obj) => {
|
|
446
|
+
// Need to get `keys` immediately, in case `obj` mutates before resolution
|
|
447
|
+
const keys = Object.keys(obj);
|
|
448
|
+
return Promise.all(Object.values(obj)).then(vals => {
|
|
449
|
+
const ret = {};
|
|
450
|
+
for (const [i, k] of keys.entries())
|
|
451
|
+
if (vals[i] !== skip)
|
|
452
|
+
ret[k] = vals[i];
|
|
453
|
+
return ret;
|
|
454
|
+
});
|
|
455
|
+
},
|
|
456
|
+
[later]: (resolve, reject) => {
|
|
457
|
+
const p = new Promise((...a) => [resolve, reject] = a);
|
|
458
|
+
return Object.assign(p, { resolve, reject });
|
|
459
|
+
}
|
|
510
460
|
}
|
|
511
461
|
});
|
|
512
462
|
protoDefs(Set, {
|
|
513
|
-
|
|
514
|
-
|
|
463
|
+
[count]() { return this.size; },
|
|
464
|
+
[empty]() { return !this.size; },
|
|
465
|
+
[find](fn) {
|
|
466
|
+
for (const val of this)
|
|
467
|
+
if (fn(val))
|
|
468
|
+
return { found: true, val };
|
|
469
|
+
return { found: false, val: null };
|
|
470
|
+
},
|
|
515
471
|
[map](fn) {
|
|
516
472
|
const ret = [];
|
|
517
473
|
let ind = 0;
|
|
@@ -522,14 +478,7 @@ const applyClearing = (() => {
|
|
|
522
478
|
}
|
|
523
479
|
return ret;
|
|
524
480
|
},
|
|
525
|
-
[
|
|
526
|
-
for (const val of this)
|
|
527
|
-
if (fn(val))
|
|
528
|
-
return { found: true, val };
|
|
529
|
-
return { found: false, val: null };
|
|
530
|
-
},
|
|
531
|
-
[count]() { return this.size; },
|
|
532
|
-
[empty]() { return !this.size; },
|
|
481
|
+
[rem]: Set.prototype.delete,
|
|
533
482
|
[toArr](fn) {
|
|
534
483
|
const ret = [];
|
|
535
484
|
let ind = 0;
|
|
@@ -551,27 +500,16 @@ const applyClearing = (() => {
|
|
|
551
500
|
}
|
|
552
501
|
});
|
|
553
502
|
protoDefs(Map, {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
[map](fn) {
|
|
558
|
-
const ret = [];
|
|
559
|
-
for (const [k, v] of this) {
|
|
560
|
-
const r = fn(v, k);
|
|
561
|
-
if (r !== skip)
|
|
562
|
-
ret.push(r);
|
|
563
|
-
}
|
|
564
|
-
return Object.fromEntries(ret);
|
|
565
|
-
},
|
|
503
|
+
[add]: Map.prototype.set,
|
|
504
|
+
[count]() { return this.size; },
|
|
505
|
+
[empty]() { return !this.size; },
|
|
566
506
|
[find](fn) {
|
|
567
507
|
for (const [k, v] of this)
|
|
568
508
|
if (fn(v, k))
|
|
569
509
|
return { found: true, val: v, key: k };
|
|
570
510
|
return { found: false, val: null, key: null };
|
|
571
511
|
},
|
|
572
|
-
[
|
|
573
|
-
[empty]() { return !this.size; },
|
|
574
|
-
[toObj](fn) {
|
|
512
|
+
[map](fn) {
|
|
575
513
|
const ret = [];
|
|
576
514
|
for (const [k, v] of this) {
|
|
577
515
|
const r = fn(v, k);
|
|
@@ -580,6 +518,7 @@ const applyClearing = (() => {
|
|
|
580
518
|
}
|
|
581
519
|
return Object.fromEntries(ret);
|
|
582
520
|
},
|
|
521
|
+
[rem]: Map.prototype.delete,
|
|
583
522
|
[toArr](fn) {
|
|
584
523
|
const ret = [];
|
|
585
524
|
for (const [k, v] of this) {
|
|
@@ -588,18 +527,15 @@ const applyClearing = (() => {
|
|
|
588
527
|
ret.push(r);
|
|
589
528
|
}
|
|
590
529
|
return ret;
|
|
591
|
-
}
|
|
592
|
-
});
|
|
593
|
-
protoDefs(GeneratorFunction, {
|
|
594
|
-
[toArr](fn) { return [...this][map](fn); },
|
|
530
|
+
},
|
|
595
531
|
[toObj](fn) {
|
|
596
|
-
const ret =
|
|
597
|
-
for (const v of this) {
|
|
598
|
-
const r = fn(v);
|
|
532
|
+
const ret = [];
|
|
533
|
+
for (const [k, v] of this) {
|
|
534
|
+
const r = fn(v, k);
|
|
599
535
|
if (r !== skip)
|
|
600
|
-
ret
|
|
536
|
+
ret.push(r);
|
|
601
537
|
}
|
|
602
|
-
return ret;
|
|
538
|
+
return Object.fromEntries(ret);
|
|
603
539
|
}
|
|
604
540
|
});
|
|
605
541
|
});
|