"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.createFromCursor = exports.createFromVerbose = exports.cursorFromInsertable = exports.createFromInsertable = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const index_js_1 = require("../../util/index.js");
const index_js_2 = require("../../feature-libraries/index.js");
const proxies_js_1 = require("../proxies.js");
const index_js_3 = require("../../feature-libraries/index.js");
const toFlexSchema_js_1 = require("../toFlexSchema.js");
const toMapTree_js_1 = require("../toMapTree.js");
const verboseTree_js_1 = require("./verboseTree.js");
/**
 * Construct tree content that is compatible with the field defined by the provided `schema`.
 * @param schema - The schema for what to construct. As this is an {@link ImplicitFieldSchema}, a {@link FieldSchema}, {@link TreeNodeSchema} or {@link AllowedTypes} array can be provided.
 * @param data - The data used to construct the field content.
 * @remarks
 * When providing a {@link TreeNodeSchemaClass}, this is the same as invoking its constructor except that an unhydrated node can also be provided.
 * This function exists as a generalization that can be used in other cases as well,
 * such as when `undefined` might be allowed (for an optional field), or when the type should be inferred from the data when more than one type is possible.
 *
 * Like with {@link TreeNodeSchemaClass}'s constructor, its an error to provide an existing node to this API.
 * TODO: For that case, use we should provide `Tree.clone`.
 * @privateRemarks
 * This could be exposed as a public `Tree.create` function.
 */
function createFromInsertable(schema, data, context) {
    const cursor = cursorFromInsertable(schema, data, context);
    const result = cursor === undefined ? undefined : createFromCursor(schema, cursor);
    return result;
}
exports.createFromInsertable = createFromInsertable;
/**
 * Construct tree content that is compatible with the field defined by the provided `schema`.
 * @param schema - The schema for what to construct. As this is an {@link ImplicitFieldSchema}, a {@link FieldSchema}, {@link TreeNodeSchema} or {@link AllowedTypes} array can be provided.
 * @param data - The data used to construct the field content.
 * @remarks
 * When providing a {@link TreeNodeSchemaClass},
 * this is the same as invoking its constructor except that an unhydrated node can also be provided and the returned value is a cursor.
 * When `undefined` is provided (for an optional field), `undefined` is returned.
 */
function cursorFromInsertable(schema, data, context) {
    const flexSchema = (0, toFlexSchema_js_1.toFlexSchema)(schema);
    const schemaValidationPolicy = {
        policy: index_js_2.defaultSchemaPolicy,
        // TODO: optimize: This isn't the most efficient operation since its not cached, and has to convert all the schema.
        schema: (0, index_js_2.intoStoredSchema)(flexSchema),
    };
    const mapTree = (0, toMapTree_js_1.mapTreeFromNodeData)(data, schema, context, schemaValidationPolicy);
    if (mapTree === undefined) {
        (0, internal_1.assert)(flexSchema.rootFieldSchema.kind === index_js_2.FieldKinds.optional, 0xa10 /* missing non-optional field */);
        return undefined;
    }
    return (0, index_js_2.cursorForMapTreeNode)(mapTree);
}
exports.cursorFromInsertable = cursorFromInsertable;
function createFromVerbose(schema, data, options) {
    const config = {
        valueConverter: (input) => {
            return input;
        },
        ...options,
    };
    const schemalessConfig = (0, verboseTree_js_1.applySchemaToParserOptions)(schema, config);
    const cursor = (0, verboseTree_js_1.cursorFromVerbose)(data, schemalessConfig);
    return createFromCursor(schema, cursor);
}
exports.createFromVerbose = createFromVerbose;
/**
 * Creates an unhydrated simple-tree field from a cursor in nodes mode.
 */
function createFromCursor(schema, cursor) {
    const mapTrees = cursor === undefined ? [] : [(0, index_js_2.mapTreeFromCursor)(cursor)];
    const flexSchema = (0, toFlexSchema_js_1.toFlexSchema)(schema);
    const schemaValidationPolicy = {
        policy: index_js_2.defaultSchemaPolicy,
        // TODO: optimize: This isn't the most efficient operation since its not cached, and has to convert all the schema.
        schema: (0, index_js_2.intoStoredSchema)(flexSchema),
    };
    const maybeError = (0, index_js_3.isFieldInSchema)(mapTrees, flexSchema.rootFieldSchema.stored, schemaValidationPolicy);
    (0, toMapTree_js_1.inSchemaOrThrow)(maybeError);
    if (mapTrees.length === 0) {
        return undefined;
    }
    (0, internal_1.assert)(mapTrees.length === 1, 0xa11 /* unexpected field length */);
    // Length asserted above, so this is safe. This assert is done instead of checking for undefined after indexing to ensure a length greater than 1 also errors.
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const mapTree = mapTrees[0];
    const rootSchema = flexSchema.nodeSchema.get(mapTree.type) ?? (0, index_js_1.fail)("missing schema");
    const mapTreeNode = (0, index_js_3.getOrCreateMapTreeNode)(new index_js_2.UnhydratedContext(flexSchema), rootSchema, mapTree);
    // TODO: ensure this works for InnerNodes to create unhydrated nodes
    const result = (0, proxies_js_1.getOrCreateNodeFromFlexTreeNode)(mapTreeNode);
    return result;
}
exports.createFromCursor = createFromCursor;
//# sourceMappingURL=create.js.map