"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.inCursorNode = exports.inCursorField = exports.castCursorToSynchronous = exports.forEachNode = exports.mapCursorField = exports.forEachField = exports.mapCursorFields = exports.CursorLocationType = exports.isCursor = exports.CursorMarker = void 0;
const common_utils_1 = require("@fluidframework/common-utils");
/**
 * A symbol for marking an object as an {@link ITreeCursor}.
 *
 * Useful when APIs want to take in tree data in multiple formats, including cursors.
 */
exports.CursorMarker = Symbol("CursorMarker");
/**
 * Check if something is an {@link ITreeCursor}.
 *
 * Useful when APIs want to take in tree data in multiple formats, including cursors.
 */
function isCursor(data) {
    // Other than on null and undefined, looking up a missing symbol shouldn't type error.
    // typeof check deals with undefined while providing an early out for other non-object types.
    return data !== null && typeof data === "object" && data[exports.CursorMarker] === true;
}
exports.isCursor = isCursor;
/**
 * @alpha
 */
var CursorLocationType;
(function (CursorLocationType) {
    /**
     * Can iterate through nodes in a field.
     * At a "current node".
     */
    CursorLocationType[CursorLocationType["Nodes"] = 0] = "Nodes";
    /**
     * Can iterate through fields of a node.
     * At a "current field".
     */
    CursorLocationType[CursorLocationType["Fields"] = 1] = "Fields";
})(CursorLocationType = exports.CursorLocationType || (exports.CursorLocationType = {}));
/**
 * @param cursor - tree whose fields will be visited.
 * @param f - builds output from field, which will be selected in cursor when cursor is provided.
 * If `f` moves cursor, it must put it back to where it was at the beginning of `f` before returning.
 * @returns array resulting from applying `f` to each field of the current node on `cursor`.
 * Returns an empty array if the node is empty or not present (which are considered the same).
 * Note that order is not specified for field iteration.
 */
function mapCursorFields(cursor, f) {
    const output = [];
    forEachField(cursor, (c) => {
        output.push(f(c));
    });
    return output;
}
exports.mapCursorFields = mapCursorFields;
/**
 * @param cursor - cursor at a node whose fields will be visited.
 * @param f - For on each field.
 * If `f` moves cursor, it must put it back to where it was at the beginning of `f` before returning.
 */
function forEachField(cursor, f) {
    (0, common_utils_1.assert)(cursor.mode === 0 /* Nodes */, 0x411 /* should be in nodes */);
    for (let inField = cursor.firstField(); inField; inField = cursor.nextField()) {
        f(cursor);
    }
}
exports.forEachField = forEachField;
/**
 * @param cursor - tree whose field will be visited.
 * @param f - builds output from field member, which will be selected in cursor when cursor is provided.
 * If `f` moves cursor, it must put it back to where it was at the beginning of `f` before returning.
 * @returns array resulting from applying `f` to each item of the current field on `cursor`.
 * Returns an empty array if the field is empty or not present (which are considered the same).
 */
function mapCursorField(cursor, f) {
    const output = [];
    forEachNode(cursor, (c) => {
        output.push(f(c));
    });
    return output;
}
exports.mapCursorField = mapCursorField;
/**
 * @param cursor - cursor at a field whose nodes will be visited.
 * @param f - For on each node.
 * If `f` moves cursor, it must put it back to where it was at the beginning of `f` before returning.
 */
function forEachNode(cursor, f) {
    (0, common_utils_1.assert)(cursor.mode === 1 /* Fields */, 0x3bd /* should be in fields */);
    for (let inNodes = cursor.firstNode(); inNodes; inNodes = cursor.nextNode()) {
        f(cursor);
    }
}
exports.forEachNode = forEachNode;
/**
 * Casts a cursor to an {@link ITreeCursorSynchronous}.
 *
 * TODO: #1404: Handle this properly for partial data loading support.
 */
function castCursorToSynchronous(cursor) {
    return cursor;
}
exports.castCursorToSynchronous = castCursorToSynchronous;
/**
 * Runs `f` inside of field `field` on `cursor`.
 * @param cursor - Cursor whoso field to enter and exit. Must be in `nodes` mode.
 * @param field - Field to enter.
 * @param f - Callback to run when in field.
 * @returns return value of `f`
 */
function inCursorField(cursor, field, f) {
    cursor.enterField(field);
    const result = f(cursor);
    cursor.exitField();
    return result;
}
exports.inCursorField = inCursorField;
/**
 * Runs `f` inside of node `index` on `cursor`.
 * @param cursor - Cursor whoso node to enter and exit. Must be in `fields` mode.
 * @param index - Node to enter.
 * @param f - Callback to run when in node.
 * @returns return value of `f`
 */
function inCursorNode(cursor, index, f) {
    cursor.enterNode(index);
    const result = f(cursor);
    cursor.exitNode();
    return result;
}
exports.inCursorNode = inCursorNode;
//# sourceMappingURL=cursor.js.map