Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | 65x 65x 65x 90x 90x 127x 127x 127x 127x 127x 127x 24x 24x 24x 19x 19x 19x 3x 3x 35x 35x 10x 10x 42x 42x 42x 12x 12x | import {s} from '../../../json-crdt-patch'; import {ConApi, ObjApi, VecApi} from '../../../json-crdt/model'; import type {ConNode, ObjNode, VecNode} from '../../../json-crdt/nodes'; import type {NestedType} from './NestedType'; /** * 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<T = string> { constructor( protected readonly type: NestedType<T>, public readonly index: number, ) {} /** * Enforces current tag at `index` to be a "vec" node, which contains * a tag, a discriminant and an object with data. */ public asVec(): VecApi<VecNode<[ConNode<number | string>, ConNode<number>, ObjNode]>> { const arr = this.type.asArr(); const typeLen = arr.length(); let index: number = 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) as VecApi; } /** * 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. */ public name(): string | number { 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. */ public setName(tag: string | number): void { 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. */ public discriminant(): number { 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. */ public setDiscriminant(value: number): void { 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. */ public data(): ObjApi { const vec = this.asVec(); const data = vec.select(2); if (data instanceof ObjApi) return data; vec.set([[2, s.obj({})]]); return vec.get(2) as ObjApi; } } |