"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStoredSchema = exports.convertAllowedTypes = exports.convertField = exports.toStoredSchema = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const internal_2 = require("@fluidframework/telemetry-utils/internal");
const index_js_1 = require("../core/index.js");
const index_js_2 = require("../feature-libraries/index.js");
const index_js_3 = require("../util/index.js");
const index_js_4 = require("./core/index.js");
const schemaTypes_js_1 = require("./schemaTypes.js");
const walkFieldSchema_js_1 = require("./walkFieldSchema.js");
const leafNodeSchema_js_1 = require("./leafNodeSchema.js");
const objectNodeTypes_js_1 = require("./objectNodeTypes.js");
const flexList_js_1 = require("./flexList.js");
const viewToStoredCache = new WeakMap();
/**
 * Converts a {@link ImplicitFieldSchema} into a {@link TreeStoredSchema}.
 */
function toStoredSchema(root) {
    return (0, index_js_3.getOrCreate)(viewToStoredCache, root, () => {
        const nodeSchema = new Map();
        (0, walkFieldSchema_js_1.walkFieldSchema)(root, {
            node(schema) {
                if (nodeSchema.has((0, index_js_3.brand)(schema.identifier))) {
                    // Use JSON.stringify to quote and escape identifier string.
                    throw new internal_2.UsageError(`Multiple schema encountered with the identifier ${JSON.stringify(schema.identifier)}. Remove or rename them to avoid the collision.`);
                }
                nodeSchema.set((0, index_js_3.brand)(schema.identifier), getStoredSchema(schema));
            },
        });
        const result = {
            nodeSchema,
            rootFieldSchema: convertField(root),
        };
        viewToStoredCache.set(root, result);
        return result;
    });
}
exports.toStoredSchema = toStoredSchema;
/**
 * Normalizes an {@link ImplicitFieldSchema} into a {@link TreeFieldSchema}.
 */
function convertField(schema) {
    let kind;
    let allowedTypes;
    if (schema instanceof schemaTypes_js_1.FieldSchema) {
        kind = convertFieldKind.get(schema.kind)?.identifier ?? (0, index_js_3.fail)("Invalid field kind");
        allowedTypes = schema.allowedTypes;
    }
    else {
        kind = index_js_2.FieldKinds.required.identifier;
        allowedTypes = schema;
    }
    const types = convertAllowedTypes(allowedTypes);
    return { kind, types };
}
exports.convertField = convertField;
const convertFieldKind = new Map([
    [schemaTypes_js_1.FieldKind.Optional, index_js_2.FieldKinds.optional],
    [schemaTypes_js_1.FieldKind.Required, index_js_2.FieldKinds.required],
    [schemaTypes_js_1.FieldKind.Identifier, index_js_2.FieldKinds.identifier],
]);
/**
 * Normalizes an {@link ImplicitAllowedTypes} into an {@link TreeTypeSet}.
 */
function convertAllowedTypes(schema) {
    if ((0, index_js_3.isReadonlyArray)(schema)) {
        return new Set((0, flexList_js_1.normalizeFlexListEager)(schema).map((item) => (0, index_js_3.brand)(item.identifier)));
    }
    return new Set([(0, index_js_3.brand)(schema.identifier)]);
}
exports.convertAllowedTypes = convertAllowedTypes;
/**
 * Converts a {@link TreeNodeSchema} into a {@link TreeNodeStoredSchema}.
 */
function getStoredSchema(schema) {
    const kind = schema.kind;
    switch (kind) {
        case index_js_4.NodeKind.Leaf: {
            (0, internal_1.assert)(schema instanceof leafNodeSchema_js_1.LeafNodeSchema, 0xa4a /* invalid kind */);
            return new index_js_1.LeafNodeStoredSchema(schema.info);
        }
        case index_js_4.NodeKind.Map: {
            const fieldInfo = schema.info;
            const types = convertAllowedTypes(fieldInfo);
            return new index_js_1.MapNodeStoredSchema({ kind: index_js_2.FieldKinds.optional.identifier, types });
        }
        case index_js_4.NodeKind.Array: {
            const fieldInfo = schema.info;
            const field = {
                kind: index_js_2.FieldKinds.sequence.identifier,
                types: convertAllowedTypes(fieldInfo),
            };
            const fields = new Map([[index_js_1.EmptyKey, field]]);
            return new index_js_1.ObjectNodeStoredSchema(fields);
        }
        case index_js_4.NodeKind.Object: {
            (0, internal_1.assert)((0, objectNodeTypes_js_1.isObjectNodeSchema)(schema), 0xa4b /* invalid kind */);
            const fields = new Map();
            for (const field of schema.flexKeyMap.values()) {
                fields.set(field.storedKey, convertField(field.schema));
            }
            return new index_js_1.ObjectNodeStoredSchema(fields);
        }
        default:
            (0, internal_1.unreachableCase)(kind);
    }
}
exports.getStoredSchema = getStoredSchema;
//# sourceMappingURL=toStoredSchema.js.map