"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.isNeverTreeRecursive = exports.isNeverTree = exports.isNeverFieldRecursive = exports.isNeverField = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const index_js_1 = require("../../core/index.js");
function isNeverField(policy, originalData, field) {
    return isNeverFieldRecursive(policy, originalData, field, new Set());
}
exports.isNeverField = isNeverField;
function isNeverFieldRecursive(policy, originalData, field, parentTypeStack) {
    if ((policy.fieldKinds.get(field.kind) ?? (0, internal_1.fail)(0xb1c /* missing field kind */))
        .multiplicity === index_js_1.Multiplicity.Single &&
        field.types !== undefined) {
        for (const type of field.types) {
            if (!isNeverTreeRecursive(policy, originalData, originalData.nodeSchema.get(type), parentTypeStack)) {
                return false;
            }
        }
        // This field requires at least one child, and there are no types permitted in it that can exist,
        // so this is a never field (field which no sequence of children content could ever be in schema for)
        return true;
    }
    return false;
}
exports.isNeverFieldRecursive = isNeverFieldRecursive;
/**
 * Returns true iff there are no possible trees that could meet this schema.
 * Trees which are infinite (like endless linked lists) are considered impossible.
 *
 * `undefined` means the schema is not present and thus a NeverTree.
 */
function isNeverTree(policy, originalData, treeNode) {
    return isNeverTreeRecursive(policy, originalData, treeNode, new Set());
}
exports.isNeverTree = isNeverTree;
/**
 * Returns true iff there are no possible trees that could meet this schema.
 * Trees which are infinite (like endless linked lists) are considered impossible.
 *
 * `undefined` means the schema is not present and thus a NeverTree.
 */
function isNeverTreeRecursive(policy, originalData, treeNode, parentTypeStack) {
    if (treeNode === undefined) {
        return true;
    }
    if (parentTypeStack.has(treeNode)) {
        return true;
    }
    try {
        parentTypeStack.add(treeNode);
        if (treeNode instanceof index_js_1.MapNodeStoredSchema) {
            return ((policy.fieldKinds.get(treeNode.mapFields.kind) ??
                (0, internal_1.fail)(0xb1d /* missing field kind */)).multiplicity === index_js_1.Multiplicity.Single);
        }
        else if (treeNode instanceof index_js_1.ObjectNodeStoredSchema) {
            for (const field of treeNode.objectNodeFields.values()) {
                // TODO: this can recurse infinitely for schema that include themselves in a value field.
                // This breaks even if there are other allowed types.
                // Such schema should either be rejected (as an error here) or considered never (and thus detected by this).
                // This can be done by passing a set/stack of current types recursively here.
                if (isNeverFieldRecursive(policy, originalData, field, parentTypeStack)) {
                    return true;
                }
            }
            return false;
        }
        else {
            (0, internal_1.assert)(treeNode instanceof index_js_1.LeafNodeStoredSchema, 0x897 /* unsupported node kind */);
            return false;
        }
    }
    finally {
        parentTypeStack.delete(treeNode);
    }
}
exports.isNeverTreeRecursive = isNeverTreeRecursive;
//# sourceMappingURL=isNeverTree.js.map