• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rjrodger / gubu / 6617156688

23 Oct 2023 06:01PM UTC coverage: 93.566% (+0.3%) from 93.315%
6617156688

push

github

rjrodger
tests-fixed

722 of 798 branches covered (0.0%)

Branch coverage included in aggregate %.

965 of 1005 relevant lines covered (96.02%)

151703.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.56
/gubu.js
1
"use strict";
2
/* Copyright (c) 2021-2022 Richard Rodger and other contributors, MIT License */
3
Object.defineProperty(exports, "__esModule", { value: true });
48✔
4
exports.GDefine = exports.GDefault = exports.GClosed = exports.GChild = exports.GCheck = exports.GBelow = exports.GBefore = exports.GAny = exports.GAll = exports.GAfter = exports.GAbove = exports.Rest = exports.Some = exports.Skip = exports.Required = exports.Rename = exports.Refer = exports.Optional = exports.Open = exports.One = exports.Never = exports.Min = exports.Max = exports.Len = exports.Key = exports.Ignore = exports.Func = exports.Fault = exports.Exact = exports.Empty = exports.Define = exports.Default = exports.Closed = exports.Child = exports.Check = exports.Below = exports.Before = exports.Any = exports.All = exports.After = exports.Above = exports.MakeArgu = exports.expr = exports.truncate = exports.stringify = exports.makeErr = exports.buildize = exports.nodize = exports.G$ = exports.Gubu = void 0;
48✔
5
exports.GRest = exports.GSome = exports.GSkip = exports.GRequired = exports.GRename = exports.GRefer = exports.GOptional = exports.GOpen = exports.GOne = exports.GNever = exports.GMin = exports.GMax = exports.GLen = exports.GKey = exports.GIgnore = exports.GFunc = exports.GFault = exports.GExact = exports.GEmpty = void 0;
48✔
6
// FEATURE: regexp in array: [/a/] => all elements must match /a/
7
// FEATURE: validator on completion of object or array
8
// FEATURE: support non-index properties on array shape
9
// FEATURE: state should indicate if value was present, not just undefined
10
// FEATURE: support custom builder registration so that can chain on builtins
11
// FEATURE: merge shapes (allows extending given shape - e.g. adding object props)
12
// TODO: Validation of Builder parameters
13
// TODO: GubuShape.d is damaged by composition
14
// TODO: Better stringifys for builder shapes
15
// TODO: Error messages should state property is missing, not `value ""`
16
// TODO: node.s can be a lazy function to avoid unnecessary string building
17
// TODO: Finish Default shape-builder
18
// DOC: Skip also makes value optional - thus Skip() means any value, or nonexistent
19
// DOC: Optional
20
const util_1 = require("util");
48✔
21
// Package version.
22
const VERSION = '5.0.1';
48✔
23
// Unique symbol for marking and recognizing Gubu shapes.
24
const GUBU$ = Symbol.for('gubu$');
48✔
25
// A singleton for fast equality checks.
26
const GUBU = { gubu$: GUBU$, v$: VERSION };
48✔
27
// A special marker for property abscence.
28
const GUBU$NIL = Symbol.for('gubu$nil');
48✔
29
// RegExp: first letter is upper case
30
const UPPER_CASE_FIRST_RE = /^[A-Z]/;
48✔
31
// Help the minifier
32
const S = {
48✔
33
    MT: '',
34
    gubu: 'gubu',
35
    name: 'name',
36
    nan: 'nan',
37
    never: 'never',
38
    number: 'number',
39
    required: 'required',
40
    array: 'array',
41
    function: 'function',
42
    object: 'object',
43
    string: 'string',
44
    undefined: 'undefined',
45
    any: 'any',
46
    list: 'list',
47
    instance: 'instance',
48
    null: 'null',
49
    type: 'type',
50
    Object: 'Object',
51
    Array: 'Array',
52
    Above: 'Above',
53
    After: 'After',
54
    All: 'All',
55
    Any: 'Any',
56
    Before: 'Before',
57
    Below: 'Below',
58
    Check: 'Check',
59
    Child: 'Child',
60
    Closed: 'Closed',
61
    Define: 'Define',
62
    Default: 'Default',
63
    Empty: 'Empty',
64
    Exact: 'Exact',
65
    Func: 'Func',
66
    Key: 'Key',
67
    Max: 'Max',
68
    Min: 'Min',
69
    Never: 'Never',
70
    Len: 'Len',
71
    One: 'One',
72
    Open: 'Open',
73
    Optional: 'Optional',
74
    Refer: 'Refer',
75
    Rename: 'Rename',
76
    Required: 'Required',
77
    Skip: 'Skip',
78
    Ignore: 'Ignore',
79
    Some: 'Some',
80
    Value: 'Value',
81
    Fault: 'Fault',
82
    Rest: 'Rest',
83
    forprop: ' for property ',
84
    $PATH: '"$PATH"',
85
    $VALUE: '"$VALUE"',
86
};
87
const keys = (arg) => Object.keys(arg);
1,149,972✔
88
const defprop = (o, p, a) => Object.defineProperty(o, p, a);
336✔
89
const isarr = (arg) => Array.isArray(arg);
615,924✔
90
const JP = (arg) => JSON.parse(arg);
7,860✔
91
const JS = (a0, a1) => JSON.stringify(a0, a1);
17,904✔
92
// The current validation state.
93
class State {
94
    constructor(root, top, ctx, match) {
95
        this.match = false;
28,740✔
96
        this.dI = 0; // Node depth.
28,740✔
97
        this.nI = 2; // Next free slot in nodes.
28,740✔
98
        this.cI = -1; // Pointer to next node.
28,740✔
99
        this.pI = 0; // Pointer to current node.
28,740✔
100
        this.sI = -1; // Pointer to next sibling node.
28,740✔
101
        this.valType = S.never;
28,740✔
102
        this.isRoot = false;
28,740✔
103
        this.key = S.MT;
28,740✔
104
        this.type = S.never;
28,740✔
105
        this.stop = true;
28,740✔
106
        this.nextSibling = true;
28,740✔
107
        this.fromDefault = false;
28,740✔
108
        // NOTE: tri-valued; undefined = soft ignore
109
        this.ignoreVal = undefined;
28,740✔
110
        this.curerr = [];
28,740✔
111
        this.err = [];
28,740✔
112
        this.parents = [];
28,740✔
113
        this.keys = [];
28,740✔
114
        // NOTE: not "clean"!
115
        // Actual path is always only path[0,dI+1]
116
        this.path = [];
28,740✔
117
        this.root = root;
28,740✔
118
        this.vals = [root, -1];
28,740✔
119
        this.node = top;
28,740✔
120
        this.nodes = [top, -1];
28,740✔
121
        this.ctx = ctx || {};
28,740✔
122
        this.match = !!match;
28,740✔
123
    }
124
    next() {
125
        // Uncomment for debugging (definition below).
126
        // this.printStacks()
127
        this.stop = false;
1,044,348✔
128
        this.fromDefault = false;
1,044,348✔
129
        this.ignoreVal = undefined;
1,044,348✔
130
        this.isRoot = 0 === this.pI;
1,044,348✔
131
        this.check = undefined;
1,044,348✔
132
        // Dereference the back pointers to ancestor siblings.
133
        // Only objects|arrays can be nodes, so a number is a back pointer.
134
        // NOTE: terminates because (+{...} -> NaN, +[] -> 0) -> false (JS wat FTW!)
135
        let nextNode = this.nodes[this.pI];
1,044,348✔
136
        while (+nextNode) {
1,044,348✔
137
            this.dI--;
459,768✔
138
            this.ctx.log &&
459,768!
139
                -1 < this.dI &&
140
                this.ctx.log('e' +
141
                    (Array.isArray(this.parents[this.pI]) ? 'a' : 'o'), this);
×
142
            this.pI = +nextNode;
459,768✔
143
            nextNode = this.nodes[this.pI];
459,768✔
144
        }
145
        if (!nextNode) {
1,044,348✔
146
            this.stop = true;
28,728✔
147
            return;
28,728✔
148
        }
149
        else {
150
            this.node = nextNode;
1,015,620✔
151
        }
152
        this.updateVal(this.vals[this.pI]);
1,015,620✔
153
        this.key = this.keys[this.pI];
1,015,620✔
154
        this.cI = this.pI;
1,015,620✔
155
        this.sI = this.pI + 1;
1,015,620✔
156
        this.parent = this.parents[this.pI];
1,015,620✔
157
        this.nextSibling = true;
1,015,620✔
158
        this.type = this.node.t;
1,015,620✔
159
        this.path[this.dI] = this.key;
1,015,620✔
160
        this.oval = this.val;
1,015,620✔
161
        this.curerr.length = 0;
1,015,620✔
162
    }
163
    updateVal(val) {
164
        this.val = val;
1,732,008✔
165
        this.valType = typeof (this.val);
1,732,008✔
166
        if (S.number === this.valType && isNaN(this.val)) {
1,732,008✔
167
            this.valType = S.nan;
528✔
168
        }
169
        if (this.isRoot && !this.match) {
1,732,008✔
170
            this.root = this.val;
45,240✔
171
        }
172
    }
173
    // Uncomment for debugging.
174
    printStacks() {
175
        var _a;
176
        console.log('\nNODE', 'd=' + this.dI, 'c=' + this.cI, 'p=' + this.pI, 'n=' + this.nI, +this.node, this.node.t, this.path, this.err.length);
×
177
        for (let i = 0; i < this.nodes.length ||
×
178
            i < this.vals.length ||
179
            i < this.parents.length; i++) {
180
            console.log(i, '\t', ('' + (isNaN(+this.nodes[i]) ?
×
181
                this.keys[i] + ':' + ((_a = this.nodes[i]) === null || _a === void 0 ? void 0 : _a.t) :
×
182
                +this.nodes[i])).padEnd(32, ' '), stringify(this.vals[i]).padEnd(32, ' '), stringify(this.parents[i]));
183
        }
184
    }
185
}
186
// Custom Error class.
187
class GubuError extends TypeError {
188
    constructor(code, prefix, err, ctx) {
189
        var _a;
190
        prefix = (null == prefix) ? '' : (prefix + ': ');
6,840✔
191
        super(prefix + err.map((e) => e.t).join('\n'));
7,476✔
192
        this.gubu = true;
6,840✔
193
        let name = 'GubuError';
6,840✔
194
        let ge = this;
6,840✔
195
        ge.name = name;
6,840✔
196
        this.code = code;
6,840✔
197
        this.prefix = prefix;
6,840✔
198
        this.desc = () => ({ name, code, err, ctx, });
6,840✔
199
        this.stack = (_a = this.stack) === null || _a === void 0 ? void 0 : _a.replace(/.*\/gubu\/gubu\.[tj]s.*\n/g, '');
6,840!
200
        this.props = err.map((e) => {
6,840✔
201
            var _a;
202
            return ({
7,476✔
203
                path: e.p,
204
                what: e.w,
205
                type: (_a = e.n) === null || _a === void 0 ? void 0 : _a.t,
22,428!
206
                value: e.v
207
            });
208
        });
209
    }
210
    toJSON() {
211
        return {
12✔
212
            ...this,
213
            err: this.desc().err,
214
            name: this.name,
215
            message: this.message,
216
        };
217
    }
218
}
219
// Identify JavaScript wrapper types by name.
220
const IS_TYPE = {
48✔
221
    String: true,
222
    Number: true,
223
    Boolean: true,
224
    Object: true,
225
    Array: true,
226
    Function: true,
227
    Symbol: true,
228
    BigInt: true,
229
};
230
// Empty values for each type.
231
const EMPTY_VAL = {
48✔
232
    string: S.MT,
233
    number: 0,
234
    boolean: false,
235
    object: {},
236
    array: [],
237
    symbol: Symbol(S.MT),
238
    bigint: BigInt(0),
239
    null: null,
240
};
241
// Normalize a value into a Node<S>.
242
function nodize(shape, depth, meta) {
243
    var _a, _b, _c, _d;
244
    // If using builder as property of Gubu, `this` is just Gubu, not a node.
245
    if (make === shape) {
999,624✔
246
        shape = undefined;
12✔
247
    }
248
    // Is this a (possibly incomplete) Node<S>?
249
    else if (null != shape && ((_a = shape.$) === null || _a === void 0 ? void 0 : _a.gubu$)) {
999,612✔
250
        // Assume complete if gubu$ has special internal reference.
251
        if (GUBU$ === shape.$.gubu$) {
440,352✔
252
            shape.d = null == depth ? shape.d : depth;
440,148✔
253
            return shape;
440,148✔
254
        }
255
        // Normalize an incomplete Node<S>, avoiding any recursive calls to norm.
256
        else if (true === shape.$.gubu$) {
204!
257
            let node = { ...shape };
204✔
258
            node.$ = { v$: VERSION, ...node.$, gubu$: GUBU$ };
204✔
259
            node.v =
204✔
260
                (null != node.v && S.object === typeof (node.v)) ? { ...node.v } : node.v;
612✔
261
            // Leave as-is: node.c
262
            node.t = node.t || typeof (node.v);
204✔
263
            if (S.function === node.t && IS_TYPE[node.v.name]) {
204✔
264
                node.t = node.v.name.toLowerCase();
12✔
265
                node.v = clone(EMPTY_VAL[node.t]);
12✔
266
                node.f = node.v;
12✔
267
            }
268
            node.r = !!node.r;
204✔
269
            node.p = !!node.p;
204✔
270
            node.d = null == depth ? null == node.d ? -1 : node.d : depth;
204!
271
            node.b = node.b || [];
204✔
272
            node.a = node.a || [];
204✔
273
            node.u = node.u || {};
204✔
274
            node.m = node.m || meta || {};
204✔
275
            return node;
204✔
276
        }
277
    }
278
    // Not a Node<S>, so build one based on value and its type.
279
    let t = (null === shape ? S.null : typeof (shape));
559,272✔
280
    t = (S.undefined === t ? S.any : t);
559,272✔
281
    let v = shape;
559,272✔
282
    let f = v;
559,272✔
283
    let c = GUBU$NIL;
559,272✔
284
    let r = false; // Not required by default.
559,272✔
285
    let p = false; // Only true when Skip builder is used.
559,272✔
286
    let u = {};
559,272✔
287
    let a = [];
559,272✔
288
    let b = [];
559,272✔
289
    if (S.object === t) {
559,272✔
290
        f = undefined;
279,348✔
291
        if (isarr(v)) {
279,348✔
292
            t = S.array;
139,188✔
293
            if (1 === v.length) {
139,188✔
294
                c = v[0];
138,576✔
295
                v = [];
138,576✔
296
            }
297
            // Else no child, thus closed.
298
        }
299
        else if (null != v &&
140,160✔
300
            Function !== v.constructor &&
301
            Object !== v.constructor &&
302
            null != v.constructor) {
303
            t = S.instance;
156✔
304
            u.n = v.constructor.name;
156✔
305
            u.i = v.constructor;
156✔
306
            f = v;
156✔
307
        }
308
        else {
309
            // c = GUBU$NIL
310
            // Empty object "{}" is considered Open
311
            if (0 === keys(v).length) {
140,004✔
312
                c = Any();
264✔
313
            }
314
        }
315
    }
316
    // NOTE: use Check for validation functions
317
    else if (S.function === t) {
279,924✔
318
        if (IS_TYPE[shape.name]) {
6,804✔
319
            t = shape.name.toLowerCase();
6,444✔
320
            r = true;
6,444✔
321
            v = clone(EMPTY_VAL[t]);
6,444✔
322
            f = v;
6,444✔
323
            // Required "Object" is considered Open
324
            if (S.Object === shape.name) {
6,444✔
325
                c = Any();
288✔
326
            }
327
        }
328
        else if (v.gubu === GUBU || true === ((_b = v.$) === null || _b === void 0 ? void 0 : _b.gubu)) {
360!
329
            let gs = v.node ? v.node() : v;
84!
330
            t = gs.t;
84✔
331
            v = gs.v;
84✔
332
            f = v;
84✔
333
            r = gs.r;
84✔
334
            u = { ...gs.u };
84✔
335
            a = [...gs.a];
84✔
336
            b = [...gs.b];
84✔
337
        }
338
        // Instance of a class.
339
        // Note: uses the convention that a class name is captialized.
340
        else if ('Function' === v.constructor.name &&
276✔
341
            UPPER_CASE_FIRST_RE.test(v.name)) {
342
            t = S.instance;
204✔
343
            r = true;
204✔
344
            u.n = (_d = (_c = v.prototype) === null || _c === void 0 ? void 0 : _c.constructor) === null || _d === void 0 ? void 0 : _d.name;
204!
345
            u.i = v;
204✔
346
        }
347
    }
348
    else if (S.number === t && isNaN(v)) {
273,120✔
349
        t = S.nan;
72✔
350
    }
351
    else if (S.string === t && S.MT === v) {
273,048✔
352
        u.empty = true;
108✔
353
    }
354
    let vmap = (null != v && (S.object === t || S.array === t)) ? { ...v } : v;
559,272✔
355
    let node = {
559,272✔
356
        $: GUBU,
357
        // o: v,
358
        t,
359
        v: vmap,
360
        f,
361
        n: null != vmap && S.object === typeof (vmap) ? keys(vmap).length : 0,
1,674,660✔
362
        c,
363
        r,
364
        p,
365
        d: null == depth ? -1 : depth,
559,272✔
366
        k: [],
367
        e: true,
368
        u,
369
        a,
370
        b,
371
        m: meta || {}
1,118,532✔
372
    };
373
    return node;
559,272✔
374
}
375
exports.nodize = nodize;
48✔
376
// Create a GubuShape from a shape specification.
377
function make(intop, inopts) {
378
    const opts = null == inopts ? {} : inopts;
6,780✔
379
    // Ironically, we can't Gubu GubuOptions, so we have to set
380
    // option defaults manually.
381
    opts.name =
6,780✔
382
        null == opts.name ?
6,780✔
383
            'G' + (S.MT + Math.random()).substring(2, 8) : S.MT + opts.name;
384
    opts.prefix = null == opts.prefix ? undefined : opts.prefix;
6,780✔
385
    // Meta properties are off by default.
386
    let optsmeta = opts.meta = opts.meta || {};
6,780✔
387
    optsmeta.active = (true === optsmeta.active) || false;
6,780✔
388
    optsmeta.suffix = 'string' == typeof optsmeta.suffix ? optsmeta.suffix : '$$';
6,780!
389
    // Key expressions are on by default.
390
    let optskeyexpr = opts.keyexpr = opts.keyexpr || {};
6,780✔
391
    optskeyexpr.active = (false !== optskeyexpr.active);
6,780✔
392
    let top = nodize(intop, 0);
6,780✔
393
    // Lazily execute top against root to see if they match
394
    function exec(root, ctx, match // Suppress errors and return boolean result (true if match)
395
    ) {
396
        let s = new State(root, top, ctx, match);
28,740✔
397
        // Iterative depth-first traversal of the shape using append-only array stacks.
398
        // Stack entries are either sub-nodes to validate, or back pointers to
399
        // next depth-first sub-node index.
400
        while (true) {
28,740✔
401
            s.next();
1,044,348✔
402
            if (s.stop) {
1,044,348✔
403
                break;
28,728✔
404
            }
405
            let n = s.node;
1,015,620✔
406
            let done = false;
1,015,620✔
407
            // Call Befores
408
            if (0 < n.b.length) {
1,015,620✔
409
                for (let bI = 0; bI < n.b.length; bI++) {
10,944✔
410
                    let update = handleValidate(n.b[bI], s);
11,412✔
411
                    n = s.node;
11,412✔
412
                    if (undefined !== update.done) {
11,412✔
413
                        done = update.done;
2,376✔
414
                    }
415
                }
416
            }
417
            if (!done) {
1,015,620✔
418
                let descend = true;
1,013,244✔
419
                let valundef = undefined === s.val;
1,013,244✔
420
                if (S.never === s.type) {
1,013,244✔
421
                    s.curerr.push(makeErrImpl(S.never, s, 1070));
108✔
422
                }
423
                else if (S.object === s.type) {
1,013,136✔
424
                    let val;
425
                    if (n.r && valundef) {
290,304✔
426
                        s.ignoreVal = true;
672✔
427
                        s.curerr.push(makeErrImpl(S.required, s, 1010));
672✔
428
                    }
429
                    else if (!valundef && (null === s.val ||
289,632✔
430
                        S.object !== s.valType ||
431
                        isarr(s.val))) {
432
                        s.curerr.push(makeErrImpl(S.type, s, 1020));
408✔
433
                        val = isarr(s.val) ? s.val : {};
408✔
434
                    }
435
                    // Not skippable, use default or create object
436
                    else if (!n.p && valundef && undefined !== n.f) {
289,224✔
437
                        s.updateVal(n.f);
168✔
438
                        s.fromDefault = true;
168✔
439
                        val = s.val;
168✔
440
                        descend = false;
168✔
441
                    }
442
                    else if (!n.p || !valundef) {
289,056✔
443
                        // Descend into object, constructing child defaults
444
                        s.updateVal(s.val || (s.fromDefault = true, {}));
288,492✔
445
                        val = s.val;
288,492✔
446
                    }
447
                    if (descend) {
290,304✔
448
                        val = null == val && false === s.ctx.err ? {} : val;
290,136✔
449
                        if (null != val) {
290,136✔
450
                            s.ctx.log && s.ctx.log('so', s);
289,788!
451
                            let hasKeys = false;
289,788✔
452
                            let vkeys = keys(n.v);
289,788✔
453
                            let start = s.nI;
289,788✔
454
                            if (0 < vkeys.length) {
289,788✔
455
                                hasKeys = true;
288,300✔
456
                                s.pI = start;
288,300✔
457
                                //for (let k of vkeys) {
458
                                for (let kI = 0; kI < vkeys.length; kI++) {
288,300✔
459
                                    let k = vkeys[kI];
837,216✔
460
                                    let meta = undefined;
837,216✔
461
                                    // TODO: make optional, needs tests
462
                                    // Experimental feature for jsonic docs
463
                                    // NOTE: Meta key *must* immediately preceed key:
464
                                    // { x$$: <META>, x: 1 }}
465
                                    if (optsmeta.active && k.endsWith(optsmeta.suffix)) {
837,216✔
466
                                        meta = { short: '' };
12✔
467
                                        if ('string' === typeof (n.v[k])) {
12!
468
                                            meta.short = n.v[k];
×
469
                                        }
470
                                        else {
471
                                            meta = { ...meta, ...n.v[k] };
12✔
472
                                        }
473
                                        delete n.v[k];
12✔
474
                                        kI++;
12✔
475
                                        if (vkeys.length <= kI) {
12!
476
                                            break;
×
477
                                        }
478
                                        if (vkeys[kI] !== k
12!
479
                                            .substring(0, k.length - optsmeta.suffix.length)) {
480
                                            throw new Error('Invalid meta key: ' + k);
×
481
                                        }
482
                                        k = vkeys[kI];
12✔
483
                                    }
484
                                    let rk = k;
837,216✔
485
                                    let ov = n.v[k];
837,216✔
486
                                    if (optskeyexpr.active) {
837,216✔
487
                                        // let parts = k.split(' ')
488
                                        let m = /^\s*("(\\.|[^"\\])*"|[^\s]+):\s*(.*?)\s*$/
837,192✔
489
                                            .exec(k);
490
                                        if (m) {
837,192✔
491
                                            rk = m[1];
156✔
492
                                            let src = m[3];
156✔
493
                                            ov = expr({ src, val: ov });
156✔
494
                                            delete n.v[k];
144✔
495
                                        }
496
                                    }
497
                                    let nvs = nodize(ov, 1 + s.dI, meta);
837,204✔
498
                                    n.v[rk] = nvs;
837,204✔
499
                                    if (!n.k.includes(rk)) {
837,204✔
500
                                        n.k.push(rk);
410,784✔
501
                                    }
502
                                    s.nodes[s.nI] = nvs;
837,204✔
503
                                    s.vals[s.nI] = val[rk];
837,204✔
504
                                    s.parents[s.nI] = val;
837,204✔
505
                                    s.keys[s.nI] = rk;
837,204✔
506
                                    s.nI++;
837,204✔
507
                                }
508
                            }
509
                            let extra = keys(val).filter(k => undefined === n.v[k]);
417,852✔
510
                            if (0 < extra.length) {
289,776✔
511
                                if (GUBU$NIL === n.c) {
1,956✔
512
                                    s.ignoreVal = true;
660✔
513
                                    s.curerr.push(makeErrImpl('closed', s, 1100, undefined, { k: extra }));
660✔
514
                                }
515
                                else {
516
                                    hasKeys = true;
1,296✔
517
                                    s.pI = start;
1,296✔
518
                                    for (let k of extra) {
1,296✔
519
                                        let nvs = n.c = nodize(n.c, 1 + s.dI);
1,632✔
520
                                        s.nodes[s.nI] = nvs;
1,632✔
521
                                        s.vals[s.nI] = val[k];
1,632✔
522
                                        s.parents[s.nI] = val;
1,632✔
523
                                        s.keys[s.nI] = k;
1,632✔
524
                                        s.nI++;
1,632✔
525
                                    }
526
                                }
527
                            }
528
                            if (hasKeys) {
289,776✔
529
                                s.dI++;
288,780✔
530
                                s.nodes[s.nI] = s.sI;
288,780✔
531
                                s.parents[s.nI] = val;
288,780✔
532
                                s.nextSibling = false;
288,780✔
533
                                s.nI++;
288,780✔
534
                            }
535
                            else {
536
                                s.ctx.log && s.ctx.log('eo', s);
996!
537
                            }
538
                        }
539
                    }
540
                }
541
                else if (S.array === s.type) {
722,832✔
542
                    if (n.r && valundef) {
150,876✔
543
                        s.ignoreVal = true;
168✔
544
                        s.curerr.push(makeErrImpl(S.required, s, 1030));
168✔
545
                    }
546
                    else if (!valundef && !isarr(s.val)) {
150,708✔
547
                        s.curerr.push(makeErrImpl(S.type, s, 1040));
216✔
548
                    }
549
                    else if (!n.p && valundef && undefined !== n.f) {
150,492✔
550
                        s.updateVal(n.f);
72✔
551
                        s.fromDefault = true;
72✔
552
                    }
553
                    else if (!n.p || null != s.val) {
150,420✔
554
                        s.updateVal(s.val || (s.fromDefault = true, []));
150,396✔
555
                        // n.c set by nodize for array with len=1
556
                        let hasChildShape = GUBU$NIL !== n.c;
150,396✔
557
                        let hasValueElements = 0 < s.val.length;
150,396✔
558
                        let elementKeys = keys(n.v).filter(k => !isNaN(+k));
150,396✔
559
                        let hasFixedElements = 0 < elementKeys.length;
150,396✔
560
                        s.ctx.log && s.ctx.log('sa', s);
150,396!
561
                        if (hasValueElements || hasFixedElements) {
150,396✔
562
                            s.pI = s.nI;
142,500✔
563
                            let elementIndex = 0;
142,500✔
564
                            // Fixed element array means match shapes at each index only.
565
                            if (hasFixedElements) {
142,500✔
566
                                if (elementKeys.length < s.val.length && !hasChildShape) {
1,956✔
567
                                    s.ignoreVal = true;
240✔
568
                                    s.curerr.push(makeErrImpl('closed', s, 1090, undefined, { k: elementKeys.length }));
240✔
569
                                }
570
                                else {
571
                                    for (; elementIndex < elementKeys.length; elementIndex++) {
1,716✔
572
                                        let elementShape = n.v[elementIndex] =
6,072✔
573
                                            nodize(n.v[elementIndex], 1 + s.dI);
574
                                        s.nodes[s.nI] = elementShape;
6,072✔
575
                                        s.vals[s.nI] = s.val[elementIndex];
6,072✔
576
                                        s.parents[s.nI] = s.val;
6,072✔
577
                                        s.keys[s.nI] = S.MT + elementIndex;
6,072✔
578
                                        s.nI++;
6,072✔
579
                                    }
580
                                }
581
                            }
582
                            // Single element array shape means 0 or more elements of shape
583
                            if (hasChildShape && hasValueElements) {
142,500✔
584
                                let elementShape = n.c = nodize(n.c, 1 + s.dI);
140,004✔
585
                                for (; elementIndex < s.val.length; elementIndex++) {
140,004✔
586
                                    s.nodes[s.nI] = elementShape;
141,972✔
587
                                    s.vals[s.nI] = s.val[elementIndex];
141,972✔
588
                                    s.parents[s.nI] = s.val;
141,972✔
589
                                    s.keys[s.nI] = S.MT + elementIndex;
141,972✔
590
                                    s.nI++;
141,972✔
591
                                }
592
                            }
593
                            if (!s.ignoreVal) {
142,500✔
594
                                s.dI++;
142,260✔
595
                                s.nodes[s.nI] = s.sI;
142,260✔
596
                                s.parents[s.nI] = s.val;
142,260✔
597
                                s.nextSibling = false;
142,260✔
598
                                s.nI++;
142,260✔
599
                            }
600
                        }
601
                        else {
602
                            // Ensure single element array still generates log
603
                            // for the element when only walking shape.
604
                            s.ctx.log &&
7,896!
605
                                hasChildShape &&
606
                                undefined == root &&
607
                                s.ctx.log('kv', { ...s, key: 0, val: n.c });
608
                            s.ctx.log && s.ctx.log('ea', s);
7,896!
609
                        }
610
                    }
611
                }
612
                // Invalid type.
613
                else if (!(S.any === s.type ||
571,956✔
614
                    S.list === s.type ||
615
                    undefined === s.val ||
616
                    s.type === s.valType ||
617
                    (S.instance === s.type && n.u.i && s.val instanceof n.u.i) ||
618
                    (S.null === s.type && null === s.val))) {
619
                    s.curerr.push(makeErrImpl(S.type, s, 1050));
3,996✔
620
                }
621
                // Value itself, or default.
622
                else if (undefined === s.val) {
567,960✔
623
                    let parentKey = s.path[s.dI];
283,848✔
624
                    if (n.r &&
283,848✔
625
                        (S.undefined !== s.type || !s.parent.hasOwnProperty(parentKey))) {
626
                        s.ignoreVal = true;
4,032✔
627
                        s.curerr.push(makeErrImpl(S.required, s, 1060));
4,032✔
628
                    }
629
                    else if (
279,816✔
630
                    // undefined !== n.v &&
631
                    undefined !== n.f &&
560,940✔
632
                        !n.p ||
633
                        S.undefined === s.type) {
634
                        // Inject default value.
635
                        s.updateVal(n.f);
276,048✔
636
                        s.fromDefault = true;
276,048✔
637
                    }
638
                    else if (S.any === s.type) {
3,768✔
639
                        s.ignoreVal = undefined === s.ignoreVal ? true : s.ignoreVal;
2,328✔
640
                    }
641
                    // TODO: ensure object,array points called even if errors
642
                    s.ctx.log && s.ctx.log('kv', s);
283,848!
643
                }
644
                // Empty strings fail even if string is optional. Use Empty() to allow.
645
                else if (S.string === s.type && S.MT === s.val && !n.u.empty) {
284,112✔
646
                    s.curerr.push(makeErrImpl(S.required, s, 1080));
180✔
647
                    s.ctx.log && s.ctx.log('kv', s);
180!
648
                }
649
                else {
650
                    s.ctx.log && s.ctx.log('kv', s);
283,932!
651
                }
652
            }
653
            // Call Afters
654
            if (0 < n.a.length) {
1,015,608✔
655
                for (let aI = 0; aI < n.a.length; aI++) {
1,032✔
656
                    let update = handleValidate(n.a[aI], s);
1,068✔
657
                    n = s.node;
1,068✔
658
                    if (undefined !== update.done) {
1,068✔
659
                        done = update.done;
384✔
660
                    }
661
                }
662
            }
663
            // Explicit ignoreVal overrides Skip
664
            let ignoreVal = s.node.p ? false === s.ignoreVal ? false : true : !!s.ignoreVal;
1,015,608✔
665
            let setParent = !s.match && null != s.parent && !done && !ignoreVal;
1,015,608✔
666
            if (setParent) {
1,015,608✔
667
                s.parent[s.key] = s.val;
977,412✔
668
            }
669
            if (s.nextSibling) {
1,015,608✔
670
                s.pI = s.sI;
584,568✔
671
            }
672
            if (s.node.e) {
1,015,608✔
673
                s.err.push(...s.curerr);
1,015,188✔
674
            }
675
        }
676
        // s.err = s.err.filter(e => null != e)
677
        if (0 < s.err.length) {
28,728✔
678
            if (isarr(s.ctx.err)) {
11,736✔
679
                s.ctx.err.push(...s.err);
1,740✔
680
            }
681
            else if (!s.match && false !== s.ctx.err) {
9,996✔
682
                throw new GubuError('shape', opts.prefix, s.err, s.ctx);
6,840✔
683
            }
684
        }
685
        return s.match ? 0 === s.err.length : s.root;
21,888✔
686
    }
