json-joy
Version:
Collection of libraries for building collaborative editing apps.
361 lines (360 loc) • 9.06 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NopOp = exports.DelOp = exports.InsArrOp = exports.InsBinOp = exports.InsStrOp = exports.InsVecOp = exports.InsObjOp = exports.InsValOp = exports.NewArrOp = exports.NewBinOp = exports.NewStrOp = exports.NewVecOp = exports.NewObjOp = exports.NewValOp = exports.NewConOp = void 0;
const printTree_1 = require("tree-dump/lib/printTree");
const clock_1 = require("./clock");
/**
* Operation which creates a constant "con" data type.
*
* @category Operations
*/
class NewConOp {
constructor(id, val) {
this.id = id;
this.val = val;
}
span() {
return 1;
}
name() {
return 'new_con';
}
toString(tab = '') {
const val = this.val;
const klass = 'Uint8Array';
const valFormatted = val instanceof clock_1.Timestamp
? `{ ${(0, clock_1.printTs)(val)} }`
: val instanceof Uint8Array
? val.length < 13
? `${klass} { ${('' + val).replaceAll(',', ', ')} }`
: `${klass}(${val.length})`
: `{ ${JSON.stringify(val)} }`;
return `${this.name()} ${(0, clock_1.printTs)(this.id)} ${valFormatted}`;
}
}
exports.NewConOp = NewConOp;
/**
* Operation which creates a new value object.
*
* @category Operations
*/
class NewValOp {
constructor(id) {
this.id = id;
}
span() {
return 1;
}
name() {
return 'new_val';
}
toString() {
return `${this.name()} ${(0, clock_1.printTs)(this.id)}`;
}
}
exports.NewValOp = NewValOp;
/**
* Operation which creates a new object.
*
* @category Operations
*/
class NewObjOp {
constructor(id) {
this.id = id;
}
span() {
return 1;
}
name() {
return 'new_obj';
}
toString() {
return `${this.name()} ${(0, clock_1.printTs)(this.id)}`;
}
}
exports.NewObjOp = NewObjOp;
/**
* Operation which creates a new vector object.
*
* @category Operations
*/
class NewVecOp {
constructor(id) {
this.id = id;
}
span() {
return 1;
}
name() {
return 'new_vec';
}
toString() {
return `${this.name()} ${(0, clock_1.printTs)(this.id)}`;
}
}
exports.NewVecOp = NewVecOp;
/**
* Operation which creates a new string object.
*
* @category Operations
*/
class NewStrOp {
constructor(id) {
this.id = id;
}
span() {
return 1;
}
name() {
return 'new_str';
}
toString() {
return `${this.name()} ${(0, clock_1.printTs)(this.id)}`;
}
}
exports.NewStrOp = NewStrOp;
/**
* Operation which creates a new binary object.
*
* @category Operations
*/
class NewBinOp {
constructor(id) {
this.id = id;
}
span() {
return 1;
}
name() {
return 'new_bin';
}
toString(tab = '') {
return `${this.name()} ${(0, clock_1.printTs)(this.id)}`;
}
}
exports.NewBinOp = NewBinOp;
/**
* Operation which creates a new array object.
*
* @category Operations
*/
class NewArrOp {
constructor(id) {
this.id = id;
}
span() {
return 1;
}
name() {
return 'new_arr';
}
toString() {
return `${this.name()} ${(0, clock_1.printTs)(this.id)}`;
}
}
exports.NewArrOp = NewArrOp;
/**
* Operation which writes a new value to a value "val" object.
*
* @category Operations
*/
class InsValOp {
constructor(id,
/** @todo Rename to `node`. */
obj, val) {
this.id = id;
this.obj = obj;
this.val = val;
}
span() {
return 1;
}
name() {
return 'ins_val';
}
toString(tab = '') {
return `${this.name()} ${(0, clock_1.printTs)(this.id)}!${this.span()}, obj = ${(0, clock_1.printTs)(this.obj)}, val = ${(0, clock_1.printTs)(this.val)}`;
}
}
exports.InsValOp = InsValOp;
/**
* Operation which sets object keys.
*
* @category Operations
*/
class InsObjOp {
constructor(id, obj, data) {
this.id = id;
this.obj = obj;
this.data = data;
}
span() {
return 1;
}
name() {
return 'ins_obj';
}
toString(tab = '') {
const header = `${this.name()} ${(0, clock_1.printTs)(this.id)}!${this.span()}, obj = ${(0, clock_1.printTs)(this.obj)}`;
return (header +
(0, printTree_1.printTree)(tab, this.data.map((item) => (tab) => `${JSON.stringify(item[0])}: ${(0, clock_1.printTs)(item[1])}`)));
}
}
exports.InsObjOp = InsObjOp;
/**
* Operation which sets vector elements.
*
* @category Operations
*/
class InsVecOp {
constructor(id, obj, data) {
this.id = id;
this.obj = obj;
this.data = data;
}
span() {
return 1;
}
name() {
return 'ins_vec';
}
toString(tab = '') {
const header = `${this.name()} ${(0, clock_1.printTs)(this.id)}!${this.span()}, obj = ${(0, clock_1.printTs)(this.obj)}`;
return (header +
(0, printTree_1.printTree)(tab, this.data.map((item) => (tab) => `${item[0]}: ${(0, clock_1.printTs)(item[1])}`)));
}
}
exports.InsVecOp = InsVecOp;
/**
* Operation which inserts text into a "str" string object.
*
* @category Operations
*/
class InsStrOp {
constructor(id, obj, ref, data) {
this.id = id;
this.obj = obj;
this.ref = ref;
this.data = data;
}
span() {
return this.data.length;
}
name() {
return 'ins_str';
}
toString() {
return `${this.name()} ${(0, clock_1.printTs)(this.id)}!${this.span()}, obj = ${(0, clock_1.printTs)(this.obj)} { ${(0, clock_1.printTs)(this.ref)} ← ${JSON.stringify(this.data)} }`;
}
}
exports.InsStrOp = InsStrOp;
/**
* Operations which inserts binary data into a "bin" binary object.
*
* @category Operations
*/
class InsBinOp {
constructor(id, obj, ref, data) {
this.id = id;
this.obj = obj;
this.ref = ref;
this.data = data;
}
span() {
return this.data.length;
}
name() {
return 'ins_bin';
}
toString(tab = '') {
const ref = (0, clock_1.printTs)(this.ref);
return `${this.name()} ${(0, clock_1.printTs)(this.id)}!${this.span()}, obj = ${(0, clock_1.printTs)(this.obj)} { ${ref} ← ${this.data} }`;
}
}
exports.InsBinOp = InsBinOp;
/**
* Operation which inserts elements into an array.
*
* @category Operations
*/
class InsArrOp {
/**
* @param id ID if the first operation in this compound operation.
* @param obj ID of the array where to insert elements. In theory `arr` is
* not necessary as it is possible to find the `arr` just using the
* `after` property, however to efficiently be able to find `arr` just
* by `after` at runtime all operations would need to be indexed and
* also they each would need to store a pointer to array type, which
* would require additional dozens of bytes of RAM for each array
* insert operation.
* @param ref ID of the element after which to insert elements.
* @param data The elements to insert.
*/
constructor(id, obj, ref, data) {
this.id = id;
this.obj = obj;
this.ref = ref;
this.data = data;
}
span() {
return this.data.length;
}
name() {
return 'ins_arr';
}
toString() {
return `${this.name()} ${(0, clock_1.printTs)(this.id)}!${this.span()}, obj = ${(0, clock_1.printTs)(this.obj)} { ${(0, clock_1.printTs)(this.ref)} ← ${this.data.map(clock_1.printTs).join(', ')} }`;
}
}
exports.InsArrOp = InsArrOp;
/**
* Operation which deletes one or more ranges of values in some object.
* The object could be a string, an array, or a binary.
*
* @category Operations
*/
class DelOp {
/**
* @param id ID of this operation.
* @param obj Object in which to delete something.
* @param what ID of the first operation to be deleted.
*/
constructor(id, obj, what) {
this.id = id;
this.obj = obj;
this.what = what;
}
span() {
return 1;
}
name() {
return 'del';
}
toString() {
const spans = this.what.map((span) => (0, clock_1.printTs)(span) + '!' + span.span).join(', ');
return `${this.name()} ${(0, clock_1.printTs)(this.id)}, obj = ${(0, clock_1.printTs)(this.obj)} { ${spans} }`;
}
}
exports.DelOp = DelOp;
/**
* Operation which does nothing. Useful for skipping clock cycles, so that
* operations with a gap in clock can be included in the same patch.
*
* @category Operations
*/
class NopOp {
constructor(id, len) {
this.id = id;
this.len = len;
}
span() {
return this.len;
}
name() {
return 'nop';
}
toString() {
return `${this.name()} ${(0, clock_1.printTs)(this.id)}!${this.len}`;
}
}
exports.NopOp = NopOp;