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