687
    function gubuShape(root, ctx) {
688
        // any {
689
        return (exec(root, ctx, false)); // as R & S)
26,364✔
690
    }
691
    // function valid<D>(root?: D, ctx?: Context): root is (D & S) {
692
    function valid(root, ctx) {
693
        let actx = ctx || {};
96✔
694
        actx.err = actx.err || [];
96✔
695
        exec(root, actx, false);
96✔
696
        return 0 === actx.err.length;
96✔
697
    }
698
    gubuShape.valid = valid;
6,780✔
699
    gubuShape.match = (root, ctx) => {
6,780✔
700
        ctx = ctx || {};
2,208✔
701
        return exec(root, ctx, true);
2,208✔
702
    };
703
    gubuShape.error = (root, ctx) => {
6,780✔
704
        let actx = ctx || {};
72✔
705
        actx.err = actx.err || [];
72✔
706
        exec(root, actx, false);
72✔
707
        return actx.err;
72✔
708
    };
709
    gubuShape.spec = () => {
6,780✔
710
        // TODO: when c is GUBU$NIL it is not present, should have some indicator value
711
        // Normalize spec, discard errors.
712
        gubuShape(undefined, { err: false });
7,452✔
713
        return JP(stringify(top, (_key, val) => {
7,440✔
714
            if (GUBU$ === val) {
5,868,255✔
715
                return true;
318,133✔
716
            }
717
            return val;
5,550,121✔
718
        }, false, true));
719
    };
