{"version":3,"file":"ChangeTree.js","sourceRoot":"","sources":["../../src/changes/ChangeTree.ts"],"names":[],"mappings":"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","sourcesContent":["import { OPERATION } from \"../spec\";\nimport { Schema } from \"../Schema\";\nimport { SchemaDefinition, FilterChildrenCallback } from \"../annotations\";\n\nimport { MapSchema } from \"../types/MapSchema\";\nimport { ArraySchema } from \"../types/ArraySchema\";\nimport { CollectionSchema } from \"../types/CollectionSchema\";\nimport { SetSchema } from \"../types/SetSchema\";\nimport { ReferenceTracker } from \"./ReferenceTracker\";\n\nexport type Ref = Schema\n    | ArraySchema\n    | MapSchema\n    | CollectionSchema\n    | SetSchema;\n\nexport interface ChangeOperation {\n    op: OPERATION,\n    index: number,\n}\n\n//\n// FieldCache is used for @filter()\n//\nexport interface FieldCache {\n    beginIndex: number;\n    endIndex: number;\n}\n\n\nexport class ChangeTree {\n    ref: Ref;\n    refId: number;\n\n    root?: ReferenceTracker;\n\n    parent?: Ref;\n    parentIndex?: number;\n\n    indexes: {[index: string]: any};\n\n    changed: boolean = false;\n    changes = new Map<number, ChangeOperation>();\n    allChanges = new Set<number>();\n\n    // cached indexes for filtering\n    caches: {[field: number]: number[]} = {};\n\n    currentCustomOperation: number = 0;\n\n    constructor(ref: Ref, parent?: Ref, root?: ReferenceTracker) {\n        this.ref = ref;\n        this.setParent(parent, root);\n    }\n\n    setParent(\n        parent: Ref,\n        root?: ReferenceTracker,\n        parentIndex?: number,\n    ) {\n        if (!this.indexes) {\n            this.indexes = (this.ref instanceof Schema)\n                ? this.ref['_definition'].indexes\n                : {};\n        }\n\n        this.parent = parent;\n        this.parentIndex = parentIndex;\n\n        // avoid setting parents with empty `root`\n        if (!root) { return; }\n        this.root = root;\n\n        //\n        // assign same parent on child structures\n        //\n        if (this.ref instanceof Schema) {\n            const definition: SchemaDefinition = this.ref['_definition'];\n\n            for (let field in definition.schema) {\n                const value = this.ref[field];\n\n                if (value && value['$changes']) {\n                    const parentIndex = definition.indexes[field];\n\n                    (value['$changes'] as ChangeTree).setParent(\n                        this.ref,\n                        root,\n                        parentIndex,\n                    );\n                }\n            }\n\n        } else if (typeof (this.ref) === \"object\") {\n            this.ref.forEach((value, key) => {\n                if (value instanceof Schema) {\n                    const changeTreee = value['$changes'];\n                    const parentIndex = this.ref['$changes'].indexes[key];\n\n                    changeTreee.setParent(\n                        this.ref,\n                        this.root,\n                        parentIndex,\n                    );\n                }\n            });\n        }\n    }\n\n    operation(op: ChangeOperation) {\n        this.changes.set(--this.currentCustomOperation, op);\n    }\n\n    change(fieldName: string | number, operation: OPERATION = OPERATION.ADD) {\n        const index = (typeof (fieldName) === \"number\")\n            ? fieldName\n            : this.indexes[fieldName];\n\n        this.assertValidIndex(index, fieldName);\n\n        const previousChange = this.changes.get(index);\n\n        if (\n            !previousChange ||\n            previousChange.op === OPERATION.DELETE ||\n            previousChange.op === OPERATION.TOUCH // (mazmorra.io's BattleAction issue)\n        ) {\n            this.changes.set(index, {\n                op: (!previousChange)\n                    ? operation\n                    : (previousChange.op === OPERATION.DELETE)\n                        ? OPERATION.DELETE_AND_ADD\n                        : operation,\n                        // : OPERATION.REPLACE,\n                index\n            });\n        }\n\n        this.allChanges.add(index);\n\n        this.changed = true;\n        this.touchParents();\n    }\n\n    touch(fieldName: string | number) {\n        const index = (typeof (fieldName) === \"number\")\n            ? fieldName\n            : this.indexes[fieldName];\n\n        this.assertValidIndex(index, fieldName);\n\n        if (!this.changes.has(index)) {\n            this.changes.set(index, { op: OPERATION.TOUCH, index });\n        }\n\n        this.allChanges.add(index);\n\n        // ensure touch is placed until the $root is found.\n        this.touchParents();\n    }\n\n    touchParents() {\n        if (this.parent) {\n            (this.parent['$changes'] as ChangeTree).touch(this.parentIndex);\n        }\n    }\n\n    getType(index?: number) {\n        if (this.ref['_definition']) {\n            const definition = (this.ref as Schema)['_definition'];\n            return definition.schema[ definition.fieldsByIndex[index] ];\n\n        } else {\n            const definition = (this.parent as Schema)['_definition'];\n            const parentType = definition.schema[ definition.fieldsByIndex[this.parentIndex] ];\n\n            //\n            // Get the child type from parent structure.\n            // - [\"string\"] => \"string\"\n            // - { map: \"string\" } => \"string\"\n            // - { set: \"string\" } => \"string\"\n            //\n            return Object.values(parentType)[0];\n        }\n    }\n\n    getChildrenFilter(): FilterChildrenCallback {\n        const childFilters = (this.parent as Schema)['_definition'].childFilters;\n        return childFilters && childFilters[this.parentIndex];\n    }\n\n    //\n    // used during `.encode()`\n    //\n    getValue(index: number) {\n        return this.ref['getByIndex'](index);\n    }\n\n    delete(fieldName: string | number) {\n        const index = (typeof (fieldName) === \"number\")\n            ? fieldName\n            : this.indexes[fieldName];\n\n        if (index === undefined) {\n            console.warn(`@colyseus/schema ${this.ref.constructor.name}: trying to delete non-existing index: ${fieldName} (${index})`);\n            return;\n        }\n\n        const previousValue = this.getValue(index);\n        // console.log(\"$changes.delete =>\", { fieldName, index, previousValue });\n\n        this.changes.set(index, { op: OPERATION.DELETE, index });\n\n        this.allChanges.delete(index);\n\n        // delete cache\n        delete this.caches[index];\n\n        // remove `root` reference\n        if (previousValue && previousValue['$changes']) {\n            previousValue['$changes'].parent = undefined;\n        }\n\n        this.changed = true;\n        this.touchParents();\n    }\n\n    discard(changed: boolean = false, discardAll: boolean = false) {\n        //\n        // Map, Array, etc:\n        // Remove cached key to ensure ADD operations is unsed instead of\n        // REPLACE in case same key is used on next patches.\n        //\n        // TODO: refactor this. this is not relevant for Collection and Set.\n        //\n        if (!(this.ref instanceof Schema)) {\n            this.changes.forEach((change) => {\n                if (change.op === OPERATION.DELETE) {\n                    const index = this.ref['getIndex'](change.index)\n                    delete this.indexes[index];\n                }\n            });\n        }\n\n        this.changes.clear();\n        this.changed = changed;\n\n        if (discardAll) {\n            this.allChanges.clear();\n        }\n\n        // re-set `currentCustomOperation`\n        this.currentCustomOperation = 0;\n    }\n\n    /**\n     * Recursively discard all changes from this, and child structures.\n     */\n    discardAll() {\n        this.changes.forEach((change) => {\n            const value = this.getValue(change.index);\n\n            if (value && value['$changes']) {\n                value['$changes'].discardAll();\n            }\n        });\n\n        this.discard();\n    }\n\n    // cache(field: number, beginIndex: number, endIndex: number) {\n    cache(field: number, cachedBytes: number[]) {\n        this.caches[field] = cachedBytes;\n    }\n\n    clone() {\n        return new ChangeTree(this.ref, this.parent, this.root);\n    }\n\n    ensureRefId() {\n        // skip if refId is already set.\n        if (this.refId !== undefined) {\n            return;\n        }\n\n        this.refId = this.root.getNextUniqueId();\n    }\n\n    protected assertValidIndex(index: number, fieldName: string | number) {\n        if (index === undefined) {\n            throw new Error(`ChangeTree: missing index for field \"${fieldName}\"`);\n        }\n    }\n\n}\n"]}