"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TableSchema = exports.System_TableSchema = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const internal_2 = require("@fluidframework/telemetry-utils/internal");
const index_js_1 = require("./shared-tree/index.js");
const index_js_2 = require("./simple-tree/index.js");
const index_js_3 = require("./util/index.js");
// Future improvement TODOs:
// - Omit `cells` property from Row insertion type.
// - Record-like type parameters / input parameters?
// - Omit `props` properties from Row and Column schemas when not provided?
// Longer-term work:
// - Add constraint APIs to make it possible to avoid situations that could yield "orphaned" cells.
/**
 * The sub-scope applied to user-provided {@link SchemaFactory}s by table schema factories.
 */
const tableSchemaFactorySubScope = "table";
/**
 * A private symbol put on table schema to help identify them.
 */
const tableSchemaSymbol = Symbol("tableNode");
/**
 * Not intended for use outside of this package.
 *
 * @privateRemarks
 * This namespace is a collection of internal system types relate to {@link TableSchema}.
 * This namespace should be strictly type-exported by the package.
 * All members should be tagged with `@system`.
 *
 * @system @alpha
 */
var System_TableSchema;
(function (System_TableSchema) {
    /**
     * Factory for creating column schema.
     * @system @alpha
     */
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is too complex to be reasonable to specify
    function createColumnSchema(inputSchemaFactory, propsSchema) {
        const schemaFactory = inputSchemaFactory.scopedFactory(tableSchemaFactorySubScope);
        // Note: `columnFields` is broken into two parts to work around a TypeScript bug
        // that results in broken `.d.ts` output.
        // See definition of `ColumnInsertableType` below.
        const columnFieldsBuiltInParts = {
            id: schemaFactory.identifier,
        };
        const columnFieldsPropsPart = {
            props: propsSchema,
        };
        /**
         * {@link Column} fields.
         *
         * @remarks
         * Extracted for re-use in returned type signature defined later in this function.
         * The implicit typing is intentional.
         *
         * Note: ideally we would add a satisfies clause here to ensure that this satisfies
         * `Record<string, ImplicitFieldSchema>`, but doing so causes TypeScript to prematurely and incorrectly evaluate the type of `propsSchema`.
         * Likely related to the following issue: https://github.com/microsoft/TypeScript/issues/52394
         */
        const columnFields = {
            ...columnFieldsBuiltInParts,
            ...columnFieldsPropsPart,
        }; // satisfies Record<string, ImplicitFieldSchema>;
        /**
         * A column in a table.
         */
        class Column extends schemaFactory.object("Column", columnFields, {
            // Will make it easier to evolve this schema in the future.
            allowUnknownOptionalFields: true,
        }) {
        }
        // Returning SingletonSchema without a type conversion results in TypeScript generating something like `readonly "__#124291@#brand": unknown;`
        // for the private brand field of TreeNode.
        // This numeric id doesn't seem to be stable over incremental builds, and thus causes diffs in the API extractor reports.
        // This is avoided by doing this type conversion.
        // The conversion is done via assignment instead of `as` to get stronger type safety.
        const ColumnSchemaType = Column;
        return ColumnSchemaType;
    }
    System_TableSchema.createColumnSchema = createColumnSchema;
    /**
     * Factory for creating row schema.
     * @sealed @alpha
     */
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is too complex to be reasonable to specify
    function createRowSchema(inputSchemaFactory, cellSchema, propsSchema) {
        const schemaFactory = inputSchemaFactory.scopedFactory(tableSchemaFactorySubScope);
        // Note: `rowFields` is broken into two parts to work around a TypeScript bug
        // that results in broken `.d.ts` output.
        // See definition of `RowInsertableType` below.
        const rowFieldsBuiltInParts = {
            id: schemaFactory.identifier,
            /**
             * The cells of the table row, keyed by column ID.
             * @remarks
             * The table row models its cells as a record, where each key is the ID of the column it belongs to. The choice of record (as opposed to a map) is intended to make interop with common table rendering libraries in TypeScript/JavaScript easier.
             */
            cells: schemaFactory.required(schemaFactory.record("Row.cells", cellSchema), {
                metadata: {
                    description: "The cells of the table row, keyed by column ID.",
                },
            }),
        };
        const rowFieldsPropsPart = {
            props: propsSchema,
        };
        /**
         * {@link RowSchema} fields.
         * @remarks Extracted for re-use in returned type signature defined later in this function.
         * The implicit typing is intentional.
         * Note: ideally we would add a satisfies clause here to ensure that this satisfies
         * `Record<string, ImplicitFieldSchema>`, but doing so causes TypeScript to prematurely and incorrectly evaluate the type of `propsSchema`.
         * Likely related to the following issue: https://github.com/microsoft/TypeScript/issues/52394
         */
        const rowFields = {
            ...rowFieldsBuiltInParts,
            ...rowFieldsPropsPart,
        }; // satisfies Record<string, ImplicitFieldSchema>;
        /**
         * The Row schema - this is a map of Cells where the key is the column id
         */
        class RowSchema extends schemaFactory.object("Row", rowFields, {
            // Will make it easier to evolve this schema in the future.
            allowUnknownOptionalFields: true,
        }) {
        }
        // Returning SingletonSchema without a type conversion results in TypeScript generating something like `readonly "__#124291@#brand": unknown;`
        // for the private brand field of TreeNode.
        // This numeric id doesn't seem to be stable over incremental builds, and thus causes diffs in the API extractor reports.
        // This is avoided by doing this type conversion.
        // The conversion is done via assignment instead of `as` to get stronger type safety.
        const RowSchemaType = RowSchema;
        return RowSchemaType;
    }
    System_TableSchema.createRowSchema = createRowSchema;
    /**
     * Factory for creating table schema.
     * @system @alpha
     */
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is too complex to be reasonable to specify
    function createTableSchema(inputSchemaFactory, _cellSchema, columnSchema, rowSchema) {
        var _Table_instances, _a, _Table_removeCells, _Table_applyEditsInBatch, _Table_tryGetColumn, _Table_getColumn, _Table_containsColumnWithId, _Table_tryGetRow, _Table_getRow;
        const schemaFactory = inputSchemaFactory.scopedFactory(tableSchemaFactorySubScope);
        /**
         * {@link Table} fields.
         * @remarks Extracted for re-use in returned type signature defined later in this function.
         * The implicit typing is intentional.
         */
        const tableFields = {
            rows: schemaFactory.array("Table.rows", rowSchema),
            columns: schemaFactory.array("Table.columns", columnSchema),
        };
        /**
         * The Table schema
         */
        class Table extends schemaFactory.object("Table", tableFields, {
            // Will make it easier to evolve this schema in the future.
            allowUnknownOptionalFields: true,
        }) {
            constructor() {
                super(...arguments);
                _Table_instances.add(this);
            }
            static empty() {
                return new this({ columns: [], rows: [] });
            }
            getColumn(indexOrId) {
                return __classPrivateFieldGet(this, _Table_instances, "m", _Table_tryGetColumn).call(this, indexOrId);
            }
            getRow(indexOrId) {
                return __classPrivateFieldGet(this, _Table_instances, "m", _Table_tryGetRow).call(this, indexOrId);
            }
            getCell(key) {
                const { column: columnOrIdOrIndex, row: rowOrIdOrIndex } = key;
                const row = __classPrivateFieldGet(this, _Table_instances, "m", _Table_tryGetRow).call(this, rowOrIdOrIndex);
                if (row === undefined) {
                    return undefined;
                }
                const column = __classPrivateFieldGet(this, _Table_instances, "m", _Table_tryGetColumn).call(this, columnOrIdOrIndex);
                if (column === undefined) {
                    return undefined;
                }
                return row.cells[column.id];
            }
            insertColumns({ columns, index, }) {
                // TypeScript is unable to narrow the column type correctly here, hence the casts below.
                // See: https://github.com/microsoft/TypeScript/issues/52144
                if (index === undefined) {
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    this.columns.insertAtEnd(index_js_2.TreeArrayNode.spread(columns));
                }
                else {
                    // Ensure specified index is valid
                    (0, index_js_3.validateIndex)(index, this.columns, "Table.insertColumns", true);
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    this.columns.insertAt(index, index_js_2.TreeArrayNode.spread(columns));
                }
                // Inserting the input nodes into the tree hydrates them, making them usable as nodes.
                return columns;
            }
            insertRows({ index, rows, }) {
                // #region Input validation
                // Ensure specified index is valid
                if (index !== undefined) {
                    (0, index_js_3.validateIndex)(index, this.rows, "Table.insertRows", true);
                }
                // Note: TypeScript is unable to narrow the type of the row type correctly here, hence the casts below.
                // See: https://github.com/microsoft/TypeScript/issues/52144
                for (const newRow of rows) {
                    // If the row contains cells, verify that the table contains the columns for those cells.
                    // Note: we intentionally hide `cells` on `IRow` to avoid leaking the internal data representation as much as possible, so we have to cast here.
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    if (newRow.cells !== undefined) {
                        // eslint-disable-next-line @typescript-eslint/no-explicit-any
                        const keys = Object.keys(newRow.cells);
                        for (const key of keys) {
                            if (!__classPrivateFieldGet(this, _Table_instances, "m", _Table_containsColumnWithId).call(this, key)) {
                                throw new internal_2.UsageError(`Attempted to insert row a cell under column ID "${key}", but the table does not contain a column with that ID.`);
                            }
                        }
                    }
                }
                // #endregion
                // TypeScript is unable to narrow the row type correctly here, hence the casts below.
                // See: https://github.com/microsoft/TypeScript/issues/52144
                if (index === undefined) {
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    this.rows.insertAtEnd(index_js_2.TreeArrayNode.spread(rows));
                }
                else {
                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
                    this.rows.insertAt(index, index_js_2.TreeArrayNode.spread(rows));
                }
                // Inserting the input nodes into the tree hydrates them, making them usable as nodes.
                return rows;
            }
            setCell({ key, cell, }) {
                const { column: columnOrId, row: rowOrId } = key;
                const row = __classPrivateFieldGet(this, _Table_instances, "m", _Table_getRow).call(this, rowOrId);
                const column = __classPrivateFieldGet(this, _Table_instances, "m", _Table_getColumn).call(this, columnOrId);
                row.cells[column.id] = cell;
            }
            removeColumns(indexOrColumns, count = undefined) {
                if (typeof indexOrColumns === "number" || indexOrColumns === undefined) {
                    let removedColumns;
                    const startIndex = indexOrColumns ?? 0;
                    const endIndex = count === undefined ? this.columns.length : startIndex + count;
                    // If there are no columns to remove, do nothing
                    if (startIndex === endIndex) {
                        return [];
                    }
                    (0, index_js_3.validateIndexRange)(startIndex, endIndex, this.columns, "Table.removeColumns");
                    __classPrivateFieldGet(this, _Table_instances, "m", _Table_applyEditsInBatch).call(this, () => {
                        const columnsToRemove = this.columns.slice(startIndex, endIndex);
                        // First, remove all cells that correspond to each column from each row:
                        for (const column of columnsToRemove) {
                            __classPrivateFieldGet(this, _Table_instances, "m", _Table_removeCells).call(this, column);
                        }
                        // Second, remove the column nodes:
                        removeRangeFromArray(startIndex, endIndex, this.columns, "Table.removeColumns");
                        removedColumns = columnsToRemove;
                    });
                    return removedColumns ?? (0, internal_1.fail)(0xc1f /* Transaction did not complete. */);
                }
                else {
                    // If there are no columns to remove, do nothing
                    if (indexOrColumns.length === 0) {
                        return [];
                    }
                    // Resolve any IDs to actual nodes.
                    // This validates that all of the rows exist before starting transaction.
                    // This improves user-facing error experience.
                    const columnsToRemove = [];
                    for (const columnOrIdToRemove of indexOrColumns) {
                        columnsToRemove.push(__classPrivateFieldGet(this, _Table_instances, "m", _Table_getColumn).call(this, columnOrIdToRemove));
                    }
                    __classPrivateFieldGet(this, _Table_instances, "m", _Table_applyEditsInBatch).call(this, () => {
                        // Note, throwing an error within a transaction will abort the entire transaction.
                        // So if we throw an error here for any column, no columns will be removed.
                        for (const columnToRemove of columnsToRemove) {
                            // Remove the corresponding cell from all rows.
                            for (const row of this.rows) {
                                // TypeScript is unable to narrow the row type correctly here, hence the cast.
                                // See: https://github.com/microsoft/TypeScript/issues/52144
                                this.removeCell({
                                    column: columnToRemove,
                                    row: row,
                                });
                            }
                            // We have already validated that all of the columns exist above, so this is safe.
                            this.columns.removeAt(this.columns.indexOf(columnToRemove));
                        }
                    });
                    return columnsToRemove;
                }
            }
            removeRows(indexOrRows, count) {
                if (typeof indexOrRows === "number" || indexOrRows === undefined) {
                    const startIndex = indexOrRows ?? 0;
                    const endIndex = count === undefined ? this.columns.length : startIndex + count;
                    // If there are no rows to remove, do nothing
                    if (startIndex === endIndex) {
                        return [];
                    }
                    return removeRangeFromArray(startIndex, endIndex, this.rows, "Table.removeRows");
                }
                // If there are no rows to remove, do nothing
                if (indexOrRows.length === 0) {
                    return [];
                }
                // Resolve any IDs to actual nodes.
                // This validates that all of the rows exist before starting transaction.
                // This improves user-facing error experience.
                const rowsToRemove = [];
                for (const rowToRemove of indexOrRows) {
                    rowsToRemove.push(__classPrivateFieldGet(this, _Table_instances, "m", _Table_getRow).call(this, rowToRemove));
                }
                __classPrivateFieldGet(this, _Table_instances, "m", _Table_applyEditsInBatch).call(this, () => {
                    // Note, throwing an error within a transaction will abort the entire transaction.
                    // So if we throw an error here for any row, no rows will be removed.
                    for (const rowToRemove of rowsToRemove) {
                        // We have already validated that all of the rows exist above, so this is safe.
                        const index = this.rows.indexOf(rowToRemove);
                        this.rows.removeAt(index);
                    }
                });
                return rowsToRemove;
            }
            removeCell(key) {
                const { column: columnOrIdOrIndex, row: rowOrIdOrIndex } = key;
                const row = __classPrivateFieldGet(this, _Table_instances, "m", _Table_getRow).call(this, rowOrIdOrIndex);
                const column = __classPrivateFieldGet(this, _Table_instances, "m", _Table_getColumn).call(this, columnOrIdOrIndex);
                const cell = row.cells[column.id];
                if (cell === undefined) {
                    return undefined;
                }
                // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
                delete row.cells[column.id];
                return cell;
            }
            /**
             * Throw a `UsageError` for a missing Column by its ID or index.
             */
            static _throwMissingColumnError(columnOrIdOrIndex) {
                if (typeof columnOrIdOrIndex === "number") {
                    throw new internal_2.UsageError(`No column exists at index ${columnOrIdOrIndex}.`);
                }
                if (typeof columnOrIdOrIndex === "string") {
                    throw new internal_2.UsageError(`No column with ID "${columnOrIdOrIndex}" exists in the table.`);
                }
                throw new internal_2.UsageError(`The specified column node with ID "${columnOrIdOrIndex.id}" does not exist in the table.`);
            }
            /**
             * Throw a `UsageError` for a missing Row by its ID or index.
             */
            static _throwMissingRowError(rowOrIdOrIndex) {
                if (typeof rowOrIdOrIndex === "number") {
                    throw new internal_2.UsageError(`No row exists at index ${rowOrIdOrIndex}.`);
                }
                if (typeof rowOrIdOrIndex === "string") {
                    throw new internal_2.UsageError(`No row with ID "${rowOrIdOrIndex}" exists in the table.`);
                }
                throw new internal_2.UsageError(`The specified row node with ID "${rowOrIdOrIndex.id}" does not exist in the table.`);
            }
        }
        _a = Table, _Table_instances = new WeakSet(), _Table_removeCells = function _Table_removeCells(column) {
            for (const row of this.rows) {
                // TypeScript is unable to narrow the row type correctly here, hence the cast.
                // See: https://github.com/microsoft/TypeScript/issues/52144
                this.removeCell({
                    column,
                    row: row,
                });
            }
        }, _Table_applyEditsInBatch = function _Table_applyEditsInBatch(applyEdits) {
            const branch = index_js_1.TreeAlpha.branch(this);
            // Ensure events are paused until all of the edits are applied.
            // This ensures that the user sees the corresponding table-level edit as atomic,
            // and ensures they are not spammed with intermediate events.
            (0, index_js_2.withBufferedTreeEvents)(() => {
                if (branch === undefined) {
                    // If this node does not have a corresponding branch, then it is unhydrated.
                    // I.e., it is not part of a collaborative session yet.
                    // Therefore, we don't need to run the edits as a transaction.
                    applyEdits();
                }
                else {
                    branch.runTransaction(() => {
                        applyEdits();
                    });
                }
            });
        }, _Table_tryGetColumn = function _Table_tryGetColumn(columnOrIdOrIndex) {
            if (typeof columnOrIdOrIndex === "number") {
                if (columnOrIdOrIndex < 0 || columnOrIdOrIndex >= this.columns.length) {
                    return undefined;
                }
                // TypeScript is unable to narrow the types correctly here, hence the cast.
                // See: https://github.com/microsoft/TypeScript/issues/52144
                return this.columns[columnOrIdOrIndex];
            }
            if (typeof columnOrIdOrIndex === "string") {
                const columnId = columnOrIdOrIndex;
                // TypeScript is unable to narrow the types correctly here, hence the casts.
                // See: https://github.com/microsoft/TypeScript/issues/52144
                return this.columns.find((col) => col.id === columnId);
            }
            // If the user provided a node, ensure it actually exists in this table.
            if (!this.columns.includes(columnOrIdOrIndex)) {
                return undefined;
            }
            return columnOrIdOrIndex;
        }, _Table_getColumn = function _Table_getColumn(columnOrIdOrIndex) {
            const column = __classPrivateFieldGet(this, _Table_instances, "m", _Table_tryGetColumn).call(this, columnOrIdOrIndex);
            if (column === undefined) {
                _a._throwMissingColumnError(columnOrIdOrIndex);
            }
            return column;
        }, _Table_containsColumnWithId = function _Table_containsColumnWithId(columnId) {
            return __classPrivateFieldGet(this, _Table_instances, "m", _Table_tryGetColumn).call(this, columnId) !== undefined;
        }, _Table_tryGetRow = function _Table_tryGetRow(rowOrIdOrIndex) {
            if (typeof rowOrIdOrIndex === "number") {
                if (rowOrIdOrIndex < 0 || rowOrIdOrIndex >= this.rows.length) {
                    return undefined;
                }
                // TypeScript is unable to narrow the types correctly here, hence the cast.
                // See: https://github.com/microsoft/TypeScript/issues/52144
                return this.rows[rowOrIdOrIndex];
            }
            if (typeof rowOrIdOrIndex === "string") {
                const rowId = rowOrIdOrIndex;
                // TypeScript is unable to narrow the types correctly here, hence the casts.
                // See: https://github.com/microsoft/TypeScript/issues/52144
                return this.rows.find((row) => row.id === rowId);
            }
            // If the user provided a node, ensure it actually exists in this table.
            if (!this.rows.includes(rowOrIdOrIndex)) {
                return undefined;
            }
            return rowOrIdOrIndex;
        }, _Table_getRow = function _Table_getRow(rowOrIdOrIndex) {
            const row = __classPrivateFieldGet(this, _Table_instances, "m", _Table_tryGetRow).call(this, rowOrIdOrIndex);
            if (row === undefined) {
                _a._throwMissingRowError(rowOrIdOrIndex);
            }
            return row;
        };
        // Set a private symbol on the schema class that marks it as having been generated by this factory.
        // Column / Row functionality use this to validate that they are being used in a table.
        // This is effectively a work-around that allows columns and rows to invoke table methods
        // without having to pass the table as a parameter to their construction, which isn't possible.
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        Table[tableSchemaSymbol] = true;
        // Returning SingletonSchema without a type conversion results in TypeScript generating something like `readonly "__#124291@#brand": unknown;`
        // for the private brand field of TreeNode.
        // This numeric id doesn't seem to be stable over incremental builds, and thus causes diffs in the API extractor reports.
        // This is avoided by doing this type conversion.
        // The conversion is done via assignment instead of `as` to get stronger type safety.
        const TableSchemaType = Table;
        // Return the table schema
        return TableSchemaType;
    }
    System_TableSchema.createTableSchema = createTableSchema;
    // #endregion
})(System_TableSchema || (exports.System_TableSchema = System_TableSchema = {}));
/**
 * Removes the specified range of elements from the array.
 * @returns The removed elements.
 */
