"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.SchemaFactoryAlpha = void 0;
const index_js_1 = require("../node-kinds/index.js");
const schemaFactory_js_1 = require("./schemaFactory.js");
const schemaStatics_js_1 = require("./schemaStatics.js");
const index_js_2 = require("../core/index.js");
const schemaStaticsAlpha = {
    staged: (t) => {
        const annotatedType = (0, index_js_2.normalizeToAnnotatedAllowedType)(t);
        return {
            type: annotatedType.type,
            metadata: {
                ...annotatedType.metadata,
                stagedSchemaUpgrade: (0, index_js_2.createSchemaUpgrade)(),
            },
        };
    },
};
/**
 * {@link SchemaFactory} with additional alpha APIs.
 *
 * @alpha
 * @privateRemarks
 *
 * Some private methods on `SchemaFactory` are intentionally duplicated here to avoid increasing their exposure to `protected`.
 * If we were to do so, they would be exposed on the public API surface of `SchemaFactory`.
 */
class SchemaFactoryAlpha extends schemaFactory_js_1.SchemaFactory {
    constructor() {
        super(...arguments);
        /**
         * {@inheritDoc SchemaStatics.leaves}
         */
        this.leaves = schemaStatics_js_1.schemaStatics.leaves;
        /**
         * {@inheritDoc SchemaStatics.optional}
         */
        this.optional = schemaStatics_js_1.schemaStatics.optional;
        /**
         * {@inheritDoc SchemaStatics.required}
         */
        this.required = schemaStatics_js_1.schemaStatics.required;
        /**
         * {@inheritDoc SchemaStatics.optionalRecursive}
         */
        this.optionalRecursive = schemaStatics_js_1.schemaStatics.optionalRecursive;
        /**
         * {@inheritDoc SchemaStatics.requiredRecursive}
         */
        this.requiredRecursive = schemaStatics_js_1.schemaStatics.requiredRecursive;
        /**
         * {@inheritDoc SchemaStaticsAlpha.staged}
         */
        this.staged = schemaStaticsAlpha.staged;
    }
    scoped2(name) {
        return (this.scope === undefined ? `${name}` : `${this.scope}.${name}`);
    }
    /**
     * Define a {@link TreeNodeSchemaClass} for a {@link TreeObjectNode}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     * @param fields - Schema for fields of the object node's schema. Defines what children can be placed under each key.
     * @param options - Additional options for the schema.
     */
    objectAlpha(name, fields, options) {
        return (0, index_js_1.objectSchema)(this.scoped2(name), fields, true, options?.allowUnknownOptionalFields ??
            schemaFactory_js_1.defaultSchemaFactoryObjectOptions.allowUnknownOptionalFields, options?.metadata, options?.persistedMetadata);
    }
    /**
     * {@inheritdoc SchemaFactory.objectRecursive}
     */
    objectRecursive(name, t, options) {
        return this.objectAlpha(name, t, options);
    }
    /**
     * Define a {@link TreeNodeSchema} for a {@link TreeMapNode}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     * @param allowedTypes - The types that may appear as values in the map.
     * @param options - Additional options for the schema.
     *
     * @example
     * ```typescript
     * class NamedMap extends factory.map("name", factory.number, {
     * 	metadata: { description: "A map of numbers" }
     * }) {}
     * ```
     */
    mapAlpha(name, allowedTypes, options) {
        return (0, index_js_1.mapSchema)(this.scoped2(name), allowedTypes, true, true, options?.metadata, options?.persistedMetadata);
    }
    /**
     * {@inheritDoc SchemaFactory.objectRecursive}
     */
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
    mapRecursive(name, allowedTypes, options) {
        return this.mapAlpha(name, allowedTypes, options);
    }
    /**
     * Define (and add to this library) a {@link TreeNodeSchemaClass} for a {@link (TreeArrayNode:interface)}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     * @param allowedTypes - The types that may appear in the array.
     * @param options - Additional options for the schema.
     *
     * @example
     * ```typescript
     * class NamedArray extends factory.arrayAlpha("name", factory.number) {}
     * ```
     */
    arrayAlpha(name, allowedTypes, options) {
        return (0, index_js_1.arraySchema)(this.scoped2(name), allowedTypes, true, true, options?.metadata, options?.persistedMetadata);
    }
    /**
     * {@inheritDoc SchemaFactory.objectRecursive}
     */
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
    arrayRecursive(name, allowedTypes, options) {
        return this.arrayAlpha(name, allowedTypes, options);
    }
    /**
     * {@link SchemaFactory.array} implementation.
     *
     * @privateRemarks
     * This should return TreeNodeSchemaBoth: see note on "map" implementation for details.
     */
    record(nameOrAllowedTypes, maybeAllowedTypes) {
        if (maybeAllowedTypes === undefined) {
            const types = nameOrAllowedTypes;
            const fullName = (0, schemaFactory_js_1.structuralName)("Record", types);
            return this.getStructuralType(fullName, types, () => this.namedRecord(fullName, nameOrAllowedTypes, 
            /* customizable */ false, 
            /* implicitlyConstructable */ true));
        }
        const out = this.namedRecord(nameOrAllowedTypes, maybeAllowedTypes, 
        /* customizable */ true, 
        /* implicitlyConstructable */ true);
        return out;
    }
    /**
     * Define a {@link TreeNodeSchema} for a {@link (TreeArrayNode:interface)}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     *
     * @remarks
     * This is not intended to be used directly, use the overload of `array` which takes a name instead.
     * This is only public to work around a compiler limitation.
     */
    namedRecord(name, allowedTypes, customizable, implicitlyConstructable) {
        const record = (0, index_js_1.recordSchema)({
            identifier: this.scoped2(name),
            info: allowedTypes,
            customizable,
            implicitlyConstructable,
        });
        return record;
    }
    /**
     * Define (and add to this library) a {@link TreeNodeSchemaClass} for a {@link (TreeRecordNode:interface)}.
     *
     * @param name - Unique identifier for this schema within this factory's scope.
     * @param allowedTypes - The types that may appear in the record.
     * @param options - Additional options for the schema.
     *
     * @example
     * ```typescript
     * class NamedRecord extends factory.recordAlpha("name", factory.number) {}
     * ```
     */
    recordAlpha(name, allowedTypes, options) {
        return (0, index_js_1.recordSchema)({
            identifier: this.scoped2(name),
            info: allowedTypes,
            customizable: true,
            implicitlyConstructable: true,
            metadata: options?.metadata,
            persistedMetadata: options?.persistedMetadata,
        });
    }
    /**
     * {@link SchemaFactoryAlpha.(record:2)} except tweaked to work better for recursive types.
     * Use with {@link ValidateRecursiveSchema} for improved type safety.
     * @remarks
     * This version of `SchemaFactory.record` uses the same workarounds as {@link SchemaFactory.objectRecursive}.
     * See {@link ValidateRecursiveSchema} for additional information about using recursive schema.
     */
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
    recordRecursive(name, allowedTypes) {
        const RecordSchema = this.namedRecord(name, allowedTypes, 
        /* customizable */ true, 
        // Setting this to true seems to work ok currently, but not for other node kinds.
        // Supporting this could be fragile and might break other future changes, so it's being kept as false for now.
        /* implicitlyConstructable */ false);
        return RecordSchema;
    }
    /**
     * Create a {@link SchemaFactory} with a {@link SchemaFactory.scope|scope} which is a combination of this factory's scope and the provided name.
     * @remarks
     * The main use-case for this is when creating a collection of related schema (for example using a function that creates multiple schema).
     * Creating such related schema using a sub-scope helps ensure they won't collide with other schema in the parent scope.
     */
    scopedFactory(name) {
        return new SchemaFactoryAlpha(this.scoped2(name));
    }
}
exports.SchemaFactoryAlpha = SchemaFactoryAlpha;
/**
 * {@inheritDoc SchemaStatics.leaves}
 */
SchemaFactoryAlpha.leaves = schemaStatics_js_1.schemaStatics.leaves;
/**
 * {@inheritDoc SchemaStatics.optional}
 */
SchemaFactoryAlpha.optional = schemaStatics_js_1.schemaStatics.optional;
/**
 * {@inheritDoc SchemaStatics.required}
 */
SchemaFactoryAlpha.required = schemaStatics_js_1.schemaStatics.required;
/**
 * {@inheritDoc SchemaStatics.optionalRecursive}
 */
SchemaFactoryAlpha.optionalRecursive = schemaStatics_js_1.schemaStatics.optionalRecursive;
/**
 * {@inheritDoc SchemaStatics.requiredRecursive}
 */
SchemaFactoryAlpha.requiredRecursive = schemaStatics_js_1.schemaStatics.requiredRecursive;
/**
 * Like {@link SchemaFactory.identifier} but static and a factory function that can be provided {@link FieldProps}.
 */
SchemaFactoryAlpha.identifier = schemaStatics_js_1.schemaStatics.identifier;
/**
 * {@inheritDoc SchemaStaticsAlpha.staged}
 */
SchemaFactoryAlpha.staged = schemaStaticsAlpha.staged;
//# sourceMappingURL=schemaFactoryAlpha.js.map