json-joy
Version:
Collection of libraries for building collaborative editing apps.
90 lines • 2.9 kB
JavaScript
import { s } from '../../../json-crdt-patch';
import { ConApi, ObjApi, VecApi } from '../../../json-crdt/model';
/**
* Represents a single nested tag in a slice type. For example, in a slice type
* like `['<blockquote>', 0, {author: 'Alice'}, ['<p>', 0, {indent: 2}]]`, there
* is a tag for the blockquote and a tag for the paragraph. Each tag can
* contain a discriminant and data.
*/
export class NestedTag {
type;
index;
constructor(type, index) {
this.type = type;
this.index = index;
}
/**
* Enforces current tag at `index` to be a "vec" node, which contains
* a tag, a discriminant and an object with data.
*/
asVec() {
const arr = this.type.asArr();
const typeLen = arr.length();
let index = this.index;
if (typeof index !== 'number' || index > typeLen - 1)
index = typeLen - 1;
const vec = arr.get(index);
if (vec instanceof VecApi)
return vec;
const tag = vec instanceof ConApi ? vec.view() : 0;
arr.upd(index, s.vec(s.con(tag)));
return arr.get(index);
}
/**
* Returns the tag name at the current index, which is either a string or a number.
* If the tag is not set, it returns `0`.
*
* @returns The tag value.
*/
name() {
const vec = this.asVec();
const tag = vec.select(0)?.view();
return typeof tag === 'string' || typeof tag === 'number' ? tag : 0;
}
/**
* Sets the tag name at the current index. If the tag is not a string or a number,
* it will be converted to a string.
*
* @param tag - The tag value to set.
*/
setName(tag) {
const vec = this.asVec();
vec.set([[0, s.con(tag)]]);
}
/**
* Returns the discriminant of the tag at the current index.
* If the discriminant is not set, it returns `0`.
*
* @returns The discriminant value.
*/
discriminant() {
const disciminant = this.asVec().select(1)?.view() || 0;
return typeof disciminant === 'number' ? disciminant : 0;
}
/**
* Sets the discriminant of the tag at the current index.
*
* @param value - The discriminant value to set.
*/
setDiscriminant(value) {
const vec = this.asVec();
vec.set([[1, s.con(value)]]);
}
/**
* Returns the data object of the tag at the current index.
* If the data is not set, it returns an empty object. Enforces the
* data to be a {@link ObjApi} node, use this API to manipulate the data
* object.
*
* @returns The data object.
*/
data() {
const vec = this.asVec();
const data = vec.select(2);
if (data instanceof ObjApi)
return data;
vec.set([[2, s.obj({})]]);
return vec.get(2);
}
}
//# sourceMappingURL=NestedTag.js.map