"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultSchemaPolicy = exports.FieldKinds = exports.fieldKinds = exports.getCodecTreeForModularChangeFormat = exports.fieldKindConfigurations = exports.forbidden = exports.identifier = exports.noChangeHandler = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const index_js_1 = require("../../core/index.js");
const fieldKindIdentifiers_js_1 = require("../fieldKindIdentifiers.js");
const index_js_2 = require("../modular-schema/index.js");
const index_js_3 = require("../optional-field/index.js");
const index_js_4 = require("../sequence-field/index.js");
const noChangeCodecs_js_1 = require("./noChangeCodecs.js");
/**
 * ChangeHandler that only handles no-op / identity changes.
 */
exports.noChangeHandler = {
    rebaser: (0, index_js_2.referenceFreeFieldChangeRebaser)({
        compose: (change1, change2) => 0,
        invert: (changes) => 0,
        rebase: (change, over) => 0,
        mute: (changes) => 0,
    }),
    codecsFactory: () => noChangeCodecs_js_1.noChangeCodecFamily,
    editor: { buildChildChanges: () => (0, internal_1.fail)(0xb0d /* Child changes not supported */) },
    intoDelta: (change, deltaFromChild) => ({}),
    relevantRemovedRoots: (change) => [],
    isEmpty: (change) => true,
    getNestedChanges: (change) => [],
    createEmpty: () => 0,
    getCrossFieldKeys: () => [],
};
/**
 * Exactly one identifier.
 */
exports.identifier = new index_js_2.FlexFieldKind(fieldKindIdentifiers_js_1.identifierFieldIdentifier, index_js_1.Multiplicity.Single, {
    changeHandler: exports.noChangeHandler,
    // By omitting required here,
    // this is making a policy choice that a schema upgrade cannot be done from required to identifier.
    // Since an identifier can be upgraded into a required field,
    // preventing the inverse helps ensure that schema upgrades are monotonic.
    // Which direction is allowed is a subjective policy choice.
    allowMonotonicUpgradeFrom: new Set([]),
});
/**
 * Exactly 0 items.
 *
 * Using Forbidden makes what types are listed for allowed in a field irrelevant
 * since the field will never have values in it.
 *
 * Using Forbidden is equivalent to picking a kind that permits empty (like sequence or optional)
 * and having no allowed types (or only never types).
 * Because of this, its possible to express everything constraint wise without Forbidden,
 * but using Forbidden can be more semantically clear than optional with no allowed types.
 *
 * For view schema, this can be useful if you need to:
 * - run a specific out of schema handler when a field is present,
 * but otherwise are ignoring or tolerating (ex: via extra fields) unmentioned fields.
 * - prevent a specific field from being used as an extra field
 * (perhaps for some past of future compatibility reason)
 * - keep a field in a schema for metadata purposes
 * (ex: for improved error messaging, error handling or documentation)
 * that is not used in this specific version of the schema (ex: to document what it was or will be used for).
 *
 * For stored schema, this can be useful if you need to:
 * - have a field which can have its schema updated to Optional or Sequence of any type.
 * - to exclude a field from extra fields
 * - for the schema system to use as a default for fields which aren't declared
 * (ex: when updating a field that did not exist into one that does)
 *
 * See {@link emptyField} for a constant, reusable field using Forbidden.
 */
exports.forbidden = new index_js_2.FlexFieldKind(index_js_1.forbiddenFieldKindIdentifier, index_js_1.Multiplicity.Forbidden, {
    changeHandler: exports.noChangeHandler,
    allowMonotonicUpgradeFrom: new Set(),
});
exports.fieldKindConfigurations = new Map([
    [
        index_js_2.ModularChangeFormatVersion.v3,
        new Map([
            [index_js_3.required.identifier, { kind: index_js_3.required, formatVersion: 2 }],
            [index_js_3.optional.identifier, { kind: index_js_3.optional, formatVersion: 2 }],
            [index_js_4.sequence.identifier, { kind: index_js_4.sequence, formatVersion: 2 }],
            [exports.forbidden.identifier, { kind: exports.forbidden, formatVersion: 1 }],
            [exports.identifier.identifier, { kind: exports.identifier, formatVersion: 1 }],
        ]),
    ],
    [
        index_js_2.ModularChangeFormatVersion.v4,
        new Map([
            [index_js_3.required.identifier, { kind: index_js_3.required, formatVersion: 2 }],
            [index_js_3.optional.identifier, { kind: index_js_3.optional, formatVersion: 2 }],
            [index_js_4.sequence.identifier, { kind: index_js_4.sequence, formatVersion: 3 }],
            [exports.forbidden.identifier, { kind: exports.forbidden, formatVersion: 1 }],
            [exports.identifier.identifier, { kind: exports.identifier, formatVersion: 1 }],
        ]),
    ],
    [
        index_js_2.ModularChangeFormatVersion.v5,
        new Map([
            [index_js_3.required.identifier, { kind: index_js_3.required, formatVersion: 2 }],
            [index_js_3.optional.identifier, { kind: index_js_3.optional, formatVersion: 2 }],
            [index_js_4.sequence.identifier, { kind: index_js_4.sequence, formatVersion: 3 }],
            [exports.forbidden.identifier, { kind: exports.forbidden, formatVersion: 1 }],
            [exports.identifier.identifier, { kind: exports.identifier, formatVersion: 1 }],
        ]),
    ],
]);
function getCodecTreeForModularChangeFormat(version) {
    const dependencies = exports.fieldKindConfigurations.get(version) ?? (0, internal_1.fail)(0xc7c /* Unknown modular change format */);
    const children = [...dependencies.entries()].map(([key, { formatVersion }]) => ({
        name: `FieldKind:${key}`,
        version: formatVersion,
    }));
    return {
        name: "ModularChange",
        version,
        children,
    };
}
exports.getCodecTreeForModularChangeFormat = getCodecTreeForModularChangeFormat;
/**
 * All supported field kinds.
 *
 * @privateRemarks
 * Before making a SharedTree format change which impacts which set of field kinds are allowed,
 * code which uses this should be audited for compatibility considerations.
 */
exports.fieldKinds = new Map([index_js_3.required, index_js_3.optional, index_js_4.sequence, exports.identifier, exports.forbidden].map((s) => [s.identifier, s]));
/**
 * Default FieldKinds with their editor types erased.
 */
exports.FieldKinds = { required: index_js_3.required, optional: index_js_3.optional, sequence: index_js_4.sequence, identifier: exports.identifier, forbidden: exports.forbidden };
/**
 * FullSchemaPolicy with the default field kinds.
 */
exports.defaultSchemaPolicy = {
    fieldKinds: exports.fieldKinds,
};
//# sourceMappingURL=defaultFieldKinds.js.map