720
    gubuShape.node = () => {
6,780✔
721
        gubuShape.spec();
252✔
722
        return top;
252✔
723
    };
724
    let desc = S.MT;
6,780✔
725
    gubuShape.toString = () => {
6,780✔
726
        desc = truncate(S.MT === desc ?
48!
727
            stringify((top &&
192!
728
                top.$ &&
729
                (GUBU$ === top.$.gubu$ || true === top.$.gubu$)) ? top.v : top) :
730
            desc);
731
        return `[Gubu ${opts.name} ${desc}]`;
48✔
732
    };
733
    if (util_1.inspect && util_1.inspect.custom) {
6,780!
734
        gubuShape[util_1.inspect.custom] = gubuShape.toString;
6,780✔
735
    }
736
    gubuShape.gubu = GUBU;
6,780✔
737
    // Validate shape spec. This will throw if there's an issue with the spec.
738
    gubuShape.spec();
6,780✔
739
    return gubuShape;
6,768✔
740
}
741
// Parse a builder expression into actual Builders.
742
// Function call syntax; Depth first; literals must be JSON values;
743
// Commas are optional. Top level builders are applied in order.
744
// Dot-concatenated builders are applied in order.
745
// Primary value is passed as Builder `this` context.
746
// Examples:
747
// Gubu({
748
//   'x: Open': {},
749
//   'y: Min(1) Max(4)': 2,
750
//   'z: Required(Min(1))': 2,
751
//   'q: Min(1).Below(4)': 3,
752
// })
753
function expr(spec) {
754
    let top = false;
324✔
755
    if (null == spec.tokens) {
324✔
756
        top = true;
156✔
757
        spec.tokens = [];
156✔
758
        let tre = /\s*,?\s*([)(\.]|"(\\.|[^"\\])*"|\/(\\.|[^\/\\])*\/[a-z]?|[^)(,\s]+)\s*/g;
156✔
759
        let t = null;
156✔
760
        while (t = tre.exec(spec.src)) {
156✔
761
            spec.tokens.push(t[1]);
600✔
762
        }
763
    }
