"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.GlobalFieldSchema = exports.allowedTypesToTypeSet = exports.FieldSchema = exports.allowedTypesIsAny = exports.Any = exports.TreeSchema = void 0;
const common_utils_1 = require("@fluidframework/common-utils");
const core_1 = require("../../../core");
const defaultFieldKinds_1 = require("../../defaultFieldKinds");
const flexList_1 = require("./flexList");
const typeUtils_1 = require("./typeUtils");
/**
 * T must extend TreeSchemaSpecification.
 * This can not be enforced using TypeScript since doing so breaks recursive type support.
 * See note on SchemaBuilder.fieldRecursive.
 * @alpha
 */
class TreeSchema {
    constructor(builder, name, info) {
        var _a, _b;
        this.builder = builder;
        this.info = info;
        this.name = name;
        this.localFieldsObject = normalizeLocalFields(this.info.local);
        this.localFields = (0, typeUtils_1.objectToMap)(this.localFieldsObject);
        this.extraLocalFields = normalizeField(this.info.extraLocalFields);
        this.extraGlobalFields = (_a = this.info.extraGlobalFields) !== null && _a !== void 0 ? _a : false;
        this.value = ((_b = this.info.value) !== null && _b !== void 0 ? _b : core_1.ValueSchema.Nothing);
    }
    // TODO: determine if this needs to be lazy. If not, remove flex list and initialize in constructor.
    // If this does need to be lazy, maybe cache result?
    get globalFields() {
        if (this.info.global === undefined) {
            return new Set();
        }
        const normalized = (0, flexList_1.normalizeFlexList)(this.info.global);
        const mapped = normalized.map((f) => f().key);
        return new Set(mapped);
    }
}
exports.TreeSchema = TreeSchema;
function normalizeLocalFields(fields) {
    if (fields === undefined) {
        return {};
    }
    const out = {};
    // eslint-disable-next-line no-restricted-syntax
    for (const key in fields) {
        if (Object.prototype.hasOwnProperty.call(fields, key)) {
            const element = fields[key];
            out[key] = normalizeField(element);
        }
    }
    return out;
}
function normalizeField(t) {
    if (t === undefined) {
        return FieldSchema.empty;
    }
    (0, common_utils_1.assert)(t instanceof FieldSchema, 0x6ae /* invalid FieldSchema */);
    return t;
}
/**
 * Allow any node (as long as it meets the schema for its own type).
 * @alpha
 */
exports.Any = "Any";
function allowedTypesIsAny(t) {
    return t.length === 1 && t[0] === exports.Any;
}
exports.allowedTypesIsAny = allowedTypesIsAny;
/**
 * All policy for a specific field,
 * including functionality that does not have to be kept consistent across versions or deterministic.
 *
 * This can include policy for how to use this schema for "view" purposes, and well as how to expose editing APIs.
 * @sealed @alpha
 */
class FieldSchema {
    constructor(kind, allowedTypes) {
        this.kind = kind;
        this.allowedTypes = allowedTypes;
    }
    get types() {
        return allowedTypesToTypeSet(this.allowedTypes);
    }
}
exports.FieldSchema = FieldSchema;
/**
 * Schema for a field which must always be empty.
 */
FieldSchema.empty = new FieldSchema(defaultFieldKinds_1.FieldKinds.forbidden, []);
// TODO: maybe remove the need for this here? Just use AllowedTypes in view schema?
function allowedTypesToTypeSet(t) {
    if (allowedTypesIsAny(t)) {
        return undefined;
    }
    const list = (0, flexList_1.normalizeFlexList)(t);
    const names = list.map((f) => f().name);
    return new Set(names);
}
exports.allowedTypesToTypeSet = allowedTypesToTypeSet;
/**
 * All policy for a specific field,
 * including functionality that does not have to be kept consistent across versions or deterministic.
 *
 * This can include policy for how to use this schema for "view" purposes, and well as how to expose editing APIs.
 * @sealed @alpha
 */
class GlobalFieldSchema {
    constructor(builder, key, schema) {
        this.builder = builder;
        this.key = key;
        this.schema = schema;
        this.symbol = (0, core_1.symbolFromKey)(key);
    }
    get kind() {
        return this.schema.kind;
    }
    get types() {
        return this.schema.types;
    }
}
exports.GlobalFieldSchema = GlobalFieldSchema;
//# sourceMappingURL=typedTreeSchema.js.map