lib0 1.0.0-rc.2 → 1.0.0-rc.21
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/README.md +0 -1315
- package/{types → dist}/buffer.d.ts +2 -10
- package/{types → dist}/delta/delta.d.ts +582 -144
- package/dist/delta/position.d.ts +65 -0
- package/dist/delta/rdt/delta.d.ts +57 -0
- package/dist/delta/rdt/dom.d.ts +102 -0
- package/dist/delta/rdt.d.ts +180 -0
- package/dist/delta/transformer/attr.d.ts +64 -0
- package/dist/delta/transformer/attribution-to-format.d.ts +52 -0
- package/dist/delta/transformer/children.d.ts +69 -0
- package/dist/delta/transformer/conform.d.ts +83 -0
- package/dist/delta/transformer/core.d.ts +189 -0
- package/dist/delta/transformer/full-attributions.d.ts +37 -0
- package/dist/delta/transformer/id.d.ts +2 -0
- package/dist/delta/transformer/inline.d.ts +89 -0
- package/dist/delta/transformer/pipe.d.ts +182 -0
- package/dist/delta/transformer/project.d.ts +223 -0
- package/dist/delta/transformer/rename-attrs.d.ts +75 -0
- package/dist/delta/transformer/rename.d.ts +41 -0
- package/dist/delta/transformer/value.d.ts +92 -0
- package/dist/delta/transformer.d.ts +14 -0
- package/dist/diff/patience.d.ts +25 -0
- package/{types → dist}/environment.d.ts +10 -0
- package/dist/hash/fnv1a.d.ts +11 -0
- package/{types → dist}/schema.d.ts +49 -38
- package/{types → dist}/ts.d.ts +4 -0
- package/dist/webcrypto.d.ts +3 -0
- package/package.json +148 -82
- package/src/bin/0serve.js +11 -3
- package/src/broadcastchannel.js +6 -1
- package/src/buffer.js +35 -25
- package/src/decoding.js +1 -1
- package/src/delta/delta.js +2531 -564
- package/src/delta/position.js +165 -0
- package/src/delta/rdt/delta.js +105 -0
- package/src/delta/rdt/dom.js +307 -0
- package/src/delta/rdt.js +255 -0
- package/src/delta/transformer/attr.js +126 -0
- package/src/delta/transformer/attribution-to-format.js +335 -0
- package/src/delta/transformer/children.js +219 -0
- package/src/delta/transformer/conform.js +401 -0
- package/src/delta/transformer/core.js +323 -0
- package/src/delta/transformer/full-attributions.js +282 -0
- package/src/delta/transformer/id.js +13 -0
- package/src/delta/transformer/inline.js +818 -0
- package/src/delta/transformer/pipe.js +272 -0
- package/src/delta/transformer/project.js +526 -0
- package/src/delta/transformer/rename-attrs.js +152 -0
- package/src/delta/transformer/rename.js +84 -0
- package/src/delta/transformer/value.js +214 -0
- package/src/delta/transformer.js +38 -0
- package/src/diff/patience.js +22 -11
- package/src/dom.js +2 -2
- package/src/encoding.js +1 -1
- package/src/environment.js +15 -0
- package/src/hash/fnv1a.js +82 -0
- package/src/number.js +1 -3
- package/src/performance.node.js +3 -3
- package/src/schema.js +231 -177
- package/src/string.js +3 -5
- package/src/testing.js +1 -1
- package/src/trait/equality.js +1 -1
- package/src/trait/fingerprint.js +1 -1
- package/src/ts.js +11 -0
- package/src/bin/gendocs.js +0 -117
- package/src/component.js +0 -414
- package/src/delta/binding.js +0 -372
- package/src/tree.js +0 -546
- package/types/bin/gendocs.d.ts +0 -3
- package/types/component.d.ts +0 -86
- package/types/delta/binding.d.ts +0 -106
- package/types/diff/patience.d.ts +0 -16
- package/types/tree.d.ts +0 -96
- package/types/webcrypto.d.ts +0 -3
- /package/{types → dist}/array.d.ts +0 -0
- /package/{types → dist}/bin/0ecdsa-generate-keypair.d.ts +0 -0
- /package/{types → dist}/bin/0serve.d.ts +0 -0
- /package/{types → dist}/bin/gentesthtml.d.ts +0 -0
- /package/{types → dist}/binary.d.ts +0 -0
- /package/{types → dist}/broadcastchannel.d.ts +0 -0
- /package/{types → dist}/cache.d.ts +0 -0
- /package/{types → dist}/conditions.d.ts +0 -0
- /package/{types → dist}/crypto/aes-gcm.d.ts +0 -0
- /package/{types → dist}/crypto/common.d.ts +0 -0
- /package/{types → dist}/crypto/ecdsa.d.ts +0 -0
- /package/{types → dist}/crypto/jwt.d.ts +0 -0
- /package/{types → dist}/crypto/rsa-oaep.d.ts +0 -0
- /package/{types → dist}/decoding.d.ts +0 -0
- /package/{types → dist}/diff.d.ts +0 -0
- /package/{types → dist}/dom.d.ts +0 -0
- /package/{types → dist}/encoding.d.ts +0 -0
- /package/{types → dist}/error.d.ts +0 -0
- /package/{types → dist}/eventloop.d.ts +0 -0
- /package/{types → dist}/function.d.ts +0 -0
- /package/{types → dist}/hash/rabin-gf2-polynomial.d.ts +0 -0
- /package/{types → dist}/hash/rabin-uncached.d.ts +0 -0
- /package/{types → dist}/hash/rabin.d.ts +0 -0
- /package/{types → dist}/hash/sha256.d.ts +0 -0
- /package/{types → dist}/hash/sha256.node.d.ts +0 -0
- /package/{types → dist}/indexeddb.d.ts +0 -0
- /package/{types → dist}/indexeddbV2.d.ts +0 -0
- /package/{types → dist}/iterator.d.ts +0 -0
- /package/{types → dist}/json.d.ts +0 -0
- /package/{types → dist}/list.d.ts +0 -0
- /package/{types → dist}/logging.common.d.ts +0 -0
- /package/{types → dist}/logging.d.ts +0 -0
- /package/{types → dist}/logging.node.d.ts +0 -0
- /package/{types → dist}/map.d.ts +0 -0
- /package/{types → dist}/math.d.ts +0 -0
- /package/{types → dist}/metric.d.ts +0 -0
- /package/{types → dist}/mutex.d.ts +0 -0
- /package/{types → dist}/number.d.ts +0 -0
- /package/{types → dist}/object.d.ts +0 -0
- /package/{types → dist}/observable.d.ts +0 -0
- /package/{types → dist}/pair.d.ts +0 -0
- /package/{types → dist}/performance.d.ts +0 -0
- /package/{types → dist}/performance.node.d.ts +0 -0
- /package/{types → dist}/pledge.d.ts +0 -0
- /package/{types → dist}/prng/Mt19937.d.ts +0 -0
- /package/{types → dist}/prng/Xoroshiro128plus.d.ts +0 -0
- /package/{types → dist}/prng/Xorshift32.d.ts +0 -0
- /package/{types → dist}/prng.d.ts +0 -0
- /package/{types → dist}/promise.d.ts +0 -0
- /package/{types → dist}/queue.d.ts +0 -0
- /package/{types → dist}/random.d.ts +0 -0
- /package/{types → dist}/set.d.ts +0 -0
- /package/{types → dist}/sort.d.ts +0 -0
- /package/{types → dist}/statistics.d.ts +0 -0
- /package/{types → dist}/storage.d.ts +0 -0
- /package/{types → dist}/string.d.ts +0 -0
- /package/{types → dist}/symbol.d.ts +0 -0
- /package/{types → dist}/testing.d.ts +0 -0
- /package/{types → dist}/time.d.ts +0 -0
- /package/{types → dist}/trait/equality.d.ts +0 -0
- /package/{types → dist}/trait/fingerprint.d.ts +0 -0
- /package/{types → dist}/trait/traits.d.ts +0 -0
- /package/{types → dist}/url.d.ts +0 -0
- /package/{types → dist}/webcrypto.deno.d.ts +0 -0
- /package/{types → dist}/webcrypto.node.d.ts +0 -0
- /package/{types → dist}/webcrypto.react-native.d.ts +0 -0
- /package/{types → dist}/websocket.d.ts +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as delta from '../delta.js'
|
|
2
|
+
import { Transformer, Template, createTransformResult, withName } from './core.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Relabels a node: side B carries the configured `name`, side A keeps the source node's original
|
|
6
|
+
* name. Otherwise identity. Useful to mark a `children`-mapped collection as `lib0:inline` (so a
|
|
7
|
+
* downstream {@link import('./inline.js').inline}`(['lib0:inline'])` splices it into its parent) or
|
|
8
|
+
* simply to rename the container (e.g. a data collection projected as a `<ul>`).
|
|
9
|
+
*
|
|
10
|
+
* @extends {Transformer<any,any>}
|
|
11
|
+
*/
|
|
12
|
+
export class RenameTransformer extends Transformer {
|
|
13
|
+
/**
|
|
14
|
+
* @param {import('../../schema.js').Schema<delta.Delta<any>>} $in
|
|
15
|
+
* @param {import('../../schema.js').Schema<delta.Delta<any>>} $out
|
|
16
|
+
* @param {string} name
|
|
17
|
+
*/
|
|
18
|
+
constructor ($in, $out, name) {
|
|
19
|
+
super($in, $out)
|
|
20
|
+
this.target = name
|
|
21
|
+
/** @type {string|undefined} */
|
|
22
|
+
this.srcName = undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {delta.DeltaBuilderAny} d
|
|
27
|
+
* @return {import('./core.js').TransformResultAny}
|
|
28
|
+
*/
|
|
29
|
+
applyA (d) {
|
|
30
|
+
if (d.name != null) this.srcName = d.name
|
|
31
|
+
const out = delta.clone(d)
|
|
32
|
+
out.name = /** @type {any} */ (this.target)
|
|
33
|
+
return createTransformResult(null, out)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {delta.DeltaBuilderAny} d
|
|
38
|
+
* @return {import('./core.js').TransformResultAny}
|
|
39
|
+
*/
|
|
40
|
+
applyB (d) {
|
|
41
|
+
const out = delta.clone(d)
|
|
42
|
+
out.name = /** @type {any} */ (this.srcName)
|
|
43
|
+
return createTransformResult(out, null)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Template for {@link RenameTransformer}.
|
|
49
|
+
*
|
|
50
|
+
* @template {string} Name
|
|
51
|
+
* @template {delta.DeltaConf} [IN=any]
|
|
52
|
+
* @extends {Template<IN, delta.DeltaConfOverwrite<IN, { name: Name }>>}
|
|
53
|
+
*/
|
|
54
|
+
export class Rename extends Template {
|
|
55
|
+
/**
|
|
56
|
+
* @param {import('../../schema.js').Schema<delta.Delta<IN>>} $d
|
|
57
|
+
* @param {Name} name
|
|
58
|
+
*/
|
|
59
|
+
constructor ($d, name) {
|
|
60
|
+
super($d, /** @type {any} */ (withName($d, name)))
|
|
61
|
+
this.target = name
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get name () { return 'lib0:rename:' + this.target }
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @return {Transformer<IN, delta.DeltaConfOverwrite<IN, { name: Name }>>}
|
|
68
|
+
*/
|
|
69
|
+
init () {
|
|
70
|
+
return /** @type {any} */ (new RenameTransformer(this.$in, this.$out, this.target))
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Relabel a node to `name` (side B) and back (side A). Returns a reusable {@link Rename} template
|
|
76
|
+
* (a `project` hole, or `.init()` for a standalone transformer).
|
|
77
|
+
*
|
|
78
|
+
* @template {delta.DeltaConf} IN
|
|
79
|
+
* @template {string} Name
|
|
80
|
+
* @param {import('../../schema.js').Schema<delta.Delta<IN>>} $d
|
|
81
|
+
* @param {Name} name
|
|
82
|
+
* @return {Rename<Name, IN>}
|
|
83
|
+
*/
|
|
84
|
+
export const rename = ($d, name) => new Rename($d, name)
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import * as delta from '../delta.js'
|
|
2
|
+
import * as math from '../../math.js'
|
|
3
|
+
import { Transformer, Template, createTransformResult } from './core.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A `lib0:value` carrier node holds a single scalar in its `value` attribute (the convention
|
|
7
|
+
* established by the {@link import('./attr.js').attr} transformer). At a *child* position such a
|
|
8
|
+
* node is resolved to a one-position **embed** of that scalar; at an *attr* position carriers are
|
|
9
|
+
* resolved by {@link import('./project.js').project} itself (it owns the position knowledge).
|
|
10
|
+
*
|
|
11
|
+
* @param {any} el
|
|
12
|
+
* @return {boolean}
|
|
13
|
+
*/
|
|
14
|
+
const isValueNode = el => delta.$deltaAny.check(el) && el.name === 'lib0:value'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The scalar carried by a `lib0:value` delta (its `value` attribute op's value), or `undefined`.
|
|
18
|
+
*
|
|
19
|
+
* @param {delta.DeltaAny} el
|
|
20
|
+
*/
|
|
21
|
+
const valueOf = el => /** @type {any} */ (el.attrs).value?.value
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Stateful transformer that resolves `lib0:value` carrier *children* of a node: a `lib0:value` node
|
|
25
|
+
* (1 position) becomes an embed of its scalar value (1 position), and back. Count-preserving, so a
|
|
26
|
+
* single sparse positional map (`insert([1])` at carrier positions, coalesced `retain(n)` over
|
|
27
|
+
* gaps) indexes both directions - the same `childTs` technique as {@link import('./children.js')}.
|
|
28
|
+
*
|
|
29
|
+
* A standalone, *composable* one-level resolver (the `lib0:value` counterpart of
|
|
30
|
+
* {@link import('./inline.js').inline}`(['lib0:inline'])`): place it after any transformer that emits
|
|
31
|
+
* `lib0:value` carriers, or compose it with {@link import('./children.js').children} to descend into
|
|
32
|
+
* deeper levels. `project` lifts the carriers in its *own* structure, so `unwrapValue` is only needed
|
|
33
|
+
* for carriers emitted by a non-`project` transformer.
|
|
34
|
+
*
|
|
35
|
+
* Editing a resolved scalar from side B (the view) is not round-tripped in v1: a value *update*
|
|
36
|
+
* driven from side A (a `modify` on the carrier) maps to `delete(1).insert([newValue])`, but a side
|
|
37
|
+
* B `delete`+`insert` of the embed is treated structurally.
|
|
38
|
+
*
|
|
39
|
+
* @extends {Transformer<any,any>}
|
|
40
|
+
*/
|
|
41
|
+
export class UnwrapValueTransformer extends Transformer {
|
|
42
|
+
/**
|
|
43
|
+
* @param {import('../../schema.js').Schema<delta.Delta<any>>} $in
|
|
44
|
+
* @param {import('../../schema.js').Schema<delta.Delta<any>>} $out
|
|
45
|
+
*/
|
|
46
|
+
constructor ($in, $out) {
|
|
47
|
+
super($in, $out)
|
|
48
|
+
/**
|
|
49
|
+
* Sparse positional map of carriers: `insert([1])` at each `lib0:value` child, `retain(n)` over
|
|
50
|
+
* gaps (text and pass-through nodes).
|
|
51
|
+
*
|
|
52
|
+
* @type {delta.DeltaBuilderAny}
|
|
53
|
+
*/
|
|
54
|
+
this.map = delta.create()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {delta.DeltaBuilderAny} d the change to map
|
|
59
|
+
* @param {boolean} fwd `true` maps side A (carriers present) -> B (resolved), `false` maps back
|
|
60
|
+
* @return {import('./core.js').TransformResultAny}
|
|
61
|
+
*/
|
|
62
|
+
transform (d, fwd) {
|
|
63
|
+
// `cloneShallow` carries the node's name, attribute ops, and own (root) marks; only child nodes are
|
|
64
|
+
// (re)built below, and nested children's marks ride on those rebuilt children. It is the shared
|
|
65
|
+
// mark-carrying primitive, so this node's marks cannot be silently dropped. `any` keeps `out` within
|
|
66
|
+
// the shared TS instantiation budget (see {@link import('./inline.js')}).
|
|
67
|
+
const out = /** @type {any} */ (delta.cloneShallow(d))
|
|
68
|
+
const newMap = delta.create()
|
|
69
|
+
let srcNode = this.map.children.start
|
|
70
|
+
let srcOff = 0
|
|
71
|
+
/**
|
|
72
|
+
* Copy `n` positions from the old map to `newMap`, advancing the cursor.
|
|
73
|
+
*
|
|
74
|
+
* @param {number} n
|
|
75
|
+
*/
|
|
76
|
+
const carry = n => {
|
|
77
|
+
let rem = n
|
|
78
|
+
while (rem > 0 && srcNode != null) {
|
|
79
|
+
const take = math.min(srcNode.length - srcOff, rem)
|
|
80
|
+
if (delta.$insertOp.check(srcNode)) {
|
|
81
|
+
newMap.insert(srcNode.insert.slice(srcOff, srcOff + take))
|
|
82
|
+
} else {
|
|
83
|
+
newMap.retain(take)
|
|
84
|
+
}
|
|
85
|
+
srcOff += take
|
|
86
|
+
rem -= take
|
|
87
|
+
if (srcOff >= srcNode.length) { srcNode = srcNode.next; srcOff = 0 }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Advance the cursor `n` positions without copying.
|
|
92
|
+
*
|
|
93
|
+
* @param {number} n
|
|
94
|
+
*/
|
|
95
|
+
const drop = n => {
|
|
96
|
+
let rem = n
|
|
97
|
+
while (rem > 0 && srcNode != null) {
|
|
98
|
+
const take = math.min(srcNode.length - srcOff, rem)
|
|
99
|
+
srcOff += take
|
|
100
|
+
rem -= take
|
|
101
|
+
if (srcOff >= srcNode.length) { srcNode = srcNode.next; srcOff = 0 }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// whether the cursor currently sits on a carrier position
|
|
105
|
+
const peekCarrier = () => srcNode != null && delta.$insertOp.check(srcNode)
|
|
106
|
+
for (const op of d.children) {
|
|
107
|
+
if (delta.$retainOp.check(op)) {
|
|
108
|
+
out.retain(op.retain, op.format, op.attribution)
|
|
109
|
+
carry(op.retain)
|
|
110
|
+
} else if (delta.$textOp.check(op)) {
|
|
111
|
+
out.insert(op.insert, op.format, op.attribution)
|
|
112
|
+
newMap.retain(op.insert.length) // text is a gap
|
|
113
|
+
} else if (delta.$insertOp.check(op)) {
|
|
114
|
+
for (const el of op.insert) {
|
|
115
|
+
if (fwd && isValueNode(el)) {
|
|
116
|
+
out.insert([valueOf(el)], op.format, op.attribution)
|
|
117
|
+
newMap.insert([1]) // mark carrier
|
|
118
|
+
} else {
|
|
119
|
+
out.insert([el], op.format, op.attribution)
|
|
120
|
+
newMap.retain(1) // pass-through / literal
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} else if (delta.$deleteOp.check(op)) {
|
|
124
|
+
out.delete(op.delete)
|
|
125
|
+
drop(op.delete)
|
|
126
|
+
} else if (delta.$modifyOp.check(op)) {
|
|
127
|
+
if (fwd && peekCarrier()) {
|
|
128
|
+
// a value update arrives as a `modify` on the carrier node setting its `value` attr
|
|
129
|
+
const newV = /** @type {any} */ (op.value.attrs).value?.value
|
|
130
|
+
if (newV !== undefined) {
|
|
131
|
+
out.delete(1)
|
|
132
|
+
out.insert([newV], op.format, op.attribution)
|
|
133
|
+
} else {
|
|
134
|
+
out.retain(1, op.format, op.attribution)
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
out.modify(delta.clone(op.value), op.format, op.attribution)
|
|
138
|
+
}
|
|
139
|
+
carry(1)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
carry(Infinity) // trailing untouched positions
|
|
143
|
+
out.done(false)
|
|
144
|
+
this.map = newMap
|
|
145
|
+
return fwd ? createTransformResult(null, out) : createTransformResult(out, null)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @param {delta.DeltaBuilderAny} da
|
|
150
|
+
*/
|
|
151
|
+
applyA (da) {
|
|
152
|
+
return this.transform(da, true)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {delta.DeltaBuilderAny} db
|
|
157
|
+
*/
|
|
158
|
+
applyB (db) {
|
|
159
|
+
return this.transform(db, false)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* A `lib0:value` carrier child lifts to its scalar `value` type; any other child passes through.
|
|
165
|
+
* Naked-param conditional, so it distributes over a children union.
|
|
166
|
+
*
|
|
167
|
+
* @template C
|
|
168
|
+
* @typedef {C extends delta.Delta<{ name: 'lib0:value', attrs: { value: infer V extends import('../../trait/fingerprint.js').Fingerprintable } }> ? V : C} UnwrapValueChild
|
|
169
|
+
*/
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* `unwrapValue`'s output conf: `IN` with every `lib0:value` carrier child replaced by its lifted
|
|
173
|
+
* scalar (see {@link UnwrapValueChild}); name/attrs/text unchanged.
|
|
174
|
+
*
|
|
175
|
+
* @template {delta.DeltaConf} IN
|
|
176
|
+
* @typedef {import('./core.js').ResolveOut<delta.DeltaConfOverwrite<IN, { children: UnwrapValueChild<delta.DeltaConfGetChildren<IN>> }>>} UnwrapValueOut
|
|
177
|
+
*/
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Template for {@link UnwrapValueTransformer}.
|
|
181
|
+
*
|
|
182
|
+
* @template {delta.DeltaConf} [IN=any]
|
|
183
|
+
* @extends {Template<IN, UnwrapValueOut<IN>>}
|
|
184
|
+
*/
|
|
185
|
+
export class UnwrapValue extends Template {
|
|
186
|
+
/**
|
|
187
|
+
* @param {import('../../schema.js').Schema<delta.Delta<IN>>} $d
|
|
188
|
+
*/
|
|
189
|
+
constructor ($d) {
|
|
190
|
+
super($d, /** @type {any} */ (delta.$deltaAny))
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
get name () { return 'lib0:unwrapValue' }
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @return {Transformer<IN, UnwrapValueOut<IN>>}
|
|
197
|
+
*/
|
|
198
|
+
init () {
|
|
199
|
+
return /** @type {any} */ (new UnwrapValueTransformer(this.$in, this.$out))
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Resolve `lib0:value` carrier *children* to embeds of their scalar value (and back). One level
|
|
205
|
+
* only; compose with {@link import('./children.js').children} to descend. A flat, composable resolver
|
|
206
|
+
* for carriers emitted *outside* a `project` (which lifts its own); symmetric with
|
|
207
|
+
* {@link import('./inline.js').inline}`(['lib0:inline'])`. Returns a reusable {@link UnwrapValue}
|
|
208
|
+
* template (`.init()` for a standalone transformer).
|
|
209
|
+
*
|
|
210
|
+
* @template {delta.DeltaConf} IN
|
|
211
|
+
* @param {import('../../schema.js').Schema<delta.Delta<IN>>} $d
|
|
212
|
+
* @return {UnwrapValue<IN>}
|
|
213
|
+
*/
|
|
214
|
+
export const unwrapValue = $d => new UnwrapValue($d)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # Delta transformers
|
|
3
|
+
*
|
|
4
|
+
* A {@link Template} is a composable transformer factory; its `init($schema)` produces a stateful
|
|
5
|
+
* {@link Transformer} that maps changes ("deltas") of one delta shape (side A) onto another (side B)
|
|
6
|
+
* and back. Transformers compose with {@link pipe}.
|
|
7
|
+
*
|
|
8
|
+
* Each concrete transformer lives in `./transformer/` and is re-exported here so the whole set is
|
|
9
|
+
* available from a single module (`lib0/delta/transformer`):
|
|
10
|
+
* - {@link id} — identity (both sides stay equal)
|
|
11
|
+
* - {@link renameAttrs} — rename node attributes
|
|
12
|
+
* - {@link conform} — drop everything the target schema does not recognize
|
|
13
|
+
* - {@link pipe} — chain templates
|
|
14
|
+
* - {@link attr} — project a single attribute into a `lib0:value` node
|
|
15
|
+
* - {@link inline} — inline child nodes whose name is in a configured set
|
|
16
|
+
* - {@link children} — descend into child nodes and apply a per-child sub-transformer
|
|
17
|
+
* - {@link project} — project the data onto a fixed structure (spec) with embedded "holes"
|
|
18
|
+
* - {@link unwrapValue} — composable resolver for `lib0:value` carrier children (scalar lift)
|
|
19
|
+
* - {@link rename} — rename a node's name (e.g. mark a `children`-map as `lib0:inline`)
|
|
20
|
+
* - {@link attributionToFormat} — render the `attribution` dimension as `y-attributed-*` formats
|
|
21
|
+
* - {@link fullAttributions} — re-emit the complete accumulated attribution on every attribution change
|
|
22
|
+
*
|
|
23
|
+
* @module delta/transformer
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
export * from './transformer/core.js'
|
|
27
|
+
export * from './transformer/id.js'
|
|
28
|
+
export * from './transformer/rename.js'
|
|
29
|
+
export * from './transformer/conform.js'
|
|
30
|
+
export * from './transformer/pipe.js'
|
|
31
|
+
export * from './transformer/attr.js'
|
|
32
|
+
export * from './transformer/inline.js'
|
|
33
|
+
export * from './transformer/children.js'
|
|
34
|
+
export * from './transformer/project.js'
|
|
35
|
+
export * from './transformer/value.js'
|
|
36
|
+
export * from './transformer/rename-attrs.js'
|
|
37
|
+
export * from './transformer/attribution-to-format.js'
|
|
38
|
+
export * from './transformer/full-attributions.js'
|
package/src/diff/patience.js
CHANGED
|
@@ -16,7 +16,7 @@ import * as array from '../array.js'
|
|
|
16
16
|
*
|
|
17
17
|
* @param {Array<string>} as
|
|
18
18
|
* @param {Array<string>} bs
|
|
19
|
-
* @return {Array<{ index: number, remove: Array<string>, insert: Array<string>}>} changeset
|
|
19
|
+
* @return {Array<{ index: number, remove: Array<string>, insert: Array<string>}>} changeset
|
|
20
20
|
*/
|
|
21
21
|
export const diff = (as, bs) => {
|
|
22
22
|
const {
|
|
@@ -30,14 +30,16 @@ export const diff = (as, bs) => {
|
|
|
30
30
|
/**
|
|
31
31
|
* @param {string} a
|
|
32
32
|
* @param {string} b
|
|
33
|
-
* @param {RegExp|string}
|
|
33
|
+
* @param {RegExp|string} regexp
|
|
34
34
|
*/
|
|
35
|
-
export const diffSplitBy = (a, b,
|
|
36
|
-
const isStringSeparator = typeof
|
|
37
|
-
const separator = isStringSeparator ?
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
export const diffSplitBy = (a, b, regexp) => {
|
|
36
|
+
const isStringSeparator = typeof regexp === 'string'
|
|
37
|
+
const separator = /** @type {string} */ (isStringSeparator ? regexp : '')
|
|
38
|
+
if (isStringSeparator) {
|
|
39
|
+
regexp = new RegExp(regexp, 'g')
|
|
40
|
+
}
|
|
41
|
+
const as = splitByRegexp(a, /** @type {RegExp} */ (regexp), !isStringSeparator)
|
|
42
|
+
const bs = splitByRegexp(b, /** @type {RegExp} */ (regexp), !isStringSeparator)
|
|
41
43
|
const changes = diff(as, bs)
|
|
42
44
|
let prevSplitIndex = 0
|
|
43
45
|
let prevStringIndex = 0
|
|
@@ -53,6 +55,15 @@ export const diffSplitBy = (a, b, _regexp) => {
|
|
|
53
55
|
})
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Idea: match all "non-word" characters and keep them separate (spaces, comma, exclamation marks, ..).
|
|
60
|
+
* Anything that can be classivied as a word (emoji, char, number) will be bundled together. All other tokens are kept
|
|
61
|
+
* individually. "hello, world!!!!" => ['hello', ',', ' ', 'world', '!', '!']
|
|
62
|
+
*
|
|
63
|
+
* @experimental
|
|
64
|
+
*/
|
|
65
|
+
export const smartSplitRegex = /[^\p{L}\p{N}\p{Extended_Pictographic}\p{Emoji_Modifier}\u200D\uFE0F]/gu // eslint-disable-line no-misleading-character-class
|
|
66
|
+
|
|
56
67
|
/**
|
|
57
68
|
* Sensible default for diffing strings using patience (it's fast though).
|
|
58
69
|
*
|
|
@@ -64,12 +75,12 @@ export const diffSplitBy = (a, b, _regexp) => {
|
|
|
64
75
|
*/
|
|
65
76
|
export const diffAuto = (a, b) =>
|
|
66
77
|
diffSplitBy(a, b, '\n').map(d =>
|
|
67
|
-
diffSplitBy(d.remove, d.insert, /\. |[a-zA-Z0-9]+|[. ()[\],;{}]/g
|
|
78
|
+
diffSplitBy(d.remove, d.insert, smartSplitRegex).map(dd => ({ // old regex: /\. |[a-zA-Z0-9]+|[. ()[\],;{}]/g
|
|
68
79
|
insert: dd.insert,
|
|
69
80
|
remove: dd.remove,
|
|
70
81
|
index: dd.index + d.index
|
|
71
82
|
}))
|
|
72
|
-
).flat()
|
|
83
|
+
).flat(1)
|
|
73
84
|
|
|
74
85
|
/**
|
|
75
86
|
* @param {Array<string>} as
|
|
@@ -97,7 +108,7 @@ const removeCommonPrefixAndSuffix = (as, bs) => {
|
|
|
97
108
|
* @param {RegExp} regexp
|
|
98
109
|
* @param {boolean} includeSeparator
|
|
99
110
|
*/
|
|
100
|
-
const splitByRegexp = (str, regexp, includeSeparator) => {
|
|
111
|
+
export const splitByRegexp = (str, regexp, includeSeparator) => {
|
|
101
112
|
const matches = [...str.matchAll(regexp)]
|
|
102
113
|
let prevIndex = 0
|
|
103
114
|
/**
|
package/src/dom.js
CHANGED
|
@@ -14,7 +14,7 @@ import * as $ from './schema.js'
|
|
|
14
14
|
/**
|
|
15
15
|
* @type {Document}
|
|
16
16
|
*/
|
|
17
|
-
export const doc = /** @type {Document} */ (typeof document !== 'undefined' ? document : {})
|
|
17
|
+
export const doc = /** @type {Document} */ (/* @__PURE__ */ (() => typeof document !== 'undefined' ? document : {})())
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* @param {string} name
|
|
@@ -38,7 +38,7 @@ export const $fragment = $.$custom(el => el.nodeType === DOCUMENT_FRAGMENT_NODE)
|
|
|
38
38
|
*/
|
|
39
39
|
export const createTextNode = text => doc.createTextNode(text)
|
|
40
40
|
|
|
41
|
-
export const domParser = /** @type {DOMParser} */ (typeof DOMParser !== 'undefined' ? new DOMParser() : null)
|
|
41
|
+
export const domParser = /** @type {DOMParser} */ (/* @__PURE__ */ (() => typeof DOMParser !== 'undefined' ? new DOMParser() : null)())
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* @param {HTMLElement} el
|
package/src/encoding.js
CHANGED
|
@@ -341,7 +341,7 @@ export const _writeVarStringPolyfill = (encoder, str) => {
|
|
|
341
341
|
* @param {String} str The string that is to be encoded.
|
|
342
342
|
*/
|
|
343
343
|
/* c8 ignore next */
|
|
344
|
-
export const writeVarString = (string.utf8TextEncoder && /** @type {any} */ (string.utf8TextEncoder).encodeInto) ? _writeVarStringNative : _writeVarStringPolyfill
|
|
344
|
+
export const writeVarString = /* @__PURE__ */(() => (string.utf8TextEncoder && /** @type {any} */ (string.utf8TextEncoder).encodeInto) ? _writeVarStringNative : _writeVarStringPolyfill)()
|
|
345
345
|
|
|
346
346
|
/**
|
|
347
347
|
* Write a string terminated by a special byte sequence. This is not very performant and is
|
package/src/environment.js
CHANGED
|
@@ -13,11 +13,26 @@ import * as f from './function.js'
|
|
|
13
13
|
/* c8 ignore next */
|
|
14
14
|
export const isNode = /* @__PURE__ */(() => typeof process !== 'undefined' && process.release && /node|io\.js/.test(process.release.name) && Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]')()
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* True iff this script is running in deno
|
|
18
|
+
* @type {boolean}
|
|
19
|
+
*/
|
|
20
|
+
/* c8 ignore next 2 */
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
export const isDeno = /* @__PURE__ */(() => typeof Deno !== 'undefined')()
|
|
23
|
+
|
|
16
24
|
/* c8 ignore next */
|
|
17
25
|
export const isBrowser = /* @__PURE__ */(() => typeof window !== 'undefined' && typeof document !== 'undefined' && !isNode)()
|
|
18
26
|
/* c8 ignore next */
|
|
19
27
|
export const isMac = /* @__PURE__ */(() => typeof navigator !== 'undefined' ? /Mac/.test(navigator.platform) : false)()
|
|
20
28
|
|
|
29
|
+
/**
|
|
30
|
+
* True iff a DOM is available — either a real browser, or Node with a jsdom shim installed (see
|
|
31
|
+
* `src/test-setup.js`). Gate DOM-dependent tests on this so they run in the browser AND under jsdom.
|
|
32
|
+
*/
|
|
33
|
+
/* c8 ignore next */
|
|
34
|
+
export const hasDom = /* @__PURE__ */(() => typeof document !== 'undefined' && typeof MutationObserver !== 'undefined')()
|
|
35
|
+
|
|
21
36
|
/**
|
|
22
37
|
* @type {Map<string,string>}
|
|
23
38
|
*/
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module fnv1a
|
|
3
|
+
* FNV-1a (32bit) - a fast, non-cryptographic hash function.
|
|
4
|
+
* Spec: http://www.isthe.com/chongo/tech/comp/fnv/
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as math from '../math.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* FNV-1a offset basis (32bit).
|
|
11
|
+
*/
|
|
12
|
+
export const offsetBasis = 0x811c9dc5
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* FNV-1a prime (32bit).
|
|
16
|
+
*/
|
|
17
|
+
export const prime = 0x01000193
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Compute the FNV-1a 32bit hash of a byte sequence.
|
|
21
|
+
*
|
|
22
|
+
* Pass the result of a previous call as `hash` to digest a message in chunks:
|
|
23
|
+
* `digest(concat(a, b)) === digest(b, digest(a))`.
|
|
24
|
+
*
|
|
25
|
+
* @param {Uint8Array} data
|
|
26
|
+
* @param {number} hash - continue hashing from a previous result (defaults to the offset basis)
|
|
27
|
+
* @return {number} unsigned 32bit hash
|
|
28
|
+
*/
|
|
29
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
30
|
+
export const digest = (data, hash = offsetBasis) => {
|
|
31
|
+
for (let i = 0; i < data.length; i++) {
|
|
32
|
+
hash = math.imul(hash ^ data[i], prime)
|
|
33
|
+
}
|
|
34
|
+
return hash >>> 0
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Compute the FNV-1a 32bit hash of a string - without allocating the utf8 encoding.
|
|
39
|
+
*
|
|
40
|
+
* Equivalent to `digest(string.encodeUtf8(str))`: the string is hashed as utf8 bytes; lone
|
|
41
|
+
* surrogates are hashed as the replacement character (like TextEncoder encodes them).
|
|
42
|
+
*
|
|
43
|
+
* Prefer this over `digest(string.encodeUtf8(str))` when hashing strings - it skips the
|
|
44
|
+
* TextEncoder call and the Uint8Array allocation, making it ~5x faster for small strings
|
|
45
|
+
* (<=20 chars, e.g. object keys) and ~2x faster for larger ones.
|
|
46
|
+
*
|
|
47
|
+
* @param {string} str
|
|
48
|
+
* @param {number} hash - continue hashing from a previous result (defaults to the offset basis)
|
|
49
|
+
* @return {number} unsigned 32bit hash
|
|
50
|
+
*/
|
|
51
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
52
|
+
export const digestString = (str, hash = offsetBasis) => {
|
|
53
|
+
for (let i = 0; i < str.length; i++) {
|
|
54
|
+
let c = str.charCodeAt(i)
|
|
55
|
+
if (c < 0x80) {
|
|
56
|
+
hash = math.imul(hash ^ c, prime)
|
|
57
|
+
} else {
|
|
58
|
+
if (c >= 0xd800 && c < 0xe000) {
|
|
59
|
+
const lo = str.charCodeAt(i + 1) // NaN when out of bounds ⇒ NaN & x === 0
|
|
60
|
+
if (c < 0xdc00 && (lo & 0xfc00) === 0xdc00) {
|
|
61
|
+
c = 0x10000 + ((c & 0x3ff) << 10) + (lo & 0x3ff)
|
|
62
|
+
i++
|
|
63
|
+
} else {
|
|
64
|
+
c = 0xfffd // lone surrogate ⇒ replacement character
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (c < 0x800) {
|
|
68
|
+
hash = math.imul(hash ^ (0xc0 | (c >> 6)), prime)
|
|
69
|
+
} else {
|
|
70
|
+
if (c < 0x10000) {
|
|
71
|
+
hash = math.imul(hash ^ (0xe0 | (c >> 12)), prime)
|
|
72
|
+
} else {
|
|
73
|
+
hash = math.imul(hash ^ (0xf0 | (c >> 18)), prime)
|
|
74
|
+
hash = math.imul(hash ^ (0x80 | ((c >> 12) & 0x3f)), prime)
|
|
75
|
+
}
|
|
76
|
+
hash = math.imul(hash ^ (0x80 | ((c >> 6) & 0x3f)), prime)
|
|
77
|
+
}
|
|
78
|
+
hash = math.imul(hash ^ (0x80 | (c & 0x3f)), prime)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return hash >>> 0
|
|
82
|
+
}
|
package/src/number.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* @module number
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import * as math from './math.js'
|
|
8
7
|
import * as binary from './binary.js'
|
|
9
8
|
|
|
10
9
|
export const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER
|
|
@@ -14,8 +13,7 @@ export const LOWEST_INT32 = 1 << 31
|
|
|
14
13
|
export const HIGHEST_INT32 = binary.BITS31
|
|
15
14
|
export const HIGHEST_UINT32 = binary.BITS32
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
export const isInteger = Number.isInteger || (num => typeof num === 'number' && isFinite(num) && math.floor(num) === num)
|
|
16
|
+
export const isInteger = Number.isInteger
|
|
19
17
|
export const isNaN = Number.isNaN
|
|
20
18
|
export const parseInt = Number.parseInt
|
|
21
19
|
|
package/src/performance.node.js
CHANGED
|
@@ -6,16 +6,16 @@ import * as time from './time.js'
|
|
|
6
6
|
* @type {typeof performance.measure}
|
|
7
7
|
*/
|
|
8
8
|
/* c8 ignore next */
|
|
9
|
-
export const measure = performance.measure ? performance.measure.bind(performance) : /** @type {any} */ (nop)
|
|
9
|
+
export const measure = /* @__PURE__ */(() => performance.measure ? performance.measure.bind(performance) : /** @type {any} */ (nop))()
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @type {typeof performance.now}
|
|
13
13
|
*/
|
|
14
14
|
/* c8 ignore next */
|
|
15
|
-
export const now = performance.now ? performance.now.bind(performance) : time.getUnixTime
|
|
15
|
+
export const now = /* @__PURE__ */(() => performance.now ? performance.now.bind(performance) : time.getUnixTime)()
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* @type {typeof performance.mark}
|
|
19
19
|
*/
|
|
20
20
|
/* c8 ignore next */
|
|
21
|
-
export const mark = performance.mark ? performance.mark.bind(performance) : /** @type {any} */ (nop)
|
|
21
|
+
export const mark = /* @__PURE__ */(() => performance.mark ? performance.mark.bind(performance) : /** @type {any} */ (nop))()
|