764
    spec.i = spec.i || 0;
324✔
765
    let head = spec.tokens[spec.i];
324✔
766
    let fn = BuilderMap[head];
324✔
767
    if (')' === spec.tokens[spec.i]) {
324!
768
        spec.i++;
×
769
        return spec.val;
×
770
    }
771
    spec.i++;
324✔
772
    let fixed = {
324✔
773
        Number: Number,
774
        String: String,
775
        Boolean: Boolean,
776
    };
777
    if (null == fn) {
324✔
778
        try {
168✔
779
            let val = fixed[head];
168✔
780
            if (val) {
168✔
781
                return val;
36✔
782
            }
783
            else if ('undefined' === head) {
132!
784
                return undefined;
×
785
            }
786
            else if ('NaN' === head) {
132!
787
                return NaN;
×
788
            }
789
            else if (head.match(/^\/.+\/$/)) {
132✔
790
                return new RegExp(head.substring(1, head.length - 1));
12✔
791
            }
792
            else {
793
                return JSON.parse(head);
120✔
794
            }
795
        }
796
        catch (je) {
797
            throw new SyntaxError(`Gubu: unexpected token ${head} in builder expression ${spec.src}`);
12✔
798
        }
799
    }
800
    if ('(' === spec.tokens[spec.i]) {
156✔
801
        spec.i++;
132✔
802
    }
803
    let args = [];
156✔
804
    let t = null;
156✔
805
    while (null != (t = spec.tokens[spec.i]) && ')' !== t) {
156✔
806
        let ev = expr(spec);
144✔
807
        args.push(ev);
144✔
808
    }
809
    spec.i++;
156✔
810
    spec.val = fn.call(spec.val, ...args);
156✔
811
    // if (!cb && spec.i < spec.tokens.length) {
812
    if ('.' === spec.tokens[spec.i]) {
156✔
813
        spec.i++;
12✔
814
        return expr(spec);
12✔
815
    }
816
    else if (top && spec.i < spec.tokens.length) {
144✔
817
        return expr(spec);
12✔
818
    }
819
    return spec.val;
