lib0 1.0.0-rc.20 → 1.0.0-rc.22
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/delta/delta.d.ts +65 -30
- package/dist/delta/rdt.d.ts +17 -2
- package/dist/environment.d.ts +6 -0
- package/package.json +1 -1
- package/src/delta/delta.js +302 -108
- package/src/delta/rdt.js +12 -3
- package/src/delta/transformer/attribution-to-format.js +2 -2
- package/src/delta/transformer/conform.js +2 -2
- package/src/delta/transformer/full-attributions.js +2 -2
- package/src/environment.js +22 -10
package/dist/delta/delta.d.ts
CHANGED
|
@@ -55,7 +55,7 @@ export const $attribution: s.Schema<Attribution>;
|
|
|
55
55
|
* @typedef {{ type: 'insert', insert: string|Array<any>, format?: { [key: string]: any }, attribution?: Attribution } | { delete: number } | { type: 'retain', retain: number, format?: { [key:string]: any }|null, attribution?: Attribution|null } | { type: 'modify', value: object, format?: { [key:string]: any }|null, attribution?: Attribution|null }} DeltaListOpJSON
|
|
56
56
|
*/
|
|
57
57
|
/**
|
|
58
|
-
* @typedef {{ type: 'insert', value: any,
|
|
58
|
+
* @typedef {{ type: 'insert', value: any, attribution?: Attribution } | { type: 'delete', attribution?: Attribution } | { type: 'modify', value: DeltaJSON, attribution?: Attribution|null }} DeltaAttrOpJSON
|
|
59
59
|
*/
|
|
60
60
|
/**
|
|
61
61
|
* @typedef {TextOp|InsertOp<any>|DeleteOp|RetainOp|ModifyOp<any>} ChildrenOpAny
|
|
@@ -224,11 +224,9 @@ export class InsertOp<ArrayContent extends unknown> extends list.ListNode {
|
|
|
224
224
|
export class DeleteOp<Conf extends DeltaConf = {}> extends list.ListNode {
|
|
225
225
|
/**
|
|
226
226
|
* @param {number} len
|
|
227
|
-
* @param {DeltaBuilder<any>?} prevValue
|
|
228
227
|
*/
|
|
229
|
-
constructor(len: number
|
|
228
|
+
constructor(len: number);
|
|
230
229
|
delete: number;
|
|
231
|
-
prevValue: Delta<Conf> | null;
|
|
232
230
|
/**
|
|
233
231
|
* @type {string|null}
|
|
234
232
|
*/
|
|
@@ -242,10 +240,10 @@ export class DeleteOp<Conf extends DeltaConf = {}> extends list.ListNode {
|
|
|
242
240
|
/**
|
|
243
241
|
* Remove a part of the operation (similar to Array.splice)
|
|
244
242
|
*
|
|
245
|
-
* @param {number}
|
|
243
|
+
* @param {number} _offset
|
|
246
244
|
* @param {number} len
|
|
247
245
|
*/
|
|
248
|
-
_splice(
|
|
246
|
+
_splice(_offset: number, len: number): this;
|
|
249
247
|
/**
|
|
250
248
|
* @return {DeltaListOpJSON}
|
|
251
249
|
*/
|
|
@@ -254,7 +252,7 @@ export class DeleteOp<Conf extends DeltaConf = {}> extends list.ListNode {
|
|
|
254
252
|
* @param {number} [start]
|
|
255
253
|
* @param {number} [end]
|
|
256
254
|
* @param {boolean} [_markAsDone] accepted for a uniform children-op `clone` signature; ignored (a
|
|
257
|
-
*
|
|
255
|
+
* delete holds no nested content).
|
|
258
256
|
* @return {DeleteOp}
|
|
259
257
|
*/
|
|
260
258
|
clone(start?: number, end?: number, _markAsDone?: boolean): DeleteOp;
|
|
@@ -400,10 +398,9 @@ export class SetAttrOp<V extends unknown = any, K extends string | number = any>
|
|
|
400
398
|
/**
|
|
401
399
|
* @param {K} key
|
|
402
400
|
* @param {V} value
|
|
403
|
-
* @param {V|undefined} prevValue
|
|
404
401
|
* @param {Attribution?} attribution
|
|
405
402
|
*/
|
|
406
|
-
constructor(key: K, value: V,
|
|
403
|
+
constructor(key: K, value: V, attribution: Attribution | null);
|
|
407
404
|
/**
|
|
408
405
|
* @readonly
|
|
409
406
|
* @type {K}
|
|
@@ -414,11 +411,6 @@ export class SetAttrOp<V extends unknown = any, K extends string | number = any>
|
|
|
414
411
|
* @type {V}
|
|
415
412
|
*/
|
|
416
413
|
readonly value: V;
|
|
417
|
-
/**
|
|
418
|
-
* @readonly
|
|
419
|
-
* @type {V|undefined}
|
|
420
|
-
*/
|
|
421
|
-
readonly prevValue: V | undefined;
|
|
422
414
|
/**
|
|
423
415
|
* @readonly
|
|
424
416
|
* @type {Attribution?}
|
|
@@ -466,18 +458,13 @@ export class SetAttrOp<V extends unknown = any, K extends string | number = any>
|
|
|
466
458
|
export class DeleteAttrOp<V = any, K extends string | number = string | number> {
|
|
467
459
|
/**
|
|
468
460
|
* @param {K} key
|
|
469
|
-
* @param {V|undefined} prevValue
|
|
470
461
|
* @param {Attribution?} attribution
|
|
471
462
|
*/
|
|
472
|
-
constructor(key: K,
|
|
463
|
+
constructor(key: K, attribution: Attribution | null);
|
|
473
464
|
/**
|
|
474
465
|
* @type {K}
|
|
475
466
|
*/
|
|
476
467
|
key: K;
|
|
477
|
-
/**
|
|
478
|
-
* @type {V|undefined}
|
|
479
|
-
*/
|
|
480
|
-
prevValue: V | undefined;
|
|
481
468
|
attribution: Attribution | null;
|
|
482
469
|
/**
|
|
483
470
|
* @type {string|null}
|
|
@@ -654,20 +641,72 @@ export class DeltaBuilder<Conf extends DeltaConf = {}, FixedConf extends boolean
|
|
|
654
641
|
/**
|
|
655
642
|
* @type {Formats?}
|
|
656
643
|
*/
|
|
657
|
-
|
|
644
|
+
_usedFormats: Formats | null;
|
|
658
645
|
/**
|
|
659
646
|
* @type {Attribution?}
|
|
660
647
|
*/
|
|
661
|
-
|
|
648
|
+
_usedAttribution: Attribution | null;
|
|
649
|
+
/**
|
|
650
|
+
* Resolved data-companion cache for the `used*` contexts ({@link resolveUsedData}): what data
|
|
651
|
+
* ops inherit instead of the raw context. `undefined` = stale, recomputed on the next data-op
|
|
652
|
+
* consumption ({@link DeltaBuilder#_getUsedFormatsData}) — {@link DeltaBuilder#useFormats} & co
|
|
653
|
+
* clear it whenever they swap the context (which is why the public slots are read-only).
|
|
654
|
+
*
|
|
655
|
+
* @type {Formats|null|undefined}
|
|
656
|
+
*/
|
|
657
|
+
_usedFormatsData: Formats | null | undefined;
|
|
658
|
+
/**
|
|
659
|
+
* @type {Attribution|null|undefined}
|
|
660
|
+
*/
|
|
661
|
+
_usedAttributionData: Attribution | null | undefined;
|
|
662
|
+
/**
|
|
663
|
+
* The ambient formats context inherited by subsequent ops. Read-only: set it via
|
|
664
|
+
* {@link DeltaBuilder#useFormats} / {@link DeltaBuilder#updateUsedFormats}, which also invalidate
|
|
665
|
+
* the cached data companion — a direct overwrite would leave it stale.
|
|
666
|
+
*
|
|
667
|
+
* @return {Formats?}
|
|
668
|
+
*/
|
|
669
|
+
get usedFormats(): Formats | null;
|
|
662
670
|
/**
|
|
671
|
+
* The ambient attribution context inherited by subsequent ops. Read-only — see
|
|
672
|
+
* {@link DeltaBuilder#usedFormats}; set it via {@link DeltaBuilder#useAttribution} /
|
|
673
|
+
* {@link DeltaBuilder#updateUsedAttribution}.
|
|
674
|
+
*
|
|
675
|
+
* @return {Attribution?}
|
|
676
|
+
*/
|
|
677
|
+
get usedAttribution(): Attribution | null;
|
|
678
|
+
/**
|
|
679
|
+
* Set the ambient attribution context inherited by subsequent ops (`undefined`/empty dim args).
|
|
680
|
+
* The object is interned — instruction ops store it, and data ops store its resolved companion
|
|
681
|
+
* ({@link resolveUsedData}), BY REFERENCE. Never mutate it after setting; pass a fresh object
|
|
682
|
+
* instead (same invariant as the objects stored on ops).
|
|
683
|
+
*
|
|
663
684
|
* @param {Attribution?} attribution
|
|
664
685
|
*/
|
|
665
686
|
useAttribution(attribution: Attribution | null): this;
|
|
666
687
|
/**
|
|
688
|
+
* Set the ambient formats context inherited by subsequent ops (`undefined`/empty dim args). The
|
|
689
|
+
* object is interned — see {@link DeltaBuilder#useAttribution}: never mutate it after setting.
|
|
690
|
+
*
|
|
667
691
|
* @param {Formats?} attributes
|
|
668
692
|
* @return {this}
|
|
669
693
|
*/
|
|
670
694
|
useFormats(attributes: Formats | null): this;
|
|
695
|
+
/**
|
|
696
|
+
* The `usedFormats` context resolved for data-op consumption ({@link resolveUsedData}): the slot
|
|
697
|
+
* object itself when it carries no `{k:null}` removals, one shared stripped copy otherwise.
|
|
698
|
+
* Cached until the context is swapped — no per-op traversal.
|
|
699
|
+
*
|
|
700
|
+
* @return {Formats?}
|
|
701
|
+
*/
|
|
702
|
+
_getUsedFormatsData(): Formats | null;
|
|
703
|
+
/**
|
|
704
|
+
* See {@link DeltaBuilder#_getUsedFormatsData} — the `usedAttribution` analogue (its `format` key
|
|
705
|
+
* resolves one level deeper).
|
|
706
|
+
*
|
|
707
|
+
* @return {Attribution?}
|
|
708
|
+
*/
|
|
709
|
+
_getUsedAttributionData(): Attribution | null;
|
|
671
710
|
/**
|
|
672
711
|
* @param {string} name
|
|
673
712
|
* @param {any} value
|
|
@@ -736,19 +775,17 @@ export class DeltaBuilder<Conf extends DeltaConf = {}, FixedConf extends boolean
|
|
|
736
775
|
retain(len: number, format?: Formats | null, attribution?: Attribution | null): this;
|
|
737
776
|
/**
|
|
738
777
|
* @param {number} len
|
|
739
|
-
* @param {DeltaBuilder<any>|null} prevValue
|
|
740
778
|
*/
|
|
741
|
-
delete(len: number
|
|
779
|
+
delete(len: number): this;
|
|
742
780
|
/**
|
|
743
781
|
* @template {Extract<keyof DeltaConfGetAllowedAttrs<Conf, FixedConf>,string|number>} Key
|
|
744
782
|
* @template {DeltaConfGetAllowedAttrs<Conf, FixedConf>[Key]} Val
|
|
745
783
|
* @param {Key} key
|
|
746
784
|
* @param {Val} val
|
|
747
785
|
* @param {Attribution?} [attribution] provenance for this attr (data: object or `null`/none)
|
|
748
|
-
* @param {Val|undefined} [prevValue]
|
|
749
786
|
* @return {DeltaBuilder<DeltaConfOverwrite<Conf,{attrs:AddToAttrs<DeltaConfGetAttrs<Conf>,Key,Val>}>, FixedConf>}
|
|
750
787
|
*/
|
|
751
|
-
setAttr<Key extends Extract<keyof DeltaConfGetAllowedAttrs<Conf, FixedConf>, string | number>, Val extends DeltaConfGetAllowedAttrs<Conf, FixedConf>[Key]>(key: Key, val: Val, attribution?: Attribution | null
|
|
788
|
+
setAttr<Key extends Extract<keyof DeltaConfGetAllowedAttrs<Conf, FixedConf>, string | number>, Val extends DeltaConfGetAllowedAttrs<Conf, FixedConf>[Key]>(key: Key, val: Val, attribution?: Attribution | null): DeltaBuilder<DeltaConfOverwrite<Conf, {
|
|
752
789
|
attrs: AddToAttrs<DeltaConfGetAttrs<Conf>, Key, Val>;
|
|
753
790
|
}>, FixedConf>;
|
|
754
791
|
/**
|
|
@@ -768,12 +805,11 @@ export class DeltaBuilder<Conf extends DeltaConf = {}, FixedConf extends boolean
|
|
|
768
805
|
* @template {Extract<keyof DeltaConfGetAllowedAttrs<Conf, FixedConf>,string|number>} Key
|
|
769
806
|
* @param {Key} key
|
|
770
807
|
* @param {Attribution?} [attribution] provenance for the deletion (data: object or `null`/none)
|
|
771
|
-
* @param {any} [prevValue]
|
|
772
808
|
* @return {DeltaBuilder<DeltaConfOverwrite<Conf, {
|
|
773
809
|
* attrs: AddToAttrs<DeltaConfGetAttrs<Conf>,Key,never>
|
|
774
810
|
* }>, FixedConf>}
|
|
775
811
|
*/
|
|
776
|
-
deleteAttr<Key extends Extract<keyof DeltaConfGetAllowedAttrs<Conf, FixedConf>, string | number>>(key: Key, attribution?: Attribution | null
|
|
812
|
+
deleteAttr<Key extends Extract<keyof DeltaConfGetAllowedAttrs<Conf, FixedConf>, string | number>>(key: Key, attribution?: Attribution | null): DeltaBuilder<DeltaConfOverwrite<Conf, {
|
|
777
813
|
attrs: AddToAttrs<DeltaConfGetAttrs<Conf>, Key, never>;
|
|
778
814
|
}>, FixedConf>;
|
|
779
815
|
/**
|
|
@@ -1050,6 +1086,7 @@ export function from<NodeName extends string | null, Attrs extends {
|
|
|
1050
1086
|
text: Extract<Children, string> extends never ? false : true;
|
|
1051
1087
|
}>;
|
|
1052
1088
|
export function diff<Conf_1 extends DeltaConf>(d1: Delta<Conf_1>, d2: NoInfer<Delta<Conf_1>>, options?: DiffOptions): Delta<Conf_1>;
|
|
1089
|
+
export function inverse<Conf_1 extends DeltaConf>(d: DeltaAny, base: Delta<Conf_1>): Delta<Conf_1>;
|
|
1053
1090
|
export function diffChangesetWithSeparator(changeset: Array<{
|
|
1054
1091
|
index: number;
|
|
1055
1092
|
remove: Array<any>;
|
|
@@ -1132,11 +1169,9 @@ export type DeltaListOpJSON = {
|
|
|
1132
1169
|
export type DeltaAttrOpJSON = {
|
|
1133
1170
|
type: "insert";
|
|
1134
1171
|
value: any;
|
|
1135
|
-
prevValue?: any;
|
|
1136
1172
|
attribution?: Attribution;
|
|
1137
1173
|
} | {
|
|
1138
1174
|
type: "delete";
|
|
1139
|
-
prevValue?: any;
|
|
1140
1175
|
attribution?: Attribution;
|
|
1141
1176
|
} | {
|
|
1142
1177
|
type: "modify";
|
package/dist/delta/rdt.d.ts
CHANGED
|
@@ -62,6 +62,12 @@ export { deltaRDT } from "./rdt/delta.js";
|
|
|
62
62
|
* @type {Schema<RDT<any>>}
|
|
63
63
|
*/
|
|
64
64
|
export const $rdt: Schema<RDT<any>>;
|
|
65
|
+
/**
|
|
66
|
+
* @typedef {object} BindOptions
|
|
67
|
+
* @property {delta.DiffOptions['compare']} [diffCompare] **Experimental** (may be changed or removed
|
|
68
|
+
* in a future release). Forwarded as `compare` to {@link delta.diff} when the initial-state sync diffs
|
|
69
|
+
* `a`'s projection against `b`'s current state, controlling how nodes are paired into `modify` ops.
|
|
70
|
+
*/
|
|
65
71
|
/**
|
|
66
72
|
* Connects two RDTs so that changes on either side are transformed and reflected on the other.
|
|
67
73
|
*
|
|
@@ -81,8 +87,9 @@ export class Binding<A extends delta.DeltaConf, B extends delta.DeltaConf> {
|
|
|
81
87
|
* @param {RDT<B>} b
|
|
82
88
|
* @param {dt.TemplateFactory<A,B>} [template] a `$d => Template` factory; defaults to the
|
|
83
89
|
* {@link dt.id identity} transformer. `bind` injects `a`'s schema, then materializes via `.init()`.
|
|
90
|
+
* @param {BindOptions} [options]
|
|
84
91
|
*/
|
|
85
|
-
constructor(a: RDT<A>, b: RDT<B>, template?: dt.TemplateFactory<A, B
|
|
92
|
+
constructor(a: RDT<A>, b: RDT<B>, template?: dt.TemplateFactory<A, B>, options?: BindOptions);
|
|
86
93
|
/**
|
|
87
94
|
* @type {dt.Transformer<A,B>}
|
|
88
95
|
*/
|
|
@@ -105,7 +112,7 @@ export class Binding<A extends delta.DeltaConf, B extends delta.DeltaConf> {
|
|
|
105
112
|
*/
|
|
106
113
|
destroy: () => void;
|
|
107
114
|
}
|
|
108
|
-
export function bind<A extends delta.DeltaConf, B extends delta.DeltaConf>(a: RDT<A>, b: RDT<B>, template?: dt.TemplateFactory<A, B
|
|
115
|
+
export function bind<A extends delta.DeltaConf, B extends delta.DeltaConf>(a: RDT<A>, b: RDT<B>, template?: dt.TemplateFactory<A, B>, options?: BindOptions): Binding<A, B>;
|
|
109
116
|
export type Schema<T> = import("../schema.js").Schema<T>;
|
|
110
117
|
/**
|
|
111
118
|
* Abstract interface for a delta-based Replicated Data Type.
|
|
@@ -158,6 +165,14 @@ export type RDT<Conf extends import("./delta.js").DeltaConf> = import("../observ
|
|
|
158
165
|
applyDelta: (delta: delta.Delta<Conf>, origin?: any) => delta.DeltaBuilder<Conf> | null;
|
|
159
166
|
destroy: () => void;
|
|
160
167
|
};
|
|
168
|
+
export type BindOptions = {
|
|
169
|
+
/**
|
|
170
|
+
* **Experimental** (may be changed or removed
|
|
171
|
+
* in a future release). Forwarded as `compare` to {@link delta.diff} when the initial-state sync diffs
|
|
172
|
+
* `a`'s projection against `b`'s current state, controlling how nodes are paired into `modify` ops.
|
|
173
|
+
*/
|
|
174
|
+
diffCompare?: delta.DiffOptions["compare"];
|
|
175
|
+
};
|
|
161
176
|
import * as delta from './delta.js';
|
|
162
177
|
import * as dt from './transformer.js';
|
|
163
178
|
import * as mux from '../mutex.js';
|
package/dist/environment.d.ts
CHANGED
|
@@ -4,6 +4,12 @@ export const isNode: boolean;
|
|
|
4
4
|
* @type {boolean}
|
|
5
5
|
*/
|
|
6
6
|
export const isDeno: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* True iff this script is running in a browser-family environment — either a DOM main
|
|
9
|
+
* thread (`window` + `document`) or a WebWorker / ServiceWorker (a `WorkerGlobalScope`,
|
|
10
|
+
* which has `btoa`/`atob`/`fetch` but no DOM). Excludes Node and Deno.
|
|
11
|
+
* @type {boolean}
|
|
12
|
+
*/
|
|
7
13
|
export const isBrowser: boolean;
|
|
8
14
|
export const isMac: boolean;
|
|
9
15
|
/**
|
package/package.json
CHANGED
package/src/delta/delta.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* This module exports a large surface, but a consumer only needs a handful of it:
|
|
7
7
|
* - **build / apply / inspect:** {@link create} (the constructor) and the {@link DeltaBuilder} methods
|
|
8
8
|
* it returns (`insert`/`delete`/`retain`/`modify`/`setAttr`/`addMark`/…, `apply`, `rebase`, `done`);
|
|
9
|
-
* {@link clone}, {@link slice}, {@link diff}, and `toJSON`/`equals`/`isEmpty` on the result.
|
|
9
|
+
* {@link clone}, {@link slice}, {@link diff}, {@link inverse}, and `toJSON`/`equals`/`isEmpty` on the result.
|
|
10
10
|
* - **schemas:** {@link $delta} (define a typed delta schema) and {@link $deltaAny} (the catch-all).
|
|
11
11
|
* - **types:** `Delta`, `DeltaBuilder`, `DeltaAny`, `DeltaConf` for annotations.
|
|
12
12
|
*
|
|
@@ -109,7 +109,7 @@ export const $attribution = /* @__PURE__ */(() => s.$object({
|
|
|
109
109
|
*/
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
|
-
* @typedef {{ type: 'insert', value: any,
|
|
112
|
+
* @typedef {{ type: 'insert', value: any, attribution?: Attribution } | { type: 'delete', attribution?: Attribution } | { type: 'modify', value: DeltaJSON, attribution?: Attribution|null }} DeltaAttrOpJSON
|
|
113
113
|
*/
|
|
114
114
|
|
|
115
115
|
/**
|
|
@@ -128,9 +128,9 @@ export const $attribution = /* @__PURE__ */(() => s.$object({
|
|
|
128
128
|
* @type {s.Schema<DeltaAttrOpJSON>}
|
|
129
129
|
*/
|
|
130
130
|
export const $deltaMapChangeJson = /* @__PURE__ */(() => s.$union(
|
|
131
|
-
s.$object({ type: s.$literal('insert'), value: s.$any,
|
|
131
|
+
s.$object({ type: s.$literal('insert'), value: s.$any, attribution: $attribution.optional }),
|
|
132
132
|
s.$object({ type: s.$literal('modify'), value: s.$any, attribution: $attribution.optional }),
|
|
133
|
-
s.$object({ type: s.$literal('delete'),
|
|
133
|
+
s.$object({ type: s.$literal('delete'), attribution: $attribution.optional })
|
|
134
134
|
))()
|
|
135
135
|
|
|
136
136
|
/**
|
|
@@ -144,8 +144,10 @@ const _cloneAttrs = attrs => attrs == null ? attrs : { ...attrs }
|
|
|
144
144
|
* as the inner step of {@link mergeAttr}). Per key: `undefined` skips, `null` removes, anything else sets.
|
|
145
145
|
* `resolve` true (data semantics) applies a `null` removal by deleting the key; false (instruction semantics)
|
|
146
146
|
* keeps the `null` verbatim so it still removes when the instruction is later applied. When `resolve` is true
|
|
147
|
-
* the `base` is canonicalised too — a `{k:null}` already present in `base`
|
|
148
|
-
*
|
|
147
|
+
* the `base` is canonicalised too — a `{k:null}` already present in `base` has nothing to clear on settled
|
|
148
|
+
* data, so it is dropped rather than copied through. (The used-context call sites pass pre-resolved
|
|
149
|
+
* companions — see {@link resolveUsedData} — so for them this is a no-op safety net; it matters for the
|
|
150
|
+
* apply/diff paths that merge instructions onto stored values.)
|
|
149
151
|
*
|
|
150
152
|
* @param {{[k:string]:any}|null|undefined} base
|
|
151
153
|
* @param {{[k:string]:any}} update
|
|
@@ -225,46 +227,83 @@ const resolveBeyond = (arg, deep) => {
|
|
|
225
227
|
return object.isEmpty(m) ? undefined : m
|
|
226
228
|
}
|
|
227
229
|
/**
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
* (
|
|
231
|
-
*
|
|
232
|
-
*
|
|
230
|
+
* Resolve a `used*` context (set via {@link DeltaBuilder#useFormats}/`useAttribution`) for **data**
|
|
231
|
+
* consumption: settled data stores canonical values only
|
|
232
|
+
* (no `null` leaves — see {@link combineData}), while the slot itself keeps removal instructions
|
|
233
|
+
* verbatim for the instruction ops it governs. Returns the SAME object when it is already canonical
|
|
234
|
+
* (the common case — provenance contexts carry no removals), so every data op under one context shares
|
|
235
|
+
* one interned object; otherwise strips the removals ONCE into a shared copy (`{}` collapses to `null`).
|
|
236
|
+
* Never called per op — {@link DeltaBuilder#_getUsedFormatsData} caches the result per context object.
|
|
233
237
|
*
|
|
234
238
|
* @param {{[k:string]:any}|null} used
|
|
235
|
-
* @param {
|
|
236
|
-
* @
|
|
237
|
-
*
|
|
238
|
-
* @param {boolean} resolve see above ({@link mergeShallow})
|
|
239
|
-
* @return {{[k:string]:any}|null|undefined}
|
|
239
|
+
* @param {boolean} deep `true` for the `attribution` dimension (its `format` key resolves one level
|
|
240
|
+
* deeper via {@link mergeAttr}); `false` for `format` (shallow, {@link mergeShallow})
|
|
241
|
+
* @return {{[k:string]:any}|null}
|
|
240
242
|
*/
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
243
|
+
const resolveUsedData = (used, deep) => {
|
|
244
|
+
if (used === null) return null
|
|
245
|
+
let empty = true
|
|
246
|
+
let canonical = true
|
|
247
|
+
for (const k in used) {
|
|
248
|
+
empty = false
|
|
249
|
+
const v = used[k]
|
|
250
|
+
if (v === null) { canonical = false; break } // a top-level removal (incl. `format: null`)
|
|
251
|
+
if (deep && k === 'format' && s.$objectAny.check(v)) {
|
|
252
|
+
// mirror mergeAttr's resolve-mode base handling: an emptied `format` is dropped on data, and an
|
|
253
|
+
// inner `{k:null}` removal is stripped — either makes the context non-canonical for data ops
|
|
254
|
+
let formatCanonical = false // empty `format: {}` ⇒ non-canonical
|
|
255
|
+
for (const ik in v) {
|
|
256
|
+
if (v[ik] === null) { formatCanonical = false; break }
|
|
257
|
+
formatCanonical = true
|
|
258
|
+
}
|
|
259
|
+
if (!formatCanonical) { canonical = false; break }
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (empty) return null
|
|
263
|
+
if (canonical) return used
|
|
264
|
+
const m = deep ? mergeAttr(used, {}, true) : mergeShallow(used, {}, true)
|
|
265
|
+
return object.isEmpty(m) ? null : m
|
|
266
|
+
}
|
|
247
267
|
/**
|
|
248
|
-
* Combine
|
|
249
|
-
*
|
|
268
|
+
* Combine a builder's `used*` context with a per-call format/attribution argument for an
|
|
269
|
+
* **instruction** op (`retain`/`modify`/`modifyAttr`) under the unified tri-state: `undefined` — or an
|
|
270
|
+
* empty object, an empty update — inherits the context BY IDENTITY (no traversal, no copy; contexts
|
|
271
|
+
* are interned); `null` clears (ignoring the context); a non-empty object merges over the context,
|
|
272
|
+
* keeping `{k:null}` removals verbatim so they still remove when the instruction is later applied.
|
|
273
|
+
* An empty result is a no-op → `undefined` (skip).
|
|
250
274
|
*
|
|
251
|
-
* @param {{[k:string]:any}|null} used
|
|
275
|
+
* @param {{[k:string]:any}|null} used the raw context slot (removal instructions intact)
|
|
252
276
|
* @param {{[k:string]:any}|null|undefined} arg
|
|
253
|
-
* @param {boolean} deep
|
|
277
|
+
* @param {boolean} deep `true` for the `attribution` dimension (its `format` key merges per inner key via
|
|
278
|
+
* {@link mergeAttr}); `false` for `format` (shallow, {@link mergeShallow}).
|
|
254
279
|
* @return {{[k:string]:any}|null|undefined}
|
|
255
280
|
*/
|
|
256
|
-
const combineInstr = (used, arg, deep) => {
|
|
281
|
+
const combineInstr = (used, arg, deep) => {
|
|
282
|
+
if (arg === null) return null // explicit clear — must precede the isEmpty check (object.isEmpty(null) is true)
|
|
283
|
+
if (arg === undefined || object.isEmpty(arg)) return used === null || object.isEmpty(used) ? undefined : used
|
|
284
|
+
const r = deep ? mergeAttr(used, arg, false) : mergeShallow(used, arg, false)
|
|
285
|
+
return object.isEmpty(r) ? undefined : r
|
|
286
|
+
}
|
|
257
287
|
/**
|
|
258
|
-
* Combine
|
|
259
|
-
*
|
|
260
|
-
* `
|
|
288
|
+
* Combine for a **data** op (`insert`/`text`/`setAttr`/`deleteAttr`): the stored value is a canonical
|
|
289
|
+
* object or `null` ("none") — never a `{k:null}` removal, there is nothing to remove on settled data.
|
|
290
|
+
* `usedData` is the builder's RESOLVED context companion ({@link resolveUsedData}, cached by
|
|
291
|
+
* {@link DeltaBuilder#_getUsedFormatsData}) and thus already canonical (`null` or a non-empty
|
|
292
|
+
* no-`null` object), so `undefined` — or an empty object, an empty update — inherits it BY IDENTITY
|
|
293
|
+
* (no traversal, no copy); `null` clears; a non-empty object merges over it, resolving the argument's
|
|
294
|
+
* own `{k:null}` removals. `{}` results collapse to `null`.
|
|
261
295
|
*
|
|
262
|
-
* @param {{[k:string]:any}|null}
|
|
296
|
+
* @param {{[k:string]:any}|null} usedData
|
|
263
297
|
* @param {{[k:string]:any}|null|undefined} arg
|
|
264
|
-
* @param {boolean} deep see {@link
|
|
298
|
+
* @param {boolean} deep see {@link combineInstr}
|
|
265
299
|
* @return {{[k:string]:any}|null}
|
|
266
300
|
*/
|
|
267
|
-
const combineData = (
|
|
301
|
+
const combineData = (usedData, arg, deep) => {
|
|
302
|
+
if (arg === null) return null // explicit clear — must precede the isEmpty check (object.isEmpty(null) is true)
|
|
303
|
+
if (arg === undefined || object.isEmpty(arg)) return usedData
|
|
304
|
+
const r = deep ? mergeAttr(usedData, arg, true) : mergeShallow(usedData, arg, true)
|
|
305
|
+
return object.isEmpty(r) ? null : /** @type {{[k:string]:any}} */ (r)
|
|
306
|
+
}
|
|
268
307
|
/**
|
|
269
308
|
* @template {any} MaybeDelta
|
|
270
309
|
* @param {MaybeDelta} maybeDelta
|
|
@@ -531,12 +570,10 @@ export class InsertOp extends list.ListNode {
|
|
|
531
570
|
export class DeleteOp extends list.ListNode {
|
|
532
571
|
/**
|
|
533
572
|
* @param {number} len
|
|
534
|
-
* @param {DeltaBuilder<any>?} prevValue
|
|
535
573
|
*/
|
|
536
|
-
constructor (len
|
|
574
|
+
constructor (len) {
|
|
537
575
|
super()
|
|
538
576
|
this.delete = len
|
|
539
|
-
this.prevValue = /** @type {Delta<Conf>?} */ (prevValue)
|
|
540
577
|
/**
|
|
541
578
|
* @type {string|null}
|
|
542
579
|
*/
|
|
@@ -564,13 +601,10 @@ export class DeleteOp extends list.ListNode {
|
|
|
564
601
|
/**
|
|
565
602
|
* Remove a part of the operation (similar to Array.splice)
|
|
566
603
|
*
|
|
567
|
-
* @param {number}
|
|
604
|
+
* @param {number} _offset
|
|
568
605
|
* @param {number} len
|
|
569
606
|
*/
|
|
570
|
-
_splice (
|
|
571
|
-
if (this.prevValue) {
|
|
572
|
-
/** @type {DeltaBuilder<any>} */ (this.prevValue).apply(create().retain(offset).delete(len))
|
|
573
|
-
}
|
|
607
|
+
_splice (_offset, len) {
|
|
574
608
|
this._fingerprint = null
|
|
575
609
|
this.delete -= len
|
|
576
610
|
return this
|
|
@@ -594,11 +628,11 @@ export class DeleteOp extends list.ListNode {
|
|
|
594
628
|
* @param {number} [start]
|
|
595
629
|
* @param {number} [end]
|
|
596
630
|
* @param {boolean} [_markAsDone] accepted for a uniform children-op `clone` signature; ignored (a
|
|
597
|
-
*
|
|
631
|
+
* delete holds no nested content).
|
|
598
632
|
* @return {DeleteOp}
|
|
599
633
|
*/
|
|
600
634
|
clone (start = 0, end = this.delete, _markAsDone = true) {
|
|
601
|
-
return new DeleteOp(end - start
|
|
635
|
+
return new DeleteOp(end - start)
|
|
602
636
|
}
|
|
603
637
|
}
|
|
604
638
|
|
|
@@ -822,10 +856,9 @@ export class SetAttrOp {
|
|
|
822
856
|
/**
|
|
823
857
|
* @param {K} key
|
|
824
858
|
* @param {V} value
|
|
825
|
-
* @param {V|undefined} prevValue
|
|
826
859
|
* @param {Attribution?} attribution
|
|
827
860
|
*/
|
|
828
|
-
constructor (key, value,
|
|
861
|
+
constructor (key, value, attribution) {
|
|
829
862
|
/**
|
|
830
863
|
* @readonly
|
|
831
864
|
* @type {K}
|
|
@@ -836,11 +869,6 @@ export class SetAttrOp {
|
|
|
836
869
|
* @type {V}
|
|
837
870
|
*/
|
|
838
871
|
this.value = value
|
|
839
|
-
/**
|
|
840
|
-
* @readonly
|
|
841
|
-
* @type {V|undefined}
|
|
842
|
-
*/
|
|
843
|
-
this.prevValue = prevValue
|
|
844
872
|
/**
|
|
845
873
|
* @readonly
|
|
846
874
|
* @type {Attribution?}
|
|
@@ -905,7 +933,7 @@ export class SetAttrOp {
|
|
|
905
933
|
* @return {SetAttrOp<V,K>}
|
|
906
934
|
*/
|
|
907
935
|
clone () {
|
|
908
|
-
return new SetAttrOp(this.key, _markMaybeDeltaAsDone(this.value),
|
|
936
|
+
return new SetAttrOp(this.key, _markMaybeDeltaAsDone(this.value), _cloneAttrs(this.attribution))
|
|
909
937
|
}
|
|
910
938
|
}
|
|
911
939
|
|
|
@@ -917,18 +945,13 @@ export class SetAttrOp {
|
|
|
917
945
|
export class DeleteAttrOp {
|
|
918
946
|
/**
|
|
919
947
|
* @param {K} key
|
|
920
|
-
* @param {V|undefined} prevValue
|
|
921
948
|
* @param {Attribution?} attribution
|
|
922
949
|
*/
|
|
923
|
-
constructor (key,
|
|
950
|
+
constructor (key, attribution) {
|
|
924
951
|
/**
|
|
925
952
|
* @type {K}
|
|
926
953
|
*/
|
|
927
954
|
this.key = key
|
|
928
|
-
/**
|
|
929
|
-
* @type {V|undefined}
|
|
930
|
-
*/
|
|
931
|
-
this.prevValue = prevValue
|
|
932
955
|
this.attribution = attribution
|
|
933
956
|
/**
|
|
934
957
|
* @type {string|null}
|
|
@@ -977,7 +1000,7 @@ export class DeleteAttrOp {
|
|
|
977
1000
|
* @return {DeleteAttrOp<V,K>}
|
|
978
1001
|
*/
|
|
979
1002
|
clone () {
|
|
980
|
-
return new DeleteAttrOp(this.key,
|
|
1003
|
+
return new DeleteAttrOp(this.key, _cloneAttrs(this.attribution))
|
|
981
1004
|
}
|
|
982
1005
|
}
|
|
983
1006
|
|
|
@@ -1609,7 +1632,7 @@ const _cloneMaybeDeltaDeep = v => $deltaAny.check(v) ? cloneDeep(v) : v
|
|
|
1609
1632
|
* Deep-clone one content (child) op for {@link cloneDeep}: a fresh op whose nested deltas (an insert's
|
|
1610
1633
|
* delta content, a modify's value) are themselves deep-cloned. `format`/`attribution` objects are
|
|
1611
1634
|
* retained (shared) — they are always copied before being mutated (see {@link cloneDeep}). Ops without a
|
|
1612
|
-
* nested delta
|
|
1635
|
+
* nested delta (`text`/`retain`/`delete`) use `op.clone()`.
|
|
1613
1636
|
*
|
|
1614
1637
|
* @param {ChildrenOpAny} op
|
|
1615
1638
|
* @return {ChildrenOpAny}
|
|
@@ -1623,7 +1646,7 @@ const _cloneChildOpDeep = op =>
|
|
|
1623
1646
|
|
|
1624
1647
|
/**
|
|
1625
1648
|
* Deep-clone one attribute op for {@link cloneDeep} — the attribute-dimension mirror of
|
|
1626
|
-
* {@link _cloneChildOpDeep}: a `setAttr`'s value
|
|
1649
|
+
* {@link _cloneChildOpDeep}: a `setAttr`'s value and a `modifyAttr`'s value may be nested
|
|
1627
1650
|
* deltas and are deep-cloned.
|
|
1628
1651
|
*
|
|
1629
1652
|
* @param {AttrOpAny} op
|
|
@@ -1631,11 +1654,11 @@ const _cloneChildOpDeep = op =>
|
|
|
1631
1654
|
*/
|
|
1632
1655
|
const _cloneAttrOpDeep = op =>
|
|
1633
1656
|
$setAttrOp.check(op)
|
|
1634
|
-
? new SetAttrOp(op.key, _cloneMaybeDeltaDeep(op.value),
|
|
1657
|
+
? new SetAttrOp(op.key, _cloneMaybeDeltaDeep(op.value), op.attribution)
|
|
1635
1658
|
: ($modifyAttrOp.check(op)
|
|
1636
1659
|
? new ModifyAttrOp(op.key, cloneDeep(op.value), op.attribution)
|
|
1637
|
-
// the only remaining attr op is a deleteAttr
|
|
1638
|
-
: new DeleteAttrOp(op.key,
|
|
1660
|
+
// the only remaining attr op is a deleteAttr
|
|
1661
|
+
: new DeleteAttrOp(op.key, op.attribution))
|
|
1639
1662
|
|
|
1640
1663
|
/**
|
|
1641
1664
|
* A **deep** clone of `d`: like {@link clone}, but every nested delta — an insert's delta content, a
|
|
@@ -1919,32 +1942,100 @@ export class DeltaBuilder extends Delta {
|
|
|
1919
1942
|
/**
|
|
1920
1943
|
* @type {Formats?}
|
|
1921
1944
|
*/
|
|
1922
|
-
this.
|
|
1945
|
+
this._usedFormats = null
|
|
1923
1946
|
/**
|
|
1924
1947
|
* @type {Attribution?}
|
|
1925
1948
|
*/
|
|
1926
|
-
this.
|
|
1949
|
+
this._usedAttribution = null
|
|
1950
|
+
/**
|
|
1951
|
+
* Resolved data-companion cache for the `used*` contexts ({@link resolveUsedData}): what data
|
|
1952
|
+
* ops inherit instead of the raw context. `undefined` = stale, recomputed on the next data-op
|
|
1953
|
+
* consumption ({@link DeltaBuilder#_getUsedFormatsData}) — {@link DeltaBuilder#useFormats} & co
|
|
1954
|
+
* clear it whenever they swap the context (which is why the public slots are read-only).
|
|
1955
|
+
*
|
|
1956
|
+
* @type {Formats|null|undefined}
|
|
1957
|
+
*/
|
|
1958
|
+
this._usedFormatsData = undefined
|
|
1959
|
+
/**
|
|
1960
|
+
* @type {Attribution|null|undefined}
|
|
1961
|
+
*/
|
|
1962
|
+
this._usedAttributionData = undefined
|
|
1927
1963
|
}
|
|
1928
1964
|
|
|
1929
1965
|
/**
|
|
1966
|
+
* The ambient formats context inherited by subsequent ops. Read-only: set it via
|
|
1967
|
+
* {@link DeltaBuilder#useFormats} / {@link DeltaBuilder#updateUsedFormats}, which also invalidate
|
|
1968
|
+
* the cached data companion — a direct overwrite would leave it stale.
|
|
1969
|
+
*
|
|
1970
|
+
* @return {Formats?}
|
|
1971
|
+
*/
|
|
1972
|
+
get usedFormats () { return this._usedFormats }
|
|
1973
|
+
|
|
1974
|
+
/**
|
|
1975
|
+
* The ambient attribution context inherited by subsequent ops. Read-only — see
|
|
1976
|
+
* {@link DeltaBuilder#usedFormats}; set it via {@link DeltaBuilder#useAttribution} /
|
|
1977
|
+
* {@link DeltaBuilder#updateUsedAttribution}.
|
|
1978
|
+
*
|
|
1979
|
+
* @return {Attribution?}
|
|
1980
|
+
*/
|
|
1981
|
+
get usedAttribution () { return this._usedAttribution }
|
|
1982
|
+
|
|
1983
|
+
/**
|
|
1984
|
+
* Set the ambient attribution context inherited by subsequent ops (`undefined`/empty dim args).
|
|
1985
|
+
* The object is interned — instruction ops store it, and data ops store its resolved companion
|
|
1986
|
+
* ({@link resolveUsedData}), BY REFERENCE. Never mutate it after setting; pass a fresh object
|
|
1987
|
+
* instead (same invariant as the objects stored on ops).
|
|
1988
|
+
*
|
|
1930
1989
|
* @param {Attribution?} attribution
|
|
1931
1990
|
*/
|
|
1932
1991
|
useAttribution (attribution) {
|
|
1933
1992
|
modDeltaCheck(this)
|
|
1934
|
-
this.
|
|
1993
|
+
if (this._usedAttribution !== attribution) {
|
|
1994
|
+
this._usedAttribution = attribution
|
|
1995
|
+
this._usedAttributionData = undefined // clear the data companion — recomputed on next consumption
|
|
1996
|
+
}
|
|
1935
1997
|
return this
|
|
1936
1998
|
}
|
|
1937
1999
|
|
|
1938
2000
|
/**
|
|
2001
|
+
* Set the ambient formats context inherited by subsequent ops (`undefined`/empty dim args). The
|
|
2002
|
+
* object is interned — see {@link DeltaBuilder#useAttribution}: never mutate it after setting.
|
|
2003
|
+
*
|
|
1939
2004
|
* @param {Formats?} attributes
|
|
1940
2005
|
* @return {this}
|
|
1941
2006
|
*/
|
|
1942
2007
|
useFormats (attributes) {
|
|
1943
2008
|
modDeltaCheck(this)
|
|
1944
|
-
this.
|
|
2009
|
+
if (this._usedFormats !== attributes) {
|
|
2010
|
+
this._usedFormats = attributes
|
|
2011
|
+
this._usedFormatsData = undefined // clear the data companion — recomputed on next consumption
|
|
2012
|
+
}
|
|
1945
2013
|
return this
|
|
1946
2014
|
}
|
|
1947
2015
|
|
|
2016
|
+
/**
|
|
2017
|
+
* The `usedFormats` context resolved for data-op consumption ({@link resolveUsedData}): the slot
|
|
2018
|
+
* object itself when it carries no `{k:null}` removals, one shared stripped copy otherwise.
|
|
2019
|
+
* Cached until the context is swapped — no per-op traversal.
|
|
2020
|
+
*
|
|
2021
|
+
* @return {Formats?}
|
|
2022
|
+
*/
|
|
2023
|
+
_getUsedFormatsData () {
|
|
2024
|
+
const d = this._usedFormatsData
|
|
2025
|
+
return d !== undefined ? d : (this._usedFormatsData = /** @type {Formats?} */ (resolveUsedData(this._usedFormats, false)))
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
/**
|
|
2029
|
+
* See {@link DeltaBuilder#_getUsedFormatsData} — the `usedAttribution` analogue (its `format` key
|
|
2030
|
+
* resolves one level deeper).
|
|
2031
|
+
*
|
|
2032
|
+
* @return {Attribution?}
|
|
2033
|
+
*/
|
|
2034
|
+
_getUsedAttributionData () {
|
|
2035
|
+
const d = this._usedAttributionData
|
|
2036
|
+
return d !== undefined ? d : (this._usedAttributionData = /** @type {Attribution?} */ (resolveUsedData(this._usedAttribution, true)))
|
|
2037
|
+
}
|
|
2038
|
+
|
|
1948
2039
|
/**
|
|
1949
2040
|
* @param {string} name
|
|
1950
2041
|
* @param {any} value
|
|
@@ -1952,14 +2043,16 @@ export class DeltaBuilder extends Delta {
|
|
|
1952
2043
|
updateUsedFormats (name, value) {
|
|
1953
2044
|
modDeltaCheck(this)
|
|
1954
2045
|
if (value == null) {
|
|
1955
|
-
this.
|
|
1956
|
-
delete this.
|
|
1957
|
-
if (object.isEmpty(this.
|
|
1958
|
-
this.
|
|
2046
|
+
this._usedFormats = object.assign({}, this._usedFormats)
|
|
2047
|
+
delete this._usedFormats?.[name]
|
|
2048
|
+
if (object.isEmpty(this._usedFormats)) {
|
|
2049
|
+
this._usedFormats = null
|
|
1959
2050
|
}
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
this.
|
|
2051
|
+
this._usedFormatsData = undefined // clear the data companion — recomputed on next consumption
|
|
2052
|
+
} else if (!fun.equalityDeep(this._usedFormats?.[name], value)) {
|
|
2053
|
+
this._usedFormats = object.assign({}, this._usedFormats)
|
|
2054
|
+
this._usedFormats[name] = value
|
|
2055
|
+
this._usedFormatsData = undefined // clear the data companion — recomputed on next consumption
|
|
1963
2056
|
}
|
|
1964
2057
|
return this
|
|
1965
2058
|
}
|
|
@@ -1972,14 +2065,16 @@ export class DeltaBuilder extends Delta {
|
|
|
1972
2065
|
updateUsedAttribution (name, value) {
|
|
1973
2066
|
modDeltaCheck(this)
|
|
1974
2067
|
if (value == null) {
|
|
1975
|
-
this.
|
|
1976
|
-
delete this.
|
|
1977
|
-
if (object.isEmpty(this.
|
|
1978
|
-
this.
|
|
2068
|
+
this._usedAttribution = object.assign({}, this._usedAttribution)
|
|
2069
|
+
delete this._usedAttribution?.[name]
|
|
2070
|
+
if (object.isEmpty(this._usedAttribution)) {
|
|
2071
|
+
this._usedAttribution = null
|
|
1979
2072
|
}
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
this.
|
|
2073
|
+
this._usedAttributionData = undefined // clear the data companion — recomputed on next consumption
|
|
2074
|
+
} else if (!fun.equalityDeep(this._usedAttribution?.[name], value)) {
|
|
2075
|
+
this._usedAttribution = object.assign({}, this._usedAttribution)
|
|
2076
|
+
this._usedAttribution[name] = value
|
|
2077
|
+
this._usedAttributionData = undefined // clear the data companion — recomputed on next consumption
|
|
1983
2078
|
}
|
|
1984
2079
|
return this
|
|
1985
2080
|
}
|
|
@@ -1996,8 +2091,8 @@ export class DeltaBuilder extends Delta {
|
|
|
1996
2091
|
*/
|
|
1997
2092
|
insert (insert, formatting, attribution) {
|
|
1998
2093
|
modDeltaCheck(this)
|
|
1999
|
-
const mergedFormats = combineData(this.
|
|
2000
|
-
const mergedAttribution = combineData(this.
|
|
2094
|
+
const mergedFormats = combineData(this._getUsedFormatsData(), formatting, false)
|
|
2095
|
+
const mergedAttribution = combineData(this._getUsedAttributionData(), attribution, true)
|
|
2001
2096
|
/**
|
|
2002
2097
|
* @param {TextOp | InsertOp<any>} lastOp
|
|
2003
2098
|
*/
|
|
@@ -2102,19 +2197,15 @@ export class DeltaBuilder extends Delta {
|
|
|
2102
2197
|
|
|
2103
2198
|
/**
|
|
2104
2199
|
* @param {number} len
|
|
2105
|
-
* @param {DeltaBuilder<any>|null} prevValue
|
|
2106
2200
|
*/
|
|
2107
|
-
delete (len
|
|
2201
|
+
delete (len) {
|
|
2108
2202
|
modDeltaCheck(this)
|
|
2109
2203
|
const lastOp = /** @type {DeleteOp<any>|InsertOp<any>} */ (this.children.end)
|
|
2110
|
-
if ($deleteOp.check(lastOp)
|
|
2204
|
+
if ($deleteOp.check(lastOp)) {
|
|
2111
2205
|
lastOp.delete += len
|
|
2112
2206
|
lastOp._fingerprint = null
|
|
2113
|
-
if (prevValue != null) {
|
|
2114
|
-
/** @type {DeltaBuilder<any>} */ (lastOp.prevValue).append(prevValue)
|
|
2115
|
-
}
|
|
2116
2207
|
} else if (len > 0) {
|
|
2117
|
-
list.pushEnd(this.children, new DeleteOp(len
|
|
2208
|
+
list.pushEnd(this.children, new DeleteOp(len))
|
|
2118
2209
|
}
|
|
2119
2210
|
this.childCnt += len
|
|
2120
2211
|
return this
|
|
@@ -2126,14 +2217,13 @@ export class DeltaBuilder extends Delta {
|
|
|
2126
2217
|
* @param {Key} key
|
|
2127
2218
|
* @param {Val} val
|
|
2128
2219
|
* @param {Attribution?} [attribution] provenance for this attr (data: object or `null`/none)
|
|
2129
|
-
* @param {Val|undefined} [prevValue]
|
|
2130
2220
|
* @return {DeltaBuilder<DeltaConfOverwrite<Conf,{attrs:AddToAttrs<DeltaConfGetAttrs<Conf>,Key,Val>}>, FixedConf>}
|
|
2131
2221
|
*/
|
|
2132
|
-
setAttr (key, val, attribution
|
|
2222
|
+
setAttr (key, val, attribution) {
|
|
2133
2223
|
modDeltaCheck(this)
|
|
2134
2224
|
// @ts-ignore
|
|
2135
2225
|
this.attrs[key] /** @type {any} */ =
|
|
2136
|
-
(new SetAttrOp(/** @type {any} */ (key), val,
|
|
2226
|
+
(new SetAttrOp(/** @type {any} */ (key), val, combineData(this._getUsedAttributionData(), attribution, true)))
|
|
2137
2227
|
// a delta-valued attribute carries marks in its subtree - flag conservatively (never decremented)
|
|
2138
2228
|
if ($deltaAny.check(val)) this.maybeHasMarks ||= val.maybeHasMarks
|
|
2139
2229
|
return /** @type {any} */ (this)
|
|
@@ -2161,18 +2251,17 @@ export class DeltaBuilder extends Delta {
|
|
|
2161
2251
|
* @template {Extract<keyof DeltaConfGetAllowedAttrs<Conf, FixedConf>,string|number>} Key
|
|
2162
2252
|
* @param {Key} key
|
|
2163
2253
|
* @param {Attribution?} [attribution] provenance for the deletion (data: object or `null`/none)
|
|
2164
|
-
* @param {any} [prevValue]
|
|
2165
2254
|
* @return {DeltaBuilder<DeltaConfOverwrite<Conf, {
|
|
2166
2255
|
* attrs: AddToAttrs<DeltaConfGetAttrs<Conf>,Key,never>
|
|
2167
2256
|
* }>, FixedConf>}
|
|
2168
2257
|
*/
|
|
2169
|
-
deleteAttr (key, attribution
|
|
2258
|
+
deleteAttr (key, attribution) {
|
|
2170
2259
|
modDeltaCheck(this)
|
|
2171
2260
|
// dropping a delta-valued attribute drops its subtree's marks; the conservative `maybeHasMarks` flag
|
|
2172
2261
|
// is left as-is (never decremented - marksToPositions self-corrects it)
|
|
2173
2262
|
// @ts-ignore
|
|
2174
2263
|
this.attrs[key] /** @type {any} */ =
|
|
2175
|
-
(new DeleteAttrOp(/** @type {any} */ (key),
|
|
2264
|
+
(new DeleteAttrOp(/** @type {any} */ (key), combineData(this._getUsedAttributionData(), attribution, true)))
|
|
2176
2265
|
return /** @type {any} */ (this)
|
|
2177
2266
|
}
|
|
2178
2267
|
|
|
@@ -2240,16 +2329,11 @@ export class DeltaBuilder extends Delta {
|
|
|
2240
2329
|
this.maybeHasMarks ||= op.value.maybeHasMarks // flag any marks the new modify value carries
|
|
2241
2330
|
}
|
|
2242
2331
|
} else if ($setAttrOp.check(op)) {
|
|
2243
|
-
const prev = c?.value
|
|
2244
|
-
// @ts-ignore
|
|
2245
|
-
op.prevValue = prev
|
|
2246
2332
|
// a delta-valued attribute carries marks in its subtree - flag conservatively (never decremented)
|
|
2247
2333
|
if ($deltaAny.check(op.value)) this.maybeHasMarks ||= op.value.maybeHasMarks
|
|
2248
2334
|
// @ts-ignore
|
|
2249
2335
|
this.attrs[op.key] = move ? op : op.clone()
|
|
2250
2336
|
} else if ($deleteAttrOp.check(op)) {
|
|
2251
|
-
const prev = c?.value
|
|
2252
|
-
op.prevValue = prev
|
|
2253
2337
|
// removing a delta-valued attribute drops its subtree's marks; the conservative `maybeHasMarks`
|
|
2254
2338
|
// flag is left as-is (never decremented - marksToPositions self-corrects it)
|
|
2255
2339
|
if (final) {
|
|
@@ -2374,7 +2458,7 @@ export class DeltaBuilder extends Delta {
|
|
|
2374
2458
|
let remainingLen = op.delete
|
|
2375
2459
|
while (remainingLen > 0) {
|
|
2376
2460
|
if (opsI == null) {
|
|
2377
|
-
_insertChild(this, null, scheduleForMerge(new DeleteOp(remainingLen
|
|
2461
|
+
_insertChild(this, null, scheduleForMerge(new DeleteOp(remainingLen)))
|
|
2378
2462
|
break
|
|
2379
2463
|
} else if ($retainOp.check(opsI)) { // retain ⇒ splice retain, insert delete
|
|
2380
2464
|
const delLen = math.min(opsI.length - offset, remainingLen)
|
|
@@ -2388,7 +2472,7 @@ export class DeltaBuilder extends Delta {
|
|
|
2388
2472
|
opsI = opNextUndeleted(opsI)
|
|
2389
2473
|
offset = 0
|
|
2390
2474
|
}
|
|
2391
|
-
insertClonedOp(new DeleteOp(delLen
|
|
2475
|
+
insertClonedOp(new DeleteOp(delLen))
|
|
2392
2476
|
remainingLen -= delLen
|
|
2393
2477
|
} else if ($modifyOp.check(opsI)) { // modify ⇒ delete the source position it stands for
|
|
2394
2478
|
// a modify op addresses an underlying source position (retain + change), so deleting it
|
|
@@ -2398,7 +2482,7 @@ export class DeltaBuilder extends Delta {
|
|
|
2398
2482
|
_removeChild(this, opsI)
|
|
2399
2483
|
opsI = opNextUndeleted(opsI)
|
|
2400
2484
|
offset = 0
|
|
2401
|
-
insertClonedOp(new DeleteOp(1
|
|
2485
|
+
insertClonedOp(new DeleteOp(1))
|
|
2402
2486
|
remainingLen -= 1
|
|
2403
2487
|
} else if (!$deleteOp.check(opsI)) { // insert / embed ⇒ replace
|
|
2404
2488
|
// case1: delete o fully
|
|
@@ -2686,10 +2770,8 @@ export class DeltaBuilder extends Delta {
|
|
|
2686
2770
|
otherOffset += maxCommonLen
|
|
2687
2771
|
} else { // insert/text.check(otherChild)
|
|
2688
2772
|
if (currOffset > 0) {
|
|
2689
|
-
//
|
|
2690
|
-
|
|
2691
|
-
_insertChild(this, currChild, currChild.clone(0, currOffset))
|
|
2692
|
-
_shrinkChild(this, currChild, 0, currOffset)
|
|
2773
|
+
// split currChild so the cursor sits on the boundary; continue on the [currOffset..] suffix
|
|
2774
|
+
currChild = _splitChildAt(this, currChild, currOffset)
|
|
2693
2775
|
currOffset = 0
|
|
2694
2776
|
}
|
|
2695
2777
|
_insertChild(this, currChild, new RetainOp(otherChild.length, undefined, undefined))
|
|
@@ -4002,6 +4084,118 @@ export const diff = (d1, d2, options = {}) => {
|
|
|
4002
4084
|
return d.done(false)
|
|
4003
4085
|
}
|
|
4004
4086
|
|
|
4087
|
+
/**
|
|
4088
|
+
* The tri-state update that undoes a `format`/`attribution` instruction `update` against the stored
|
|
4089
|
+
* value `stored` (object or `null`/none) it was applied to: applying the result after `update` restores
|
|
4090
|
+
* `stored`. Merge the instruction onto `stored` the way an apply resolves it ({@link applyDim}), then
|
|
4091
|
+
* diff the merged result back to `stored` ({@link diffDim}). `undefined` (skip) inverts to `undefined`.
|
|
4092
|
+
*
|
|
4093
|
+
* @param {{[k:string]:any}|null|undefined} stored
|
|
4094
|
+
* @param {{[k:string]:any}|null|undefined} update
|
|
4095
|
+
* @param {boolean} deep `true` for the `attribution` dimension (its `format` key merges per inner key —
|
|
4096
|
+
* see {@link mergeAttr}); `false` for `format` (shallow)
|
|
4097
|
+
* @return {{[k:string]:any}|null|undefined}
|
|
4098
|
+
*/
|
|
4099
|
+
const inverseDim = (stored, update, deep) => {
|
|
4100
|
+
if (update === undefined) return undefined
|
|
4101
|
+
const merged = update === null ? null : (deep ? mergeAttr(stored, update, true) : mergeShallow(stored, update, true))
|
|
4102
|
+
return diffDim(object.isEmpty(merged) ? null : merged, stored ?? null, deep)
|
|
4103
|
+
}
|
|
4104
|
+
|
|
4105
|
+
/**
|
|
4106
|
+
* Compute a delta that undoes `d` — a change that was applied to the settled document state `base`
|
|
4107
|
+
* (inserts and set attributes only, e.g. an RDT's final state): `base.apply(d).apply(inverse(d, base))`
|
|
4108
|
+
* equals `base`. Inspired by Quill's `Delta#invert`, `base` supplies what the change alone doesn't
|
|
4109
|
+
* carry: deleted content is re-inserted from `base` (with its stored format/attribution), an
|
|
4110
|
+
* overwritten or deleted attribute is restored to its `base` value, and an inverted `retain`/`modify`
|
|
4111
|
+
* instruction is diffed against the `base` op's stored format/attribution.
|
|
4112
|
+
*
|
|
4113
|
+
* Content only: marks are local/ephemeral cursor state and are not inverted (mirroring {@link diff}).
|
|
4114
|
+
* Like {@link diff}, the result *shares* re-inserted children and restored attribute values with `base`.
|
|
4115
|
+
*
|
|
4116
|
+
* The round-trip holds for changes whose content-consuming ops (`retain`/`delete`/`modify`) stay within
|
|
4117
|
+
* `base`'s bounds. Beyond-base ops degrade gracefully: following ops stay positioned, but there is no
|
|
4118
|
+
* stored content to restore — and what a final apply *materializes* beyond content (e.g. a format set
|
|
4119
|
+
* kept as a trailing formatted retain, or an appended modify) cannot be removed by any change, so such
|
|
4120
|
+
* a change is not fully undone.
|
|
4121
|
+
*
|
|
4122
|
+
* @template {DeltaConf} Conf
|
|
4123
|
+
* @param {DeltaAny} d
|
|
4124
|
+
* @param {Delta<Conf>} base
|
|
4125
|
+
* @return {Delta<Conf>}
|
|
4126
|
+
*/
|
|
4127
|
+
export const inverse = (d, base) => {
|
|
4128
|
+
const inv = create(d.name === base.name ? d.name : null, $deltaAny)
|
|
4129
|
+
for (const op of d.attrs) {
|
|
4130
|
+
const baseOp = /** @type {AttrOpAny|undefined} */ ((/** @type {any} */ (base.attrs))[op.key])
|
|
4131
|
+
if ($modifyAttrOp.check(op) && $setAttrOp.check(baseOp) && $deltaAny.check(baseOp.value)) {
|
|
4132
|
+
// the modify edited base's nested delta in place: undo it there, and undo the attribution
|
|
4133
|
+
// instruction it merged onto the attr op
|
|
4134
|
+
inv.modifyAttr(op.key, inverse(op.value, baseOp.value), /** @type {Attribution?} */ (inverseDim(baseOp.attribution, op.attribution, true)))
|
|
4135
|
+
} else if ($setAttrOp.check(baseOp)) {
|
|
4136
|
+
// a set/delete (or a modify that replaced a non-delta value) overwrote a settled attr:
|
|
4137
|
+
// restore value + attribution from base
|
|
4138
|
+
inv.setAttr(op.key, baseOp.value, baseOp.attribution)
|
|
4139
|
+
} else if (!$deleteAttrOp.check(op)) {
|
|
4140
|
+
// a set/modify introduced an attr base didn't have: undo by deleting it
|
|
4141
|
+
inv.deleteAttr(op.key)
|
|
4142
|
+
} // else: deleted an attr base didn't have — nothing to restore
|
|
4143
|
+
}
|
|
4144
|
+
// walk base's children alongside d's ops: an insert consumes no base positions; retain/delete/modify
|
|
4145
|
+
// consume their length in base coordinates
|
|
4146
|
+
let baseOp = /** @type {ChildrenOpAny?} */ (base.children.start)
|
|
4147
|
+
let baseOffset = 0
|
|
4148
|
+
/**
|
|
4149
|
+
* Advance the base cursor by `len`, reporting each traversed chunk `(op, start, end)` (stored
|
|
4150
|
+
* format/attribution are uniform per op, so per-op chunks are exact); returns the length that
|
|
4151
|
+
* extends beyond base's content.
|
|
4152
|
+
*
|
|
4153
|
+
* @param {number} len
|
|
4154
|
+
* @param {(op: TextOp|InsertOp<any>, start: number, end: number) => void} f
|
|
4155
|
+
*/
|
|
4156
|
+
const forBase = (len, f) => {
|
|
4157
|
+
while (len > 0 && baseOp != null) {
|
|
4158
|
+
const chunk = math.min(len, baseOp.length - baseOffset)
|
|
4159
|
+
f(/** @type {TextOp|InsertOp<any>} */ (baseOp), baseOffset, baseOffset + chunk)
|
|
4160
|
+
len -= chunk
|
|
4161
|
+
baseOffset += chunk
|
|
4162
|
+
if (baseOffset === baseOp.length) {
|
|
4163
|
+
baseOp = baseOp.next
|
|
4164
|
+
baseOffset = 0
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
return len
|
|
4168
|
+
}
|
|
4169
|
+
for (const op of d.children) {
|
|
4170
|
+
if ($textOp.check(op) || $insertOp.check(op)) {
|
|
4171
|
+
inv.delete(op.length)
|
|
4172
|
+
} else if ($retainOp.check(op)) {
|
|
4173
|
+
const rest = forBase(op.retain, (bop, start, end) => {
|
|
4174
|
+
inv.retain(end - start, inverseDim(bop.format, op.format, false), /** @type {Attribution?} */ (inverseDim(bop.attribution, op.attribution, true)))
|
|
4175
|
+
})
|
|
4176
|
+
// beyond base there is no stored content to restore — keep following ops positioned (see the
|
|
4177
|
+
// beyond-base note in the fn docs)
|
|
4178
|
+
rest > 0 && inv.retain(rest)
|
|
4179
|
+
} else if ($modifyOp.check(op)) {
|
|
4180
|
+
if (baseOp == null) {
|
|
4181
|
+
// a modify beyond base edited no stored content — keep the position (mirrors retain-beyond)
|
|
4182
|
+
inv.retain(1)
|
|
4183
|
+
} else {
|
|
4184
|
+
const bop = /** @type {InsertOp<any>} */ (baseOp)
|
|
4185
|
+
const node = /** @type {DeltaAny} */ (bop.insert[baseOffset])
|
|
4186
|
+
inv.modify(inverse(/** @type {DeltaAny} */ (op.value), node), inverseDim(bop.format, op.format, false), /** @type {Attribution?} */ (inverseDim(bop.attribution, op.attribution, true)))
|
|
4187
|
+
forBase(1, () => {})
|
|
4188
|
+
}
|
|
4189
|
+
} else if ($deleteOp.check(op)) {
|
|
4190
|
+
// re-insert the deleted base content with its stored format/attribution
|
|
4191
|
+
forBase(op.delete, (bop, start, end) => {
|
|
4192
|
+
inv.insert(bop.insert.slice(start, end), bop.format, bop.attribution)
|
|
4193
|
+
})
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4196
|
+
return inv.done(false)
|
|
4197
|
+
}
|
|
4198
|
+
|
|
4005
4199
|
/**
|
|
4006
4200
|
* Default pairing predicate for {@link diff}: two delta nodes are paired (and recursed into via
|
|
4007
4201
|
* `modify`) when their names match.
|
package/src/delta/rdt.js
CHANGED
|
@@ -155,6 +155,13 @@ const propagate = (binding, ta, tb) => {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
/**
|
|
159
|
+
* @typedef {object} BindOptions
|
|
160
|
+
* @property {delta.DiffOptions['compare']} [diffCompare] **Experimental** (may be changed or removed
|
|
161
|
+
* in a future release). Forwarded as `compare` to {@link delta.diff} when the initial-state sync diffs
|
|
162
|
+
* `a`'s projection against `b`'s current state, controlling how nodes are paired into `modify` ops.
|
|
163
|
+
*/
|
|
164
|
+
|
|
158
165
|
/**
|
|
159
166
|
* Connects two RDTs so that changes on either side are transformed and reflected on the other.
|
|
160
167
|
*
|
|
@@ -174,8 +181,9 @@ export class Binding {
|
|
|
174
181
|
* @param {RDT<B>} b
|
|
175
182
|
* @param {dt.TemplateFactory<A,B>} [template] a `$d => Template` factory; defaults to the
|
|
176
183
|
* {@link dt.id identity} transformer. `bind` injects `a`'s schema, then materializes via `.init()`.
|
|
184
|
+
* @param {BindOptions} [options]
|
|
177
185
|
*/
|
|
178
|
-
constructor (a, b, template = /** @type {dt.TemplateFactory<A,B>} */ (dt.id)) {
|
|
186
|
+
constructor (a, b, template = /** @type {dt.TemplateFactory<A,B>} */ (dt.id), options = {}) {
|
|
179
187
|
/**
|
|
180
188
|
* @type {dt.Transformer<A,B>}
|
|
181
189
|
*/
|
|
@@ -210,7 +218,7 @@ export class Binding {
|
|
|
210
218
|
// `diff` shares nested children with `tres.b` by default, and `tres.b` is a (possibly stateful)
|
|
211
219
|
// transformer's output that may still alias its internal state — so `clone` keeps the diff
|
|
212
220
|
// independent, since it is then applied into `b` (which freezes it) and propagated onward.
|
|
213
|
-
const diffB = tres.b ? delta.diff(this.b.delta, tres.b, { clone: true }) : null
|
|
221
|
+
const diffB = tres.b ? delta.diff(this.b.delta, tres.b, { clone: true, compare: options.diffCompare }) : null
|
|
214
222
|
const fb = diffB ? this.b.applyDelta(diffB, this) : null
|
|
215
223
|
propagate(this, fa, fb)
|
|
216
224
|
})
|
|
@@ -241,6 +249,7 @@ export class Binding {
|
|
|
241
249
|
* @param {RDT<B>} b
|
|
242
250
|
* @param {dt.TemplateFactory<A,B>} [template] a `$d => Template` factory (e.g. `dt.id` or
|
|
243
251
|
* `$d => dt.renameAttrs($d, {a:'b'})`)
|
|
252
|
+
* @param {BindOptions} [options] `diffCompare` is **experimental** — see {@link BindOptions}.
|
|
244
253
|
* @return {Binding<A,B>}
|
|
245
254
|
*/
|
|
246
|
-
export const bind = (a, b, template) => new Binding(a, b, template)
|
|
255
|
+
export const bind = (a, b, template, options = {}) => new Binding(a, b, template, options)
|
|
@@ -173,9 +173,9 @@ const stripAttrAttributions = (out) => {
|
|
|
173
173
|
if (delta.$modifyAttrOp.check(op)) {
|
|
174
174
|
if (op.attribution !== undefined) out.modifyAttr(op.key, op.value)
|
|
175
175
|
} else if (delta.$setAttrOp.check(op)) {
|
|
176
|
-
if (op.attribution != null) out.setAttr(op.key, op.value
|
|
176
|
+
if (op.attribution != null) out.setAttr(op.key, op.value)
|
|
177
177
|
} else if (op.attribution != null) { // DeleteAttrOp
|
|
178
|
-
out.deleteAttr(op.key
|
|
178
|
+
out.deleteAttr(op.key)
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
}
|
|
@@ -246,7 +246,7 @@ export class ConformTransformer extends Transformer {
|
|
|
246
246
|
if (t != null) { out.modifyAttr(key, t.applyA(op.value).b); keptAttrKeys.add(key) }
|
|
247
247
|
} else { // deleteAttr (the only remaining attr-op kind)
|
|
248
248
|
const dop = /** @type {delta.DeleteAttrOp<any>} */ (op)
|
|
249
|
-
out.deleteAttr(key, dop.attribution
|
|
249
|
+
out.deleteAttr(key, dop.attribution)
|
|
250
250
|
this.transformAttrs.delete(key)
|
|
251
251
|
keptAttrKeys.add(key)
|
|
252
252
|
}
|
|
@@ -276,7 +276,7 @@ export class ConformTransformer extends Transformer {
|
|
|
276
276
|
/** @param {number} n */
|
|
277
277
|
const addRetain = n => addUniform(delta.$retainOp, n, () => new delta.RetainOp(n, null, null)) // n pass-through positions
|
|
278
278
|
/** @param {number} n */
|
|
279
|
-
const addDrop = n => addUniform(delta.$deleteOp, n, () => new delta.DeleteOp(n
|
|
279
|
+
const addDrop = n => addUniform(delta.$deleteOp, n, () => new delta.DeleteOp(n)) // n dropped positions
|
|
280
280
|
/** @param {ConformTransformer} t */
|
|
281
281
|
const addTransformed = t => { // one child routed through nested conform `t`
|
|
282
282
|
if (src != null && delta.$insertOp.check(src)) { delta._spliceInsert(cmap, src, off, [t]); off += 1 } else { splitCursor(); delta._mergeChildWithPrev(cmap, delta._insertChild(cmap, src, new delta.InsertOp([t], null, null))) }
|
|
@@ -181,9 +181,9 @@ const buildFull = (d, overlay) => {
|
|
|
181
181
|
const childOverlay = (oa != null && delta.$modifyAttrOp.check(oa) && delta.$deltaAny.check(oa.value)) ? oa.value : null
|
|
182
182
|
full.modifyAttr(aop.key, delta.$deltaAny.check(aop.value) ? buildFull(aop.value, childOverlay) : aop.value, applyFull(oa == null ? undefined : oa.attribution, aop.attribution))
|
|
183
183
|
} else if (delta.$setAttrOp.check(aop)) {
|
|
184
|
-
full.setAttr(aop.key, aop.value, aop.attribution
|
|
184
|
+
full.setAttr(aop.key, aop.value, aop.attribution)
|
|
185
185
|
} else if (delta.$deleteAttrOp.check(aop)) {
|
|
186
|
-
full.deleteAttr(aop.key, aop.attribution
|
|
186
|
+
full.deleteAttr(aop.key, aop.attribution)
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
full.done(false)
|
package/src/environment.js
CHANGED
|
@@ -21,8 +21,29 @@ export const isNode = /* @__PURE__ */(() => typeof process !== 'undefined' && pr
|
|
|
21
21
|
// @ts-ignore
|
|
22
22
|
export const isDeno = /* @__PURE__ */(() => typeof Deno !== 'undefined')()
|
|
23
23
|
|
|
24
|
+
/* c8 ignore start */
|
|
25
|
+
const globalScope = /* @__PURE__ */(() =>/** @type {any} */ (typeof globalThis !== 'undefined'
|
|
26
|
+
? globalThis
|
|
27
|
+
: typeof window !== 'undefined'
|
|
28
|
+
? window
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
: typeof global !== 'undefined' ? global : {}))()
|
|
31
|
+
/* c8 ignore stop */
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* True iff this script is running in a browser-family environment — either a DOM main
|
|
35
|
+
* thread (`window` + `document`) or a WebWorker / ServiceWorker (a `WorkerGlobalScope`,
|
|
36
|
+
* which has `btoa`/`atob`/`fetch` but no DOM). Excludes Node and Deno.
|
|
37
|
+
* @type {boolean}
|
|
38
|
+
*/
|
|
24
39
|
/* c8 ignore next */
|
|
25
|
-
export const isBrowser = /* @__PURE__ */(() =>
|
|
40
|
+
export const isBrowser = /* @__PURE__ */(() =>
|
|
41
|
+
!isNode && !isDeno && (
|
|
42
|
+
(typeof window !== 'undefined' && typeof document !== 'undefined') ||
|
|
43
|
+
// WebWorker / ServiceWorker: no window/document, but a worker global scope
|
|
44
|
+
(typeof globalScope.WorkerGlobalScope !== 'undefined' && globalScope.self instanceof globalScope.WorkerGlobalScope)
|
|
45
|
+
)
|
|
46
|
+
)()
|
|
26
47
|
/* c8 ignore next */
|
|
27
48
|
export const isMac = /* @__PURE__ */(() => typeof navigator !== 'undefined' ? /Mac/.test(navigator.platform) : false)()
|
|
28
49
|
|
|
@@ -168,13 +189,4 @@ export const supportsColor = /* @__PURE__ */(() => forceColor || (
|
|
|
168
189
|
))()
|
|
169
190
|
/* c8 ignore stop */
|
|
170
191
|
|
|
171
|
-
/* c8 ignore start */
|
|
172
|
-
const globalScope = /* @__PURE__ */(() =>/** @type {any} */ (typeof globalThis !== 'undefined'
|
|
173
|
-
? globalThis
|
|
174
|
-
: typeof window !== 'undefined'
|
|
175
|
-
? window
|
|
176
|
-
// @ts-ignore
|
|
177
|
-
: typeof global !== 'undefined' ? global : {}))()
|
|
178
|
-
/* c8 ignore stop */
|
|
179
|
-
|
|
180
192
|
export { globalScope as global }
|