"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.allowsRepoSuperset = exports.allowsTreeSchemaIdentifierSuperset = exports.allowsFieldSuperset = exports.allowsValueSuperset = exports.allowsTreeSuperset = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const index_js_1 = require("../../core/index.js");
const index_js_2 = require("../../util/index.js");
const fieldKindWithEditor_js_1 = require("./fieldKindWithEditor.js");
const isNeverTree_js_1 = require("./isNeverTree.js");
/**
 * Returns true iff `superset` is a superset of `original`.
 *
 * This does not require a strict (aka proper) superset: equivalent schema will return true.
 *
 * `undefined` TreeNodeStoredSchema means the schema is not present (and thus treated as a NeverTree).
 */
function allowsTreeSuperset(policy, originalData, original, superset) {
    if ((0, isNeverTree_js_1.isNeverTree)(policy, originalData, original)) {
        return true;
    }
    if ((0, isNeverTree_js_1.isNeverTree)(policy, originalData, superset)) {
        return false;
    }
    (0, internal_1.assert)(original !== undefined, 0x716 /* only never trees have undefined schema */);
    (0, internal_1.assert)(superset !== undefined, 0x717 /* only never trees have undefined schema */);
    if (original instanceof index_js_1.LeafNodeStoredSchema) {
        if (superset instanceof index_js_1.LeafNodeStoredSchema) {
            return allowsValueSuperset(original.leafValue, superset.leafValue);
        }
        return false;
    }
    if (superset instanceof index_js_1.LeafNodeStoredSchema) {
        return false;
    }
    (0, internal_1.assert)(original instanceof index_js_1.MapNodeStoredSchema || original instanceof index_js_1.ObjectNodeStoredSchema, 0x893 /* unsupported node kind */);
    (0, internal_1.assert)(superset instanceof index_js_1.MapNodeStoredSchema || superset instanceof index_js_1.ObjectNodeStoredSchema, 0x894 /* unsupported node kind */);
    if (original instanceof index_js_1.MapNodeStoredSchema) {
        if (superset instanceof index_js_1.MapNodeStoredSchema) {
            return allowsFieldSuperset(policy, originalData, original.mapFields, superset.mapFields);
        }
        return false;
    }
    (0, internal_1.assert)(original instanceof index_js_1.ObjectNodeStoredSchema, 0x895 /* unsupported node kind */);
    if (superset instanceof index_js_1.MapNodeStoredSchema) {
        for (const [_key, field] of original.objectNodeFields) {
            if (!allowsFieldSuperset(policy, originalData, field, superset.mapFields)) {
                return false;
            }
        }
        return true;
    }
    (0, internal_1.assert)(superset instanceof index_js_1.ObjectNodeStoredSchema, 0x896 /* unsupported node kind */);
    return (0, index_js_2.compareSets)({
        a: original.objectNodeFields,
        b: superset.objectNodeFields,
        aExtra: (originalField) => allowsFieldSuperset(policy, originalData, original.objectNodeFields.get(originalField) ??
            (0, internal_1.fail)(0xb17 /* missing expected field */), index_js_1.storedEmptyFieldSchema),
        bExtra: (supersetField) => allowsFieldSuperset(policy, originalData, index_js_1.storedEmptyFieldSchema, superset.objectNodeFields.get(supersetField) ??
            (0, internal_1.fail)(0xb18 /* missing expected field */)),
        same: (sameField) => allowsFieldSuperset(policy, originalData, original.objectNodeFields.get(sameField) ?? (0, internal_1.fail)(0xb19 /* missing expected field */), superset.objectNodeFields.get(sameField) ?? (0, internal_1.fail)(0xb1a /* missing expected field */)),
    });
}
exports.allowsTreeSuperset = allowsTreeSuperset;
/**
 * Returns true iff `superset` is a superset of `original`.
 *
 * This does not require a strict (aka proper) superset: equivalent schema will return true.
 */
function allowsValueSuperset(original, superset) {
    return original === superset;
}
exports.allowsValueSuperset = allowsValueSuperset;
/**
 * Returns true iff `superset` is a superset of `original`.
 *
 * This does not require a strict (aka proper) superset: equivalent schema will return true.
 */
function allowsFieldSuperset(policy, originalData, original, superset) {
    return (0, fieldKindWithEditor_js_1.withEditor)(policy.fieldKinds.get(original.kind) ?? (0, internal_1.fail)(0xb1b /* missing kind */)).allowsFieldSuperset(policy, originalData, original.types, superset);
}
exports.allowsFieldSuperset = allowsFieldSuperset;
/**
 * Returns true iff `superset` is a superset of `original`.
 *
 * This does not require a strict (aka proper) superset: equivalent schema will return true.
 */
function allowsTreeSchemaIdentifierSuperset(original, superset) {
    for (const originalType of original) {
        if (!superset.has(originalType)) {
            return false;
        }
    }
    return true;
}
exports.allowsTreeSchemaIdentifierSuperset = allowsTreeSchemaIdentifierSuperset;
/**
 * Returns true iff `superset` is a superset of `original`.
 *
 * This does not require a strict (aka proper) superset: equivalent schema will return true.
 *
 * A version of this that assumes a specific root field could be slightly more permissive in some simple cases,
 * however if any extra fields and fields with unconstrained types are reachable,
 * it would have to compare everything anyway.
 */
function allowsRepoSuperset(policy, original, superset) {
    {
        if (!allowsFieldSuperset(policy, original, original.rootFieldSchema, superset.rootFieldSchema)) {
            return false;
        }
    }
    // Check if all schema in original are included in superset, and permit a superset of the node content.
    // Note that any schema from `original.nodeSchema` can be used as the schema for a node at the root of a detached field,
    // so we must check all of them, even if they are not reachable from the root field schema.
    for (const [key, schema] of original.nodeSchema) {
        if (!allowsTreeSuperset(policy, original, schema, superset.nodeSchema.get(key))) {
            return false;
        }
    }
    // Any schema in superset not in original are already known to be superset of original since they are "never" due to being missing.
    // Therefore, we do not need to check them.
    return true;
}
exports.allowsRepoSuperset = allowsRepoSuperset;
//# sourceMappingURL=comparison.js.map