"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RawFieldNode = exports.RawMapNode = exports.RawObjectNode = exports.RawTreeNode = exports.createRawNode = exports.extractRawNodeContent = void 0;
const index_js_1 = require("../feature-libraries/index.js");
const index_js_2 = require("../util/index.js");
/** Stores the content of the raw node, i.e. the data that was passed to the factory */
const nodeContent = Symbol();
/**
 * Retrieve the content of a raw object node created via {@link createRawNode}.
 * @remarks
 * Raw nodes should only ever be processed as input once.
 * Therefore, this extraction removes the content from the node and will error if called twice on the same node.
 */
function extractRawNodeContent(node) {
    if (node instanceof RawTreeNode) {
        const content = node[nodeContent] ?? (0, index_js_2.fail)("Node content may only be extracted once");
        Reflect.deleteProperty(node, nodeContent);
        return content;
    }
    return undefined;
}
exports.extractRawNodeContent = extractRawNodeContent;
/**
 * Creates a node that pretends to satisfy the given schema while wrapping the given node content.
 * Retrieve the node content via {@link extractRawNodeContent}.
 *
 * @remarks This is useful for creating "raw" nodes: nodes which capture data about a pending insertion but are not yet inserted.
 * These raw nodes can be then used on the right-hand side of an assignment (via `=`) to the tree.
 * However, many of their properties and methods are currently unimplemented and will error if accessed.
 */
function createRawNode(schema, content) {
    if (schema instanceof index_js_1.FlexObjectNodeSchema) {
        return new RawObjectNode(schema, content);
    }
    if (schema instanceof index_js_1.FlexMapNodeSchema) {
        return new RawMapNode(schema, content);
    }
    if (schema instanceof index_js_1.FlexFieldNodeSchema) {
        return new RawFieldNode(schema, content);
    }
    (0, index_js_2.fail)("Unrecognized schema");
}
exports.createRawNode = createRawNode;
/**
 * The base implementation of a node created by {@link createRawNode}.
 */
class RawTreeNode {
    constructor(schema, content) {
        this.schema = schema;
        this[_a] = index_js_1.FlexTreeEntityKind.Node;
        this.type = schema.name;
        this[nodeContent] = content;
    }
    get context() {
        throw rawError("Getting context");
    }
    get parentField() {
        throw rawError("Accessing parentage");
    }
    is(schema) {
        return schema === this.schema;
    }
    tryGetField(key) {
        throw rawError("Reading fields");
    }
    boxedIterator() {
        throw rawError("Boxed iteration");
    }
    treeStatus() {
        // TODO: We could add a new TreeStatus for "raw" nodes.
        throw rawError("Status querying");
    }
    on(eventName, listener) {
        throw rawError("Event registration");
    }
    [(_a = index_js_1.flexTreeMarker, index_js_1.onNextChange)](fn) {
        throw rawError("onNextChange event registration");
    }
}
exports.RawTreeNode = RawTreeNode;
/**
 * The implementation of an object node created by {@link createRawNode}.
 */
class RawObjectNode extends RawTreeNode {
    get localNodeKey() {
        throw rawError("Reading local node keys");
    }
}
exports.RawObjectNode = RawObjectNode;
/**
 * The implementation of a map node created by {@link createRawNode}.
 */
class RawMapNode extends RawTreeNode {
    get size() {
        return this[nodeContent].size;
    }
    has(key) {
        return this[nodeContent].has(key);
    }
    get(key) {
        return this[nodeContent].get(key);
    }
    getBoxed(key) {
        throw rawError("Reading boxed map values");
    }
    keys() {
        return this[nodeContent].keys();
    }
    values() {
        throw rawError("Iterating map values");
    }
    entries() {
        throw rawError("Iterating map entries");
    }
    forEach(callbackFn, thisArg) {
        throw rawError("Iterating maps with forEach");
    }
    set(key, value) {
        throw rawError("Setting a map entry");
    }
    delete(key) {
        throw rawError("Deleting a map entry");
    }
    get asObject() {
        throw rawError("Converting a map to an object");
    }
    [Symbol.iterator]() {
        return this.entries();
    }
    boxedIterator() {
        throw rawError("Boxed iteration");
    }
}
exports.RawMapNode = RawMapNode;
/**
 * The implementation of a field node created by {@link createRawNode}.
 */
class RawFieldNode extends RawTreeNode {
    get content() {
        throw rawError("Reading content of an array node");
    }
    get boxedContent() {
        throw rawError("Reading boxed content of an array node");
    }
}
exports.RawFieldNode = RawFieldNode;
function rawError(message) {
    return new Error(`${message ?? "Operation"} is not supported on content which has not yet been inserted into the tree`);
}
//# sourceMappingURL=rawNode.js.map