lib0 1.0.0-rc.25 → 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 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,6 +1,6 @@
1
1
  {
2
2
  "name": "lib0",
3
- "version": "1.0.0-rc.25",
3
+ "version": "1.0.0-rc.26",
4
4
  "description": "isomorphic utility functions",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -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
  /**
package/src/schema.js CHANGED
@@ -357,23 +357,23 @@ export const $$constructedBy = $type('s:$ConstructedBy', $ConstructedBy)
357
357
  */
358
358
  export class $Custom extends Schema {
359
359
  /**
360
- * @param {(o:any) => boolean} check
360
+ * @param {(o:any,err?:ValidationError) => boolean} check
361
361
  */
362
362
  constructor (check) {
363
363
  super()
364
364
  /**
365
- * @type {(o:any) => boolean}
365
+ * @type {(o:any,err?:ValidationError) => boolean}
366
366
  */
367
367
  this.shape = check
368
368
  }
369
369
 
370
370
  /**
371
371
  * @param {any} o
372
- * @param {ValidationError} err
372
+ * @param {ValidationError} [err]
373
373
  * @return {o is any}
374
374
  */
375
375
  check (o, err) {
376
- const c = this.shape(o)
376
+ const c = this.shape(o, err)
377
377
  /* c8 ignore next */
378
378
  !c && err?.extend(null, 'custom prop', o?.constructor.name, 'failed to check custom prop')
379
379
  return c
@@ -381,7 +381,7 @@ export class $Custom extends Schema {
381
381
  }
382
382
 
383
383
  /**
384
- * @param {(o:any) => boolean} check
384
+ * @param {(o:any,err?:ValidationError) => boolean} check
385
385
  * @return {Schema<any>}
386
386
  */
387
387
  /* @__NO_SIDE_EFFECTS__ */
@@ -424,6 +424,17 @@ export class $Literal extends Schema {
424
424
  export const $literal = (...literals) => new $Literal(literals)
425
425
  export const $$literal = $type('s:$Literal', $Literal)
426
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
+
427
438
  /**
428
439
  * @template {Array<string|Schema<string|number>>} Ts
429
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
@@ -624,9 +635,17 @@ export const $$object = /* @__PURE__ */$type('s:$Object', $Object)
624
635
  export const $partial = def => /** @type {any} */ (new $Object(def, true))
625
636
 
626
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
+ *
627
642
  * @type {Schema<{[key:string]: any}>}
628
643
  */
629
- export const $objectAny = $custom(o => o != null && (o.constructor === Object || o.constructor == null))
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
+ })
630
649
 
631
650
  /**
632
651
  * @template {Schema<string|number|symbol>} Keys
@@ -1008,6 +1027,24 @@ export const $$symbol = /** @type {Schema<Schema<Symbol>>} */ (/* @__PURE__ */$t
1008
1027
  export const $number = /* @__PURE__ */$custom(o => typeof o === 'number')
1009
1028
  export const $$number = /** @type {Schema<Schema<number>>} */ (/* @__PURE__ */$type('s:$number', $number))
1010
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
+
1011
1048
  /**
1012
1049
  * @type {Schema<string>}
1013
1050
  */
@@ -1020,20 +1057,30 @@ export const $$string = /** @type {Schema<Schema<string>>} */ (/* @__PURE__ */$t
1020
1057
  export const $boolean = /* @__PURE__ */$custom(o => typeof o === 'boolean')
1021
1058
  export const $$boolean = /** @type {Schema<Schema<Boolean>>} */ (/* @__PURE__ */$type('s:$boolean', $boolean))
1022
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
+
1023
1073
  /**
1024
1074
  * @type {Schema<undefined>}
1025
1075
  */
1026
1076
  export const $undefined = /* @__PURE__ */$literal(undefined)
1027
- export const $$undefined = /** @type {Schema<Schema<undefined>>} */ (/* @__PURE__ */$type('s:$undefined', $undefined))
1028
1077
 
1029
1078
  /**
1030
1079
  * @type {Schema<void>}
1031
1080
  */
1032
1081
  export const $void = $undefined
1033
- export const $$void = /** @type {Schema<Schema<void>>} */ ($$undefined)
1034
1082
 
1035
1083
  export const $null = $literal(null)
1036
- export const $$null = /** @type {Schema<Schema<null>>} */ ($type('s:$null', $null))
1037
1084
 
1038
1085
  export const $uint8Array = $constructedBy(Uint8Array)
1039
1086
  export const $$uint8Array = /** @type {Schema<Schema<Uint8Array>>} */ ($type('s:$uint8Array', $uint8Array))
@@ -1166,9 +1213,10 @@ export const match = state => new PatternMatcher(/** @type {any} */ (state))
1166
1213
  */
1167
1214
  const _random = /* @__PURE__ */ (() => match({ gen: /** @type {Schema<prng.PRNG>} */ ($any), fallback: $lambda($any, $any, $any).optional })
1168
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)]))
1169
1218
  .if($$string, (_o, { gen }) => prng.word(gen))
1170
1219
  .if($$boolean, (_o, { gen }) => prng.bool(gen))
1171
- .if($$undefined, (_o) => undefined)
1172
1220
  .if($$bigint, (_o, { gen }) => BigInt(prng.int53(gen, number.MIN_SAFE_INTEGER, number.MAX_SAFE_INTEGER)))
1173
1221
  .if($$union, (o, opts) => _random(prng.oneOf(opts.gen, o.shape), opts))
1174
1222
  .if($$object, (o, opts) => {
@@ -1200,9 +1248,6 @@ const _random = /* @__PURE__ */ (() => match({ gen: /** @type {Schema<prng.PRNG>
1200
1248
  .if($$literal, (o, { gen }) => {
1201
1249
  return prng.oneOf(gen, o.shape)
1202
1250
  })
1203
- .if($$null, (_o) => {
1204
- return null
1205
- })
1206
1251
  .if($$lambda, (o, opts) => {
1207
1252
  const res = _random(o.res, opts)
1208
1253
  return () => res
@@ -1325,10 +1370,12 @@ const _nameOf = $s => {
1325
1370
  if (_isMeta($$any, $s)) return 'any'
1326
1371
  if (_isMeta($$string, $s)) return 'string'
1327
1372
  if (_isMeta($$number, $s)) return 'number'
1373
+ if (_isMeta($$int, $s)) return 'int'
1374
+ if (_isMeta($$uint, $s)) return 'uint'
1328
1375
  if (_isMeta($$bigint, $s)) return 'bigint'
1329
1376
  if (_isMeta($$boolean, $s)) return 'boolean'
1330
1377
  if (_isMeta($$symbol, $s)) return 'symbol'
1331
- if (_isMeta($$literal, $s) || _isMeta($$null, $s) || _isMeta($$undefined, $s)) {
1378
+ if (_isMeta($$literal, $s)) {
1332
1379
  return /** @type {Array<Primitive>} */ (shape).map(l => String(l)).join(' | ')
1333
1380
  }
1334
1381
  if (_isMeta($$optional, $s)) return `${_nameOf(shape)} | undefined`
@@ -1345,8 +1392,7 @@ const _nameOf = $s => {
1345
1392
 
1346
1393
  /**
1347
1394
  * Compile a coercer for `$s`. Dispatches on the meta schemas (`$$string`, `$$object`, ..) which are
1348
- * an exact identity check. The order matters: `$string` & friends are `$Custom` instances and
1349
- * `$null` & `$undefined` are `$Literal` instances that are only distinguishable by their `$type`.
1395
+ * an exact identity check.
1350
1396
  *
1351
1397
  * @param {Schema<any>} $s
1352
1398
  * @param {Map<Schema<any>,_Coercer>} cache
@@ -1376,6 +1422,18 @@ const _createCoercer = ($s, cache) => {
1376
1422
  return _fail(ctx, path, o, expected)
1377
1423
  }
1378
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
+ }
1379
1437
  if (_isMeta($$bigint, $s)) {
1380
1438
  return (o, path, ctx) => {
1381
1439
  const t = typeof o
@@ -1405,7 +1463,7 @@ const _createCoercer = ($s, cache) => {
1405
1463
  return (o.endsWith('=') ? rest === 0 : rest !== 1) ? buffer.fromBase64(o) : _fail(ctx, path, o, expected)
1406
1464
  }
1407
1465
  }
1408
- if (_isMeta($$literal, $s) || _isMeta($$null, $s) || _isMeta($$undefined, $s)) {
1466
+ if (_isMeta($$literal, $s)) {
1409
1467
  const literals = /** @type {Array<Primitive>} */ (shape)
1410
1468
  return (o, path, ctx) => {
1411
1469
  if (arr.some(literals, l => l === o)) return o