"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.jsonableTreeFromForest = exports.jsonableTreeFromFieldCursor = exports.jsonableTreeFromCursor = exports.adapter = exports.cursorForJsonableTreeField = exports.cursorForJsonableTreeNode = void 0;
const core_utils_1 = require("@fluidframework/core-utils");
const core_1 = require("../core");
const treeCursorUtils_1 = require("./treeCursorUtils");
/**
 * This module provides support for reading and writing a human readable (and
 * editable) tree format.
 *
 * This implementation can handle all trees (so it does not need a fallback for any special cases),
 * and is not optimized.
 *
 * It's suitable for testing and debugging,
 * though it could also reasonably be used as a fallback for edge cases or for small trees.
 *
 * TODO: Use placeholders.
 * build / add operations should be able to include detached ranges instead of children directly.
 * summaries should be able to reference unloaded chunks instead of having children directly.
 * Leverage placeholders in the types below to accomplish this.
 * Determine how this relates to Cursor: should cursor be generic over placeholder values?
 * (Could use them for errors to allow non erroring cursors?)
 *
 * Note:
 * Currently a lot of Tree's codebase is using json for serialization.
 * Because putting json strings inside json works poorly (adds lots of escaping),
 * for now this library actually outputs and inputs the Json compatible type JsonableTree
 * rather than actual strings.
 */
/**
 * Create a cursor, in `nodes` mode at the root of the provided tree.
 *
 * @returns an {@link ITreeCursorSynchronous} in nodes mode for a single {@link JsonableTree}.
 * @remarks
 * Do not confuse this with {@link JsonableTree} with the JSON domain:
 * this takes in data in a specific format that is json compatible (except for FluidHandle values).
 * That is distinct from treating arbitrary JSON data as a tree in the JSON domain.
 * @alpha
 */
function cursorForJsonableTreeNode(root) {
    return (0, treeCursorUtils_1.stackTreeNodeCursor)(exports.adapter, root);
}
exports.cursorForJsonableTreeNode = cursorForJsonableTreeNode;
/**
 * @returns an {@link ITreeCursorSynchronous} in fields mode for a JsonableTree field.
 */
function cursorForJsonableTreeField(trees, detachedField = core_1.rootField) {
    const key = (0, core_1.detachedFieldAsKey)(detachedField);
    return (0, treeCursorUtils_1.stackTreeFieldCursor)(exports.adapter, { type: core_1.aboveRootPlaceholder, fields: { [key]: trees } }, detachedField);
}
exports.cursorForJsonableTreeField = cursorForJsonableTreeField;
exports.adapter = {
    value: (node) => node.value,
    type: (node) => node.type,
    keysFromNode: core_1.genericTreeKeys,
    getFieldFromNode: (node, key) => (0, core_1.getGenericTreeField)(node, key, false),
};
/**
 * Extract a JsonableTree from the contents of the given ITreeCursor's current node.
 * @alpha
 */
function jsonableTreeFromCursor(cursor) {
    (0, core_utils_1.assert)(cursor.mode === 0 /* CursorLocationType.Nodes */, 0x3ba /* must start at node */);
    const node = {
        type: cursor.type,
    };
    // Normalize object by only including fields that are required.
    if (cursor.value !== undefined) {
        node.value = cursor.value;
    }
    for (let inFields = cursor.firstField(); inFields; inFields = cursor.nextField()) {
        const field = (0, core_1.mapCursorField)(cursor, jsonableTreeFromCursor);
        (0, core_1.setGenericTreeField)(node, cursor.getFieldKey(), field);
    }
    return node;
}
exports.jsonableTreeFromCursor = jsonableTreeFromCursor;
/**
 * Extract a JsonableTree from the contents of the given ITreeCursor's current node.
 */
function jsonableTreeFromFieldCursor(cursor) {
    (0, core_utils_1.assert)(cursor.mode === 1 /* CursorLocationType.Fields */, 0x7ca /* must start at field */);
    return (0, core_1.mapCursorField)(cursor, jsonableTreeFromCursor);
}
exports.jsonableTreeFromFieldCursor = jsonableTreeFromFieldCursor;
/**
 * Copy forest content into a JsonableTree.
 * @remarks
 * This is not a time or memory efficient way to pass around forest content:
 * its intended for debugging and testing purposes when forest content is needed in a human readable serializable format.
 */
function jsonableTreeFromForest(forest) {
    const readCursor = forest.allocateCursor();
    (0, core_1.moveToDetachedField)(forest, readCursor);
    const jsonable = jsonableTreeFromFieldCursor(readCursor);
    readCursor.free();
    return jsonable;
}
exports.jsonableTreeFromForest = jsonableTreeFromForest;
//# sourceMappingURL=treeTextCursor.js.map