lib0 1.0.0-rc.23 → 1.0.0-rc.26
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/dist/schema.d.ts +37 -14
- package/package.json +5 -5
- package/src/delta/delta.js +18 -0
- package/src/environment.common.js +2 -1
- package/src/schema.js +95 -19
package/dist/schema.d.ts
CHANGED
|
@@ -191,21 +191,15 @@ export const $$constructedBy: Schema<$ConstructedBy<(new (...args: any[]) => any
|
|
|
191
191
|
*/
|
|
192
192
|
export class $Custom extends Schema<any> {
|
|
193
193
|
/**
|
|
194
|
-
* @param {(o:any) => boolean} check
|
|
194
|
+
* @param {(o:any,err?:ValidationError) => boolean} check
|
|
195
195
|
*/
|
|
196
|
-
constructor(check: (o: any) => boolean);
|
|
196
|
+
constructor(check: (o: any, err?: ValidationError) => boolean);
|
|
197
197
|
/**
|
|
198
|
-
* @type {(o:any) => boolean}
|
|
198
|
+
* @type {(o:any,err?:ValidationError) => boolean}
|
|
199
199
|
*/
|
|
200
|
-
shape: (o: any) => boolean;
|
|
201
|
-
/**
|
|
202
|
-
* @param {any} o
|
|
203
|
-
* @param {ValidationError} err
|
|
204
|
-
* @return {o is any}
|
|
205
|
-
*/
|
|
206
|
-
check(o: any, err: ValidationError): o is any;
|
|
200
|
+
shape: (o: any, err?: ValidationError) => boolean;
|
|
207
201
|
}
|
|
208
|
-
export function $custom(check: (o: any) => boolean): Schema<any>;
|
|
202
|
+
export function $custom(check: (o: any, err?: ValidationError) => boolean): Schema<any>;
|
|
209
203
|
export const $$custom: Schema<$Custom>;
|
|
210
204
|
/**
|
|
211
205
|
* @template {Primitive} T
|
|
@@ -220,6 +214,7 @@ export class $Literal<T extends Primitive> extends Schema<T> {
|
|
|
220
214
|
}
|
|
221
215
|
export function $literal<T extends Primitive[]>(...literals: T): CastToSchema<$Literal<T[number]>>;
|
|
222
216
|
export const $$literal: Schema<$Literal<Primitive>>;
|
|
217
|
+
export function $$literalWith<T extends Primitive[]>(...literals: T): Schema<CastToSchema<$Literal<T[number]>>>;
|
|
223
218
|
/**
|
|
224
219
|
* @template {Array<string|Schema<string|number>>} T
|
|
225
220
|
* @extends {Schema<CastStringTemplateArgsToTemplate<T>>}
|
|
@@ -295,6 +290,10 @@ export function $partial<S extends {
|
|
|
295
290
|
[key: string | symbol | number]: any;
|
|
296
291
|
}>(def: S): Schema<Partial<_ObjectDefToSchema<S>>>;
|
|
297
292
|
/**
|
|
293
|
+
* Matches plain objects only - `{}`-literals and `Object.create(null)` objects, not class
|
|
294
|
+
* instances. The check is prototype-based, not `o.constructor === Object`, because a plain
|
|
295
|
+
* object may declare an own property named "constructor".
|
|
296
|
+
*
|
|
298
297
|
* @type {Schema<{[key:string]: any}>}
|
|
299
298
|
*/
|
|
300
299
|
export const $objectAny: Schema<{
|
|
@@ -480,6 +479,22 @@ export const $$symbol: Schema<Schema<Symbol>>;
|
|
|
480
479
|
*/
|
|
481
480
|
export const $number: Schema<number>;
|
|
482
481
|
export const $$number: Schema<Schema<number>>;
|
|
482
|
+
/**
|
|
483
|
+
* A number without fractional component (`Number.isInteger`). The unwrapped type is still
|
|
484
|
+
* `number` - JS has no separate integer type.
|
|
485
|
+
*
|
|
486
|
+
* @type {Schema<number>}
|
|
487
|
+
*/
|
|
488
|
+
export const $int: Schema<number>;
|
|
489
|
+
export const $$int: Schema<Schema<number>>;
|
|
490
|
+
/**
|
|
491
|
+
* An unsigned integer: a number without fractional component that is `>= 0`. The unwrapped type is
|
|
492
|
+
* still `number` - JS has no separate integer type.
|
|
493
|
+
*
|
|
494
|
+
* @type {Schema<number>}
|
|
495
|
+
*/
|
|
496
|
+
export const $uint: Schema<number>;
|
|
497
|
+
export const $$uint: Schema<Schema<number>>;
|
|
483
498
|
/**
|
|
484
499
|
* @type {Schema<string>}
|
|
485
500
|
*/
|
|
@@ -490,18 +505,26 @@ export const $$string: Schema<Schema<string>>;
|
|
|
490
505
|
*/
|
|
491
506
|
export const $boolean: Schema<boolean>;
|
|
492
507
|
export const $$boolean: Schema<Schema<boolean>>;
|
|
508
|
+
/**
|
|
509
|
+
* `$true`, `$false`, `$undefined` & `$null` are plain `$Literal`s (no own `$type`), so the generic
|
|
510
|
+
* `$$literal` handling covers them in `random`, `coerce` & error messages.
|
|
511
|
+
*
|
|
512
|
+
* @type {Schema<true>}
|
|
513
|
+
*/
|
|
514
|
+
export const $true: Schema<true>;
|
|
515
|
+
/**
|
|
516
|
+
* @type {Schema<false>}
|
|
517
|
+
*/
|
|
518
|
+
export const $false: Schema<false>;
|
|
493
519
|
/**
|
|
494
520
|
* @type {Schema<undefined>}
|
|
495
521
|
*/
|
|
496
522
|
export const $undefined: Schema<undefined>;
|
|
497
|
-
export const $$undefined: Schema<Schema<undefined>>;
|
|
498
523
|
/**
|
|
499
524
|
* @type {Schema<void>}
|
|
500
525
|
*/
|
|
501
526
|
export const $void: Schema<void>;
|
|
502
|
-
export const $$void: Schema<Schema<void>>;
|
|
503
527
|
export const $null: Schema<null>;
|
|
504
|
-
export const $$null: Schema<Schema<null>>;
|
|
505
528
|
export const $uint8Array: Schema<Uint8Array<ArrayBuffer>>;
|
|
506
529
|
export const $$uint8Array: Schema<Schema<Uint8Array>>;
|
|
507
530
|
export const $promise: Schema<Promise<unknown>>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lib0",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "1.0.0-rc.26",
|
|
4
|
+
"description": "isomorphic utility functions",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"funding": {
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"url": "https://github.com/sponsors/dmonad"
|
|
10
10
|
},
|
|
11
11
|
"bin": {
|
|
12
|
-
"0gentesthtml": "
|
|
13
|
-
"0serve": "
|
|
14
|
-
"0ecdsa-generate-keypair": "
|
|
12
|
+
"0gentesthtml": "src/bin/gentesthtml.js",
|
|
13
|
+
"0serve": "src/bin/0serve.js",
|
|
14
|
+
"0ecdsa-generate-keypair": "src/bin/0ecdsa-generate-keypair.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"dist/**/*.d.ts",
|
package/src/delta/delta.js
CHANGED
|
@@ -822,6 +822,10 @@ export class ModifyOp extends list.ListNode {
|
|
|
822
822
|
* @return {ModifyOp<DTypes>}
|
|
823
823
|
*/
|
|
824
824
|
clone (_start = 0, _end = 1, markAsDone = true) {
|
|
825
|
+
// `markAsDone=false` is currently unreachable: only `_splitOp` passes `false`, and a length-1
|
|
826
|
+
// modify is never split (apply's `move ? op : op.clone(0, 1, keep)` evaluates the clone only when
|
|
827
|
+
// `keep` is true). Kept for the uniform children-op `clone` signature.
|
|
828
|
+
/* c8 ignore next */
|
|
825
829
|
return new ModifyOp(/** @type {DTypes} */ (markAsDone ? this.value.done() : this.value), _cloneAttrs(this.format), _cloneAttrs(this.attribution))
|
|
826
830
|
}
|
|
827
831
|
}
|
|
@@ -2847,6 +2851,11 @@ const applyDim = (op, field, update) => {
|
|
|
2847
2851
|
// additionally merges its nested `format` key one level (see {@link mergeAttr}); format stays shallow.
|
|
2848
2852
|
const cur = /** @type {any} */ (op)[field]
|
|
2849
2853
|
const merged = field === 'attribution' ? mergeAttr(cur, update, false) : object.assign({}, cur, update)
|
|
2854
|
+
// the empty-merge guard is currently unreachable: a stored `update` is canonical (the builder's
|
|
2855
|
+
// combine strips `{k:undefined}` keys and drops empty objects to `undefined`, which `applyDim`
|
|
2856
|
+
// already returned on), and a verbatim (non-resolving) merge never removes keys — so `merged`
|
|
2857
|
+
// keeps at least one key of `update`. Kept to document that an empty result means skip.
|
|
2858
|
+
/* c8 ignore next */
|
|
2850
2859
|
;/** @type {any} */ (op)[field] = object.isEmpty(merged) ? undefined : merged
|
|
2851
2860
|
} else if (field === 'attribution') {
|
|
2852
2861
|
// data op, attribution: resolve per key; the nested `format` key merges one level (see {@link mergeAttr})
|
|
@@ -2857,6 +2866,9 @@ const applyDim = (op, field, update) => {
|
|
|
2857
2866
|
let f = /** @type {any} */ (op)[field]
|
|
2858
2867
|
for (const k in update) {
|
|
2859
2868
|
const v = update[k]
|
|
2869
|
+
// the skip is currently unreachable: a stored `update` never carries a `{k:undefined}` key
|
|
2870
|
+
// (the builder's combine strips them). Kept for the unified tri-state contract.
|
|
2871
|
+
/* c8 ignore next */
|
|
2860
2872
|
if (v === undefined) continue // skip this key
|
|
2861
2873
|
if (v === null) { // remove this key (no-op when the stored value is already `null`)
|
|
2862
2874
|
if (f !== null) {
|
|
@@ -2915,6 +2927,9 @@ const diffDim = (aVal, bVal, deep) => {
|
|
|
2915
2927
|
* @param {{[k:string]:any}|null|undefined} attributionUpdate
|
|
2916
2928
|
*/
|
|
2917
2929
|
const updateOpFormat = (op, formatUpdate, attributionUpdate) => {
|
|
2930
|
+
// defensive: apply's walk never passes a delete op (the initial `opsI` skips leading deletes and
|
|
2931
|
+
// every advance goes through `opNextUndeleted`)
|
|
2932
|
+
/* c8 ignore next */
|
|
2918
2933
|
if ($deleteOp.check(op)) return
|
|
2919
2934
|
const changedF = applyDim(op, 'format', formatUpdate)
|
|
2920
2935
|
const changedA = applyDim(op, 'attribution', attributionUpdate)
|
|
@@ -2960,6 +2975,9 @@ const cmpKey = (a, b) =>
|
|
|
2960
2975
|
* @param {Mark} a
|
|
2961
2976
|
* @param {Mark} b
|
|
2962
2977
|
*/
|
|
2978
|
+
// the `: 0` id tie is unreachable: a Marks set is deduplicated by id (`add` replaces), so the sort
|
|
2979
|
+
// never compares two marks with the same id
|
|
2980
|
+
/* c8 ignore next */
|
|
2963
2981
|
const cmpMarkKey = (a, b) => cmpKey(a.key, b.key) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)
|
|
2964
2982
|
|
|
2965
2983
|
/**
|
|
@@ -31,7 +31,7 @@ export const globalScope = /* @__PURE__ */(() =>/** @type {any} */ (typeof globa
|
|
|
31
31
|
* which has `btoa`/`atob`/`fetch` but no DOM). Excludes Node and Deno.
|
|
32
32
|
* @type {boolean}
|
|
33
33
|
*/
|
|
34
|
-
/* c8 ignore
|
|
34
|
+
/* c8 ignore start */
|
|
35
35
|
export const isBrowser = /* @__PURE__ */(() =>
|
|
36
36
|
!isNode && !isDeno && (
|
|
37
37
|
(typeof window !== 'undefined' && typeof document !== 'undefined') ||
|
|
@@ -39,3 +39,4 @@ export const isBrowser = /* @__PURE__ */(() =>
|
|
|
39
39
|
(typeof globalScope.WorkerGlobalScope !== 'undefined' && globalScope.self instanceof globalScope.WorkerGlobalScope)
|
|
40
40
|
)
|
|
41
41
|
)()
|
|
42
|
+
/* c8 ignore stop */
|
package/src/schema.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as arr from './array.js'
|
|
8
|
+
import * as buffer from './buffer.js'
|
|
8
9
|
import * as error from './error.js'
|
|
9
10
|
import * as equalityTraits from './trait/equality.js'
|
|
10
11
|
import * as fun from './function.js'
|
|
@@ -356,23 +357,23 @@ export const $$constructedBy = $type('s:$ConstructedBy', $ConstructedBy)
|
|
|
356
357
|
*/
|
|
357
358
|
export class $Custom extends Schema {
|
|
358
359
|
/**
|
|
359
|
-
* @param {(o:any) => boolean} check
|
|
360
|
+
* @param {(o:any,err?:ValidationError) => boolean} check
|
|
360
361
|
*/
|
|
361
362
|
constructor (check) {
|
|
362
363
|
super()
|
|
363
364
|
/**
|
|
364
|
-
* @type {(o:any) => boolean}
|
|
365
|
+
* @type {(o:any,err?:ValidationError) => boolean}
|
|
365
366
|
*/
|
|
366
367
|
this.shape = check
|
|
367
368
|
}
|
|
368
369
|
|
|
369
370
|
/**
|
|
370
371
|
* @param {any} o
|
|
371
|
-
* @param {ValidationError} err
|
|
372
|
+
* @param {ValidationError} [err]
|
|
372
373
|
* @return {o is any}
|
|
373
374
|
*/
|
|
374
375
|
check (o, err) {
|
|
375
|
-
const c = this.shape(o)
|
|
376
|
+
const c = this.shape(o, err)
|
|
376
377
|
/* c8 ignore next */
|
|
377
378
|
!c && err?.extend(null, 'custom prop', o?.constructor.name, 'failed to check custom prop')
|
|
378
379
|
return c
|
|
@@ -380,7 +381,7 @@ export class $Custom extends Schema {
|
|
|
380
381
|
}
|
|
381
382
|
|
|
382
383
|
/**
|
|
383
|
-
* @param {(o:any) => boolean} check
|
|
384
|
+
* @param {(o:any,err?:ValidationError) => boolean} check
|
|
384
385
|
* @return {Schema<any>}
|
|
385
386
|
*/
|
|
386
387
|
/* @__NO_SIDE_EFFECTS__ */
|
|
@@ -423,6 +424,17 @@ export class $Literal extends Schema {
|
|
|
423
424
|
export const $literal = (...literals) => new $Literal(literals)
|
|
424
425
|
export const $$literal = $type('s:$Literal', $Literal)
|
|
425
426
|
|
|
427
|
+
/**
|
|
428
|
+
* Meta schema that matches a `$Literal` whose shape is exactly `literals` - e.g.
|
|
429
|
+
* `$$literalWith(null).check($null)` or `.if($$literalWith(true), ..)` in a pattern matcher.
|
|
430
|
+
*
|
|
431
|
+
* @template {Primitive[]} T
|
|
432
|
+
* @param {T} literals
|
|
433
|
+
* @return {Schema<CastToSchema<$Literal<T[number]>>>}
|
|
434
|
+
*/
|
|
435
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
436
|
+
export const $$literalWith = (...literals) => $custom((o, err) => $$literal.check(o, err) && o.shape.length === literals.length && arr.every(o.shape, (l, i) => l === literals[i]))
|
|
437
|
+
|
|
426
438
|
/**
|
|
427
439
|
* @template {Array<string|Schema<string|number>>} Ts
|
|
428
440
|
* @typedef {Ts extends [] ? `` : (Ts extends [infer T] ? (Unwrap<T> extends (string|number) ? Unwrap<T> : never) : (Ts extends [infer T1, ...infer Rest] ? `${Unwrap<T1> extends (string|number) ? Unwrap<T1> : never}${Rest extends Array<string|Schema<string|number>> ? CastStringTemplateArgsToTemplate<Rest> : never}` : never))} CastStringTemplateArgsToTemplate
|
|
@@ -623,9 +635,17 @@ export const $$object = /* @__PURE__ */$type('s:$Object', $Object)
|
|
|
623
635
|
export const $partial = def => /** @type {any} */ (new $Object(def, true))
|
|
624
636
|
|
|
625
637
|
/**
|
|
638
|
+
* Matches plain objects only - `{}`-literals and `Object.create(null)` objects, not class
|
|
639
|
+
* instances. The check is prototype-based, not `o.constructor === Object`, because a plain
|
|
640
|
+
* object may declare an own property named "constructor".
|
|
641
|
+
*
|
|
626
642
|
* @type {Schema<{[key:string]: any}>}
|
|
627
643
|
*/
|
|
628
|
-
export const $objectAny = $custom(o =>
|
|
644
|
+
export const $objectAny = $custom(o => {
|
|
645
|
+
if (o == null) return false
|
|
646
|
+
const proto = Object.getPrototypeOf(o)
|
|
647
|
+
return proto === Object.prototype || proto === null
|
|
648
|
+
})
|
|
629
649
|
|
|
630
650
|
/**
|
|
631
651
|
* @template {Schema<string|number|symbol>} Keys
|
|
@@ -1007,6 +1027,24 @@ export const $$symbol = /** @type {Schema<Schema<Symbol>>} */ (/* @__PURE__ */$t
|
|
|
1007
1027
|
export const $number = /* @__PURE__ */$custom(o => typeof o === 'number')
|
|
1008
1028
|
export const $$number = /** @type {Schema<Schema<number>>} */ (/* @__PURE__ */$type('s:$number', $number))
|
|
1009
1029
|
|
|
1030
|
+
/**
|
|
1031
|
+
* A number without fractional component (`Number.isInteger`). The unwrapped type is still
|
|
1032
|
+
* `number` - JS has no separate integer type.
|
|
1033
|
+
*
|
|
1034
|
+
* @type {Schema<number>}
|
|
1035
|
+
*/
|
|
1036
|
+
export const $int = /* @__PURE__ */$custom(o => number.isInteger(o))
|
|
1037
|
+
export const $$int = /** @type {Schema<Schema<number>>} */ (/* @__PURE__ */$type('s:$int', $int))
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* An unsigned integer: a number without fractional component that is `>= 0`. The unwrapped type is
|
|
1041
|
+
* still `number` - JS has no separate integer type.
|
|
1042
|
+
*
|
|
1043
|
+
* @type {Schema<number>}
|
|
1044
|
+
*/
|
|
1045
|
+
export const $uint = /* @__PURE__ */$custom(o => number.isInteger(o) && o >= 0)
|
|
1046
|
+
export const $$uint = /** @type {Schema<Schema<number>>} */ (/* @__PURE__ */$type('s:$uint', $uint))
|
|
1047
|
+
|
|
1010
1048
|
/**
|
|
1011
1049
|
* @type {Schema<string>}
|
|
1012
1050
|
*/
|
|
@@ -1019,20 +1057,30 @@ export const $$string = /** @type {Schema<Schema<string>>} */ (/* @__PURE__ */$t
|
|
|
1019
1057
|
export const $boolean = /* @__PURE__ */$custom(o => typeof o === 'boolean')
|
|
1020
1058
|
export const $$boolean = /** @type {Schema<Schema<Boolean>>} */ (/* @__PURE__ */$type('s:$boolean', $boolean))
|
|
1021
1059
|
|
|
1060
|
+
/**
|
|
1061
|
+
* `$true`, `$false`, `$undefined` & `$null` are plain `$Literal`s (no own `$type`), so the generic
|
|
1062
|
+
* `$$literal` handling covers them in `random`, `coerce` & error messages.
|
|
1063
|
+
*
|
|
1064
|
+
* @type {Schema<true>}
|
|
1065
|
+
*/
|
|
1066
|
+
export const $true = /* @__PURE__ */$literal(true)
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* @type {Schema<false>}
|
|
1070
|
+
*/
|
|
1071
|
+
export const $false = /* @__PURE__ */$literal(false)
|
|
1072
|
+
|
|
1022
1073
|
/**
|
|
1023
1074
|
* @type {Schema<undefined>}
|
|
1024
1075
|
*/
|
|
1025
1076
|
export const $undefined = /* @__PURE__ */$literal(undefined)
|
|
1026
|
-
export const $$undefined = /** @type {Schema<Schema<undefined>>} */ (/* @__PURE__ */$type('s:$undefined', $undefined))
|
|
1027
1077
|
|
|
1028
1078
|
/**
|
|
1029
1079
|
* @type {Schema<void>}
|
|
1030
1080
|
*/
|
|
1031
1081
|
export const $void = $undefined
|
|
1032
|
-
export const $$void = /** @type {Schema<Schema<void>>} */ ($$undefined)
|
|
1033
1082
|
|
|
1034
1083
|
export const $null = $literal(null)
|
|
1035
|
-
export const $$null = /** @type {Schema<Schema<null>>} */ ($type('s:$null', $null))
|
|
1036
1084
|
|
|
1037
1085
|
export const $uint8Array = $constructedBy(Uint8Array)
|
|
1038
1086
|
export const $$uint8Array = /** @type {Schema<Schema<Uint8Array>>} */ ($type('s:$uint8Array', $uint8Array))
|
|
@@ -1165,9 +1213,10 @@ export const match = state => new PatternMatcher(/** @type {any} */ (state))
|
|
|
1165
1213
|
*/
|
|
1166
1214
|
const _random = /* @__PURE__ */ (() => match({ gen: /** @type {Schema<prng.PRNG>} */ ($any), fallback: $lambda($any, $any, $any).optional })
|
|
1167
1215
|
.if($$number, (_o, { gen }) => prng.oneOf(gen, [-1, 0, 1, prng.int53(gen, number.MIN_SAFE_INTEGER, number.MAX_SAFE_INTEGER)]))
|
|
1216
|
+
.if($$int, (_o, { gen }) => prng.oneOf(gen, [-1, 0, 1, prng.int53(gen, number.MIN_SAFE_INTEGER, number.MAX_SAFE_INTEGER)]))
|
|
1217
|
+
.if($$uint, (_o, { gen }) => prng.oneOf(gen, [0, 1, prng.int53(gen, 0, number.MAX_SAFE_INTEGER)]))
|
|
1168
1218
|
.if($$string, (_o, { gen }) => prng.word(gen))
|
|
1169
1219
|
.if($$boolean, (_o, { gen }) => prng.bool(gen))
|
|
1170
|
-
.if($$undefined, (_o) => undefined)
|
|
1171
1220
|
.if($$bigint, (_o, { gen }) => BigInt(prng.int53(gen, number.MIN_SAFE_INTEGER, number.MAX_SAFE_INTEGER)))
|
|
1172
1221
|
.if($$union, (o, opts) => _random(prng.oneOf(opts.gen, o.shape), opts))
|
|
1173
1222
|
.if($$object, (o, opts) => {
|
|
@@ -1199,9 +1248,6 @@ const _random = /* @__PURE__ */ (() => match({ gen: /** @type {Schema<prng.PRNG>
|
|
|
1199
1248
|
.if($$literal, (o, { gen }) => {
|
|
1200
1249
|
return prng.oneOf(gen, o.shape)
|
|
1201
1250
|
})
|
|
1202
|
-
.if($$null, (_o) => {
|
|
1203
|
-
return null
|
|
1204
|
-
})
|
|
1205
1251
|
.if($$lambda, (o, opts) => {
|
|
1206
1252
|
const res = _random(o.res, opts)
|
|
1207
1253
|
return () => res
|
|
@@ -1259,6 +1305,8 @@ const _failed = Symbol('schema:coercion failed')
|
|
|
1259
1305
|
|
|
1260
1306
|
const _bigintRegex = /^[+-]?\d+$/
|
|
1261
1307
|
|
|
1308
|
+
const _base64Regex = /^[A-Za-z0-9+/]+={0,2}$/
|
|
1309
|
+
|
|
1262
1310
|
/**
|
|
1263
1311
|
* Render a value for an error message. Objects are only rendered by kind - printing them adds
|
|
1264
1312
|
* noise (and `String` throws on null-prototype objects).
|
|
@@ -1322,10 +1370,12 @@ const _nameOf = $s => {
|
|
|
1322
1370
|
if (_isMeta($$any, $s)) return 'any'
|
|
1323
1371
|
if (_isMeta($$string, $s)) return 'string'
|
|
1324
1372
|
if (_isMeta($$number, $s)) return 'number'
|
|
1373
|
+
if (_isMeta($$int, $s)) return 'int'
|
|
1374
|
+
if (_isMeta($$uint, $s)) return 'uint'
|
|
1325
1375
|
if (_isMeta($$bigint, $s)) return 'bigint'
|
|
1326
1376
|
if (_isMeta($$boolean, $s)) return 'boolean'
|
|
1327
1377
|
if (_isMeta($$symbol, $s)) return 'symbol'
|
|
1328
|
-
if (_isMeta($$literal, $s)
|
|
1378
|
+
if (_isMeta($$literal, $s)) {
|
|
1329
1379
|
return /** @type {Array<Primitive>} */ (shape).map(l => String(l)).join(' | ')
|
|
1330
1380
|
}
|
|
1331
1381
|
if (_isMeta($$optional, $s)) return `${_nameOf(shape)} | undefined`
|
|
@@ -1342,8 +1392,7 @@ const _nameOf = $s => {
|
|
|
1342
1392
|
|
|
1343
1393
|
/**
|
|
1344
1394
|
* Compile a coercer for `$s`. Dispatches on the meta schemas (`$$string`, `$$object`, ..) which are
|
|
1345
|
-
* an exact identity check.
|
|
1346
|
-
* `$null` & `$undefined` are `$Literal` instances that are only distinguishable by their `$type`.
|
|
1395
|
+
* an exact identity check.
|
|
1347
1396
|
*
|
|
1348
1397
|
* @param {Schema<any>} $s
|
|
1349
1398
|
* @param {Map<Schema<any>,_Coercer>} cache
|
|
@@ -1373,6 +1422,18 @@ const _createCoercer = ($s, cache) => {
|
|
|
1373
1422
|
return _fail(ctx, path, o, expected)
|
|
1374
1423
|
}
|
|
1375
1424
|
}
|
|
1425
|
+
if (_isMeta($$int, $s) || _isMeta($$uint, $s)) {
|
|
1426
|
+
const min = _isMeta($$uint, $s) ? 0 : -Infinity
|
|
1427
|
+
return (o, path, ctx) => {
|
|
1428
|
+
if (number.isInteger(o) && o >= min) return o
|
|
1429
|
+
const t = typeof o
|
|
1430
|
+
if (t === 'boolean' || t === 'bigint' || (t === 'string' && o.trim() !== '')) {
|
|
1431
|
+
const n = Number(o)
|
|
1432
|
+
if (number.isInteger(n) && n >= min) return n
|
|
1433
|
+
}
|
|
1434
|
+
return _fail(ctx, path, o, expected)
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1376
1437
|
if (_isMeta($$bigint, $s)) {
|
|
1377
1438
|
return (o, path, ctx) => {
|
|
1378
1439
|
const t = typeof o
|
|
@@ -1388,7 +1449,21 @@ const _createCoercer = ($s, cache) => {
|
|
|
1388
1449
|
? o
|
|
1389
1450
|
: (o === 'true' ? true : (o === 'false' ? false : _fail(ctx, path, o, expected)))
|
|
1390
1451
|
}
|
|
1391
|
-
if (_isMeta($$
|
|
1452
|
+
if (_isMeta($$uint8Array, $s)) {
|
|
1453
|
+
// the format is checked here (rather than left to the decoder) because the `buffer.fromBase64`
|
|
1454
|
+
// backends disagree on invalid input: `Buffer` silently ignores unexpected characters, `atob` &
|
|
1455
|
+
// `Uint8Array.fromBase64` throw
|
|
1456
|
+
return (o, path, ctx) => {
|
|
1457
|
+
if ($uint8Array.check(o)) return o
|
|
1458
|
+
if (typeof o !== 'string' || !_base64Regex.test(o)) return _fail(ctx, path, o, expected)
|
|
1459
|
+
// base64 encodes 3 bytes as 4 characters. The '=' padding is optional, but when it is there
|
|
1460
|
+
// the length has to be a multiple of 4 - and without it the last chunk must not be a single
|
|
1461
|
+
// character, which carries no full byte.
|
|
1462
|
+
const rest = o.length % 4
|
|
1463
|
+
return (o.endsWith('=') ? rest === 0 : rest !== 1) ? buffer.fromBase64(o) : _fail(ctx, path, o, expected)
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
if (_isMeta($$literal, $s)) {
|
|
1392
1467
|
const literals = /** @type {Array<Primitive>} */ (shape)
|
|
1393
1468
|
return (o, path, ctx) => {
|
|
1394
1469
|
if (arr.some(literals, l => l === o)) return o
|
|
@@ -1530,8 +1605,9 @@ const _buildCoercer = ($s, cache) => {
|
|
|
1530
1605
|
* Unlike `check` (which only validates) a coercion converts values that don't match yet - `'42'`
|
|
1531
1606
|
* becomes `42` for `$number`, `'true'` becomes `true` for `$boolean`. Values that already match
|
|
1532
1607
|
* are returned untouched (including object identity). Containers (`$object`, `$array`, `$record`,
|
|
1533
|
-
* `$tuple`, `$union`, `$optional`) are coerced recursively.
|
|
1534
|
-
*
|
|
1608
|
+
* `$tuple`, `$union`, `$optional`) are coerced recursively. `$uint8Array` accepts a base64 string
|
|
1609
|
+
* (padding optional) - the inverse of `buffer.toBase64`. Schemas without a meaningful conversion
|
|
1610
|
+
* (`$instanceOf`, `$custom`, ..) simply have to match.
|
|
1535
1611
|
*
|
|
1536
1612
|
* Failures are returned instead of thrown - this is the only api in lib0 that reports errors as a
|
|
1537
1613
|
* value.
|