/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { assert, isObject } from "@fluidframework/core-utils/internal";
import { MergeBlock } from "./mergeTreeNodes.js";
export function propExists(thing, prop) {
    return isObject(thing) && prop in thing;
}
export function hasProp(thing, prop, type) {
    return (propExists(thing, prop) &&
        (type === "array" ? Array.isArray(thing[prop]) : typeof thing[prop] === type));
}
export function propInstanceOf(thing, prop, type) {
    return propExists(thing, prop) && thing[prop] instanceof type;
}
/**
 * Converts a segment-like object to an insertion info object if possible.
 *
 * @param segmentLike - The segment-like object to convert.
 * @returns The insertion info object if the conversion is possible, otherwise undefined.
 */
export const toInsertionInfo = (segmentLike) => hasProp(segmentLike, "clientId", "number") && hasProp(segmentLike, "seq", "number")
    ? segmentLike
    : undefined;
/**
 * A type-guard which determines if the segment has insertion info, and
 * returns true if it does, along with applying strong typing.
 *
 * @param segmentLike - The segment-like object to check.
 * @returns True if the segment has insertion info, otherwise false.
 */
export const isInserted = (segmentLike) => toInsertionInfo(segmentLike) !== undefined;
/**
 * Asserts that the segment has insertion info. Usage of this function should not produce a user facing error.
 *
 * @param segmentLike - The segment-like object to check.
 * @throws Will throw an error if the segment does not have insertion info.
 */
export const assertInserted = (segmentLike) => assert(segmentLike === undefined || isInserted(segmentLike), 0xaa0 /* must be insertionInfo */);
/**
 * Converts a segment-like object to a merge node info object if possible.
 *
 * @param segmentLike - The segment-like object to convert.
 * @returns The merge node info object if the conversion is possible, otherwise undefined.
 */
export const toMergeNodeInfo = (nodeLike) => propInstanceOf(nodeLike, "parent", MergeBlock) &&
    hasProp(nodeLike, "ordinal", "string") &&
    hasProp(nodeLike, "index", "number")
    ? nodeLike
    : undefined;
/**
 * A type-guard which determines if the segment has merge node info, and
 * returns true if it does, along with applying strong typing.
 *
 * @param nodeLike - The segment-like object to check.
 * @returns True if the segment has merge node info, otherwise false.
 */
export const isMergeNodeInfo = (nodeLike) => toMergeNodeInfo(nodeLike) !== undefined;
/**
 * Asserts that the segment has merge node info. Usage of this function should not produce a user facing error.
 *
 * @param segmentLike - The segment-like object to check.
 * @throws Will throw an error if the segment does not have merge node info.
 */
export const assertMergeNode = (segmentLike) => assert(segmentLike === undefined || isMergeNodeInfo(segmentLike), 0xaa1 /* must be MergeNodeInfo */);
/**
 * Removes the merge node info. This is used to remove nodes from the merge-tree.
 * @param segmentLike - The segment-like object to check.
 * @returns This function will change the type of the provided node like to never via an assertion. This
 * ensures no further usage of the removed merge node info is allowed. if continued use is required other
 * type coercion methods should be used to correctly re-type the variable.
 */
export const removeMergeNodeInfo = (nodeLike) => Object.assign(nodeLike, {
    parent: undefined,
    index: undefined,
    ordinal: undefined,
});
/**
 * Converts a segment-like object to a removal info object if possible.
 *
 * @param segmentLike - The segment-like object to convert.
 * @returns The removal info object if the conversion is possible, otherwise undefined.
 */
export const toRemovalInfo = (segmentLike) => hasProp(segmentLike, "removedClientIds", "array") &&
    hasProp(segmentLike, "removedSeq", "number")
    ? segmentLike
    : undefined;
/**
 * A type-guard which determines if the segment has removal info, and
 * returns true if it does, along with applying strong typing.
 *
 * @param segmentLike - The segment-like object to check.
 * @returns True if the segment has removal info, otherwise false.
 */
export const isRemoved = (segmentLike) => toRemovalInfo(segmentLike) !== undefined;
/**
 * Asserts that the segment has removal info. Usage of this function should not produce a user facing error.
 *
 * @param segmentLike - The segment-like object to check.
 * @throws Will throw an error if the segment does not have removal info.
 */
export const assertRemoved = (segmentLike) => assert(segmentLike === undefined || isRemoved(segmentLike), 0xaa2 /* must be removalInfo */);
/**
 * Removes the removal info. This is used in rollback.
 * @param segmentLike - The segment-like object to check.
 * @returns This function will change the type of the provided node like to never via an assertion. This
 * ensures no further usage of the removed removal info is allowed. if continued use is required other
 * type coercion methods should be use to correctly re-type the variable.
 */
export const removeRemovalInfo = (nodeLike) => Object.assign(nodeLike, {
    localRemovedSeq: undefined,
    removedClientIds: undefined,
    removedSeq: undefined,
});
export const toMoveInfo = (segmentLike) => hasProp(segmentLike, "movedClientIds", "array") &&
    hasProp(segmentLike, "movedSeq", "number") &&
    hasProp(segmentLike, "movedSeqs", "array") &&
    hasProp(segmentLike, "wasMovedOnInsert", "boolean")
    ? segmentLike
    : undefined;
/**
 * A type-guard which determines if the segment has move info, and
 * returns true if it does, along with applying strong typing.
 *
 * @param segmentLike - The segment-like object to check.
 * @returns True if the segment has move info, otherwise false.
 */
export const isMoved = (segmentLike) => toMoveInfo(segmentLike) !== undefined;
/**
 * Asserts that the segment has move info. Usage of this function should not produce a user facing error.
 *
 * @param segmentLike - The segment-like object to check.
 * @throws Will throw an error if the segment does not have move info.
 */
export const assertMoved = (segmentLike) => assert(segmentLike === undefined || isMoved(segmentLike), 0xaa3 /* must be moveInfo */);
/**
 * Overwrites the segment info on a segment-like object.
 *
 * @param segmentLike - The segment-like object to set the info on.
 * @param info - The segment info to overwrite.
 * @returns The segment-like object with the info set.
 */
export const overwriteInfo = (segmentLike, info) => Object.assign(segmentLike, info);
//# sourceMappingURL=segmentInfos.js.map