"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.withSchemaValidation = exports.unitCodec = exports.ensureBinaryEncoding = exports.withDefaultBinaryEncoding = exports.makeCodecFamily = void 0;
const client_utils_1 = require("@fluid-internal/client-utils");
const core_utils_1 = require("@fluidframework/core-utils");
const index_js_1 = require("../util/index.js");
/**
 * Creates a codec family from a registry of codecs.
 * Any codec that is not a {@link IMultiFormatCodec} will be wrapped with a default binary encoding.
 */
function makeCodecFamily(registry) {
    const codecs = new Map();
    for (const [formatVersion, codec] of registry) {
        if (codecs.has(formatVersion)) {
            (0, index_js_1.fail)("Duplicate codecs specified.");
        }
        codecs.set(formatVersion, ensureBinaryEncoding(codec));
    }
    return {
        resolve(formatVersion) {
            const codec = codecs.get(formatVersion);
            (0, core_utils_1.assert)(codec !== undefined, 0x5e6 /* Requested coded for unsupported format. */);
            return codec;
        },
        getSupportedFormats() {
            return codecs.keys();
        },
    };
}
exports.makeCodecFamily = makeCodecFamily;
class DefaultBinaryCodec {
    constructor(jsonCodec) {
        this.jsonCodec = jsonCodec;
    }
    encode(change, context) {
        const jsonable = this.jsonCodec.encode(change, context);
        const json = JSON.stringify(jsonable);
        return client_utils_1.IsoBuffer.from(json);
    }
    decode(change, context) {
        const json = (0, client_utils_1.bufferToString)(change, "utf8");
        const jsonable = JSON.parse(json);
        return this.jsonCodec.decode(jsonable, context);
    }
}
function isJsonCodec(codec) {
    return typeof codec.encode === "function" && typeof codec.decode === "function";
}
/**
 * Constructs a {@link IMultiFormatCodec} from a `IJsonCodec` using a generic binary encoding that simply writes
 * the json representation of the object to a buffer.
 */
function withDefaultBinaryEncoding(jsonCodec) {
    return {
        json: jsonCodec,
        binary: new DefaultBinaryCodec(jsonCodec),
    };
}
exports.withDefaultBinaryEncoding = withDefaultBinaryEncoding;
/**
 * Ensures that the provided single or multi-format codec has a binary encoding.
 * Adapts the json encoding using {@link withDefaultBinaryEncoding} if necessary.
 */
function ensureBinaryEncoding(codec) {
    return isJsonCodec(codec) ? withDefaultBinaryEncoding(codec) : codec;
}
exports.ensureBinaryEncoding = ensureBinaryEncoding;
/**
 * Codec for objects which carry no information.
 */
exports.unitCodec = {
    json: {
        encode: () => 0,
        decode: () => 0,
    },
    binary: {
        encode: () => client_utils_1.IsoBuffer.from(""),
        decode: () => 0,
    },
};
/**
 * Wraps a codec with JSON schema validation for its encoded type.
 * @returns An {@link IJsonCodec} which validates the data it encodes and decodes matches the provided schema.
 */
function withSchemaValidation(schema, codec, validator) {
    if (!validator) {
        return codec;
    }
    const compiledFormat = validator.compile(schema);
    return {
        encode: (obj, context) => {
            const encoded = codec.encode(obj, context);
            if (!compiledFormat.check(encoded)) {
                (0, index_js_1.fail)("Encoded schema should validate");
            }
            return encoded;
        },
        decode: (encoded, context) => {
            if (!compiledFormat.check(encoded)) {
                (0, index_js_1.fail)("Encoded schema should validate");
            }
            // TODO: would be nice to provide a more specific validate type to the inner codec than the outer one gets.
            return codec.decode(encoded, context);
        },
    };
}
exports.withSchemaValidation = withSchemaValidation;
//# sourceMappingURL=codec.js.map