lib0 1.0.0-rc.21 → 1.0.0-rc.23
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/array.d.ts +4 -4
- package/dist/broadcastchannel.d.ts +3 -3
- package/dist/decoding.d.ts +3 -3
- package/dist/delta/delta.d.ts +0 -8
- package/dist/delta/rdt/dom.d.ts +19 -25
- package/dist/delta/rdt.d.ts +24 -0
- package/dist/diff.d.ts +1 -1
- package/dist/encoding.d.ts +4 -4
- package/dist/environment.common.d.ts +21 -0
- package/dist/environment.d.ts +2 -8
- package/dist/error.d.ts +21 -3
- package/dist/eventloop.d.ts +1 -1
- package/dist/indexeddb.d.ts +3 -3
- package/dist/indexeddbV2.d.ts +3 -3
- package/dist/iterator.d.ts +3 -3
- package/dist/list.d.ts +6 -6
- package/dist/logging.common.d.ts +1 -1
- package/dist/logging.d.ts +1 -1
- package/dist/logging.node.d.ts +1 -1
- package/dist/map.d.ts +4 -4
- package/dist/object.d.ts +2 -2
- package/dist/observable.d.ts +2 -2
- package/dist/pair.d.ts +2 -2
- package/dist/pledge.d.ts +10 -10
- package/dist/promise.d.ts +2 -2
- package/dist/schema.d.ts +19 -1
- package/dist/sort.d.ts +3 -3
- package/dist/storage.d.ts +2 -2
- package/dist/testing.d.ts +18 -11
- package/package.json +3 -3
- package/src/array.js +5 -5
- package/src/broadcastchannel.js +4 -4
- package/src/cache.js +1 -1
- package/src/decoding.js +2 -2
- package/src/delta/delta.js +13 -26
- package/src/delta/rdt/dom.js +176 -63
- package/src/delta/rdt.js +39 -10
- package/src/diff.js +1 -1
- package/src/encoding.js +2 -2
- package/src/environment.common.js +41 -0
- package/src/environment.js +2 -21
- package/src/error.js +10 -4
- package/src/eventloop.js +3 -3
- package/src/function.js +1 -1
- package/src/indexeddb.js +4 -4
- package/src/indexeddbV2.js +4 -4
- package/src/iterator.js +4 -4
- package/src/list.js +4 -4
- package/src/logging.common.js +3 -3
- package/src/logging.js +3 -3
- package/src/logging.node.js +3 -3
- package/src/map.js +4 -4
- package/src/mutex.js +2 -2
- package/src/object.js +2 -2
- package/src/observable.js +1 -1
- package/src/pair.js +2 -2
- package/src/pledge.js +6 -6
- package/src/promise.js +3 -3
- package/src/schema.js +316 -3
- package/src/sort.js +4 -4
- package/src/storage.js +8 -4
- package/src/testing.js +15 -15
package/src/promise.js
CHANGED
|
@@ -14,13 +14,13 @@ import * as time from './time.js'
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* @template T
|
|
17
|
-
* @param {
|
|
17
|
+
* @param {(resolve: PromiseResolve<T>, reject: (err: Error) => void) => any} f
|
|
18
18
|
* @return {Promise<T>}
|
|
19
19
|
*/
|
|
20
20
|
export const create = f => /** @type {Promise<T>} */ (new Promise(f))
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
|
-
* @param {
|
|
23
|
+
* @param {(resolve: () => void, reject: (err: Error) => void) => void} f
|
|
24
24
|
* @return {Promise<void>}
|
|
25
25
|
*/
|
|
26
26
|
export const createEmpty = f => new Promise(f)
|
|
@@ -59,7 +59,7 @@ export const resolveWith = res => Promise.resolve(res)
|
|
|
59
59
|
* @deprecated use untilAsync instead
|
|
60
60
|
*
|
|
61
61
|
* @param {number} timeout
|
|
62
|
-
* @param {
|
|
62
|
+
* @param {() => boolean} check
|
|
63
63
|
* @param {number} [intervalResolution]
|
|
64
64
|
* @return {Promise<void>}
|
|
65
65
|
*/
|
package/src/schema.js
CHANGED
|
@@ -228,7 +228,7 @@ export class Schema {
|
|
|
228
228
|
* Can be useful when defining lambdas: `s.lambda(s.$number, s.$number).expect((n) => n + 1)`
|
|
229
229
|
*
|
|
230
230
|
* @param {T} o
|
|
231
|
-
* @return {
|
|
231
|
+
* @return {T extends T ? T : never}
|
|
232
232
|
*/
|
|
233
233
|
expect (o) {
|
|
234
234
|
assert(o, this)
|
|
@@ -1058,8 +1058,8 @@ export const $primitive = $union($number, $string, $null, $undefined, $bigint, $
|
|
|
1058
1058
|
* @type {Schema<null|number|string|boolean|JSON[]|{[key:string]:JSON}>}
|
|
1059
1059
|
*/
|
|
1060
1060
|
export const $json = /* @__PURE__ */(() => {
|
|
1061
|
-
const $jsonArr = /** @type {$Array
|
|
1062
|
-
const $jsonRecord = /** @type {$Record
|
|
1061
|
+
const $jsonArr = /** @type {$Array<typeof $any>} */ ($array($any))
|
|
1062
|
+
const $jsonRecord = /** @type {$Record<typeof $string,typeof $any>} */ ($record($string, $any))
|
|
1063
1063
|
const $json = $union($number, $string, $null, $boolean, $jsonArr, $jsonRecord)
|
|
1064
1064
|
$jsonArr.shape = $json
|
|
1065
1065
|
$jsonRecord.shape.values = $json
|
|
@@ -1241,3 +1241,316 @@ const _random = /* @__PURE__ */ (() => match({ gen: /** @type {Schema<prng.PRNG>
|
|
|
1241
1241
|
*/
|
|
1242
1242
|
/* @__NO_SIDE_EFFECTS__ */
|
|
1243
1243
|
export const random = (gen, schema, fallback) => /* @__PURE__ */_random($(schema), { gen, fallback })
|
|
1244
|
+
|
|
1245
|
+
/**
|
|
1246
|
+
* Carries the reason of a failed coercion out of the recursion.
|
|
1247
|
+
*
|
|
1248
|
+
* @typedef {{ err: string }} _CoerceCtx
|
|
1249
|
+
*/
|
|
1250
|
+
|
|
1251
|
+
/**
|
|
1252
|
+
* A compiled coercer. Returns the coerced value, or `_failed` after writing the reason to
|
|
1253
|
+
* `ctx.err`.
|
|
1254
|
+
*
|
|
1255
|
+
* @typedef {(o:any, path:string, ctx:_CoerceCtx) => any} _Coercer
|
|
1256
|
+
*/
|
|
1257
|
+
|
|
1258
|
+
const _failed = Symbol('schema:coercion failed')
|
|
1259
|
+
|
|
1260
|
+
const _bigintRegex = /^[+-]?\d+$/
|
|
1261
|
+
|
|
1262
|
+
/**
|
|
1263
|
+
* Render a value for an error message. Objects are only rendered by kind - printing them adds
|
|
1264
|
+
* noise (and `String` throws on null-prototype objects).
|
|
1265
|
+
*
|
|
1266
|
+
* @param {any} o
|
|
1267
|
+
* @return {string}
|
|
1268
|
+
*/
|
|
1269
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
1270
|
+
const _show = o => typeof o === 'string'
|
|
1271
|
+
? JSON.stringify(o)
|
|
1272
|
+
: (o !== null && object.isObject(o) ? (arr.isArray(o) ? 'array' : 'object') : String(o))
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* @param {_CoerceCtx} ctx
|
|
1276
|
+
* @param {string} path
|
|
1277
|
+
* @param {any} o
|
|
1278
|
+
* @param {string} expected
|
|
1279
|
+
* @return {typeof _failed}
|
|
1280
|
+
*/
|
|
1281
|
+
const _fail = (ctx, path, o, expected) => {
|
|
1282
|
+
ctx.err = `${path === '' ? '' : `[${path}] `}${_show(o)} doesn't match ${expected}`
|
|
1283
|
+
return _failed
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
/**
|
|
1287
|
+
* @param {string} path
|
|
1288
|
+
* @param {string} key
|
|
1289
|
+
*/
|
|
1290
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
1291
|
+
const _prop = (path, key) => path === '' ? key : `${path}.${key}`
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* @param {string} path
|
|
1295
|
+
* @param {number} i
|
|
1296
|
+
*/
|
|
1297
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
1298
|
+
const _idx = (path, i) => path === '' ? `${i}` : `${path}[${i}]`
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* `$$x.check` is a type predicate. Dispatching through this indirection keeps `$s` from being
|
|
1302
|
+
* narrowed to `never` in the negative branches of the coercer dispatch.
|
|
1303
|
+
*
|
|
1304
|
+
* @param {Schema<any>} $meta
|
|
1305
|
+
* @param {Schema<any>} $s
|
|
1306
|
+
* @return {boolean}
|
|
1307
|
+
*/
|
|
1308
|
+
const _isMeta = ($meta, $s) => $meta.check($s)
|
|
1309
|
+
|
|
1310
|
+
/**
|
|
1311
|
+
* A short, human readable name for a schema - used in coercion error messages.
|
|
1312
|
+
*
|
|
1313
|
+
* Only `$union` & `$optional` are descended into (`$union` flattens nested unions, so this
|
|
1314
|
+
* terminates). Container shapes are *not* descended into - that's what makes this safe on
|
|
1315
|
+
* self-referential schemas like `$json`.
|
|
1316
|
+
*
|
|
1317
|
+
* @param {Schema<any>} $s
|
|
1318
|
+
* @return {string}
|
|
1319
|
+
*/
|
|
1320
|
+
const _nameOf = $s => {
|
|
1321
|
+
const shape = /** @type {any} */ ($s).shape
|
|
1322
|
+
if (_isMeta($$any, $s)) return 'any'
|
|
1323
|
+
if (_isMeta($$string, $s)) return 'string'
|
|
1324
|
+
if (_isMeta($$number, $s)) return 'number'
|
|
1325
|
+
if (_isMeta($$bigint, $s)) return 'bigint'
|
|
1326
|
+
if (_isMeta($$boolean, $s)) return 'boolean'
|
|
1327
|
+
if (_isMeta($$symbol, $s)) return 'symbol'
|
|
1328
|
+
if (_isMeta($$literal, $s) || _isMeta($$null, $s) || _isMeta($$undefined, $s)) {
|
|
1329
|
+
return /** @type {Array<Primitive>} */ (shape).map(l => String(l)).join(' | ')
|
|
1330
|
+
}
|
|
1331
|
+
if (_isMeta($$optional, $s)) return `${_nameOf(shape)} | undefined`
|
|
1332
|
+
if (_isMeta($$union, $s)) return /** @type {Array<Schema<any>>} */ (shape).map(_nameOf).join(' | ')
|
|
1333
|
+
if (_isMeta($$object, $s)) return 'object'
|
|
1334
|
+
if (_isMeta($$record, $s)) return 'record'
|
|
1335
|
+
if (_isMeta($$tuple, $s)) return 'tuple'
|
|
1336
|
+
if (_isMeta($$array, $s)) return 'array'
|
|
1337
|
+
// `instanceof` instead of the meta schemas: `$uint8Array` & `$promise` overwrite their inherited
|
|
1338
|
+
// `$type` with a more specific one, so `_isMeta($$constructedBy, ..)` doesn't hold for them
|
|
1339
|
+
if ($s instanceof $ConstructedBy || $s instanceof $InstanceOf) return shape.name
|
|
1340
|
+
return $s.constructor.name
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
/**
|
|
1344
|
+
* Compile a coercer for `$s`. Dispatches on the meta schemas (`$$string`, `$$object`, ..) which are
|
|
1345
|
+
* an exact identity check. The order matters: `$string` & friends are `$Custom` instances and
|
|
1346
|
+
* `$null` & `$undefined` are `$Literal` instances that are only distinguishable by their `$type`.
|
|
1347
|
+
*
|
|
1348
|
+
* @param {Schema<any>} $s
|
|
1349
|
+
* @param {Map<Schema<any>,_Coercer>} cache
|
|
1350
|
+
* @return {_Coercer}
|
|
1351
|
+
*/
|
|
1352
|
+
const _createCoercer = ($s, cache) => {
|
|
1353
|
+
// `shape` is only defined on the subclasses - see the comment on `Schema`
|
|
1354
|
+
const shape = /** @type {any} */ ($s).shape
|
|
1355
|
+
const expected = _nameOf($s)
|
|
1356
|
+
if (_isMeta($$any, $s)) {
|
|
1357
|
+
return o => o
|
|
1358
|
+
}
|
|
1359
|
+
if (_isMeta($$string, $s)) {
|
|
1360
|
+
return (o, path, ctx) => {
|
|
1361
|
+
const t = typeof o
|
|
1362
|
+
return t === 'string' ? o : (t === 'number' || t === 'bigint' || t === 'boolean' ? o + '' : _fail(ctx, path, o, expected))
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
if (_isMeta($$number, $s)) {
|
|
1366
|
+
return (o, path, ctx) => {
|
|
1367
|
+
const t = typeof o
|
|
1368
|
+
if (t === 'number') return o
|
|
1369
|
+
if (t === 'boolean' || t === 'bigint' || (t === 'string' && o.trim() !== '')) {
|
|
1370
|
+
const n = Number(o)
|
|
1371
|
+
if (!number.isNaN(n)) return n
|
|
1372
|
+
}
|
|
1373
|
+
return _fail(ctx, path, o, expected)
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
if (_isMeta($$bigint, $s)) {
|
|
1377
|
+
return (o, path, ctx) => {
|
|
1378
|
+
const t = typeof o
|
|
1379
|
+
return t === 'bigint'
|
|
1380
|
+
? o
|
|
1381
|
+
: ((t === 'number' && number.isInteger(o)) || (t === 'string' && _bigintRegex.test(o))
|
|
1382
|
+
? BigInt(o)
|
|
1383
|
+
: _fail(ctx, path, o, expected))
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
if (_isMeta($$boolean, $s)) {
|
|
1387
|
+
return (o, path, ctx) => typeof o === 'boolean'
|
|
1388
|
+
? o
|
|
1389
|
+
: (o === 'true' ? true : (o === 'false' ? false : _fail(ctx, path, o, expected)))
|
|
1390
|
+
}
|
|
1391
|
+
if (_isMeta($$literal, $s) || _isMeta($$null, $s) || _isMeta($$undefined, $s)) {
|
|
1392
|
+
const literals = /** @type {Array<Primitive>} */ (shape)
|
|
1393
|
+
return (o, path, ctx) => {
|
|
1394
|
+
if (arr.some(literals, l => l === o)) return o
|
|
1395
|
+
if (typeof o === 'string') {
|
|
1396
|
+
const i = literals.findIndex(l => String(l) === o)
|
|
1397
|
+
if (i >= 0) return literals[i]
|
|
1398
|
+
}
|
|
1399
|
+
return _fail(ctx, path, o, expected)
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
if (_isMeta($$optional, $s)) {
|
|
1403
|
+
const c = _buildCoercer(shape, cache)
|
|
1404
|
+
return (o, path, ctx) => o === undefined ? undefined : c(o, path, ctx)
|
|
1405
|
+
}
|
|
1406
|
+
if (_isMeta($$union, $s)) {
|
|
1407
|
+
const members = /** @type {Array<Schema<any>>} */ (shape)
|
|
1408
|
+
const cs = members.map($m => _buildCoercer($m, cache))
|
|
1409
|
+
return (o, path, ctx) => {
|
|
1410
|
+
// a value that already matches one of the members is never converted
|
|
1411
|
+
if (arr.some(members, $m => $m.check(o))) return o
|
|
1412
|
+
for (let i = 0; i < cs.length; i++) {
|
|
1413
|
+
const v = cs[i](o, path, ctx)
|
|
1414
|
+
if (v !== _failed) return v
|
|
1415
|
+
}
|
|
1416
|
+
return _fail(ctx, path, o, expected)
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
if (_isMeta($$object, $s)) {
|
|
1420
|
+
const isPartial = /** @type {any} */ ($s)._isPartial
|
|
1421
|
+
/**
|
|
1422
|
+
* @type {Array<{ key: string, skippable: boolean, c: _Coercer }>}
|
|
1423
|
+
*/
|
|
1424
|
+
const props = []
|
|
1425
|
+
for (const key in shape) {
|
|
1426
|
+
props.push({ key, skippable: isPartial || $$optional.check(shape[key]), c: _buildCoercer(shape[key], cache) })
|
|
1427
|
+
}
|
|
1428
|
+
return (o, path, ctx) => {
|
|
1429
|
+
if (o === null || !object.isObject(o)) return _fail(ctx, path, o, expected)
|
|
1430
|
+
let changed = false
|
|
1431
|
+
/**
|
|
1432
|
+
* @type {any}
|
|
1433
|
+
*/
|
|
1434
|
+
const res = {}
|
|
1435
|
+
for (let i = 0; i < props.length; i++) {
|
|
1436
|
+
const { key, skippable, c } = props[i]
|
|
1437
|
+
if (skippable && !object.hasProperty(o, key)) continue
|
|
1438
|
+
const v = c(o[key], _prop(path, key), ctx)
|
|
1439
|
+
if (v === _failed) return _failed
|
|
1440
|
+
changed = changed || v !== o[key]
|
|
1441
|
+
res[key] = v
|
|
1442
|
+
}
|
|
1443
|
+
// unknown props are preserved - `$Object` accepts them as well
|
|
1444
|
+
return changed ? object.assign({}, o, res) : o
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
if (_isMeta($$record, $s)) {
|
|
1448
|
+
const ckey = _buildCoercer(shape.keys, cache)
|
|
1449
|
+
const cval = _buildCoercer(shape.values, cache)
|
|
1450
|
+
return (o, path, ctx) => {
|
|
1451
|
+
if (o === null || !object.isObject(o)) return _fail(ctx, path, o, expected)
|
|
1452
|
+
let changed = false
|
|
1453
|
+
/**
|
|
1454
|
+
* @type {any}
|
|
1455
|
+
*/
|
|
1456
|
+
const res = {}
|
|
1457
|
+
for (const key in o) {
|
|
1458
|
+
const p = _prop(path, key)
|
|
1459
|
+
// keys are coerced only to validate them - the property name stays a string either way
|
|
1460
|
+
if (ckey(key, p, ctx) === _failed) return _failed
|
|
1461
|
+
const v = cval(o[key], p, ctx)
|
|
1462
|
+
if (v === _failed) return _failed
|
|
1463
|
+
changed = changed || v !== o[key]
|
|
1464
|
+
res[key] = v
|
|
1465
|
+
}
|
|
1466
|
+
return changed ? res : o
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
if (_isMeta($$tuple, $s)) {
|
|
1470
|
+
const cs = /** @type {Array<Schema<any>>} */ (shape).map($m => _buildCoercer($m, cache))
|
|
1471
|
+
return (o, path, ctx) => {
|
|
1472
|
+
if (!arr.isArray(o)) return _fail(ctx, path, o, expected)
|
|
1473
|
+
let changed = false
|
|
1474
|
+
// `$Tuple` doesn't constrain the length - additional items are preserved
|
|
1475
|
+
const res = o.slice()
|
|
1476
|
+
for (let i = 0; i < cs.length; i++) {
|
|
1477
|
+
const v = cs[i](o[i], _idx(path, i), ctx)
|
|
1478
|
+
if (v === _failed) return _failed
|
|
1479
|
+
changed = changed || v !== o[i]
|
|
1480
|
+
res[i] = v
|
|
1481
|
+
}
|
|
1482
|
+
return changed ? res : o
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
if (_isMeta($$array, $s)) {
|
|
1486
|
+
const c = _buildCoercer(shape, cache)
|
|
1487
|
+
return (o, path, ctx) => {
|
|
1488
|
+
if (!arr.isArray(o)) return _fail(ctx, path, o, expected)
|
|
1489
|
+
let changed = false
|
|
1490
|
+
const res = new Array(o.length)
|
|
1491
|
+
for (let i = 0; i < o.length; i++) {
|
|
1492
|
+
const v = c(o[i], _idx(path, i), ctx)
|
|
1493
|
+
if (v === _failed) return _failed
|
|
1494
|
+
changed = changed || v !== o[i]
|
|
1495
|
+
res[i] = v
|
|
1496
|
+
}
|
|
1497
|
+
return changed ? res : o
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
// everything else ($instanceOf, $constructedBy, $custom, $lambda, $intersect, $stringTemplate,
|
|
1501
|
+
// $type, ..) has no meaningful conversion - accept the value iff it already matches
|
|
1502
|
+
return (o, path, ctx) => $s.check(o) ? o : _fail(ctx, path, o, expected)
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
/**
|
|
1506
|
+
* Compile with memoization. The coercer is registered *before* recursing so that self-referential
|
|
1507
|
+
* schemas (e.g. `$json`) terminate.
|
|
1508
|
+
*
|
|
1509
|
+
* @param {Schema<any>} $s
|
|
1510
|
+
* @param {Map<Schema<any>,_Coercer>} cache
|
|
1511
|
+
* @return {_Coercer}
|
|
1512
|
+
*/
|
|
1513
|
+
const _buildCoercer = ($s, cache) => {
|
|
1514
|
+
const cached = cache.get($s)
|
|
1515
|
+
if (cached != null) return cached
|
|
1516
|
+
// `self` is a box because the registered forwarder must close over a coercer that doesn't exist
|
|
1517
|
+
// yet
|
|
1518
|
+
/**
|
|
1519
|
+
* @type {Array<_Coercer>}
|
|
1520
|
+
*/
|
|
1521
|
+
const self = []
|
|
1522
|
+
cache.set($s, (o, path, ctx) => self[0](o, path, ctx))
|
|
1523
|
+
self.push(_createCoercer($s, cache))
|
|
1524
|
+
return self[0]
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
/**
|
|
1528
|
+
* Compile a coercion function for `schema`.
|
|
1529
|
+
*
|
|
1530
|
+
* Unlike `check` (which only validates) a coercion converts values that don't match yet - `'42'`
|
|
1531
|
+
* becomes `42` for `$number`, `'true'` becomes `true` for `$boolean`. Values that already match
|
|
1532
|
+
* are returned untouched (including object identity). Containers (`$object`, `$array`, `$record`,
|
|
1533
|
+
* `$tuple`, `$union`, `$optional`) are coerced recursively. Schemas without a meaningful
|
|
1534
|
+
* conversion (`$instanceOf`, `$custom`, ..) simply have to match.
|
|
1535
|
+
*
|
|
1536
|
+
* Failures are returned instead of thrown - this is the only api in lib0 that reports errors as a
|
|
1537
|
+
* value.
|
|
1538
|
+
*
|
|
1539
|
+
* @example
|
|
1540
|
+
* const readConfig = coerce($object({ port: $number, dev: $boolean }))
|
|
1541
|
+
* readConfig({ port: '8080', dev: 'true' }) // => { err: null, result: { port: 8080, dev: true } }
|
|
1542
|
+
* readConfig({ port: 'x', dev: 'true' }) // => { err: '[port] "x" doesn\'t match number', result: null }
|
|
1543
|
+
*
|
|
1544
|
+
* @template {Schema<any>} S
|
|
1545
|
+
* @param {S} schema
|
|
1546
|
+
* @return {(o:any) => { err: string, result: null } | { err: null, result: Unwrap<S> }}
|
|
1547
|
+
*/
|
|
1548
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
1549
|
+
export const coerce = schema => {
|
|
1550
|
+
const c = _buildCoercer(schema, new Map())
|
|
1551
|
+
return o => {
|
|
1552
|
+
const ctx = { err: '' }
|
|
1553
|
+
const res = c(o, '', ctx)
|
|
1554
|
+
return res === _failed ? { err: ctx.err, result: null } : { err: null, result: res }
|
|
1555
|
+
}
|
|
1556
|
+
}
|
package/src/sort.js
CHANGED
|
@@ -14,7 +14,7 @@ import * as math from './math.js'
|
|
|
14
14
|
* @param {Array<T>} arr
|
|
15
15
|
* @param {number} lo
|
|
16
16
|
* @param {number} hi
|
|
17
|
-
* @param {
|
|
17
|
+
* @param {(a: T, b: T) => number} compare
|
|
18
18
|
*/
|
|
19
19
|
export const _insertionSort = (arr, lo, hi, compare) => {
|
|
20
20
|
for (let i = lo + 1; i <= hi; i++) {
|
|
@@ -29,7 +29,7 @@ export const _insertionSort = (arr, lo, hi, compare) => {
|
|
|
29
29
|
/**
|
|
30
30
|
* @template T
|
|
31
31
|
* @param {Array<T>} arr
|
|
32
|
-
* @param {
|
|
32
|
+
* @param {(a: T, b: T) => number} compare
|
|
33
33
|
* @return {void}
|
|
34
34
|
*/
|
|
35
35
|
export const insertionSort = (arr, compare) => {
|
|
@@ -41,7 +41,7 @@ export const insertionSort = (arr, compare) => {
|
|
|
41
41
|
* @param {Array<T>} arr
|
|
42
42
|
* @param {number} lo
|
|
43
43
|
* @param {number} hi
|
|
44
|
-
* @param {
|
|
44
|
+
* @param {(a: T, b: T) => number} compare
|
|
45
45
|
*/
|
|
46
46
|
const _quickSort = (arr, lo, hi, compare) => {
|
|
47
47
|
if (hi - lo < 42) {
|
|
@@ -80,7 +80,7 @@ const _quickSort = (arr, lo, hi, compare) => {
|
|
|
80
80
|
*
|
|
81
81
|
* @template T
|
|
82
82
|
* @param {Array<T>} arr
|
|
83
|
-
* @param {
|
|
83
|
+
* @param {(a: T, b: T) => number} compare
|
|
84
84
|
* @return {void}
|
|
85
85
|
*/
|
|
86
86
|
export const quicksort = (arr, compare) => {
|
package/src/storage.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* @module storage
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import { isBrowser } from './environment.common.js'
|
|
12
|
+
|
|
11
13
|
/* c8 ignore start */
|
|
12
14
|
class VarStoragePolyfill {
|
|
13
15
|
constructor () {
|
|
@@ -39,8 +41,10 @@ let usePolyfill = true
|
|
|
39
41
|
|
|
40
42
|
/* c8 ignore start */
|
|
41
43
|
try {
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
+
// Only use localStorage in the browser — node & deno also define a localStorage global, but
|
|
45
|
+
// with different semantics (in node it is non-functional unless `--localstorage-file` is set).
|
|
46
|
+
// If the same-origin rule is violated, accessing localStorage might throw an error.
|
|
47
|
+
if (isBrowser && typeof localStorage !== 'undefined' && localStorage) {
|
|
44
48
|
_localStorage = localStorage
|
|
45
49
|
usePolyfill = false
|
|
46
50
|
}
|
|
@@ -56,7 +60,7 @@ export const varStorage = _localStorage
|
|
|
56
60
|
/**
|
|
57
61
|
* A polyfill for `addEventListener('storage', event => {..})` that does nothing if the polyfill is being used.
|
|
58
62
|
*
|
|
59
|
-
* @param {
|
|
63
|
+
* @param {(e: { key: string, newValue: string, oldValue: string }) => void} eventHandler
|
|
60
64
|
* @function
|
|
61
65
|
*/
|
|
62
66
|
/* c8 ignore next */
|
|
@@ -65,7 +69,7 @@ export const onChange = eventHandler => usePolyfill || addEventListener('storage
|
|
|
65
69
|
/**
|
|
66
70
|
* A polyfill for `removeEventListener('storage', event => {..})` that does nothing if the polyfill is being used.
|
|
67
71
|
*
|
|
68
|
-
* @param {
|
|
72
|
+
* @param {(e: { key: string, newValue: string, oldValue: string }) => void} eventHandler
|
|
69
73
|
* @function
|
|
70
74
|
*/
|
|
71
75
|
/* c8 ignore next */
|
package/src/testing.js
CHANGED
|
@@ -133,7 +133,7 @@ const repeatTestRegex = /^(repeat|repeating)\s/
|
|
|
133
133
|
/**
|
|
134
134
|
* @param {string} moduleName
|
|
135
135
|
* @param {string} name
|
|
136
|
-
* @param {
|
|
136
|
+
* @param {(tc: TestCase) => void|Promise<any>} f
|
|
137
137
|
* @param {number} i
|
|
138
138
|
* @param {number} numberOfTests
|
|
139
139
|
*/
|
|
@@ -257,7 +257,7 @@ export const printCanvas = log.printCanvas
|
|
|
257
257
|
* ```
|
|
258
258
|
*
|
|
259
259
|
* @param {string} description
|
|
260
|
-
* @param {
|
|
260
|
+
* @param {(...args: Array<any>) => void} f
|
|
261
261
|
*/
|
|
262
262
|
export const group = (description, f) => {
|
|
263
263
|
log.group(log.BLUE, description)
|
|
@@ -284,7 +284,7 @@ export const group = (description, f) => {
|
|
|
284
284
|
* ```
|
|
285
285
|
*
|
|
286
286
|
* @param {string} description
|
|
287
|
-
* @param {
|
|
287
|
+
* @param {(...args: Array<any>) => Promise<any>} f
|
|
288
288
|
*/
|
|
289
289
|
export const groupAsync = async (description, f) => {
|
|
290
290
|
log.group(log.BLUE, description)
|
|
@@ -310,7 +310,7 @@ export const groupAsync = async (description, f) => {
|
|
|
310
310
|
* ```
|
|
311
311
|
*
|
|
312
312
|
* @param {string} message
|
|
313
|
-
* @param {
|
|
313
|
+
* @param {(...args: Array<any>) => void} f
|
|
314
314
|
* @return {number} Returns a promise that resolves the measured duration to apply f
|
|
315
315
|
*/
|
|
316
316
|
export const measureTime = (message, f) => {
|
|
@@ -340,7 +340,7 @@ export const measureTime = (message, f) => {
|
|
|
340
340
|
* ```
|
|
341
341
|
*
|
|
342
342
|
* @param {string} message
|
|
343
|
-
* @param {
|
|
343
|
+
* @param {(...args: Array<any>) => Promise<any>} f
|
|
344
344
|
* @return {Promise<number>} Returns a promise that resolves the measured duration to apply f
|
|
345
345
|
*/
|
|
346
346
|
export const measureTimeAsync = async (message, f) => {
|
|
@@ -428,7 +428,7 @@ const _failMessage = (message, reason, path) => fail(
|
|
|
428
428
|
* @param {any} b
|
|
429
429
|
* @param {string} path
|
|
430
430
|
* @param {string?} message
|
|
431
|
-
* @param {
|
|
431
|
+
* @param {(constructor: any, a: any, b: any, path: string, compareValues: any) => boolean} customCompare
|
|
432
432
|
*/
|
|
433
433
|
const _compare = (a, b, path, message, customCompare) => {
|
|
434
434
|
// we don't use assert here because we want to test all branches (istanbul errors if one branch is not tested)
|
|
@@ -519,22 +519,22 @@ const _compare = (a, b, path, message, customCompare) => {
|
|
|
519
519
|
* @param {T} a
|
|
520
520
|
* @param {T} b
|
|
521
521
|
* @param {string?} [message]
|
|
522
|
-
* @param {
|
|
522
|
+
* @param {(constructor: any, a: T, b: T, path: string, compareValues: any) => boolean} [customCompare]
|
|
523
523
|
*/
|
|
524
524
|
export const compare = (a, b, message = null, customCompare = compareValues) => _compare(a, b, 'obj', message, customCompare)
|
|
525
525
|
|
|
526
526
|
/**
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
* @return {asserts property is NonNullable<T>}
|
|
527
|
+
* `@type` (not `@param`/`@return`) is required — an assertion signature only narrows if the
|
|
528
|
+
* callee is declared with an explicit type annotation.
|
|
529
|
+
*
|
|
531
530
|
* @throws {TestError}
|
|
531
|
+
* @type {<T>(property: T, message?: string|null) => asserts property is NonNullable<T>}
|
|
532
532
|
*/
|
|
533
533
|
/* c8 ignore next */
|
|
534
534
|
export const assert = (property, message = null) => { property || fail(`Assertion failed${message !== null ? `: ${message}` : ''}`) }
|
|
535
535
|
|
|
536
536
|
/**
|
|
537
|
-
* @param {
|
|
537
|
+
* @param {(...args: Array<any>) => Promise<any>} f
|
|
538
538
|
*/
|
|
539
539
|
export const promiseRejected = async f => {
|
|
540
540
|
try {
|
|
@@ -546,7 +546,7 @@ export const promiseRejected = async f => {
|
|
|
546
546
|
}
|
|
547
547
|
|
|
548
548
|
/**
|
|
549
|
-
* @param {
|
|
549
|
+
* @param {(...args: Array<any>) => void} f
|
|
550
550
|
* @throws {TestError}
|
|
551
551
|
*/
|
|
552
552
|
export const fails = f => {
|
|
@@ -560,7 +560,7 @@ export const fails = f => {
|
|
|
560
560
|
}
|
|
561
561
|
|
|
562
562
|
/**
|
|
563
|
-
* @param {
|
|
563
|
+
* @param {(...args: Array<any>) => Promise<any>} f
|
|
564
564
|
* @throws {TestError}
|
|
565
565
|
*/
|
|
566
566
|
export const failsAsync = async f => {
|
|
@@ -574,7 +574,7 @@ export const failsAsync = async f => {
|
|
|
574
574
|
}
|
|
575
575
|
|
|
576
576
|
/**
|
|
577
|
-
* @param {Object<string, Object<string,
|
|
577
|
+
* @param {Object<string, Object<string, (tc: TestCase) => any|Promise<any>>>} tests
|
|
578
578
|
*/
|
|
579
579
|
export const runTests = async tests => {
|
|
580
580
|
/**
|