@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 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 memSym = Symbol.for('clearing:mem');
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 = ['add', 'at', 'apart', 'assert', 'bind', 'bits', 'built', 'char', 'code', 'count', 'cut', 'dive', 'empty', 'fire', 'group', 'has', 'hasHead', 'hasTail', 'indent', 'isInt', 'limn', 'lower', 'mod', 'map', 'mapk', 'merge', 'padHead', 'padTail', 'rem', 'find', 'slash', 'slice', 'suppress', 'toArr', 'toNum', 'toObj', 'toStr', 'upper'];
11
- const syms = Object.fromEntries(symNames.map(term => [term, Symbol(`clearing:${term}`)]));
12
- const sovereign = v => v;
13
- Object.assign(global, {
14
- // Reference native constructors
15
- AsyncFunction: (async () => { }).constructor,
16
- GeneratorFunction: (function* () { })().constructor,
17
- AsyncGeneratorFunction: (async function* () { })().constructor,
18
- // Symbols
19
- ...syms,
20
- // Forms
21
- getFormName: f => {
22
- if (f === null)
23
- return 'Null';
24
- if (f === undefined)
25
- return 'Undef';
26
- if (f !== f)
27
- return 'UndefNum';
28
- return Object.getPrototypeOf(f)?.constructor.name ?? 'Prototypeless'; // e.g. `getFormName(Object.plain()) === 'Prototypeless'`
29
- },
30
- getForm: f => Object.getPrototypeOf(f)?.constructor ?? null,
31
- isForm: (fact, Form) => {
32
- // NaN only matches against the NaN primitive (not the Number Form)
33
- if (fact !== fact)
34
- return Form !== Form;
35
- if (fact == null)
36
- return false;
37
- return Object.getPrototypeOf(fact).constructor === Form;
38
- },
39
- hasForm: (fact, Form) => fact instanceof Form,
40
- // Utility
41
- skip: undefined,
42
- sovereign,
43
- then: (val, rsv = Function.stub, rjc) => {
44
- // Act on `val` regardless of whether it's a Promise or an immediate
45
- // value; return `rsv(val)` either immediately or as a Promise;
46
- // Promises are returned with `then`/`fail` handling
47
- if (hasForm(val, Promise))
48
- return val.then(rsv).catch(rjc);
49
- // No `rjc` means no `try`/`catch` handling
50
- if (!rjc)
51
- return rsv(val);
52
- try {
53
- return rsv(val);
54
- }
55
- catch (err) {
56
- return rjc(err);
57
- }
58
- },
59
- safe: (val, acc = Function.stub, rjc) => {
60
- try {
61
- return then(val(), acc, rjc);
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
- catch (err) {
64
- if (!rjc)
65
- throw err;
66
- return rjc(err);
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
- Object.assign(Cls, Object.fromEntries(classVals.map(({ key, val }) => [key, val])));
116
- // Avoid making more properties available on `global` - if a typo winds up referring to a
117
- // global property, the bug which results can be highly unexpected!
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 (!isForm(cmps, Array))
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
- [built](diveFromKey = (key) => key.split('.')) {
159
- // The reverse operation of `apart` - takes a flat list of (dive, value) pairs and produces a
160
- // structured object
161
- const result = {};
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 dive = diveFromKey(k);
164
- const last = dive.pop();
165
- let ptr = result;
166
- for (const cmp of dive)
167
- ptr = ptr[at](cmp) ?? (ptr[cmp] = {});
168
- ptr[last] = isForm(v, Object) ? v[built]() : v;
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 result;
142
+ return ret;
171
143
  },
172
- [count]() { let c = 0; for (const k in this)
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 (!isForm(v, Object)) {
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) || !isForm(this[k], Object))
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
- *[Symbol.iterator]() { for (const k in this)
254
- yield [k, this[k]]; }
255
- });
256
- protoDefs(Array, {
257
- $stub: Object.freeze([]),
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
- [toArr](it) { return this[map](it); },
271
- [toObj](it) {
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 len = this.length;
274
- for (let i = 0; i < len; i++) {
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 Object.fromEntries(ret);
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 t = fn(elem);
303
- if (!ret[has](t))
304
- ret[t] = [];
305
- ret[t].push(elem);
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
- $baseline: (str, seq = '| ') => {
312
- return str.split('\n')[map](ln => {
313
- const ind = ln.indexOf(seq);
314
- if (ind === -1)
315
- return skip;
316
- return ln.slice(ind + seq.length);
317
- }).join('\n');
318
- },
319
- $charset: str => {
320
- const cache = new Map();
321
- return {
322
- str,
323
- size: BigInt(str.length),
324
- charVal: (c) => {
325
- if (!cache.has(c)) {
326
- const ind = str.indexOf(c);
327
- if (ind < 0)
328
- throw Error('char outside charset')[mod]({ char: c });
329
- cache.set(c, BigInt(ind));
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
- return cache.get(c);
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
- $base32: '0123456789abcdefghijklmnopqrstuv',
341
- $base36: '0123456789abcdefghijklmnopqrstuvwxyz',
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
- [code](ind = 0) { return this.charCodeAt(ind); },
364
- [count]() { return this.length; },
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 (isForm(args[0], String)) {
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
- [toNum](charset = String.base62) {
379
- if (isForm(charset, String))
380
- charset = String.charset(charset);
381
- const base = charset.size;
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)) * charset.charVal(this[ind]);
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
- $int32: Math.pow(2, 32),
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](charset, padLen = 0) {
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 (isForm(charset, String))
416
- charset = String.charset(charset);
417
- const base = charset.size;
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) ? '' : charset[0].repeat(Math.max(padLen, 1));
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(charset.valChar(num % base));
378
+ digits.push(cs.valChar(num % base));
426
379
  num /= base;
427
380
  }
428
- return digits.reverse().join('')[padHead](padLen, charset.str[0]);
381
+ return digits.reverse().join('')[padHead](padLen, cs.str[0]);
429
382
  },
430
- [isInt]() { return this === Math.round(this); }, // No bitwise shortcut - it disrupts Infinity
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
- $stackTraceLimit: 150,
446
- $assert: (args, fn) => {
447
- if (fn(args))
448
- return;
449
- throw Error('assert failed')[mod]({
450
- fn: `false === (${fn.toString().replace(/[\s]+/, ' ')})(args)`,
451
- args
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 (isForm(props, Function))
420
+ if (isCls(props, Function))
456
421
  props = props(this.message, this);
457
- if (isForm(props, String))
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, hasForm(cause, Error) ? cause : {}, moreProps, cause ? { message, cause } : { message });
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 = hasForm(this.cause, Error) ? [this.cause] : this.cause;
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
- $resolve: Promise.resolve,
493
- $reject: Promise.reject,
494
- $all: Promise.all,
495
- $allArr: Promise.all,
496
- $later: (resolve, reject) => {
497
- const p = new Promise((...a) => [resolve, reject] = a);
498
- return Object.assign(p, { resolve, reject });
499
- },
500
- $allObj: (obj) => {
501
- // Need to get `keys` here in case `obj` mutates before resolution
502
- const keys = Object.keys(obj);
503
- return Promise.allArr(Object.values(obj)).then(vals => {
504
- const ret = {};
505
- for (const [i, k] of keys.entries())
506
- if (vals[i] !== skip)
507
- ret[k] = vals[i];
508
- return ret;
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
- $stub: { count: () => 0, add: Function.stub, rem: Function.stub, has: () => false, values: () => Array.stub },
514
- 'delete->': rem,
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
- [find](fn) {
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
- $stub: { count: () => 0, set: Function.stub, rem: Function.stub, has: () => false, values: () => Array.stub },
555
- 'set->': add,
556
- 'delete->': rem,
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
- [count]() { return this.size; },
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[r[0]] = r[1];
536
+ ret.push(r);
601
537
  }
602
- return ret;
538
+ return Object.fromEntries(ret);
603
539
  }
604
540
  });
605
541
  });