132✔
820
}
821
exports.expr = expr;
48✔
822
function handleValidate(vf, s) {
823
    var _a;
824
    let update = {};
12,480✔
825
    let valid = false;
12,480✔
826
    let thrown;
827
    try {
12,480✔
828
        // Check does not have to deal with `undefined`
829
        valid = undefined === s.val && ((_a = vf.gubu$) === null || _a === void 0 ? void 0 : _a.Check) ? true :
12,480✔
830
            (s.check = vf, vf(s.val, update, s));
831
    }
832
    catch (ve) {
833
        thrown = ve;
48✔
834
    }
835
    let hasErrs = isarr(update.err) ? 0 < update.err.length : null != update.err;
12,480✔
836
    if (!valid || hasErrs) {
12,480✔
837
        // Skip allows undefined
838
        if (undefined === s.val && (s.node.p || !s.node.r) && true !== update.done) {
5,856✔
839
            delete update.err;
3,444✔
840
            return update;
3,444✔
841
        }
842
        let w = update.why || 'check';
2,412✔
843
        let p = pathstr(s);
2,412✔
844
        if (S.string === typeof (update.err)) {
2,412✔
845
            s.curerr.push(makeErr(s, update.err));
24✔
846
        }
847
        else if (S.object === typeof (update.err)) {
2,388✔
848
            // Assumes makeErr already called
849
            s.curerr.push(...[update.err].flat().filter(e => null != e).map((e) => {
1,932✔
850
                e.p = null == e.p ? p : e.p;
1,932!
851
                e.m = null == e.m ? 2010 : e.m;
1,932!
852
                return e;
1,932✔
853
            }));
854
        }
855
        else {
856
            let fname = vf.name;
456✔
857
            if (null == fname || S.MT == fname) {
456✔
858
                fname = truncate(vf.toString().replace(/[ \t\r\n]+/g, ' '));
360✔
859
            }
860
            s.curerr.push(makeErrImpl(w, s, 1045, undefined, { thrown }, fname));
456✔
861
        }
862
        update.done = null == update.done ? true : update.done;
2,412✔
863
    }
864
    // Use uval for undefined and NaN
865
    if (update.hasOwnProperty('uval')) {
9,036✔
866
        s.updateVal(update.uval);
168✔
867
        s.ignoreVal = false;
168✔
868
    }
869
    else if (undefined !== update.val && !Number.isNaN(update.val)) {
8,868✔
870
        s.updateVal(update.val);
1,044✔
871
        s.ignoreVal = false;
1,044✔
872
    }
873
    if (undefined !== update.node) {
9,036✔
874
        s.node = update.node;
420✔
875
    }
876
    if (undefined !== update.type) {
9,036✔
877
        s.type = update.type;
420✔
878
    }
879
    return update;
9,036✔
880
}
881
// Create string description of property path, using "dot notation".
882
function pathstr(s) {
883
    return s.path.slice(1, s.dI + 1).filter(p => null != p).join('.');
18,888✔
884
}
885
function valueLen(val) {
886
    return S.number === typeof (val) ? val :
5,220✔
887
        S.number === typeof (val === null || val === void 0 ? void 0 : val.length) ? val.length :
17,040✔
888
            null != val && S.object === typeof (val) ? keys(val).length :
7,464✔
889
                NaN;
890
}
891
function truncate(str, len) {
892
    let strval = String(str);
19,092✔
893
    let outlen = null == len || isNaN(len) ? 30 : len < 0 ? 0 : ~~len;
19,092✔
894
    let strlen = null == str ? 0 : strval.length;
19,092✔
895
    let substr = null == str ? S.MT : strval.substring(0, strlen);
19,092✔
896
    substr = outlen < strlen ? substr.substring(0, outlen - 3) + '...' : substr;
19,092✔
897
    return substr.substring(0, outlen);
19,092✔
898
}
899
exports.truncate = truncate;
48✔
900
// Value is required.
901
const Required = function (shape) {
48✔
902
    let node = buildize(this, shape);
732✔
903
    node.r = true;
732✔
904
    node.p = false;
732✔
905
    // Handle an explicit undefined.
906
    if (undefined === shape && 1 === arguments.length) {
732✔
907
        node.t = S.undefined;
12✔
908
        node.v = undefined;
12✔
909
    }
910
    return node;
732✔
911
};
912
exports.Required = Required;
48✔
913
// Value can contain additional undeclared properties.
914
const Open = function (shape) {
48✔
915
    let node = buildize(this, shape);
396✔
916
    node.c = Any();
396✔
917
    return node;
396✔
918
};
919
exports.Open = Open;
48✔
920
// Value is optional.
921
const Optional = function (shape) {
48✔
922
    let node = buildize(this, shape);
564✔
923
    node.r = false;
564✔
924
    // Handle an explicit undefined.
925
    if (undefined === shape && 1 === arguments.length) {
564✔
926
        node.t = S.undefined;
36✔
927
        node.v = undefined;
36✔
928
    }
929
    return node;
564✔
930
};
931
exports.Optional = Optional;
48✔
932
// Value can be anything.
933
const Any = function (shape) {
48✔
934
    let node = buildize(this, shape);
1,284✔
935
    node.t = S.any;
1,284✔
936
    if (undefined !== shape) {
1,284✔
937
        node.v = shape;
24✔
938
        node.f = shape;
24✔
939
    }
940
    return node;
1,284✔
941
};
942
exports.Any = Any;
48✔
943
// Custom error message.
944
const Fault = function (msg, shape) {
48✔
945
    let node = buildize(this, shape);
×
946
    node.z = msg;
×
947
    return node;
×
948
};
949
exports.Fault = Fault;
48✔
950
// Value is skipped if not present (optional, but no default).
951
const Skip = function (shape) {
48✔
952
    let node = buildize(this, shape);
1,224✔
953
    node.r = false;
1,224✔
954
    // Do not insert empty arrays and objects.
955
    node.p = true;
1,224✔
956
    return node;
1,224✔
957
};
958
exports.Skip = Skip;
48✔
959
// Errors for this value are ignored, and the value is undefined.
960
const Ignore = function (shape) {
48✔
961
    let node = buildize(this, shape);
×
962
    node.r = false;
×
963
    // Do not insert empty arrays and objects.
964
    node.p = true;
×
965
    node.e = false;
×
966
    node.a.push(function Ignore(_val, update, state) {
×
967
        if (0 < state.curerr.length) {
×
968
            update.uval = undefined;
×
969
            update.done = false;
×
970
        }
971
        return true;
×
972
    });
973
    return node;
×
974
};
975
exports.Ignore = Ignore;
48✔
976
// Value must be a function.
977
const Func = function (shape) {
48✔
978
    let node = buildize(this);
36✔
979
    node.t = S.function;
36✔
980
    node.v = shape;
36✔
981
    node.f = shape;
36✔
982
    return node;
36✔
983
};
984
exports.Func = Func;
48✔
985
// Specify default value.
986
const Default = function (dval, shape) {
48✔
987
    let node = buildize(this, undefined === shape ? dval : shape);
96✔
988
    node.r = false;
96✔
989
    node.f = dval;
96✔
990
    let t = typeof dval;
96✔
991
    if (S.function === t && IS_TYPE[dval.name]) {
96✔
992
        node.t = dval.name.toLowerCase();
60✔
993
        node.f = clone(EMPTY_VAL[node.t]);
60✔
994
    }
995
    // Always insert default.
996
    node.p = false;
96✔
997
    return node;
96✔
998
};
999
exports.Default = Default;
48✔
1000
// String can be empty.
1001
const Empty = function (shape) {
48✔
1002
    let node = buildize(this, shape);
192✔
1003
    node.u.empty = true;
192✔
1004
    return node;
192✔
1005
};
1006
exports.Empty = Empty;
48✔
1007
// Value will never match anything.
1008
const Never = function (shape) {
48✔
1009
    let node = buildize(this, shape);
48✔
1010
    node.t = S.never;
48✔
1011
    return node;
48✔
1012
};
1013
exports.Never = Never;
48✔
1014
// Inject the key path of the value.
1015
const Key = function (depth, join) {
48✔
1016
    let node = buildize(this);
96✔
1017
    let ascend = 'number' === typeof depth;
96✔
1018
    node.t = S.string;
96✔
1019
    if (ascend && null == join) {
96✔
1020
        node = nodize([]);
48✔
1021
    }
1022
    let custom = null;
96✔
1023
    if ('function' === typeof depth) {
96✔
1024
        custom = depth;
12✔
1025
        node = Any();
12✔
1026
    }
1027
    node.b.push(function Key(_val, update, state) {
96✔
1028
        if (custom) {
192✔
1029
            update.val = custom(state.path, state);
24✔
1030
        }
1031
        else if (ascend) {
168✔
1032
            let d = depth;
120✔
1033
            update.val = state.path.slice(state.path.length - 1 - (0 <= d ? d : 0), state.path.length - 1 + (0 <= d ? 0 : 1));
120✔
1034
            if ('string' === typeof join) {
120✔
1035
                update.val = update.val.join(join);
24✔
1036
            }
1037
        }
1038
        else if (null == depth) {
48!
1039
            update.val = state.path[state.path.length - 2];
48✔
1040
        }
1041
        return true;
192✔
1042
    });
1043
    return node;
96✔
1044
};
1045
exports.Key = Key;
48✔
1046
// Pass only if all match. Does not short circuit (as defaults may be missed).
1047
const All = function (...inshapes) {
48✔
1048
    let node = buildize();
120✔
1049
    node.t = S.list;
120✔
1050
    node.r = true;
120✔
1051
    let shapes = inshapes.map(s => Gubu(s));
216✔
1052
    node.u.list = inshapes;
120✔
1053
    node.b.push(function All(val, update, state) {
120✔
1054
        let pass = true;
408✔
1055
        // let err: any = []
1056
        for (let shape of shapes) {
408✔
1057
            let subctx = { ...state.ctx, err: [] };
744✔
1058
            shape(val, subctx);
744✔
1059
            if (0 < subctx.err.length) {
744✔
1060
                pass = false;
204✔
1061
            }
1062
        }
1063
        if (!pass) {
408✔
1064
            update.why = S.All;
156✔
1065
            update.err = [
156✔
1066
                makeErr(state, S.Value + ' ' + S.$VALUE + S.forprop + S.$PATH +
1067
                    ' does not satisfy all of: ' +
1068
                    `${inshapes.map(x => stringify(x, null, true)).join(', ')}`)
312✔
1069
            ];
1070
        }
1071
        return pass;
408✔
1072
    });
1073
    return node;
120✔
1074
};
1075
exports.All = All;
48✔
1076
// Pass if some match.
1077
// TODO: UDPATE DOC: Does not short circuit (as defaults may be missed).
1078
const Some = function (...inshapes) {
48✔
1079
    let node = buildize();
84✔
1080
    node.t = S.list;
84✔
1081
    node.r = true;
84✔
1082
    let shapes = inshapes.map(s => Gubu(s));
168✔
1083
    node.u.list = inshapes;
84✔
1084
    node.b.push(function Some(val, update, state) {
84✔
1085
        let pass = false;
552✔
1086
        for (let shape of shapes) {
552✔
1087
            let subctx = { ...state.ctx, err: [] };
1,104✔
1088
            let match = shape.match(val, subctx);
1,104✔
1089
            if (match) {
1,104✔
1090
                update.val = shape(val, subctx);
432✔
1091
            }
1092
            pass || (pass = match);
1,104✔
1093
        }
1094
        if (!pass) {
552✔
1095
            update.why = S.Some;
132✔
1096
            update.err = [
132✔
1097
                makeErr(state, S.Value + ' ' + S.$VALUE + S.forprop + S.$PATH +
1098
                    ' does not satisfy any of: ' +
1099
                    `${inshapes.map(x => stringify(x, null, true)).join(', ')}`)
264✔
1100
            ];
1101
        }
1102
        return pass;
552✔
1103
    });
1104
    return node;
84✔
1105
};
1106
exports.Some = Some;
48✔
1107
// Pass if exactly one matches. Does not short circuit (as defaults may be missed).
1108
const One = function (...inshapes) {
48✔
1109
    let node = buildize();
84✔
1110
    node.t = S.list;
84✔
1111
    node.r = true;
84✔
1112
    let shapes = inshapes.map(s => Gubu(s));
180✔
1113
    node.u.list = inshapes;
84✔
1114
    node.b.push(function One(val, update, state) {
84✔
1115
        let passN = 0;
504✔
1116
        for (let shape of shapes) {
504✔
1117
            let subctx = { ...state.ctx, err: [] };
984✔
1118
            if (shape.match(val, subctx)) {
984✔
1119
                passN++;
228✔
1120
                update.val = shape(val, subctx);
228✔
1121
                // TODO: update docs - short circuits!
1122
                break;
228✔
1123
            }
1124
        }
1125
        if (1 !== passN) {
504✔
1126
            update.why = S.One;
276✔
1127
            update.err = [
276✔
1128
                makeErr(state, S.Value + ' ' + S.$VALUE + S.forprop + S.$PATH +
1129
                    ' does not satisfy one of: ' +
1130
                    `${inshapes.map(x => stringify(x, null, true)).join(', ')}`)
636✔
1131
            ];
1132
        }
1133
        return true;
504✔
1134
    });
1135
    return node;
84✔
1136
};
1137
exports.One = One;
48✔
1138
// Vlaue must match excatly one of the literal values provided.
1139
const Exact = function (...vals) {
48✔
1140
    let node = buildize();
168✔
1141
    node.b.push(function Exact(val, update, state) {
168✔
1142
        for (let i = 0; i < vals.length; i++) {
1,056✔
1143
            if (val === vals[i]) {
1,200✔
1144
                return true;
396✔
1145
            }
1146
        }
1147
        update.err =
660✔
1148
            makeErr(state, S.Value + ' ' + S.$VALUE + S.forprop + S.$PATH + ' must be exactly one of: ' +
1149
                `${state.node.s}.`);
1150
        update.done = true;
660✔
1151
        return false;
660✔
1152
    });
1153
    node.s = vals.map(v => stringify(v, null, true)).join(', ');
204✔
1154
    return node;
168✔
1155
};
1156
exports.Exact = Exact;
48✔
1157
// Define a custom operation to run before standard matching.
1158
const Before = function (validate, shape) {
48✔
1159
    let node = buildize(this, shape);
48✔
1160
    node.b.push(validate);
48✔
1161
    return node;
48✔
1162
};
1163
exports.Before = Before;
48✔
1164
// Define a custom operation to run after standard matching.
1165
const After = function (validate, shape) {
48✔
1166
    let node = buildize(this, shape);
372✔
1167
    node.a.push(validate);
372✔
1168
    return node;
372✔
1169
};
1170
exports.After = After;
48✔
1171
// Define a customer validation function.
1172
const Check = function (check, shape) {
48✔
1173
    let node = buildize(this, shape);
408✔
1174
    if (S.function === typeof check) {
408✔
1175
        let c$ = check;
324✔
1176
        c$.gubu$ = c$.gubu$ || {};
324✔
1177
        c$.gubu$.Check = true;
324✔
1178
        node.b.push(check);
324✔
1179
        node.s = (null == node.s ? S.MT : node.s + ';') + stringify(check, null, true);
324!
1180
        node.r = true;
324✔
1181
    }
1182
    else if (S.object === typeof check) {
84✔
1183
        let dstr = Object.prototype.toString.call(check);
60✔
1184
        if (dstr.includes('RegExp')) {
60!
1185
            let refn = (v) => (null == v || Number.isNaN(v)) ? false : !!String(v).match(check);
168✔
1186
            defprop(refn, S.name, {
60✔
1187
                value: String(check)
1188
            });
1189
            defprop(refn, 'gubu$', { value: { Check: true } });
60✔
1190
            node.b.push(refn);
60✔
1191
            node.s = stringify(check);
60✔
1192
            node.r = true;
60✔
1193
        }
1194
    }
1195
    // string is type name.
1196
    // TODO: validate check is ValType
1197
    else if (S.string === typeof check) {
24!
1198
        node.t = check;
24✔
1199
        node.r = true;
24✔
1200
    }
1201
    return node;
408✔
1202
};
1203
exports.Check = Check;
48✔
1204
// Value cannot contain undeclared properties or elements.
1205
const Closed = function (shape) {
48✔
1206
    let node = buildize(this, shape);
300✔
1207
    // Makes one element array fixed.
1208
    if (S.array === node.t && GUBU$NIL !== node.c && 0 === node.n) {
300✔
1209
        node.v = [node.c];
84✔
1210
        node.c = GUBU$NIL;
84✔
1211
    }
1212
    else {
1213
        node.c = GUBU$NIL;
216✔
1214
    }
1215
    return node;
300✔
1216
};
1217
exports.Closed = Closed;
48✔
1218
// Define a named reference to this value. See Refer.
1219
const Define = function (inopts, shape) {
48✔
1220
    let node = buildize(this, shape);
84✔
1221
    let opts = S.object === typeof inopts ? inopts || {} : {};
84!
1222
    let name = S.string === typeof inopts ? inopts : opts.name;
84!
1223
    if (null != name && S.MT != name) {
84!
1224
        node.b.push(function Define(_val, _update, state) {
84✔
1225
            let ref = state.ctx.ref = state.ctx.ref || {};
384✔
1226
            ref[name] = state.node;
384✔
1227
            return true;
384✔
1228
        });
1229
    }
1230
    return node;
84✔
1231
};
1232
exports.Define = Define;
48✔
1233
// TODO: copy option to copy value instead of node - need index of value in stack
1234
// Inject a referenced value. See Define.
1235
const Refer = function (inopts, shape) {
48✔
1236
    let node = buildize(this, shape);
120✔
1237
    let opts = S.object === typeof inopts ? inopts || {} : {};
120!
1238
    let name = S.string === typeof inopts ? inopts : opts.name;
120✔
1239
    // Fill should be false (the default) if used recursively, to prevent loops.
1240
    let fill = !!opts.fill;
120✔
1241
    if (null != name && S.MT != name) {
120!
1242
        node.b.push(function Refer(val, update, state) {
120✔
1243
            if (undefined !== val || fill) {
768✔
1244
                let ref = state.ctx.ref = state.ctx.ref || {};
420!
1245
                if (undefined !== ref[name]) {
420!
1246
                    let node = { ...ref[name] };
420✔
1247
                    node.t = node.t || S.never;
420!
1248
                    update.node = node;
420✔
1249
                    update.type = node.t;
420✔
1250
                }
1251
            }
1252
            // TODO: option to fail if ref not found?
1253
            return true;
768✔
1254
        });
1255
    }
1256
    return node;
120✔
1257
};
1258
exports.Refer = Refer;
48✔
1259
// TODO: no mutate is State.match
1260
// Rename a property.
1261
const Rename = function (inopts, shape) {
48✔
1262
    let node = buildize(this, shape);
84✔
1263
    let opts = S.object === typeof inopts ? inopts || {} : {};
84!
1264
    let name = S.string === typeof inopts ? inopts : opts.name;
84✔
1265
    let keep = 'boolean' === typeof opts.keep ? opts.keep : undefined;
84✔
1266
    // NOTE: Rename claims are experimental.
1267
    let claim = isarr(opts.claim) ? opts.claim : [];
84✔
1268
    if (null != name && S.MT != name) {
84!
1269
        // If there is a claim, grab the value so that validations
1270
        // can be applied to it.
1271
        let before = (val, update, s) => {
84✔
1272
            if (undefined === val && 0 < claim.length) {
384✔
1273
                s.ctx.Rename = (s.ctx.Rename || {});
24✔
1274
                s.ctx.Rename.fromDefault = (s.ctx.Rename.fromDefault || {});
24✔
1275
                for (let cn of claim) {
24✔
1276
                    let fromDefault = s.ctx.Rename.fromDefault[cn] || {};
24✔
1277
                    // Only use claim if it was not a default value.
1278
                    if (undefined !== s.parent[cn] && !fromDefault.yes) {
24✔
1279
                        update.val = s.parent[cn];
12✔
1280
                        if (!s.match) {
12!
1281
                            s.parent[name] = update.val;
12✔
1282
                        }
1283
                        update.node = fromDefault.node;
12✔
1284
                        // Old errors on the claimed value are no longer valid.
1285
                        for (let eI = 0; eI < s.err.length; eI++) {
12✔
1286
                            if (s.err[eI].k === fromDefault.key) {
×
1287
                                s.err.splice(eI, 1);
×
1288
                                eI--;
×
1289
                            }
1290
                        }
1291
                        if (!keep) {
12!
1292
                            delete s.parent[cn];
12✔
1293
                        }
1294
                        else {
1295
                            let j = s.cI + 1;
×
1296
                            // Add the default to the end of the node set to ensure it
1297
                            // is properly validated.
1298
                            s.nodes.splice(j, 0, nodize(fromDefault.dval));
×
1299
                            s.vals.splice(j, 0, undefined);
×
1300
                            s.parents.splice(j, 0, s.parent);
×
1301
                            s.keys.splice(j, 0, cn);
×
1302
                            s.nI++;
×
1303
                            s.pI++;
×
1304
                        }
1305
                        break;
12✔
1306
                    }
1307
                }
1308
                if (undefined === update.val) {
24✔
1309
                    update.val = s.node.v;
12✔
1310
                }
1311
            }
1312
            return true;
384✔
1313
        };
1314
        defprop(before, S.name, { value: 'Rename:' + name });
84✔
1315
        node.b.push(before);
84✔
1316
        let after = (val, update, s) => {
84✔
1317
            s.parent[name] = val;
384✔
1318
            if (!s.match &&
384✔
1319
                !keep &&
1320
                s.key !== name &&
1321
                // Arrays require explicit deletion as validation is based on index
1322
                // and will be lost.
1323
                !(isarr(s.parent) && false !== keep)) {
564✔
1324
                delete s.parent[s.key];
144✔
1325
                update.done = true;
144✔
1326
            }
1327
            s.ctx.Rename = (s.ctx.Rename || {});
384✔
1328
            s.ctx.Rename.fromDefault = (s.ctx.Rename.fromDefault || {});
384✔
1329
            s.ctx.Rename.fromDefault[name] = {
384✔
1330
                yes: s.fromDefault,
1331
                key: s.key,
1332
                dval: s.node.v,
1333
                node: s.node
1334
            };
1335
            return true;
384✔
1336
        };
1337
        defprop(after, S.name, { value: 'Rename:' + name });
84✔
1338
        node.a.push(after);
84✔
1339
    }
1340
    return node;
84✔
1341
};
1342
exports.Rename = Rename;
48✔
1343
// Specific a minimum value or length.
1344
const Min = function (min, shape) {
48✔
1345
    let node = buildize(this, shape);
156✔
1346
    node.b.push(function Min(val, update, state) {
156✔
1347
        let vlen = valueLen(val);
1,380✔
1348
        if (min <= vlen) {
1,380✔
1349
            return true;
324✔
1350
        }
1351
        state.checkargs = { min: 1 };
1,056✔
1352
        let errmsgpart = S.number === typeof (val) ? S.MT : 'length ';
1,056✔
1353
        update.err =
1,056✔
1354
            makeErr(state, S.Value + ' ' + S.$VALUE + S.forprop + S.$PATH +
1355
                ` must be a minimum ${errmsgpart}of ${min} (was ${vlen}).`);
1356
        return false;
1,056✔
1357
    });
1358
    node.s = S.Min + '(' + min + (null == shape ? S.MT :
156✔
1359
        (',' + stringify(shape))) + ')';
1360
    return node;
156✔
1361
};
1362
exports.Min = Min;
48✔
1363
// Specific a maximum value or length.
1364
const Max = function (max, shape) {
48✔
1365
    let node = buildize(this, shape);
168✔
1366
    node.b.push(function Max(val, update, state) {
168✔
1367
        let vlen = valueLen(val);
1,560✔
1368
        if (vlen <= max) {
1,560✔
1369
            return true;
420✔
1370
        }
1371
        let errmsgpart = S.number === typeof (val) ? S.MT : 'length ';
1,140✔
1372
        update.err =
1,140✔
1373
            makeErr(state, S.Value + ' ' + S.$VALUE + S.forprop + S.$PATH + ` must be a maximum ${errmsgpart}of ${max} (was ${vlen}).`);
1374
        return false;
1,140✔
1375
    });
1376
    node.s = S.Max + '(' + max + (null == shape ? S.MT : (',' + stringify(shape))) + ')';
168✔
1377
    return node;
168✔
1378
};
1379
exports.Max = Max;
48✔
1380
// Specify a lower bound value or length.
1381
const Above = function (above, shape) {
48✔
1382
    let node = buildize(this, shape);
108✔
1383
    node.b.push(function Above(val, update, state) {
108✔
1384
        let vlen = valueLen(val);
1,080✔
1385
        if (above < vlen) {
1,080✔
1386
            return true;
192✔
1387
        }
1388
        let errmsgpart = S.number === typeof (val) ? 'be' : 'have length';
888✔
1389
        update.err =
888✔
1390
            makeErr(state, S.Value + ' ' + S.$VALUE + S.forprop + S.$PATH + ` must ${errmsgpart} above ${above} (was ${vlen}).`);
1391
        return false;
888✔
1392
    });
1393
    node.s = S.Above + '(' + above + (null == shape ? S.MT : (',' + stringify(shape))) + ')';
108✔
1394
    return node;
108✔
1395
};
1396
exports.Above = Above;
48✔
1397
// Specify an upper bound value or length.
1398
const Below = function (below, shape) {
48✔
1399
    let node = buildize(this, shape);
72✔
1400
    node.b.push(function Below(val, update, state) {
72✔
1401
        let vlen = valueLen(val);
912✔
1402
        if (vlen < below) {
912✔
1403
            return true;
180✔
1404
        }
1405
        let errmsgpart = S.number === typeof (val) ? 'be' : 'have length';
732✔
1406
        update.err =
732✔
1407
            makeErr(state, S.Value + ' ' + S.$VALUE + S.forprop + S.$PATH + ` must ${errmsgpart} below ${below} (was ${vlen}).`);
1408
        return false;
732✔
1409
    });
1410
    node.s = S.Below + '(' + below + (null == shape ? S.MT : (',' + stringify(shape))) + ')';
72✔
1411
    return node;
72✔
1412
};
1413
exports.Below = Below;
48✔
1414
// Value must have a specific length.
1415
const Len = function (len, shape) {
48✔
1416
    let node = buildize(this, shape || Any());
60✔
1417
    node.b.push(function Len(val, update, state) {
60✔
1418
        let vlen = valueLen(val);
288✔
1419
        if (len === vlen) {
288✔
1420
            return true;
36✔
1421
        }
1422
        let errmsgpart = S.number === typeof (val) ? S.MT : ' in length';
252!
1423
        update.err =
252✔
1424
            makeErr(state, S.Value + ' ' + S.$VALUE + S.forprop + S.$PATH + ` must be exactly ${len}${errmsgpart} (was ${vlen}).`);
1425
        return false;
252✔
1426
    });
1427
    node.s = S.Len + '(' + len + (null == shape ? S.MT : (',' + stringify(shape))) + ')';
60✔
1428
    return node;
60✔
1429
};
1430
exports.Len = Len;
48✔
1431
// Children must have a specified shape.
1432
const Child = function (child, shape) {
48✔
1433
    let node = buildize(this, shape || {});
168✔
1434
    node.c = nodize(child);
168✔
1435
    return node;
168✔
1436
};
1437
exports.Child = Child;
48✔
1438
const Rest = function (child, shape) {
48✔
1439
    let node = buildize(this, shape || []);
144✔
1440
    node.t = 'array';
144✔
1441
    node.c = nodize(child);
144✔
1442
    node.m = node.m || {};
144!
1443
    node.m.rest = true;
144✔
1444
    // console.log('RN', node)
1445
    return node;
144✔
1446
};
1447
exports.Rest = Rest;
48✔
1448
// Make a Node chainable with Builder methods.
1449
function buildize(node0, node1) {
1450
    // Detect chaining. If not chained, ignore `this` if it is the global context.
1451
    let node = nodize(null == node0 || node0.window === node0 || node0.global === node0
7,452✔
1452
        ? node1 : node0);
1453
    // Only add chainable Builders.
1454
    // NOTE: One, Some, All not chainable.
1455
    return Object.assign(node, {
7,452✔
1456
        Above,
1457
        After,
1458
        Any,
1459
        Before,
1460
        Below,
1461
        Check,
1462
        Child,
1463
        Closed,
1464
        Define,
1465
        Empty,
1466
        Exact,
1467
        Fault,
1468
        Ignore,
1469
        Len,
1470
        Max,
1471
        Min,
1472
        Never,
1473
        Open,
1474
        Refer,
1475
        Rename,
1476
        Required,
1477
        Skip,
1478
        Rest,
1479
    });
1480
}
1481
exports.buildize = buildize;
48✔
1482
// External utility to make ErrDesc objects.
1483
function makeErr(state, text, why, user) {
1484
    return makeErrImpl(why || 'check', state, 4000, text, user);
5,340✔
1485
}
1486
exports.makeErr = makeErr;
48✔
1487
// TODO: optional message prefix from ctx
1488
// Internal utility to make ErrDesc objects.
1489
function makeErrImpl(why, s, mark, text, user, fname) {
1490
    var _a;
1491
    let err = {
16,476✔
1492
        k: s.key,
1493
        n: s.node,
1494
        v: s.val,
1495
        p: pathstr(s),
1496
        w: why,
1497
        c: ((_a = s.check) === null || _a === void 0 ? void 0 : _a.name) || 'none',
76,752✔
1498
        a: s.checkargs || {},
31,668✔
1499
        m: mark,
1500
        t: S.MT,
1501
        u: user || {},
31,596✔
1502
    };
1503
    let jstr = undefined === s.val ? 'undefined' : stringify(s.val);
16,476✔
1504
    let valstr = truncate(jstr.replace(/"/g, S.MT));
16,476✔
1505
    text = text || s.node.z;
16,476✔
1506
    if (null == text || S.MT === text) {
16,476✔
1507
        let valkind = valstr.startsWith('[') ? S.array :
11,136✔
1508
            valstr.startsWith('{') ? S.object :
10,704✔
1509
                (null == s.val || ('number' === typeof s.val && isNaN(s.val))
25,668✔
1510
                    ? 'value' : (typeof s.val));
1511
        let propkind = (valstr.startsWith('[') || isarr(s.parents[s.pI])) ?
11,136✔
1512
            'index' : 'property';
1513
        let propkindverb = 'is';
11,136✔
1514
        let propkey = user === null || user === void 0 ? void 0 : user.k;
11,136✔
1515
        propkey = isarr(propkey) ?
11,136✔
1516
            (propkind = (1 < propkey.length ?
660✔
1517
                (propkindverb = 'are', 'properties') : propkind),
1518
                propkey.join(', ')) :
1519
            propkey;
1520
        err.t = `Validation failed for ` +
11,136✔
1521
            (0 < err.p.length ? `${propkind} "${err.p}" with ` : S.MT) +
11,136✔
1522
            `${valkind} "${valstr}" because ` +
1523
            (S.type === why ? (S.instance === s.node.t ?
15,756✔
1524
                `the ${valkind} is not an instance of ${s.node.u.n} ` :
1525
                `the ${valkind} is not of type ${s.node.t}`) :
1526
                S.required === why ? (S.MT === s.val ? 'an empty string is not allowed' :
11,568✔
1527
                    `the ${valkind} is required`) :
1528
                    'closed' === why ?
1,464✔
1529
                        `the ${propkind} "${propkey}" ${propkindverb} not allowed` :
1530
                        S.never === why ? 'no value is allowed' :
564✔
1531
                            `check "${null == fname ? why : fname}" failed`) +
456!
1532
            (err.u.thrown ? ' (threw: ' + err.u.thrown.message + ')' : '.');
11,136✔
1533
    }
1534
    else {
1535
        err.t = text
5,340✔
1536
            .replace(/\$VALUE/g, valstr)
1537
            .replace(/\$PATH/g, err.p);
1538
    }
1539
    return err;
16,476✔
1540
}
1541
function node2str(n) {
1542
    return (null != n.s && S.MT !== n.s) ? n.s :
828✔
1543
        (!n.r && undefined !== n.v) ? n.v : n.t;
936✔
1544
}
1545
function stringify(src, replacer, dequote, expand) {
1546
    let str;
1547
    if (!expand &&
17,448✔
1548
        src && src.$ && (GUBU$ === src.$.gubu$ || true === src.$.gubu$)) {
1549
        src = node2str(src);
540✔
1550
    }
1551
    try {
17,448✔
1552
        str = JS(src, (key, val) => {
17,448✔
1553
            var _a, _b;
1554
            if (replacer) {
5,881,947✔
1555
                val = replacer(key, val);
5,868,255✔
1556
            }
1557
            if (null != val &&
5,881,946✔
1558
                S.object === typeof (val) &&
1559
                val.constructor &&
1560
                S.Object !== val.constructor.name &&
1561
                S.Array !== val.constructor.name) {
1562
                val =
492✔
1563
                    S.function === typeof val.toString ? val.toString() : val.constructor.name;
492!
1564
            }
1565
            else if (S.function === typeof (val)) {
5,881,451✔
1566
                if (S.function === typeof (make[val.name]) && isNaN(+key)) {
179,148✔
1567
                    val = undefined;
170,292✔
1568
                }
1569
                else if (null != val.name && S.MT !== val.name) {
8,856✔
1570
                    val = val.name;
7,908✔
1571
                }
1572
                else {
1573
                    val = truncate(val.toString().replace(/[ \t\r\n]+/g, ' '));
948✔
1574
                }
1575
            }
1576
            else if ('bigint' === typeof (val)) {
5,702,303✔
1577
                val = String(val.toString());
192✔
1578
            }
1579
            else if (Number.isNaN(val)) {
5,702,111✔
1580
                return 'NaN';
528✔
1581
            }
1582
            else if (true !== expand &&
5,701,583✔
1583
                (true === ((_a = val === null || val === void 0 ? void 0 : val.$) === null || _a === void 0 ? void 0 : _a.gubu$) || GUBU$ === ((_b = val === null || val === void 0 ? void 0 : val.$) === null || _b === void 0 ? void 0 : _b.gubu$))) {
139,560✔
1584
                val = node2str(val);
288✔
1585
            }
1586
            return val;
5,881,415✔
1587
        });
1588
        str = String(str);
17,412✔
1589
    }
1590
    catch (e) {
1591
        str = JS(String(src));
36✔
1592
    }
1593
    if (true === dequote) {
17,448✔
1594
        str = str.replace(/^"/, S.MT).replace(/"$/, S.MT);
1,740✔
1595
    }
1596
    return str;
17,448✔
1597
}
1598
exports.stringify = stringify;
48✔
1599
function clone(x) {
1600
    return null == x ? x : S.object !== typeof (x) ? x : JP(JS(x));
6,516✔
1601
}
1602
const G$ = (node) => nodize({
108✔
1603
    ...node,
1604
    $: { gubu$: true }
1605
});
1606
exports.G$ = G$;
48✔
1607
const BuilderMap = {
48✔
1608
    Above,
1609
    After,
1610
    All,
1611
    Any,
1612
    Before,
1613
    Below,
1614
    Check,
1615
    Child,
1616
    Closed,
1617
    Default,
1618
    Define,
1619
    Empty,
1620
    Exact,
1621
    Fault,
1622
    Func,
1623
    Ignore,
1624
    Key,
1625
    Len,
1626
    Max,
1627
    Min,
1628
    Never,
1629
    One,
1630
    Open,
1631
    Optional,
1632
    Refer,
1633
    Rename,
1634
    Required,
1635
    Skip,
1636
    Some,
1637
    Rest,
1638
};
1639
// Fix builder names after terser mangles them.
1640
/* istanbul ignore next */
1641
if (S.undefined !== typeof (window)) {
1642
    for (let builderName in BuilderMap) {
1643
        defprop(BuilderMap[builderName], S.name, { value: builderName });
1644
    }
1645
}
1646
Object.assign(make, {
48✔
1647
    Gubu: make,
1648
    // Builders by name, allows `const { Open } = Gubu`.
1649
    ...BuilderMap,
1650
    // Builders by alias, allows `const { GOpen } = Gubu`, to avoid naming conflicts.
1651
    ...(Object.entries(BuilderMap).reduce((a, n) => (a['G' + n[0]] = n[1], a), {})),
1,440✔
1652
    isShape: (v) => (v && GUBU === v.gubu),
×
1653
    G$,
1654
    buildize,
1655
    makeErr,
1656
    stringify,
1657
    truncate,
1658
    nodize,
1659
    expr,
1660
    MakeArgu,
1661
});
1662
defprop(make, S.name, { value: S.gubu });
48✔
1663
// The primary export.
1664
const Gubu = make;
48✔
1665
exports.Gubu = Gubu;
48✔
1666
// "G" Namespaced builders for convenient use in case of conflicts.
1667
const GAbove = Above;
48✔
1668
exports.GAbove = GAbove;
48✔
1669
const GAfter = After;
48✔
1670
exports.GAfter = GAfter;
48✔
1671
const GAll = All;
48✔
1672
exports.GAll = GAll;
48✔
1673
const GAny = Any;
48✔
1674
exports.GAny = GAny;
48✔
1675
const GBefore = Before;
48✔
1676
exports.GBefore = GBefore;
48✔
1677
const GBelow = Below;
48✔
1678
exports.GBelow = GBelow;
48✔
1679
const GCheck = Check;
48✔
1680
exports.GCheck = GCheck;
48✔
1681
const GChild = Child;
48✔
1682
exports.GChild = GChild;
48✔
1683
const GRest = Rest;
48✔
1684
exports.GRest = GRest;
48✔
1685
const GClosed = Closed;
48✔
1686
exports.GClosed = GClosed;
48✔
1687
const GDefault = Default;
48✔
1688
exports.GDefault = GDefault;
48✔
1689
const GDefine = Define;
48✔
1690
exports.GDefine = GDefine;
48✔
1691
const GEmpty = Empty;
48✔
1692
exports.GEmpty = GEmpty;
48✔
1693
const GExact = Exact;
48✔
1694
exports.GExact = GExact;
48✔
1695
const GFault = Fault;
48✔
1696
exports.GFault = GFault;
48✔
1697
const GFunc = Func;
48✔
1698
exports.GFunc = GFunc;
48✔
1699
const GIgnore = Ignore;
48✔
1700
exports.GIgnore = GIgnore;
48✔
1701
const GKey = Key;
48✔
1702
exports.GKey = GKey;
48✔
1703
const GLen = Len;
48✔
1704
exports.GLen = GLen;
48✔
1705
const GMax = Max;
48✔
1706
exports.GMax = GMax;
48✔
1707
const GMin = Min;
48✔
1708
exports.GMin = GMin;
48✔
1709
const GNever = Never;
48✔
1710
exports.GNever = GNever;
48✔
1711
const GOne = One;
48✔
1712
exports.GOne = GOne;
48✔
1713
const GOpen = Open;
48✔
1714
exports.GOpen = GOpen;
48✔
1715
const GOptional = Optional;
48✔
1716
exports.GOptional = GOptional;
48✔
1717
const GRefer = Refer;
48✔
1718
exports.GRefer = GRefer;
48✔
1719
const GRename = Rename;
48✔
1720
exports.GRename = GRename;
48✔
1721
const GRequired = Required;
48✔
1722
exports.GRequired = GRequired;
48✔
1723
const GSkip = Skip;
48✔
1724
exports.GSkip = GSkip;
48✔
1725
const GSome = Some;
48✔
1726
exports.GSome = GSome;
48✔
1727
function MakeArgu(prefix) {
1728
    // TODO: caching, make arguments optionals
1729
    return function Argu(args, whence, argSpec) {
24✔
1730
        let partial = false;
168✔
1731
        if ('string' === typeof args) {
168!
1732
            partial = true;
×
1733
            argSpec = whence;
×
1734
            whence = args;
×
1735
        }
1736
        argSpec = argSpec || whence;
168!
1737
        whence = 'string' === typeof whence ? ' (' + whence + ')' : '';
168!
1738
        const shape = Gubu(argSpec, { prefix: prefix + whence });
168✔
1739
        // let shapeSpec = shape.spec()
1740
        // console.dir(shapeSpec, { depth: null })
1741
        const top = shape.node();
168✔
1742
        // console.dir(top, { depth: null })
1743
        const keys = top.k;
168✔
1744
        let argmap = {};
168✔
1745
        let kI = 0;
168✔
1746
        // console.log('KEYS', keys)
1747
        for (; kI < keys.length; kI++) {
168✔
1748
            let kn = top.v[keys[kI]];
624✔
1749
            // console.log('KEY', kI, keys[kI], kn.m.rest)
1750
            // Skip in arg shape means a literal skip,
1751
            // shifting all following agument elements down.
1752
            if (kn.p) {
624✔
1753
                // if (0 === kI) {
1754
                kn = top.v[keys[kI]] =
288✔
1755
                    ((kI) => After(function Skipper(_val, update, state) {
288✔
1756
                        // console.log('Skipper', kI, keys[kI], state.curerr.length)
1757
                        if (0 < state.curerr.length) {
288✔
1758
                            // console.log('AMS A', argmap, keys)
1759
                            for (let sI = keys.length - 1; sI > kI; sI--) {
144✔
1760
                                // console.log('KS', keys[sI], sI, kI, 'S', state.pI, state.pI + sI)
1761
                                // Subtract kI as state.pI has already advanced kI along val list.
1762
                                // If Rest, append to array at correct position.
1763
                                if (top.v[keys[sI]].m.rest) {
360✔
1764
                                    argmap[keys[sI]]
144✔
1765
                                        .splice(top.v[keys[sI]].m.rest_pos + kI - sI, 0, argmap[keys[sI - 1]]);
1766
                                }
1767
                                else {
1768
                                    state.vals[state.pI + sI - kI] = state.vals[state.pI + sI - kI - 1];
216✔
1769
                                    argmap[keys[sI]] = argmap[keys[sI - 1]];
216✔
1770
                                }
1771
                                // console.log('AMS S', sI, argmap)
1772
                            }
1773
                            update.uval = undefined;
144✔
1774
                            update.done = false;
144✔
1775
                            // console.log('AMS B', kI, argmap)
1776
                        }
1777
                        return true;
288✔
1778
                    }, kn))(kI);
1779
                kn.e = false;
288✔
1780
            }
1781
        }
1782
        // console.dir(shape.node(), { depth: null })
1783
        // ONLY if last prop is Rest  - make in meta
1784
        // if (kI < args.length) {
1785
        // argmap[keys[kI - 1]] = [...args].slice(kI - 1)
1786
        // }
1787
        function buildArgMap(args) {
1788
            for (let kI = 0; kI < keys.length; kI++) {
168✔
1789
                let kn = top.v[keys[kI]];
624✔
1790
                if (kn.m.rest) {
624✔
1791
                    argmap[keys[kI]] = [...args].slice(kI);
144✔
1792
                    kn.m.rest_pos = argmap[keys[kI]].length;
144✔
1793
                }
1794
                else {
1795
                    argmap[keys[kI]] = args[kI];
480✔
1796
                }
1797
            }
1798
            // console.log('AM', argmap)
1799
            return argmap;
168✔
1800
        }
1801
        return partial ?
168!
1802
            function PartialArgu(args) {
1803
                argmap = {};
×
1804
                kI = 0;
×
1805
                return shape(buildArgMap(args));
×
1806
            } :
1807
            shape(buildArgMap(args));
1808
    };
1809
}
1810
exports.MakeArgu = MakeArgu;
48✔
1811
//# sourceMappingURL=gubu.js.map
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc