@gershy/clearing 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/clearing.ts +765 -0
- package/global.d.ts +197 -0
- package/package.json +11 -0
package/clearing.ts
ADDED
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// version [0]
|
|
4
|
+
|
|
5
|
+
if (!global['~clearing']) {
|
|
6
|
+
global['~clearing'] = true;
|
|
7
|
+
|
|
8
|
+
Object.assign(global, {
|
|
9
|
+
|
|
10
|
+
AsyncFunction: (async () => {}).constructor,
|
|
11
|
+
GeneratorFunction: (function*(){})().constructor,
|
|
12
|
+
AsyncGeneratorFunction: (async function*(){})().constructor,
|
|
13
|
+
C: Object.freeze({
|
|
14
|
+
def: (obj, prop, value, opts={}) => Object.defineProperty(obj, prop, { value, configurable: true, ...opts }),
|
|
15
|
+
skip: undefined,
|
|
16
|
+
'Promise.all': Promise.all.bind(Promise),
|
|
17
|
+
'Error.prototype.toString': Error.prototype.toString
|
|
18
|
+
}),
|
|
19
|
+
skip: undefined,
|
|
20
|
+
|
|
21
|
+
// Flow controls, sync/async interoperability
|
|
22
|
+
onto: (val, fn) => (fn(val), val),
|
|
23
|
+
safe: (fn, onErr: (err: Error) => void) => {
|
|
24
|
+
|
|
25
|
+
// Returns `fn()` with error handling provided by `onErr` regardless
|
|
26
|
+
// of whether `fn()` results in a Promise or an immediate value
|
|
27
|
+
|
|
28
|
+
let p = new Promise(r => r('abc'));
|
|
29
|
+
p.catch()
|
|
30
|
+
try { let val = fn(); return isForm(val, Promise) ? val.fail(onErr) : val; }
|
|
31
|
+
catch (err: any) { return onErr(err); }
|
|
32
|
+
|
|
33
|
+
},
|
|
34
|
+
soon: fn => fn ? Promise.resolve().then(fn) : Promise.resolve(),
|
|
35
|
+
then: (val, rsv=Function.stub, rjc?: (...args: any[]) => any) => {
|
|
36
|
+
|
|
37
|
+
// Act on `val` regardless of whether it's a Promise or an immediate
|
|
38
|
+
// value; return `rsv(val)` either immediately or as a Promise;
|
|
39
|
+
|
|
40
|
+
// Promises are returned with `then`/`fail` handling
|
|
41
|
+
if (val instanceof Promise) return val.then(rsv).catch(rjc);
|
|
42
|
+
|
|
43
|
+
// No `rjc` means no `try`/`catch` handling
|
|
44
|
+
if (!rjc) return rsv(val);
|
|
45
|
+
|
|
46
|
+
try { return rsv(val); } catch (err) { return rjc(err); }
|
|
47
|
+
|
|
48
|
+
},
|
|
49
|
+
thenAll: (vals, ...args /* rsv, rjc */) => {
|
|
50
|
+
if (vals.seek(v => v instanceof Promise).found) vals = Promise.all(vals);
|
|
51
|
+
return (then as any)(vals, ...args);
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// Forms
|
|
55
|
+
form: ({ name, has={}, pars=has, props=()=>({}) }: { name: string, has?: { [key: string]: any }, pars?: any, props?: any }) => {
|
|
56
|
+
|
|
57
|
+
let reservedFormProps = [ 'constructor', 'Form' ];
|
|
58
|
+
|
|
59
|
+
// Ensure every ParForm is truly a Form
|
|
60
|
+
for (let [ k, Form ] of pars) if (!Form || !Form['~forms']) throw Error(`Invalid Form: "${k}" (it's Form is ${getFormName(Form)})`);
|
|
61
|
+
|
|
62
|
+
// // TODO: This is definitely faster than `eval`, but it prevents the
|
|
63
|
+
// // names of Forms from displaying correctly in the console
|
|
64
|
+
// let Form = function(...p) { return (this && this.constructor === Form) ? this.init(...p) : new Form(...p); }
|
|
65
|
+
// Object.defineProperty(Form, 'name', { value: name, writable: false, enumerable: true });
|
|
66
|
+
let fName = name.replace(/[^a-zA-Z0-9]/g, '$');
|
|
67
|
+
let Form = eval(
|
|
68
|
+
`let ${fName} = function ${fName}(...p) { return (this && this.Form === Form) ? this.init(...p) : new Form(...p); }; ${fName};`
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
Form['~forms'] = Set([ Form ]);
|
|
72
|
+
Form.prototype = Object.create(null);
|
|
73
|
+
|
|
74
|
+
// We'll store a Set of inherited static props for each static key
|
|
75
|
+
let statics = Object.create(null);
|
|
76
|
+
|
|
77
|
+
// Loop over all ParentForms; for each:
|
|
78
|
+
// - add to `Form['~forms']` to enable `hasForm` testing
|
|
79
|
+
// - collect static properties (to apply to `name` later)
|
|
80
|
+
// - map to a representation of its prototype (to supply Parent
|
|
81
|
+
// prototype methods to overriding methods)
|
|
82
|
+
let protos = Object.assign({}, pars);
|
|
83
|
+
for (let parName in pars) {
|
|
84
|
+
|
|
85
|
+
let { '~forms': parForms, ...parProps } = pars[parName];
|
|
86
|
+
|
|
87
|
+
// Add all ParentForms to the ~forms Set (facilitates `hasType`)
|
|
88
|
+
for (let ParForm of parForms) Form['~forms'].add(ParForm);
|
|
89
|
+
|
|
90
|
+
// Collect the rest of the properties
|
|
91
|
+
for (let [ k, v ] of parProps) {
|
|
92
|
+
if (!statics[k]) statics[k] = Set();
|
|
93
|
+
statics[k].add(v);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// `protoDef` sets non-enumerable prototype properties
|
|
97
|
+
// Iterate non-enumerable props via `Object.getOwnPropertyNames`
|
|
98
|
+
let proto = pars[parName].prototype;
|
|
99
|
+
protos[parName] = Object.fromEntries(Object.getOwnPropertyNames(proto).map( n => [ n, proto[n] ] ));
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
pars = null;
|
|
103
|
+
|
|
104
|
+
// If `props` is a function it becomes the result of its call
|
|
105
|
+
if (isForm(props, Function)) {
|
|
106
|
+
|
|
107
|
+
// Apply any immediately-unambiguous static properties to `Form`
|
|
108
|
+
// so they are available to the function body of `props`
|
|
109
|
+
let immediateStatics: [ string, any ][] = [];
|
|
110
|
+
for (let k in statics) if (statics[k].size === 1) {
|
|
111
|
+
immediateStatics.push([ k, [ ...statics[k] ][0] ]);
|
|
112
|
+
}
|
|
113
|
+
Object.assign(Form, Object.fromEntries(immediateStatics));
|
|
114
|
+
|
|
115
|
+
props = (props as any)(protos, Form);
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Ensure we have valid "props", and all prop names are valid
|
|
120
|
+
if (!isForm(props, Object)) throw Error(`Couldn't resolve "props" to Object`);
|
|
121
|
+
for (let prop of reservedFormProps) if (({}).has.call(props, prop)) throw Error(`Used reserved "${prop}" key`);
|
|
122
|
+
|
|
123
|
+
// Iterate all props of ParForm prototypes; collect inherited ones
|
|
124
|
+
let propsByName = {};
|
|
125
|
+
for (let [ formName, proto ] of protos) for (let [ propName, prop ] of proto) {
|
|
126
|
+
|
|
127
|
+
// Skip reserved names (they certainly exist in `formProto`!)
|
|
128
|
+
if (reservedFormProps.has(propName)) continue;
|
|
129
|
+
|
|
130
|
+
// Store all props under the same name in the same Set
|
|
131
|
+
if (!({}).has.call(propsByName, propName)) propsByName[propName] = Set();
|
|
132
|
+
propsByName[propName].add(prop);
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// `propsByName` already has all ParForm props; now add in the props
|
|
137
|
+
// unique to the Form being created!
|
|
138
|
+
// TODO: Allow classes to define getters + setters??? Should really
|
|
139
|
+
// be iterating `Object.getOwnPropertyDescriptors(props)` rather
|
|
140
|
+
// than `props` itself...
|
|
141
|
+
for (let [ propName, prop ] of props) {
|
|
142
|
+
|
|
143
|
+
if (prop === skip) throw Error(`Provided ${name} @ ${propName} as skip`);
|
|
144
|
+
|
|
145
|
+
// `propName` values iterated here will be unique; `props` is an
|
|
146
|
+
// object, and must have unique keys. Note `Set` is used to ignore
|
|
147
|
+
// duplicate properties with the same identity (these would mean
|
|
148
|
+
// that multiple ancestors define the property, but they define it
|
|
149
|
+
// to the exact same value!)
|
|
150
|
+
if (propName[0] === '$') statics[propName.slice(1)] = Set([ prop ]); // Guaranteed to be singular
|
|
151
|
+
else propsByName[propName] = Set([ prop ]); // Guaranteed to be singular
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// At this point ambiguous static props should be resolved
|
|
156
|
+
for (let k in statics) if (statics[k].size > 1) throw Error(`Multiple static props named "${k}" inherited by Form ${name} (define ${name}.$${k}!)`);
|
|
157
|
+
|
|
158
|
+
if (!({}).has.call(propsByName, 'init')) throw Error('No "init" method available');
|
|
159
|
+
|
|
160
|
+
for (let [ propName, propsOfThatName ] of propsByName) {
|
|
161
|
+
|
|
162
|
+
// If there are collidable props under this name there can only be
|
|
163
|
+
// one! Multiple collidable props indicates the prop needs to be
|
|
164
|
+
// defined directly on `Form.prototype`, guaranteeing singularity.
|
|
165
|
+
// If *no* collidable props are set, use any non-collidable prop
|
|
166
|
+
let collisionProps = propsOfThatName.toArr(v => (v && v['~noFormCollision']) ? skip : v);
|
|
167
|
+
|
|
168
|
+
// If there are no collision props we still may be able to assign
|
|
169
|
+
// one of the "no form collision" props; this is useful as calling
|
|
170
|
+
// the "uncolliding" method gives useful feedback (e.g. "function
|
|
171
|
+
// not implemented") whereas not defining anything would result in
|
|
172
|
+
// trying to call `undefined` as a function
|
|
173
|
+
if (collisionProps.length === 0) {
|
|
174
|
+
|
|
175
|
+
let utilProp = propsOfThatName.seek(v => !!v).val;
|
|
176
|
+
if (utilProp) collisionProps = [ utilProp ];
|
|
177
|
+
else continue;
|
|
178
|
+
|
|
179
|
+
} else if (collisionProps.length > 1) {
|
|
180
|
+
|
|
181
|
+
let definingForms = collisionProps.map(prop => Form['~forms'].seek(ParForm => ParForm.prototype[propName] === prop).val);
|
|
182
|
+
throw Error([
|
|
183
|
+
`Form ${name} has ambiguous "${propName}" property `,
|
|
184
|
+
`from ${collisionProps.length} ParentForms `,
|
|
185
|
+
`(${definingForms.map(Form => Form ? Form.name : '???').join(', ')}). `,
|
|
186
|
+
`Define ${name}.prototype.${propName}.`
|
|
187
|
+
].join(''));
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
C.def(Form.prototype, propName, collisionProps[0], { enumerable: false, writable: true });
|
|
192
|
+
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
C.def(Form.prototype, 'Form', Form, { enumerable: false, writable: true });
|
|
196
|
+
C.def(Form.prototype, 'constructor', Form, { enumerable: false, writable: true });
|
|
197
|
+
Object.freeze(Form.prototype);
|
|
198
|
+
|
|
199
|
+
// Would be very satisifying to freeze `Form`, but the current
|
|
200
|
+
// pattern of defining specialized subclasses:
|
|
201
|
+
// | FnSrc.Tmp1 = form(...);
|
|
202
|
+
// relies on `Form` being mutable :(
|
|
203
|
+
// TODO: MapSrc and MemSrc are being refactored... maybe do this??
|
|
204
|
+
for (let k in statics) statics[k] = [ ...statics[k] ][0];
|
|
205
|
+
Object.assign(Form, statics);
|
|
206
|
+
// Object.freeze(Form);
|
|
207
|
+
|
|
208
|
+
return Form;
|
|
209
|
+
|
|
210
|
+
},
|
|
211
|
+
getFormName: f => {
|
|
212
|
+
if (f === null) return 'Null';
|
|
213
|
+
if (f === undefined) return 'Undef';
|
|
214
|
+
if (f !== f) return 'UndefNum';
|
|
215
|
+
return Object.getPrototypeOf(f)?.constructor.name ?? 'Prototypeless'; // e.g. `getFormName(Object.plain()) === 'Prototypeless'`
|
|
216
|
+
},
|
|
217
|
+
isForm: (fact, Form) => {
|
|
218
|
+
|
|
219
|
+
// NaN only matches against the NaN primitive (not the Number Form)
|
|
220
|
+
if (fact !== fact) return Form !== Form;
|
|
221
|
+
if (fact == null) return false;
|
|
222
|
+
|
|
223
|
+
return Object.getPrototypeOf(fact).constructor === (Form.Native ?? Form);
|
|
224
|
+
|
|
225
|
+
},
|
|
226
|
+
hasForm: (fact, FormOrCls) => {
|
|
227
|
+
|
|
228
|
+
if (fact == null) return false;
|
|
229
|
+
|
|
230
|
+
// `fact` may either be a fact/Form, or an instance/Cls. In case a
|
|
231
|
+
// fact/instance was given, the "constructor" property points us to
|
|
232
|
+
// the appropriate Form/Cls. We name this value "Form", although it
|
|
233
|
+
// is ambiguously a Form/Cls.
|
|
234
|
+
let Form = (Object.getPrototypeOf(fact)?.constructor === Function) ? fact : fact.constructor;
|
|
235
|
+
if (Form === FormOrCls) return true;
|
|
236
|
+
|
|
237
|
+
// If a "~forms" property exists `FormOrCls` is specifically a Form
|
|
238
|
+
// and inheritance can be checked by existence in the set
|
|
239
|
+
if (Form?.['~forms']) return Form['~forms'].has(FormOrCls);
|
|
240
|
+
|
|
241
|
+
// No "forms" property; FormOrCls is specifically a Cls. Inheritance
|
|
242
|
+
// can be checked using `instanceof`; prefer to compare against a
|
|
243
|
+
// "Native" property (which facilitates "newless" instances)
|
|
244
|
+
return (fact instanceof (FormOrCls.Native || FormOrCls));
|
|
245
|
+
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
// Keep access
|
|
249
|
+
keep: () => null,
|
|
250
|
+
|
|
251
|
+
// Configuration
|
|
252
|
+
conf: () => null,
|
|
253
|
+
|
|
254
|
+
// Timing
|
|
255
|
+
getMs: Date.now,
|
|
256
|
+
getDate: (ms=getMs()) => {
|
|
257
|
+
let [ yr, mo, dy, hr, mn, sc, ap ] = (new Date(ms)).toLocaleString().split(/[^0-9apm]+/i); // TODO: Happens to work on local and remote, but should probably just provide locale opts??
|
|
258
|
+
hr = (parseInt(hr, 10) + (ap[0].lower() === 'p' ? 12 : 0)).toString().padHead(2, '0');
|
|
259
|
+
return `${yr}-${mo}-${dy} ${hr}:${mn}:${sc}`;
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
// Room loading
|
|
263
|
+
mapCmpToSrc: (file, row, col) => ({ file, row, col, context: null }),
|
|
264
|
+
|
|
265
|
+
// Urls
|
|
266
|
+
uriRaw: ({ path='', cacheBust, query }) => {
|
|
267
|
+
let url = '';
|
|
268
|
+
if (cacheBust) url += `/!${cacheBust}`;
|
|
269
|
+
if (path) url += `/${path}`;
|
|
270
|
+
if (query && !query.empty()) url += '?' + query.toArr((v, k) => `${k}=${v}`).join('&'); // Note: DON'T encode here!
|
|
271
|
+
return url;
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
// Util
|
|
275
|
+
denumerate: (obj, prop) => C.def(obj, prop, obj[prop], { enumerable: false }),
|
|
276
|
+
formatAnyValue: val => { try { return valToJson(val); } catch (err) { return '<unformattable>'; } },
|
|
277
|
+
valToJson: JSON.stringify,
|
|
278
|
+
jsonToVal: JSON.parse,
|
|
279
|
+
valToSer: JSON.stringify,
|
|
280
|
+
serToVal: JSON.parse
|
|
281
|
+
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
let protoDefs = (Cls, vals) => {
|
|
285
|
+
|
|
286
|
+
if ('$$' in vals) {
|
|
287
|
+
|
|
288
|
+
// Convert, e.g., 'padHead:padStart,padTail:padEnd' into:
|
|
289
|
+
// | {
|
|
290
|
+
// | padHead: String.prototype['padStart'],
|
|
291
|
+
// | padTail: String.prototype['padEnd']
|
|
292
|
+
// | }
|
|
293
|
+
|
|
294
|
+
let v = Object.fromEntries(vals['$$'].split(',').map(v => (v = v.split(':'), [ v[0], Cls.prototype[v[1]] ])));
|
|
295
|
+
delete vals['$$'];
|
|
296
|
+
Object.assign(vals, v);
|
|
297
|
+
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
let keys = Reflect.ownKeys(vals);
|
|
301
|
+
for (let key of keys) if (isForm(key, String) && key[0] === '$') Cls[key.slice(1)] = vals[key];
|
|
302
|
+
|
|
303
|
+
// Avoid making more properties available on `global` - if a typo
|
|
304
|
+
// winds up referring to a global property the bug which results
|
|
305
|
+
// can be highly unexpected!
|
|
306
|
+
if (Cls === global.constructor) for (let key of keys) if (key[0] !== '$') global[key] = skip;
|
|
307
|
+
|
|
308
|
+
Object.defineProperties(Cls.prototype, Object.fromEntries(
|
|
309
|
+
keys
|
|
310
|
+
.filter(key => key[0] !== '$')
|
|
311
|
+
.map(key => [ key, { enumerable: false, writable: true, value: vals[key] } ])
|
|
312
|
+
));
|
|
313
|
+
|
|
314
|
+
};
|
|
315
|
+
protoDefs(Object, {
|
|
316
|
+
|
|
317
|
+
$stub: Object.freeze({}),
|
|
318
|
+
$plain: obj => obj ? Object.assign(Object.create(null), obj) : Object.create(null),
|
|
319
|
+
|
|
320
|
+
$$: 'has:hasOwnProperty',
|
|
321
|
+
|
|
322
|
+
at(k, def=skip) {
|
|
323
|
+
if (k?.constructor === Array && isForm(k, Array)) {
|
|
324
|
+
let ret = this;
|
|
325
|
+
for (let p of k) { if (!ret.has(p)) return def; ret = ret[p]; }
|
|
326
|
+
return ret;
|
|
327
|
+
}
|
|
328
|
+
return this.has(k) ? this[k] : def;
|
|
329
|
+
},
|
|
330
|
+
each(fn) { for (let [ k, v ] of this) fn(v, k); },
|
|
331
|
+
map(fn) { // Iterator: (val, key) => val
|
|
332
|
+
let ret = Object.assign({}, this);
|
|
333
|
+
for (let k in ret) { let v = fn(ret[k], k); if (v !== skip) ret[k] = v; else delete ret[k]; }
|
|
334
|
+
return ret;
|
|
335
|
+
},
|
|
336
|
+
mapk(fn) { // Iterator: (val, k) => [ k, v ]
|
|
337
|
+
let arr: any[] = [];
|
|
338
|
+
for (let k in this) { let v = fn(this[k], k); if (v !== skip) arr.push(v); }
|
|
339
|
+
return Object.fromEntries(arr);
|
|
340
|
+
},
|
|
341
|
+
toArr(fn) { // Iterator: (val, k) => [ k, v ]
|
|
342
|
+
let ret: any[] = [];
|
|
343
|
+
for (let k in this) { let v = fn(this[k], k); if (v !== skip) ret.push(v); }
|
|
344
|
+
return ret;
|
|
345
|
+
},
|
|
346
|
+
slice(p) { // TODO: Rename to "subset"?
|
|
347
|
+
|
|
348
|
+
// >> { a: 1, b: 2, c: 3, d: 4 }.slice([ 'b', 'd' ]);
|
|
349
|
+
// { b: 2, d: 4 }
|
|
350
|
+
return p.toObj(p => this.has(p) ? [ p, this[p] ] : skip);
|
|
351
|
+
|
|
352
|
+
},
|
|
353
|
+
omit(p) {
|
|
354
|
+
|
|
355
|
+
let obj = { ...this };
|
|
356
|
+
for (let k of p) delete obj[k];
|
|
357
|
+
return obj;
|
|
358
|
+
|
|
359
|
+
},
|
|
360
|
+
find(f) { // Iterator: (val, key) => bool; returns { found, val=null, key=null }
|
|
361
|
+
for (let k in this) if (f(this[k], k)) return { found: true, val: this[k], key: k };
|
|
362
|
+
return { found: false, val: null, k: null };
|
|
363
|
+
},
|
|
364
|
+
empty() { for (let k in this) return false; return true; },
|
|
365
|
+
gain(...objs) {
|
|
366
|
+
// Note for performance we combine all source Objects first, to
|
|
367
|
+
// reduce the number of items that need to be checked for skips -
|
|
368
|
+
// probably worth the overhead of calling `Object.assign` x2
|
|
369
|
+
let gain = Object.assign({}, ...objs);
|
|
370
|
+
for (let k in gain) if (gain[k] === skip) delete gain[k];
|
|
371
|
+
return Object.assign(this, gain);
|
|
372
|
+
},
|
|
373
|
+
merge(o) { // Modifies `this` in-place
|
|
374
|
+
for (let [ k, v ] of o) {
|
|
375
|
+
// `skip` can be passed to remove properties
|
|
376
|
+
if (v === skip) { delete this[k]; continue; }
|
|
377
|
+
|
|
378
|
+
// Incoming non-Object properties are simple
|
|
379
|
+
if (!isForm(v, Object)) { this[k] = v; continue; }
|
|
380
|
+
|
|
381
|
+
// `v` is an Object; existing non-Object replaced with `{}`
|
|
382
|
+
if (!isForm(this[k], Object) || !this.has(k)) this[k] = {};
|
|
383
|
+
|
|
384
|
+
// And simply recurse!
|
|
385
|
+
this[k].merge(v);
|
|
386
|
+
}
|
|
387
|
+
return this;
|
|
388
|
+
},
|
|
389
|
+
built() {
|
|
390
|
+
let result = {};
|
|
391
|
+
for (let [ k, v ] of this) {
|
|
392
|
+
let dive = k.split('.');
|
|
393
|
+
let last = dive.pop();
|
|
394
|
+
let ptr = result;
|
|
395
|
+
for (let cmp of dive) ptr = (ptr.has(cmp) && ptr[cmp] != null) ? ptr[cmp] : (ptr[cmp] = {});
|
|
396
|
+
ptr[last] = isForm(v, Object) ? v.built() : v;
|
|
397
|
+
}
|
|
398
|
+
return result;
|
|
399
|
+
},
|
|
400
|
+
* unbuilt(dive=[]) {
|
|
401
|
+
for (let [ k, val ] of this) {
|
|
402
|
+
if (isForm(val, Object)) yield* val.unbuilt([ ...dive, k ]);
|
|
403
|
+
else yield { dive: [ ...dive, k ], val };
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
count() { let c = 0; for (let k in this) c++; return c; },
|
|
407
|
+
categorize(fn) { // Iterator: (val, key) => '<categoryTerm>'
|
|
408
|
+
|
|
409
|
+
// { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10 }.categorize(n => {
|
|
410
|
+
// if (n < 4) return 'small';
|
|
411
|
+
// if (n < 8) return 'medium';
|
|
412
|
+
// return 'big';
|
|
413
|
+
// });
|
|
414
|
+
// >> { small: { a: 1, b: 2, c: 3 }, medium: { d: 4, e: 5, f: 6, g: 7 }, big: { h: 8, i: 9, j: 10 } }
|
|
415
|
+
|
|
416
|
+
let ret = {};
|
|
417
|
+
for (let [ k, v ] of this) {
|
|
418
|
+
let t = fn(v, k);
|
|
419
|
+
if (!ret.has(t)) ret[t] = {};
|
|
420
|
+
ret[t][k] = v;
|
|
421
|
+
}
|
|
422
|
+
return ret;
|
|
423
|
+
|
|
424
|
+
},
|
|
425
|
+
*[Symbol.iterator]() { for (let k in this) yield [ k, this[k] ]; }
|
|
426
|
+
|
|
427
|
+
});
|
|
428
|
+
protoDefs(Array, {
|
|
429
|
+
|
|
430
|
+
$stub: Object.freeze([]),
|
|
431
|
+
$from: Array.from, // (it, fn) => (isForm(it, Array) ? it : [ ...it ]).map(fn),
|
|
432
|
+
|
|
433
|
+
$$: 'each:forEach,has:includes',
|
|
434
|
+
|
|
435
|
+
map(it) { // Iterator: (val, ind) => val
|
|
436
|
+
let ret: any[] = [];
|
|
437
|
+
let len = this.length;
|
|
438
|
+
for (let i = 0; i < len; i++) { let v = it(this[i], i); if (v !== skip) ret.push(v); }
|
|
439
|
+
return ret;
|
|
440
|
+
},
|
|
441
|
+
toArr(it) { return this.map(it); }, // Can't inherit Object.prototype.toArr - it passes keys as Strings!
|
|
442
|
+
toObj(it) { // Iterator: (val, ind) => [ key0, val0 ]
|
|
443
|
+
let ret: any[] = [];
|
|
444
|
+
let len = this.length;
|
|
445
|
+
for (let i = 0; i < len; i++) { let v = it(this[i], i); if (v !== skip) ret.push(v); }
|
|
446
|
+
return Object.fromEntries(ret);
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
seek(f) { // Iterator: (val, ind) => bool; returns { found=false, val=null, ind=null }
|
|
450
|
+
let n = this.length;
|
|
451
|
+
for (let i = 0; i < n; i++) if (f(this[i], i)) return { found: true, val: this[i], ind: i };
|
|
452
|
+
return { found: false, val: null, ind: null };
|
|
453
|
+
},
|
|
454
|
+
all(fn=Boolean) { return this.every(fn); },
|
|
455
|
+
any(fn=Boolean) { return this.some(fn); },
|
|
456
|
+
sift(fn=Boolean) { return this.filter(fn); },
|
|
457
|
+
empty() { return !this.length; },
|
|
458
|
+
add(...args) { this.push(...args); return args[0]; },
|
|
459
|
+
rem(val) { let ind = this.indexOf(val); if (ind > -1) this.splice(ind, 1); },
|
|
460
|
+
gain(...arrs) { for (let arr of arrs) this.push(...arr); return this; },
|
|
461
|
+
count() { return this.length; },
|
|
462
|
+
valSort(fn) { return this.sort((a, b) => fn(a) - fn(b)); },
|
|
463
|
+
categorize(fn) { // Iterator: val => '<categoryTerm>'
|
|
464
|
+
|
|
465
|
+
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ].categorize(n => {
|
|
466
|
+
// if (n < 4) return 'small';
|
|
467
|
+
// if (n < 8) return 'medium';
|
|
468
|
+
// return 'big';
|
|
469
|
+
// });
|
|
470
|
+
// >> { small: [ 1, 2, 3 ], medium: [ 4, 5, 6, 7 ], big: [ 8, 9, 10 ] }
|
|
471
|
+
|
|
472
|
+
let ret = {};
|
|
473
|
+
for (let elem of this) { let t = fn(elem); if (!ret.has(t)) ret[t] = []; ret[t].push(elem); }
|
|
474
|
+
return ret;
|
|
475
|
+
|
|
476
|
+
},
|
|
477
|
+
equals(arr) {
|
|
478
|
+
if (this.length !== arr.length) return false;
|
|
479
|
+
for (let i = 0; i < this.length; i++)
|
|
480
|
+
if (this[i] !== arr[i]) return false;
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
});
|
|
485
|
+
protoDefs(String, {
|
|
486
|
+
|
|
487
|
+
$multiline: str => {
|
|
488
|
+
|
|
489
|
+
let lines = str.replace(/\r/g, '').split('\n');
|
|
490
|
+
|
|
491
|
+
// Trim any leading empty lines
|
|
492
|
+
while (lines.length && !lines[0].trim()) lines = lines.slice(1);
|
|
493
|
+
|
|
494
|
+
// Count leading whitespace chars on first line with content
|
|
495
|
+
let initSpace = 0;
|
|
496
|
+
while (lines[0][initSpace] === ' ') initSpace++;
|
|
497
|
+
|
|
498
|
+
let ret = lines.map(ln => ln.slice(initSpace)).join('\n');
|
|
499
|
+
return ret.trimTail();
|
|
500
|
+
|
|
501
|
+
},
|
|
502
|
+
$baseline: (str, seq='| ') => {
|
|
503
|
+
|
|
504
|
+
return str.split('\n').map(ln => {
|
|
505
|
+
ln = ln.trimHead();
|
|
506
|
+
if (!ln.startsWith(seq)) return skip; // After whitespace should come `seq`; ignore lines not containing `seq`!
|
|
507
|
+
return ln.slice(seq.length).trimTail(); // Trim off the baseline; remove tailing whitespace
|
|
508
|
+
}).join('\n');
|
|
509
|
+
|
|
510
|
+
},
|
|
511
|
+
$charset: str => {
|
|
512
|
+
let cache = Map<string, bigint>();
|
|
513
|
+
return {
|
|
514
|
+
str,
|
|
515
|
+
size: BigInt(str.length),
|
|
516
|
+
charVal: (c: string) => {
|
|
517
|
+
if (!cache.has(c)) {
|
|
518
|
+
let ind = str.indexOf(c);
|
|
519
|
+
if (ind < 0) throw Error('Char outside charset');
|
|
520
|
+
cache.set(c, BigInt(ind));
|
|
521
|
+
}
|
|
522
|
+
return cache.get(c);
|
|
523
|
+
},
|
|
524
|
+
valChar: (n: bigint) => {
|
|
525
|
+
if (n < 0 || n >= str.length) throw Error('Val outside charset');
|
|
526
|
+
return str[n as any as number];
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
},
|
|
530
|
+
$base32: '0123456789abcdefghijklmnopqrstuv',
|
|
531
|
+
$base36: '0123456789abcdefghijklmnopqrstuvwxyz',
|
|
532
|
+
$base62: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
533
|
+
$base64: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ=-',
|
|
534
|
+
|
|
535
|
+
$$: 'has:includes,hasHead:startsWith,hasTail:endsWith,padHead:padStart,padTail:padEnd,trimHead:trimStart,trimTail:trimEnd,upper:toUpperCase,lower:toLowerCase',
|
|
536
|
+
|
|
537
|
+
cut(delim, cuts=1) { // e.g. `cuts === 1` produces Array of length 2
|
|
538
|
+
// `cuts` defines # of cuts (resulting array length is `num + 1`)
|
|
539
|
+
let split = this.split(delim, cuts < Infinity ? cuts : skip);
|
|
540
|
+
let numDelimsSplit = split.length - 1;
|
|
541
|
+
let lenConsumed = 0
|
|
542
|
+
+ split.reduce((a, s) => a + s.length, 0)
|
|
543
|
+
+ delim.length * numDelimsSplit;
|
|
544
|
+
if (lenConsumed < this.length) split = [ ...split, this.slice(lenConsumed + delim.length) ];
|
|
545
|
+
return split;
|
|
546
|
+
},
|
|
547
|
+
code(ind=0) { return this.charCodeAt(0); },
|
|
548
|
+
count() { return this.length; },
|
|
549
|
+
indent(...args /* amt=2, char=' ' | indentStr=' '.repeat(2) */) {
|
|
550
|
+
|
|
551
|
+
if (!this) return this; // No-op on empty String (otherwise it would transform a 0-line string to a 1-line string)
|
|
552
|
+
let indentStr: string;
|
|
553
|
+
if (isForm(args[0], String)) { indentStr = args[0]; }
|
|
554
|
+
else { let [ amt=2, char=' ' ] = args; indentStr = char.repeat(amt); }
|
|
555
|
+
return this.split('\n').map(ln => `${indentStr}${ln}`).join('\n');
|
|
556
|
+
|
|
557
|
+
},
|
|
558
|
+
encodeInt(charset: string | CharSet=String.base62) {
|
|
559
|
+
|
|
560
|
+
if (isForm(charset, String)) charset = String.charset(charset);
|
|
561
|
+
|
|
562
|
+
let base = charset.size;
|
|
563
|
+
if (base === 1n) return this.count();
|
|
564
|
+
|
|
565
|
+
let sum = 0n;
|
|
566
|
+
let n = this.length;
|
|
567
|
+
for (let ind = 0; ind < n; ind++)
|
|
568
|
+
// Earlier values of `i` represent higher places same as with written numbers further left
|
|
569
|
+
// digits are more significant
|
|
570
|
+
// The value of the place `i` is `ind - 1`
|
|
571
|
+
sum += (base ** BigInt(n - ind - 1)) * charset.charVal(this[ind]);
|
|
572
|
+
return sum;
|
|
573
|
+
|
|
574
|
+
},
|
|
575
|
+
reencode(srcCharset: string | CharSet, trgCharset: string | CharSet) {
|
|
576
|
+
return this.encodeInt(srcCharset).encodeStr(trgCharset);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
});
|
|
580
|
+
protoDefs(Number, {
|
|
581
|
+
|
|
582
|
+
$int32: Math.pow(2, 32),
|
|
583
|
+
$int64: Math.pow(2, 64),
|
|
584
|
+
|
|
585
|
+
char() { return String.fromCharCode(this); },
|
|
586
|
+
each(fn) { for (let i = 0; i < this; i++) fn(i); },
|
|
587
|
+
toArr(fn) { let arr = new Array(this || 0); for (let i = 0; i < this; i++) arr[i] = fn(i); return arr; },
|
|
588
|
+
toObj(fn) { // Iterator: n => [ key, val ]
|
|
589
|
+
let ret: [ string, any ][] = [];
|
|
590
|
+
for (let i = 0; i < this; i++) { let v = fn(i); if (v !== skip) ret.push(v); }
|
|
591
|
+
return Object.fromEntries(ret);
|
|
592
|
+
},
|
|
593
|
+
encodeStr(charset: string | CharSet, padLen=0) {
|
|
594
|
+
|
|
595
|
+
// Note that base-1 requires 0 to map to the empty string. This also
|
|
596
|
+
// means that, for `n >= 1`:
|
|
597
|
+
// | (n).encodeStr(singleChr)
|
|
598
|
+
// is always equivalent to
|
|
599
|
+
// | singleChr.repeat(n - 1)
|
|
600
|
+
|
|
601
|
+
if (isForm(charset, String)) charset = String.charset(charset);
|
|
602
|
+
|
|
603
|
+
let base = charset.size;
|
|
604
|
+
if (base === 1n && padLen) throw Error(`Can't pad when using base-1 encoding`);
|
|
605
|
+
|
|
606
|
+
if (this !== this) return (base === 1n) ? '' : charset[0].repeat(Math.max(padLen, 1));
|
|
607
|
+
|
|
608
|
+
let num = this.constructor === BigInt ? this : BigInt(Math.floor(this));
|
|
609
|
+
let digits: string[] = [];
|
|
610
|
+
while (num) { digits.push(charset.valChar(num % base)); num /= base; }
|
|
611
|
+
return digits.reverse().join('').padHead(padLen, charset.str[0]);
|
|
612
|
+
|
|
613
|
+
},
|
|
614
|
+
isInteger() { return this === Math.round(this); }, // No bitwise shortcut - it disrupts Infinity
|
|
615
|
+
* [Symbol.iterator]() { for (let i = 0; i < this; i++) yield i; },
|
|
616
|
+
* bits() { let n = this >= 0 ? this : -this; while (n) { yield n & 1; n = n >> 1; } },
|
|
617
|
+
|
|
618
|
+
map: undefined // Prevent `Number(...).map`
|
|
619
|
+
|
|
620
|
+
});
|
|
621
|
+
protoDefs(BigInt, {
|
|
622
|
+
|
|
623
|
+
encodeStr: Number.prototype.encodeStr
|
|
624
|
+
|
|
625
|
+
});
|
|
626
|
+
protoDefs(Function, {
|
|
627
|
+
|
|
628
|
+
$stub: v => v,
|
|
629
|
+
$createStub: v => () => v,
|
|
630
|
+
bound(...args) { return this.bind(null, ...args); }
|
|
631
|
+
|
|
632
|
+
});
|
|
633
|
+
protoDefs(Error, {
|
|
634
|
+
|
|
635
|
+
$stackTraceLimit: 150,
|
|
636
|
+
|
|
637
|
+
mod(props: any = {} /* { cause, msg, message, ...more } */) {
|
|
638
|
+
|
|
639
|
+
if (isForm(props, Function)) props = props(this.message, this);
|
|
640
|
+
if (isForm(props, String)) props = { message: props };
|
|
641
|
+
|
|
642
|
+
let { cause=null, msg=null, message=msg??this.message, ...moreProps } = props;
|
|
643
|
+
|
|
644
|
+
// - Assign `cause` to transfer props like fs "code" props, etc. - watch out, `cause` may be
|
|
645
|
+
// an Array or Object!
|
|
646
|
+
// - Assign `moreProps` to transfer any other properties
|
|
647
|
+
// - Add `message` prop
|
|
648
|
+
// - Only add `cause` prop if `cause` is non-null
|
|
649
|
+
return Object.assign(this, hasForm(cause, Error) ? cause : {}, moreProps, cause ? { message, cause } : { message });
|
|
650
|
+
|
|
651
|
+
},
|
|
652
|
+
propagate(props /* { cause, msg, message, ...more } */) { throw this.mod(props); },
|
|
653
|
+
suppress() {
|
|
654
|
+
this['~suppressed'] = true;
|
|
655
|
+
|
|
656
|
+
if (!this.cause) return;
|
|
657
|
+
let causes = (hasForm(this.cause, Error) ? [ this.cause ] : this.cause);
|
|
658
|
+
causes.each(err => err.suppress());
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
let newlessProtoDefs = (Cls, vals) => {
|
|
664
|
+
|
|
665
|
+
// Extend prototypes and allow instantiation without "new"
|
|
666
|
+
|
|
667
|
+
let name = Cls.name;
|
|
668
|
+
let Newless = global[name] = function(...args) { return new Cls(...args); } as any;
|
|
669
|
+
C.def(Newless, 'name', name);
|
|
670
|
+
Newless.Native = Cls;
|
|
671
|
+
Newless.prototype = Cls.prototype;
|
|
672
|
+
|
|
673
|
+
protoDefs(Newless, vals);
|
|
674
|
+
|
|
675
|
+
};
|
|
676
|
+
newlessProtoDefs(Promise, {
|
|
677
|
+
|
|
678
|
+
$all: (prms, mapFn=null) => {
|
|
679
|
+
|
|
680
|
+
if (mapFn) prms = prms.map(mapFn);
|
|
681
|
+
|
|
682
|
+
if (isForm(prms, Array)) return C['Promise.all'](prms).then(a => a.toArr(v => v)); // Remove any `skip` results
|
|
683
|
+
|
|
684
|
+
if (isForm(prms, Object)) {
|
|
685
|
+
|
|
686
|
+
// Need to get `keys` here in case `obj` mutates before resolution
|
|
687
|
+
let keys = Object.keys(prms);
|
|
688
|
+
return C['Promise.all'](Object.values(prms))
|
|
689
|
+
.then(vals => { let ret = {}; for (let [ i, k ] of keys.entries()) ret[k] = vals[i]; return ret; });
|
|
690
|
+
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
throw Error(`Unexpected parameter for Promise.all: ${getFormName(prms)}`);
|
|
694
|
+
|
|
695
|
+
},
|
|
696
|
+
$resolve: Promise.resolve,
|
|
697
|
+
$reject: Promise.reject,
|
|
698
|
+
$later: (resolve, reject) => {
|
|
699
|
+
let p = Promise((...a) => [ resolve, reject ] = a);
|
|
700
|
+
return Object.assign(p, { resolve, reject });
|
|
701
|
+
},
|
|
702
|
+
|
|
703
|
+
$$: 'route:then,fail:catch'
|
|
704
|
+
|
|
705
|
+
});
|
|
706
|
+
newlessProtoDefs(Set, {
|
|
707
|
+
|
|
708
|
+
$stub: { count: () => 0, add: Function.stub, rem: Function.stub, has: () => false, values: () => Array.stub },
|
|
709
|
+
|
|
710
|
+
$$: 'each:forEach,rem:delete',
|
|
711
|
+
|
|
712
|
+
map(fn) { // Iterator: (val, ind) => val0
|
|
713
|
+
let ret: any[] = [], ind = 0;
|
|
714
|
+
for (let v of this) { v = fn(v, ind++); if (v !== skip) ret.push(v); }
|
|
715
|
+
return ret;
|
|
716
|
+
},
|
|
717
|
+
find(fn) { // Iterator: (val) => bool; returns { found, val }
|
|
718
|
+
for (let val of this) if (fn(val)) return { found: true, val };
|
|
719
|
+
return { found: false, val: null };
|
|
720
|
+
},
|
|
721
|
+
count() { return this.size; },
|
|
722
|
+
empty() { return !this.size; },
|
|
723
|
+
toArr(...args) { return this.map(...args); },
|
|
724
|
+
toObj(fn) {
|
|
725
|
+
let ret: any[] = [];
|
|
726
|
+
for (let v of this) { v = fn(v); if (v !== skip) ret.push(v); }
|
|
727
|
+
return Object.fromEntries(ret);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
});
|
|
731
|
+
newlessProtoDefs(Map, {
|
|
732
|
+
|
|
733
|
+
$stub: { count: () => 0, set: Function.stub, rem: Function.stub, has: () => false, values: () => Array.stub },
|
|
734
|
+
|
|
735
|
+
$$: 'each:forEach,add:set,rem:delete',
|
|
736
|
+
|
|
737
|
+
map(fn) { // Iterator: (val, key) => [ key0, val0 ]
|
|
738
|
+
let ret: any = [];
|
|
739
|
+
for (let [ k, v ] of this) { v = fn(v, k); if (v !== skip) ret.push(v); }
|
|
740
|
+
return Object.fromEntries(ret);
|
|
741
|
+
},
|
|
742
|
+
find(f) { // Iterator: (val, key) => bool; returns { found, val, key }
|
|
743
|
+
for (let [ k, v ] of this) if (f(v, k)) return { found: true, val: v, key: k };
|
|
744
|
+
return { found: false, val: null, key: null };
|
|
745
|
+
},
|
|
746
|
+
count() { return this.size; },
|
|
747
|
+
empty() { return !this.size; },
|
|
748
|
+
toObj(...args) { return this.map(...args); },
|
|
749
|
+
toArr(fn) { // Iterator: (val, key) => val0
|
|
750
|
+
let ret: any[] = [];
|
|
751
|
+
for (let [ k, v ] of this) { v = fn(v, k); if (v !== skip) ret.push(v); }
|
|
752
|
+
return ret;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
});
|
|
756
|
+
newlessProtoDefs(GeneratorFunction, {
|
|
757
|
+
each(fn) { for (let v of this) fn(v); },
|
|
758
|
+
toArr(fn) { return [ ...this ].map(fn); },
|
|
759
|
+
toObj(fn) {
|
|
760
|
+
let ret = {};
|
|
761
|
+
for (let v of this) { v = fn(v); if (v !== skip) ret[v[0]] = v[1]; }
|
|
762
|
+
return ret;
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
}
|
package/global.d.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// Util
|
|
2
|
+
type fn = (...args: any[]) => any;
|
|
3
|
+
type obj = { [key: string]: any };
|
|
4
|
+
type maybeFn<T> = T | ((...args: any[]) => T);
|
|
5
|
+
type maybeFnResolved<T> = T extends (...args: any[]) => any ? ReturnType<T> : T;
|
|
6
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
7
|
+
|
|
8
|
+
// Forms
|
|
9
|
+
type formConfig = {
|
|
10
|
+
name: string,
|
|
11
|
+
has: { [key: string]: any },
|
|
12
|
+
props: { [key: string]: any }
|
|
13
|
+
};
|
|
14
|
+
type Form<props extends {}, initArgs extends any[], state extends {}> = {
|
|
15
|
+
'~props': maybeFnResolved<props>,
|
|
16
|
+
'~initArgs': initArgs,
|
|
17
|
+
'~state': state,
|
|
18
|
+
(...a: initArgs): formInstance<Form<props, initArgs, state>>,
|
|
19
|
+
new (...a: initArgs): formInstance<Form<props, initArgs, state>>
|
|
20
|
+
};
|
|
21
|
+
type formInstance<MyForm extends Form> = { '~form': MyForm }
|
|
22
|
+
& { [ key in keyof MyForm['~props'] ]: MyForm['~props'][key] }
|
|
23
|
+
& { [ key in keyof MyForm['~state'] ]: MyForm['~state'][key] };
|
|
24
|
+
|
|
25
|
+
// Globals
|
|
26
|
+
declare const global: any;
|
|
27
|
+
declare const window: any;
|
|
28
|
+
declare const getFormName: (f: any) => string;
|
|
29
|
+
declare const denumerate: (val: any, name: string) => void;
|
|
30
|
+
declare const skip: never;
|
|
31
|
+
declare const isForm: {
|
|
32
|
+
(val: any, arr: FunctionConstructor): val is fn;
|
|
33
|
+
(val: any, obj: ObjectConstructor): val is { [key: string]: any };
|
|
34
|
+
(val: any, str: StringConstructor): val is string;
|
|
35
|
+
(val: any, num: NumberConstructor): val is number;
|
|
36
|
+
(val: any, arr: ArrayConstructor): val is any[];
|
|
37
|
+
<T>(val: any, prm: PromiseConstructor): val is Promise<T>;
|
|
38
|
+
<T>(val: any, t: T): val is T;
|
|
39
|
+
}
|
|
40
|
+
declare const hasForm: {
|
|
41
|
+
(val: any, t: any): boolean;
|
|
42
|
+
}
|
|
43
|
+
declare const form: <initArgs extends any[], state extends {}>(c: formConfig) => Form<formConfig['props'], initArgs, state>;
|
|
44
|
+
declare const formatAnyValue: (val: any) => string;
|
|
45
|
+
declare const C: {
|
|
46
|
+
def: fn
|
|
47
|
+
};
|
|
48
|
+
declare const getMs: () => number;
|
|
49
|
+
declare const getDate: () => string;
|
|
50
|
+
declare const then: (val: any, resolve: fn, reject?: fn) => any;
|
|
51
|
+
declare const valToJson: (val: any) => string;
|
|
52
|
+
declare const valToSer: (val: any) => string;
|
|
53
|
+
declare const jsonToVal: (val: string | Buffer | null) => any;
|
|
54
|
+
declare const GeneratorFunction: any;
|
|
55
|
+
declare const global: { [key: string|symbol]: any } & {
|
|
56
|
+
skip: typeof skip,
|
|
57
|
+
GeneratorFunction: typeof GeneratorFunction,
|
|
58
|
+
isForm: typeof isForm,
|
|
59
|
+
hasForm: typeof hasForm,
|
|
60
|
+
formatAnyValue: typeof formatAnyValue,
|
|
61
|
+
then: typeof then,
|
|
62
|
+
getMs: typeof getMs,
|
|
63
|
+
getDate: typeof getDate,
|
|
64
|
+
valToJson: typeof valToJson,
|
|
65
|
+
jsonToVal: typeof jsonToVal,
|
|
66
|
+
C: typeof C,
|
|
67
|
+
denumerate: typeof denumerate
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
interface JSON {
|
|
71
|
+
parse: (val: Buffer) => any
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface Array<T> {
|
|
75
|
+
any: (fn: fn) => boolean,
|
|
76
|
+
has: (val: T) => boolean,
|
|
77
|
+
add: (val: T) => void,
|
|
78
|
+
count: () => number,
|
|
79
|
+
valSort: (fn: (val: T) => number) => Array<T>,
|
|
80
|
+
find: (fn: fn) => ({ found: true, val: T } | { found: false }),
|
|
81
|
+
each: (fn: (val: T) => void) => void,
|
|
82
|
+
empty: () => boolean,
|
|
83
|
+
equals: <Z>(arr: Array<T>) => Z extends T ? boolean : false,
|
|
84
|
+
toObj: (fn: fn) => any,
|
|
85
|
+
seek: (fn: (val: T) => any) => { found: boolean, val: T | undefined, ind: number },
|
|
86
|
+
}
|
|
87
|
+
interface ArrayConstructor {
|
|
88
|
+
stub: any[]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface Error {
|
|
92
|
+
mod: (props: { [key: string]: any }) => Error
|
|
93
|
+
propagate: (props?: { [key: string]: any }) => never
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface FunctionConstructor {
|
|
97
|
+
stub: (...args: any[]) => any
|
|
98
|
+
}
|
|
99
|
+
interface Function {
|
|
100
|
+
bound: fn
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface GeneratorFunctionConstructor {
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface Number {
|
|
107
|
+
encodeStr: (str: string | CharSet, len?: number) => string,
|
|
108
|
+
each: (fn: (n: number) => void) => void,
|
|
109
|
+
toArr: <T>(fn: (n: number) => T) => T[]
|
|
110
|
+
}
|
|
111
|
+
interface NumberConstructor {
|
|
112
|
+
int32: number
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface BigInt {
|
|
116
|
+
encodeStr: Number[encodeStr]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
interface ObjectConstructor {
|
|
120
|
+
}
|
|
121
|
+
interface Object {
|
|
122
|
+
empty: () => boolean,
|
|
123
|
+
has: (k: string) => boolean,
|
|
124
|
+
map: (fn: (val: any, key: string) => any) => any,
|
|
125
|
+
mapk: (fn: (val: any, key: string) => [ string, any ]) => any,
|
|
126
|
+
at: (k: string | string[], def?: any) => any,
|
|
127
|
+
plain: (obj?: any) => any,
|
|
128
|
+
slice: <T>(this: T, keys: (keyof T)[]) => Partial<T>,
|
|
129
|
+
omit: <T>(this: T, keys: (keyof T)[]) => Partial<T>,
|
|
130
|
+
toArr: <T extends (v: any, k: string) => any>(fn: T) => ReturnType<T>[],
|
|
131
|
+
built: () => Object,
|
|
132
|
+
merge: <T>(val: T) => Object & T,
|
|
133
|
+
gain: (...args: any[]) => any,
|
|
134
|
+
[Symbol.iterator]: () => Iterator<[ string, any]>
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
interface Promise<T> {
|
|
138
|
+
fail: Promise<T>['catch'],
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface PromiseLater<T=void> extends Promise<T> {
|
|
142
|
+
resolve: T extends void ? () => void : (v: T) => void,
|
|
143
|
+
reject: (err: any) => void
|
|
144
|
+
}
|
|
145
|
+
interface PromiseConstructor {
|
|
146
|
+
<T>(fn: (resolve: (v: T) => void, reject: (err: any) => void) => any): Promise<T>,
|
|
147
|
+
later: <T=void>() => PromiseLater<T>,
|
|
148
|
+
all: {
|
|
149
|
+
<T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>[]>;
|
|
150
|
+
|
|
151
|
+
//<T>(arr: Promise<T>[]): Promise<T[]>,
|
|
152
|
+
//<T>(obj: { [key: string]: Promise<T> }): Promise<{ [key: string]: T }>
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
interface SetConstructor {
|
|
157
|
+
<T>(arr?: T[]): Set<T>
|
|
158
|
+
}
|
|
159
|
+
interface Set<T> {
|
|
160
|
+
toArr: (fn: (val: T, ind: number) => void) => T[],
|
|
161
|
+
rem: (val: T) => void
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface MapConstructor {
|
|
165
|
+
<K, V>(arr?: [ K, V ][]): Map<K, V>
|
|
166
|
+
}
|
|
167
|
+
interface Map<K, V> {
|
|
168
|
+
add: (k: K, v: V) => void,
|
|
169
|
+
toArr: <T>(fn: (val: V, key: K) => T) => T[],
|
|
170
|
+
rem: (key: K) => void
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
type CharSet = { str: string, size: bigint, charVal: (c: string) => bigint, valChar: (n: bigint) => string };
|
|
174
|
+
interface String {
|
|
175
|
+
count(): number,
|
|
176
|
+
padHead(n: number, s?: string): string,
|
|
177
|
+
padTail(n: number, s?: string): string,
|
|
178
|
+
encodeInt: (chrs: string | CharSet) => bigint,
|
|
179
|
+
reencode: (src: string | CharSet, trg: string | CharSet) => string,
|
|
180
|
+
trimHead(): string,
|
|
181
|
+
trimTail(): string,
|
|
182
|
+
hasHead(head: string): boolean,
|
|
183
|
+
upper(): string,
|
|
184
|
+
lower(): string,
|
|
185
|
+
cut(str: string, cuts?: number): string[],
|
|
186
|
+
indent: {
|
|
187
|
+
(amount: number, char?: string): string,
|
|
188
|
+
(str: string): string
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
interface StringConstructor {
|
|
192
|
+
charset: (str: string) => CharSet,
|
|
193
|
+
base32: string,
|
|
194
|
+
base62: string,
|
|
195
|
+
baseline: (str: string) => str,
|
|
196
|
+
multiline: (str: string) => str,
|
|
197
|
+
}
|