function removeRangeFromArray(startIndex, endIndex, array, methodName) {
    (0, index_js_3.validateIndexRange)(startIndex, endIndex, array, methodName);
    // TypeScript is unable to narrow the array element type correctly here, hence the cast.
    // See: https://github.com/microsoft/TypeScript/issues/52144
    const removedRows = array.slice(startIndex, endIndex);
    array.removeRange(startIndex, endIndex);
    return removedRows;
}
/**
 * Contains types and factories for creating schema to represent dynamic tabular data.
 *
 * @remarks
 *
 * WARNING: These APIs are in preview and are subject to change.
 * Until these APIs have stabilized, it is not recommended to use them in production code.
 * There may be breaking changes to these APIs and their underlying data format.
 * Using these APIs in production code may result in data loss or corruption.
 *
 * The primary APIs for create tabular data schema are:
 *
 * - {@link TableSchema.(table:1)}
 *
 * - {@link TableSchema.(column:1)}
 *
 * - {@link TableSchema.(row:1)}
 *
 * Tables created using these APIs are...
 *
 * - sparse, meaning that cells may be omitted, and new rows are empty by default.
 *
 * - dynamic, meaning that their structure can be modified at runtime.
 * Columns and rows can be inserted, removed, modified, and reordered.
 * Cells can be inserted, removed, and modified.
 *
 * - row-major, meaning that operating on rows (including inserts, removal, moves, and traversal) is more efficient than operating on columns.
 *
 * Column and Row schema created using these APIs are extensible via the `props` field.
 * This allows association of additional properties with column and row nodes.
 *
 * Cells in the table may become "orphaned."
 * That is, it is possible to enter a state where one or more rows contain cells with no corresponding column.
 * To reduce the likelihood of this, you can manually remove corresponding cells when removing columns.
 * Either way, it is possible to enter such a state via the merging of edits.
 * For example: one client might add a row while another concurrently removes a column, orphaning the cell where the column and row intersected.
 *
 * @example Defining a Table schema
 *
 * ```typescript
 * class MyTable extends TableSchema.table({
 * 	schemaFactory,
 * 	cell: schemaFactory.string,
 * }) {}
 *
 * const table = new MyTable({
 * 	columns: [{ id: "column-0" }],
 * 	rows: [{ id: "row-0", cells: { "column-0": "Hello world!" } }],
 * });
 * ```
 *
 * @example Customizing Column and Row schema
 *
 * ```typescript
 * const Cell = schemaFactory.string;
 *
 * class MyColumn extends TableSchema.column({
 * 	schemaFactory,
 * 	cell: Cell,
 * 	props: schemaFactory.object("TableColumnProps", {
 * 		label: schemaFactory.string,
 * 	}),
 * }) {}
 *
 * class MyRow extends TableSchema.row({
 * 	schemaFactory,
 * 	cell: Cell,
 * }) {}
 *
 * class MyTable extends TableSchema.table({
 * 	schemaFactory,
 * 	cell: Cell,
 * 	column: MyColumn,
 * 	row: MyRow,
 * }) {}
 *
 * const table = new MyTable({
 * 	columns: [
 * 		new MyColumn({ props: { label: "Entry" } }),
 * 		new MyColumn({ props: { label: "Date" } }),
 * 		new MyColumn({ props: { label: "Amount" } }),
 * 	],
 * 	rows: [],
 * });
 * ```
 *
 * @example Listening for changes in the table
 *
 * ```typescript
 * // Listen for any changes to the table and its children.
 * // The "treeChanged" event will fire when the associated node or any of its descendants change.
 * Tree.on(table, "treeChanged", () => {
 * 	// Respond to the change.
 * });
 * ```
 *
 * @example Listening for changes to the rows list only
 *
 * ```typescript
 * // Listen for any changes to the list of rows.
 * // The "nodeChanged" event will fire only when the specified node itself changes (i.e., its own properties change).
 * // In this case, the event will fire when a row is added or removed, or the order of the list is changed.
 * // But it won't fire when a row's properties change, or when the row's cells change, etc.
 * Tree.on(table.rows, "nodeChanged", () => {
 * 	// Respond to the change.
 * });
 * ```
 *
 * @privateRemarks
 * The above examples are backed by tests in `tableSchema.spec.ts`.
 * Those tests and these examples should be kept in-sync to ensure that the examples are correct.
 *
 * @alpha
 */
var TableSchema;
(function (TableSchema) {
    // #region Column
    /**
     * Overload implementation
     */
    function column({ schemaFactory, cell, props = index_js_2.SchemaFactory.optional(index_js_2.SchemaFactory.null), }) {
        return System_TableSchema.createColumnSchema(schemaFactory, props);
    }
    TableSchema.column = column;
    /**
     * Overload implementation
     */
    function row({ schemaFactory, cell, props = index_js_2.SchemaFactory.optional(index_js_2.SchemaFactory.null), }) {
        return System_TableSchema.createRowSchema(schemaFactory, cell, props);
    }
    TableSchema.row = row;
    /**
     * Overload implementation
     */
    function table({ schemaFactory, cell: cellSchema, column: columnSchema = column({
        schemaFactory,
        cell: cellSchema,
    }), row: rowSchema = row({
        schemaFactory,
        cell: cellSchema,
    }), }) {
        return System_TableSchema.createTableSchema(schemaFactory, cellSchema, columnSchema, rowSchema);
    }
    TableSchema.table = table;
    // #endregion
})(TableSchema || (exports.TableSchema = TableSchema = {}));
//# sourceMappingURL=tableSchema.js.map