"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapTreeFieldFromCursor = exports.mapTreeFromCursor = exports.cursorForMapTreeField = exports.mapTreeFieldsWithField = exports.mapTreeWithField = exports.cursorForMapTreeNode = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const index_js_1 = require("../core/index.js");
const treeCursorUtils_js_1 = require("./treeCursorUtils.js");
{
}
/**
 * Returns an {@link ITreeCursorSynchronous} in nodes mode for a single {@link MapTree}.
 */
function cursorForMapTreeNode(root) {
    // There doesn't seem to be a clean way to get TypeScript to type check this without casting
    // without declaring the adapter inside this generic function and needlessly recreating it on every call.
    const adapterTyped = adapter;
    return (0, treeCursorUtils_js_1.stackTreeNodeCursor)(adapterTyped, root);
}
exports.cursorForMapTreeNode = cursorForMapTreeNode;
/**
 * Creates an {@link ExclusiveMapTree} with a single field and no value.
 * @remarks
 * This handles ensuring the field is omitted if empty, and defaults to making the node above the root.
 */
function mapTreeWithField(children, key = index_js_1.rootFieldKey, type = index_js_1.aboveRootPlaceholder) {
    return {
        type,
        fields: mapTreeFieldsWithField(children, key),
    };
}
exports.mapTreeWithField = mapTreeWithField;
/**
 * Creates a Map suitable for use as {@link MapTree.fields} with a single field.
 * @remarks
 * This handles ensuring the field is omitted if empty.
 */
function mapTreeFieldsWithField(children, key) {
    return new Map(children.length === 0 ? [] : [[key, children]]);
}
exports.mapTreeFieldsWithField = mapTreeFieldsWithField;
/**
 * Returns an {@link ITreeCursorSynchronous} in fields mode for a MapTree field.
 */
function cursorForMapTreeField(root, detachedField = index_js_1.rootField) {
    const key = (0, index_js_1.detachedFieldAsKey)(detachedField);
    const adapterTyped = adapter;
    const dummyRoot = {
        type: index_js_1.aboveRootPlaceholder,
        fields: mapTreeFieldsWithField(root, key),
    };
    return (0, treeCursorUtils_js_1.stackTreeFieldCursor)(adapterTyped, dummyRoot, detachedField);
}
exports.cursorForMapTreeField = cursorForMapTreeField;
const adapter = {
    value: (node) => node.value,
    type: (node) => node.type,
    keysFromNode: (node) => Array.from(node.fields, ([key, field]) => key),
    getFieldFromNode: (node, key) => {
        const field = node.fields.get(key);
        if (field === undefined) {
            return [];
        }
        if (Array.isArray(field)) {
            return field;
        }
        // TODO: this copy could be avoided by using Array.at instead of indexing in `Field`, but that requires ES2022.
        return [...field];
    },
};
/**
 * Extract a MapTree from the contents of the given ITreeCursor's current node.
 */
function mapTreeFromCursor(cursor) {
    (0, internal_1.assert)(cursor.mode === 0 /* CursorLocationType.Nodes */, 0x3b7 /* must start at node */);
    const fields = new Map();
    for (let inField = cursor.firstField(); inField; inField = cursor.nextField()) {
        const field = (0, index_js_1.mapCursorField)(cursor, mapTreeFromCursor);
        fields.set(cursor.getFieldKey(), field);
    }
    const node = {
        type: cursor.type,
        value: cursor.value,
        fields,
    };
    return node;
}
exports.mapTreeFromCursor = mapTreeFromCursor;
/**
 * Extract an array of MapTrees (a field) from the contents of the given ITreeCursor's current field.
 */
function mapTreeFieldFromCursor(cursor) {
    (0, internal_1.assert)(cursor.mode === 1 /* CursorLocationType.Fields */, 0xa03 /* must start at field */);
    return (0, index_js_1.mapCursorField)(cursor, mapTreeFromCursor);
}
exports.mapTreeFieldFromCursor = mapTreeFieldFromCursor;
//# sourceMappingURL=mapTreeCursor.js.map