"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.withEditor = exports.FieldKindWithEditor = exports.FieldKind = void 0;
const core_utils_1 = require("@fluidframework/core-utils");
const comparison_1 = require("./comparison");
/**
 * Functionality for FieldKinds that is stable,
 * meaning that it can not change in any measurable way without providing a new identifier.
 *
 * It is assumed that this information and policy is available on all clients interacting with a document
 * using the identifier.
 *
 * This must contain enough information to process remote edits to this FieldKind consistently with all clients.
 * All behavior must be deterministic, and not change across versions of the app/library.
 *
 * These policies include the data encoding, change encoding, change rebase and change application.
 *
 * @sealed @alpha
 * @privateRemarks
 * This being @sealed is for users of this package.
 * This package itself may provide implementations.
 * This pattern was picked instead of an interface since we do not have a convention for how to mark interfaces as only allowed to be implemented by the package declaring them,
 * and using a class also gets stronger (nominal) typing for objects which will be down cast.
 */
class FieldKind {
    /**
     * @param identifier - Globally scoped identifier.
     * @param multiplicity - bound on the number of children that fields of this kind may have.
     * TODO: consider replacing with numeric upper and lower bounds.
     */
    constructor(identifier, multiplicity) {
        this.identifier = identifier;
        this.multiplicity = multiplicity;
    }
}
exports.FieldKind = FieldKind;
/**
 * Functionality for FieldKinds that is stable,
 * meaning that it can not change in any measurable way without providing a new identifier.
 *
 * It is assumed that this information and policy is available on all clients interacting with a document
 * using the identifier.
 *
 * This must contain enough information to process remote edits to this FieldKind consistently with all clients.
 * All behavior must be deterministic, and not change across versions of the app/library.
 *
 * These policies include the data encoding, change encoding, change rebase and change application.
 */
class FieldKindWithEditor extends FieldKind {
    /**
     * @param identifier - Globally scoped identifier.
     * @param multiplicity - bound on the number of children that fields of this kind may have.
     * TODO: replace with numeric upper and lower bounds.
     * @param changeHandler - Change handling policy.
     * @param allowsTreeSupersetOf - returns true iff `superset` supports all that this does
     * and `superset` is an allowed upgrade. Does not have to handle the `never` cases.
     * See {@link isNeverField}.
     * TODO: when used as a method (instead of a free function like the other superset related functions),
     * this name is/signature is confusing and seems backwards.
     * @param handlesEditsFrom - Kinds (in addition to this) whose edits can be processed by changeHandler.
     * If the kind of a field changes, and edits are rebased across that kind change,
     * listing the other old kind here can prevent those edits from being conflicted and
     * provide a chance to handle them.
     */
    constructor(identifier, multiplicity, changeHandler, allowsTreeSupersetOf, handlesEditsFrom) {
        super(identifier, multiplicity);
        this.changeHandler = changeHandler;
        this.allowsTreeSupersetOf = allowsTreeSupersetOf;
        this.handlesEditsFrom = handlesEditsFrom;
    }
    /**
     * @returns true iff `superset` permits a (non-strict) superset of the subtrees
     * allowed by field made from `this` and `originalTypes`.
     */
    allowsFieldSuperset(policy, originalData, originalTypes, superset) {
        if ((0, comparison_1.isNeverField)(policy, originalData, {
            kind: this,
            types: originalTypes,
        })) {
            return true;
        }
        if ((0, comparison_1.isNeverField)(policy, originalData, superset)) {
            return false;
        }
        return this.allowsTreeSupersetOf(originalTypes, superset);
    }
}
exports.FieldKindWithEditor = FieldKindWithEditor;
/**
 * Downcasts to FieldKindWithEditor.
 */
function withEditor(kind) {
    (0, core_utils_1.assert)(kind instanceof FieldKindWithEditor, 0x7b5 /* kind must be FieldKindWithEditor */);
    return kind;
}
exports.withEditor = withEditor;
//# sourceMappingURL=fieldKind.js.map