"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeRepo = exports.makeSchemaCodecs = exports.makeSchemaCodec = exports.clientVersionToSchemaVersion = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const index_js_1 = require("../../codec/index.js");
const index_js_2 = require("../../core/index.js");
const index_js_3 = require("../../util/index.js");
const formatV1_js_1 = require("./formatV1.js");
const formatV2_js_1 = require("./formatV2.js");
/**
 * Convert a FluidClientVersion to a SchemaVersion.
 * @param clientVersion - The FluidClientVersion to convert.
 * @returns The SchemaVersion that corresponds to the provided FluidClientVersion.
 */
function clientVersionToSchemaVersion(clientVersion) {
    // Only one version of the schema codec is currently supported.
    return index_js_2.SchemaVersion.v1;
}
exports.clientVersionToSchemaVersion = clientVersionToSchemaVersion;
/**
 * Create a schema codec.
 * @param options - Specifies common codec options, including which `validator` to use.
 * @param writeVersion - The schema write version.
 * @returns The composed codec.
 *
 * @privateRemarks We should consider using the Shared Tree format version instead as it may be more valuable for application authors than the schema version.
 */
function makeSchemaCodec(options, writeVersion) {
    const family = makeSchemaCodecs(options);
    return (0, index_js_1.makeVersionDispatchingCodec)(family, { ...options, writeVersion });
}
exports.makeSchemaCodec = makeSchemaCodec;
/**
 * Create a family of schema codecs.
 * @param options - Specifies common codec options, including which `validator` to use.
 * @returns The composed codec family.
 */
function makeSchemaCodecs(options) {
    return (0, index_js_1.makeCodecFamily)([
        [index_js_2.SchemaVersion.v1, makeSchemaCodecV1(options)],
        [index_js_2.SchemaVersion.v2, makeSchemaCodecV2(options)],
    ]);
}
exports.makeSchemaCodecs = makeSchemaCodecs;
/**
 * Encode an in-memory TreeStoredSchema into the specified format version.
 * @param repo - The in-memory schema.
 * @param version - The schema write version.
 * @returns The encoded schema.
 */
function encodeRepo(repo, version) {
    switch (version) {
        case index_js_2.SchemaVersion.v1:
            return encodeRepoV1(repo);
        case index_js_2.SchemaVersion.v2:
            return encodeRepoV2(repo);
        default:
            (0, internal_1.unreachableCase)(version);
    }
}
exports.encodeRepo = encodeRepo;
function encodeRepoV1(repo) {
    const nodeSchema = encodeNodeSchema(repo, (schema) => schema.encodeV1());
    const rootFieldSchema = (0, index_js_2.encodeFieldSchemaV1)(repo.rootFieldSchema);
    return {
        version: index_js_2.SchemaVersion.v1,
        nodes: nodeSchema,
        root: rootFieldSchema,
    };
}
function encodeRepoV2(repo) {
    const nodeSchema = encodeNodeSchema(repo, (schema) => schema.encodeV2());
    const rootFieldSchema = (0, index_js_2.encodeFieldSchemaV2)(repo.rootFieldSchema);
    return {
        version: index_js_2.SchemaVersion.v2,
        nodes: nodeSchema,
        root: rootFieldSchema,
    };
}
/**
 * Shared logic for encoding node schemas.
 * @param repo - The stored schema to encode.
 * @param encodeValue - A function which encodes a single node schema.
 * @returns The encoded node schema.
 */
function encodeNodeSchema(repo, encodeValue) {
    const nodeSchema = Object.create(null);
    for (const name of [...repo.nodeSchema.keys()].sort()) {
        const schema = repo.nodeSchema.get(name) ?? (0, internal_1.fail)(0xb28 /* missing schema */);
        Object.defineProperty(nodeSchema, name, {
            enumerable: true,
            configurable: true,
            writable: true,
            value: encodeValue(schema),
        });
    }
    return nodeSchema;
}
function decodeV1(f) {
    const nodeSchema = new Map();
    for (const [key, schema] of Object.entries(f.nodes)) {
        const storedSchemaDecoder = index_js_2.storedSchemaDecodeDispatcher.dispatch(schema);
        // No metadata in v1, so pass undefined
        nodeSchema.set((0, index_js_3.brand)(key), storedSchemaDecoder(undefined));
    }
    return {
        rootFieldSchema: (0, index_js_2.decodeFieldSchema)(f.root),
        nodeSchema,
    };
}
function decodeV2(f) {
    const nodeSchema = new Map();
    for (const [key, schema] of Object.entries(f.nodes)) {
        const storedSchemaDecoder = index_js_2.storedSchemaDecodeDispatcher.dispatch(schema.kind);
        // Pass in the node metadata
        nodeSchema.set((0, index_js_3.brand)(key), storedSchemaDecoder(schema.metadata));
    }
    return {
        rootFieldSchema: (0, index_js_2.decodeFieldSchema)(f.root),
        nodeSchema,
    };
}
/**
 * Creates a codec which performs synchronous monolithic encoding of schema content.
 * @param options - Specifies common codec options, including which `validator` to use.
 * @returns The codec.
 */
function makeSchemaCodecV1(options) {
    return (0, index_js_1.makeVersionedValidatedCodec)(options, new Set([index_js_2.SchemaVersion.v1]), formatV1_js_1.Format, {
        encode: (data) => encodeRepoV1(data),
        decode: (data) => decodeV1(data),
    });
}
/**
 * Creates a codec which performs synchronous monolithic encoding of schema content.
 * @param options - Specifies common codec options, including which `validator` to use.
 * @returns The codec.
 */
function makeSchemaCodecV2(options) {
    return (0, index_js_1.makeVersionedValidatedCodec)(options, new Set([index_js_2.SchemaVersion.v2]), formatV2_js_1.Format, {
        encode: (data) => encodeRepoV2(data),
        decode: (data) => decodeV2(data),
    });
}
//# sourceMappingURL=codec.js.map