"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.tryStoredSchemaAsArray = exports.customFromCursorStored = exports.customFromCursor = void 0;
const internal_1 = require("@fluidframework/runtime-utils/internal");
const internal_2 = require("@fluidframework/core-utils/internal");
const index_js_1 = require("../../core/index.js");
const index_js_2 = require("../../util/index.js");
const index_js_3 = require("../core/index.js");
const leafNodeSchema_js_1 = require("../leafNodeSchema.js");
const objectNodeTypes_js_1 = require("../objectNodeTypes.js");
const index_js_4 = require("../../feature-libraries/index.js");
/**
 * Builds an {@link CustomTree} from a cursor in Nodes mode.
 */
function customFromCursor(reader, options, schema, childHandler) {
    const type = reader.type;
    const nodeSchema = schema.get(type) ?? (0, index_js_2.fail)("missing schema for type in cursor");
    switch (type) {
        case leafNodeSchema_js_1.numberSchema.identifier:
        case leafNodeSchema_js_1.booleanSchema.identifier:
        case leafNodeSchema_js_1.nullSchema.identifier:
        case leafNodeSchema_js_1.stringSchema.identifier:
            (0, internal_2.assert)(reader.value !== undefined, 0xa50 /* out of schema: missing value */);
            (0, internal_2.assert)(!(0, internal_1.isFluidHandle)(reader.value), 0xa51 /* out of schema: unexpected FluidHandle */);
            return reader.value;
        case leafNodeSchema_js_1.handleSchema.identifier:
            (0, internal_2.assert)(reader.value !== undefined, 0xa52 /* out of schema: missing value */);
            (0, internal_2.assert)((0, internal_1.isFluidHandle)(reader.value), 0xa53 /* out of schema: expected FluidHandle */);
            return options.valueConverter(reader.value);
        default: {
            (0, internal_2.assert)(reader.value === undefined, 0xa54 /* out of schema: unexpected value */);
            if (nodeSchema.kind === index_js_3.NodeKind.Array) {
                const fields = (0, index_js_1.inCursorField)(reader, index_js_1.EmptyKey, () => (0, index_js_1.mapCursorField)(reader, () => childHandler(reader, options, schema)));
                return fields;
            }
            else {
                const fields = {};
                (0, index_js_1.forEachField)(reader, () => {
                    const children = (0, index_js_1.mapCursorField)(reader, () => childHandler(reader, options, schema));
                    if (children.length === 1) {
                        const storedKey = reader.getFieldKey();
                        const key = (0, objectNodeTypes_js_1.isObjectNodeSchema)(nodeSchema) && !options.useStoredKeys
                            ? (nodeSchema.storedKeyToPropertyKey.get(storedKey) ??
                                (0, index_js_2.fail)("missing property key"))
                            : storedKey;
                        // Length is checked above.
                        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                        fields[key] = children[0];
                    }
                    else {
                        (0, internal_2.assert)(children.length === 0, 0xa19 /* invalid children number */);
                    }
                });
                return fields;
            }
        }
    }
}
exports.customFromCursor = customFromCursor;
/**
 * Builds an {@link CustomTree} from a cursor in Nodes mode.
 * @remarks
 * Uses stored keys and stored schema.
 */
function customFromCursorStored(reader, schema, childHandler) {
    const type = reader.type;
    const nodeSchema = schema.get(type) ?? (0, index_js_2.fail)("missing schema for type in cursor");
    if (nodeSchema instanceof index_js_1.LeafNodeStoredSchema) {
        (0, internal_2.assert)((0, index_js_4.valueSchemaAllows)(nodeSchema.leafValue, reader.value), 0xa9c /* invalid value */);
        return reader.value;
    }
    (0, internal_2.assert)(reader.value === undefined, 0xa9d /* out of schema: unexpected value */);
    const arrayTypes = tryStoredSchemaAsArray(nodeSchema);
    if (arrayTypes !== undefined) {
        const field = (0, index_js_1.inCursorField)(reader, index_js_1.EmptyKey, () => (0, index_js_1.mapCursorField)(reader, () => childHandler(reader, schema)));
        return field;
    }
    const fields = {};
    (0, index_js_1.forEachField)(reader, () => {
        const children = (0, index_js_1.mapCursorField)(reader, () => childHandler(reader, schema));
        if (children.length === 1) {
            const storedKey = reader.getFieldKey();
            // Length is checked above.
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
            fields[storedKey] = children[0];
        }
        else {
            (0, internal_2.assert)(children.length === 0, 0xa9e /* invalid children number */);
        }
    });
    return fields;
}
exports.customFromCursorStored = customFromCursorStored;
/**
 * Assumes `schema` corresponds to a simple-tree schema.
 * If it is an array schema, returns the allowed types for the array field.
 * Otherwise returns `undefined`.
 */
function tryStoredSchemaAsArray(schema) {
    if (schema instanceof index_js_1.ObjectNodeStoredSchema) {
        const empty = schema.getFieldSchema(index_js_1.EmptyKey);
        if (empty.kind === index_js_4.FieldKinds.sequence.identifier) {
            (0, internal_2.assert)(schema.objectNodeFields.size === 1, 0xa9f /* invalid schema */);
            return empty.types;
        }
    }
}
exports.tryStoredSchemaAsArray = tryStoredSchemaAsArray;
//# sourceMappingURL=customTree.js.map