@fluidframework/tree 2.32.0 → 2.33.0-333010

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/feature-libraries/flex-tree/context.d.ts +5 -0
  2. package/dist/feature-libraries/flex-tree/context.d.ts.map +1 -1
  3. package/dist/feature-libraries/flex-tree/context.js +4 -0
  4. package/dist/feature-libraries/flex-tree/context.js.map +1 -1
  5. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +8 -0
  6. package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  7. package/dist/feature-libraries/flex-tree/flexTreeTypes.js +8 -0
  8. package/dist/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  9. package/dist/feature-libraries/node-identifier/nodeIdentifierManager.d.ts.map +1 -1
  10. package/dist/feature-libraries/node-identifier/nodeIdentifierManager.js +29 -25
  11. package/dist/feature-libraries/node-identifier/nodeIdentifierManager.js.map +1 -1
  12. package/dist/packageVersion.d.ts +1 -1
  13. package/dist/packageVersion.d.ts.map +1 -1
  14. package/dist/packageVersion.js +1 -1
  15. package/dist/packageVersion.js.map +1 -1
  16. package/dist/shared-tree/checkoutFlexTreeView.d.ts +1 -0
  17. package/dist/shared-tree/checkoutFlexTreeView.d.ts.map +1 -1
  18. package/dist/shared-tree/checkoutFlexTreeView.js +4 -0
  19. package/dist/shared-tree/checkoutFlexTreeView.js.map +1 -1
  20. package/dist/simple-tree/core/treeNodeKernel.d.ts +9 -2
  21. package/dist/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
  22. package/dist/simple-tree/core/treeNodeKernel.js +39 -24
  23. package/dist/simple-tree/core/treeNodeKernel.js.map +1 -1
  24. package/dist/simple-tree/core/unhydratedFlexTree.d.ts +2 -1
  25. package/dist/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
  26. package/dist/simple-tree/core/unhydratedFlexTree.js +3 -0
  27. package/dist/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  28. package/dist/simple-tree/objectNode.d.ts.map +1 -1
  29. package/dist/simple-tree/objectNode.js +3 -0
  30. package/dist/simple-tree/objectNode.js.map +1 -1
  31. package/dist/tableSchema.d.ts +26 -12
  32. package/dist/tableSchema.d.ts.map +1 -1
  33. package/dist/tableSchema.js +17 -13
  34. package/dist/tableSchema.js.map +1 -1
  35. package/lib/feature-libraries/flex-tree/context.d.ts +5 -0
  36. package/lib/feature-libraries/flex-tree/context.d.ts.map +1 -1
  37. package/lib/feature-libraries/flex-tree/context.js +5 -1
  38. package/lib/feature-libraries/flex-tree/context.js.map +1 -1
  39. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +8 -0
  40. package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
  41. package/lib/feature-libraries/flex-tree/flexTreeTypes.js +8 -0
  42. package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
  43. package/lib/feature-libraries/node-identifier/nodeIdentifierManager.d.ts.map +1 -1
  44. package/lib/feature-libraries/node-identifier/nodeIdentifierManager.js +28 -24
  45. package/lib/feature-libraries/node-identifier/nodeIdentifierManager.js.map +1 -1
  46. package/lib/packageVersion.d.ts +1 -1
  47. package/lib/packageVersion.d.ts.map +1 -1
  48. package/lib/packageVersion.js +1 -1
  49. package/lib/packageVersion.js.map +1 -1
  50. package/lib/shared-tree/checkoutFlexTreeView.d.ts +1 -0
  51. package/lib/shared-tree/checkoutFlexTreeView.d.ts.map +1 -1
  52. package/lib/shared-tree/checkoutFlexTreeView.js +4 -0
  53. package/lib/shared-tree/checkoutFlexTreeView.js.map +1 -1
  54. package/lib/simple-tree/core/treeNodeKernel.d.ts +9 -2
  55. package/lib/simple-tree/core/treeNodeKernel.d.ts.map +1 -1
  56. package/lib/simple-tree/core/treeNodeKernel.js +40 -25
  57. package/lib/simple-tree/core/treeNodeKernel.js.map +1 -1
  58. package/lib/simple-tree/core/unhydratedFlexTree.d.ts +2 -1
  59. package/lib/simple-tree/core/unhydratedFlexTree.d.ts.map +1 -1
  60. package/lib/simple-tree/core/unhydratedFlexTree.js +3 -0
  61. package/lib/simple-tree/core/unhydratedFlexTree.js.map +1 -1
  62. package/lib/simple-tree/objectNode.d.ts.map +1 -1
  63. package/lib/simple-tree/objectNode.js +4 -1
  64. package/lib/simple-tree/objectNode.js.map +1 -1
  65. package/lib/tableSchema.d.ts +26 -12
  66. package/lib/tableSchema.d.ts.map +1 -1
  67. package/lib/tableSchema.js +17 -13
  68. package/lib/tableSchema.js.map +1 -1
  69. package/package.json +20 -20
  70. package/src/feature-libraries/flex-tree/context.ts +11 -1
  71. package/src/feature-libraries/flex-tree/flexTreeTypes.ts +8 -0
  72. package/src/feature-libraries/node-identifier/nodeIdentifierManager.ts +39 -38
  73. package/src/packageVersion.ts +1 -1
  74. package/src/shared-tree/checkoutFlexTreeView.ts +6 -0
  75. package/src/simple-tree/core/treeNodeKernel.ts +46 -28
  76. package/src/simple-tree/core/unhydratedFlexTree.ts +5 -1
  77. package/src/simple-tree/objectNode.ts +4 -2
  78. package/src/tableSchema.ts +80 -21
@@ -1 +1 @@
1
- {"version":3,"file":"tableSchema.js","sourceRoot":"","sources":["../src/tableSchema.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { oob } from \"@fluidframework/core-utils/internal\";\n\nimport { Tree } from \"./shared-tree/index.js\";\nimport {\n\ttype ImplicitAllowedTypes,\n\ttype ImplicitFieldSchema,\n\ttype InsertableObjectFromSchemaRecord,\n\ttype InsertableTreeNodeFromImplicitAllowedTypes,\n\ttype NodeKind,\n\ttype SchemaFactoryAlpha,\n\ttype ScopedSchemaName,\n\tTreeArrayNode,\n\ttype TreeNode,\n\ttype TreeNodeFromImplicitAllowedTypes,\n\ttype TreeNodeSchemaClass,\n\ttype WithType,\n} from \"./simple-tree/index.js\";\n\n// Future improvement TODOs (ideally to be done before promoting these APIs to `@alpha`):\n// - Custom fields on Table/Row/Column (props pattern from Nick's demo)\n// - Overloads to make Column/Row schema optional when constructing Tables\n// - Record-like type parameters / input parameters?\n// - Move `@system` types into separate / sub scope?\n\n/**\n * Contains types and factories for creating schema to represent dynamic tabular data.\n * @privateRemarks TODO: document in more detail and add `@example`s.\n * @internal\n */\nexport namespace TableSchema {\n\tconst tableSchemaFactorySubScope = \"table\";\n\n\t// #region Column\n\n\t/**\n\t * A column in a table.\n\t * @remarks Implemented by the schema class returned from {@link TableSchema.createColumn}.\n\t * @sealed @internal\n\t */\n\texport interface IColumn {\n\t\t/**\n\t\t * The unique identifier of the column.\n\t\t * @remarks Uniquely identifies the node within the entire tree, not just the table.\n\t\t */\n\t\treadonly id: string;\n\t}\n\n\t/**\n\t * Factory for creating new table column schema.\n\t * @internal\n\t */\n\t// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is too complex to be reasonable to specify\n\texport function createColumn<const TInputScope extends string | undefined>(\n\t\tinputSchemaFactory: SchemaFactoryAlpha<TInputScope>,\n\t) {\n\t\tconst schemaFactory = inputSchemaFactory.scopedFactory(tableSchemaFactorySubScope);\n\t\ttype Scope = ScopedSchemaName<TInputScope, typeof tableSchemaFactorySubScope>;\n\n\t\t/**\n\t\t * {@link Column} fields.\n\t\t * @remarks Extracted for re-use in returned type signature defined later in this function.\n\t\t * The implicit typing is intentional.\n\t\t */\n\t\tconst columnFields = {\n\t\t\tid: schemaFactory.identifier,\n\t\t} as const satisfies Record<string, ImplicitFieldSchema>;\n\n\t\t/**\n\t\t * A column in a table.\n\t\t */\n\t\tclass Column extends schemaFactory.object(\"Column\", columnFields) implements IColumn {}\n\n\t\ttype ColumnValueType = TreeNode & IColumn & WithType<ScopedSchemaName<Scope, \"Column\">>;\n\t\ttype ColumnInsertableType = InsertableObjectFromSchemaRecord<typeof columnFields>;\n\n\t\t// Returning SingletonSchema without a type conversion results in TypeScript generating something like `readonly \"__#124291@#brand\": unknown;`\n\t\t// for the private brand field of TreeNode.\n\t\t// This numeric id doesn't seem to be stable over incremental builds, and thus causes diffs in the API extractor reports.\n\t\t// This is avoided by doing this type conversion.\n\t\t// The conversion is done via assignment instead of `as` to get stronger type safety.\n\t\tconst ColumnSchemaType: TreeNodeSchemaClass<\n\t\t\t/* Name */ ScopedSchemaName<Scope, \"Column\">,\n\t\t\t/* Kind */ NodeKind.Object,\n\t\t\t/* TNode */ ColumnValueType,\n\t\t\t/* TInsertable */ object & ColumnInsertableType,\n\t\t\t/* ImplicitlyConstructable */ true,\n\t\t\t/* Info */ typeof columnFields\n\t\t> = Column;\n\n\t\treturn ColumnSchemaType;\n\t}\n\n\t/**\n\t * Base column schema type.\n\t * @sealed @system @internal\n\t */\n\texport type ColumnSchemaBase<TScope extends string | undefined> = ReturnType<\n\t\ttypeof createColumn<TScope>\n\t>;\n\n\t// #endregion\n\n\t// #region Row\n\n\t/**\n\t * A row in a table.\n\t * @remarks Implemented by the schema class returned from {@link TableSchema.createRow}.\n\t * @sealed @internal\n\t */\n\texport interface IRow<\n\t\tTCellSchema extends ImplicitAllowedTypes,\n\t\tTColumnSchema extends ImplicitAllowedTypes,\n\t> {\n\t\t/**\n\t\t * The unique identifier of the row.\n\t\t * @remarks Uniquely identifies the node within the entire tree, not just the table.\n\t\t */\n\t\treadonly id: string;\n\n\t\t/**\n\t\t * Gets the cell in the specified column\n\t\t * @returns The cell if it exists, otherwise undefined.\n\t\t * @privateRemarks TODO: add overload that takes column ID.\n\t\t */\n\t\tgetCell(\n\t\t\tcolumn: TreeNodeFromImplicitAllowedTypes<TColumnSchema>,\n\t\t): TreeNodeFromImplicitAllowedTypes<TCellSchema> | undefined;\n\n\t\t/**\n\t\t * Sets the cell in the specified column.\n\t\t * @remarks To delete a cell, call {@link TableSchema.IRow.deleteCell} instead.\n\t\t * @privateRemarks TODO: add overload that takes column ID.\n\t\t */\n\t\tsetCell(\n\t\t\tcolumn: TreeNodeFromImplicitAllowedTypes<TColumnSchema>,\n\t\t\tvalue: InsertableTreeNodeFromImplicitAllowedTypes<TCellSchema>,\n\t\t): void;\n\n\t\t/**\n\t\t * Deletes the cell in the specified column.\n\t\t * @privateRemarks TODO: add overload that takes column ID.\n\t\t */\n\t\tdeleteCell(column: TreeNodeFromImplicitAllowedTypes<TColumnSchema>): void;\n\t}\n\n\t/**\n\t * Factory for creating new table row schema.\n\t * @privateRemarks TODO: add overloads to make column schema optional.\n\t * @sealed @internal\n\t */\n\t// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is too complex to be reasonable to specify\n\texport function createRow<\n\t\tconst TInputScope extends string | undefined,\n\t\tconst TCellSchema extends ImplicitAllowedTypes,\n\t\tconst TColumnSchema extends ColumnSchemaBase<TInputScope> = ColumnSchemaBase<TInputScope>,\n\t>(\n\t\tinputSchemaFactory: SchemaFactoryAlpha<TInputScope>,\n\t\tcellSchema: TCellSchema,\n\t\t_columnSchema: TColumnSchema,\n\t) {\n\t\tconst schemaFactory = inputSchemaFactory.scopedFactory(tableSchemaFactorySubScope);\n\t\ttype Scope = ScopedSchemaName<TInputScope, typeof tableSchemaFactorySubScope>;\n\n\t\ttype CellValueType = TreeNodeFromImplicitAllowedTypes<TCellSchema>;\n\t\ttype CellInsertableType = InsertableTreeNodeFromImplicitAllowedTypes<TCellSchema>;\n\n\t\ttype ColumnValueType = TreeNodeFromImplicitAllowedTypes<TColumnSchema>;\n\n\t\t/**\n\t\t * {@link Row} fields.\n\t\t * @remarks Extracted for re-use in returned type signature defined later in this function.\n\t\t * The implicit typing is intentional.\n\t\t */\n\t\tconst rowFields = {\n\t\t\tid: schemaFactory.identifier,\n\t\t\tcells: schemaFactory.map(\"Row.cells\", cellSchema),\n\t\t} as const satisfies Record<string, ImplicitFieldSchema>;\n\n\t\t/**\n\t\t * The Row schema - this is a map of Cells where the key is the column id\n\t\t */\n\t\tclass Row\n\t\t\textends schemaFactory.object(\"Row\", rowFields)\n\t\t\timplements IRow<TCellSchema, TColumnSchema>\n\t\t{\n\t\t\tpublic getCell(column: ColumnValueType): CellValueType | undefined {\n\t\t\t\treturn this.cells.get(column.id) as CellValueType | undefined;\n\t\t\t}\n\n\t\t\tpublic setCell(column: ColumnValueType, value: CellInsertableType | undefined): void {\n\t\t\t\tthis.cells.set(column.id, value);\n\t\t\t}\n\n\t\t\tpublic deleteCell(column: ColumnValueType): void {\n\t\t\t\tif (!this.cells.has(column.id)) return;\n\t\t\t\tthis.cells.delete(column.id);\n\t\t\t}\n\t\t}\n\n\t\ttype RowValueType = TreeNode &\n\t\t\tIRow<TCellSchema, TColumnSchema> &\n\t\t\tWithType<ScopedSchemaName<Scope, \"Row\">>;\n\t\ttype RowInsertableType = InsertableObjectFromSchemaRecord<typeof rowFields>;\n\n\t\t// Returning SingletonSchema without a type conversion results in TypeScript generating something like `readonly \"__#124291@#brand\": unknown;`\n\t\t// for the private brand field of TreeNode.\n\t\t// This numeric id doesn't seem to be stable over incremental builds, and thus causes diffs in the API extractor reports.\n\t\t// This is avoided by doing this type conversion.\n\t\t// The conversion is done via assignment instead of `as` to get stronger type safety.\n\t\tconst RowSchemaType: TreeNodeSchemaClass<\n\t\t\t/* Name */ ScopedSchemaName<Scope, \"Row\">,\n\t\t\t/* Kind */ NodeKind.Object,\n\t\t\t/* TNode */ RowValueType,\n\t\t\t/* TInsertable */ object & RowInsertableType,\n\t\t\t/* ImplicitlyConstructable */ true,\n\t\t\t/* Info */ typeof rowFields\n\t\t> = Row;\n\n\t\treturn RowSchemaType;\n\t}\n\n\t/**\n\t * Base row schema type.\n\t * @sealed @system @internal\n\t */\n\texport type RowSchemaBase<\n\t\tTScope extends string | undefined,\n\t\tTCellSchema extends ImplicitAllowedTypes,\n\t\tTColumnSchema extends ColumnSchemaBase<TScope> = ColumnSchemaBase<TScope>,\n\t> = ReturnType<typeof createRow<TScope, TCellSchema, TColumnSchema>>;\n\n\t// #endregion\n\n\t// #region Table\n\n\t/**\n\t * A key to uniquely identify a cell in a table.\n\t * @sealed @internal\n\t */\n\texport interface CellKey {\n\t\t/**\n\t\t * {@link TableSchema.IColumn.id} of the containing {@link TableSchema.IColumn}.\n\t\t */\n\t\treadonly columnId: string;\n\n\t\t/**\n\t\t * {@link TableSchema.IRow.id} of the containing {@link TableSchema.IRow}.\n\t\t */\n\t\treadonly rowId: string;\n\t}\n\n\t/**\n\t * {@link TableSchema.ITable.insertColumn} parameters.\n\t * @sealed @internal\n\t */\n\texport interface InsertColumnParameters<TInsertableColumn> {\n\t\t/**\n\t\t * The index at which to insert the new column.\n\t\t * @remarks If not provided, the column will be appended to the end of the table.\n\t\t */\n\t\treadonly index?: number | undefined;\n\n\t\t/**\n\t\t * The column to insert.\n\t\t */\n\t\treadonly column: TInsertableColumn;\n\t}\n\n\t/**\n\t * {@link TableSchema.ITable.insertRows} parameters.\n\t * @sealed @internal\n\t */\n\texport interface InsertRowsParameters<TInsertableRow> {\n\t\t/**\n\t\t * The index at which to insert the new rows.\n\t\t * @remarks If not provided, the rows will be appended to the end of the table.\n\t\t */\n\t\treadonly index?: number | undefined;\n\n\t\t/**\n\t\t * The rows to insert.\n\t\t */\n\t\treadonly rows: TInsertableRow[];\n\t}\n\n\t/**\n\t * {@link TableSchema.ITable.setCell} parameters.\n\t * @sealed @internal\n\t */\n\texport interface SetCellParameters<TInsertableCell> {\n\t\t/**\n\t\t * The key to uniquely identify a cell in a table.\n\t\t */\n\t\treadonly key: CellKey;\n\n\t\t/**\n\t\t * The cell to set.\n\t\t */\n\t\treadonly cell: TInsertableCell;\n\t}\n\n\t/**\n\t * A table.\n\t * @sealed @internal\n\t */\n\texport interface ITable<\n\t\tTCellSchema extends ImplicitAllowedTypes,\n\t\tTColumnSchema extends ImplicitAllowedTypes,\n\t\tTRowSchema extends ImplicitAllowedTypes,\n\t> {\n\t\t/**\n\t\t * The table's columns.\n\t\t */\n\t\treadonly columns: TreeArrayNode<TColumnSchema>;\n\n\t\t/**\n\t\t * The table's rows.\n\t\t */\n\t\treadonly rows: TreeArrayNode<TRowSchema>;\n\n\t\t/**\n\t\t * Gets a table column by its {@link TableSchema.IRow.id}.\n\t\t */\n\t\tgetColumn(id: string): TreeNodeFromImplicitAllowedTypes<TColumnSchema> | undefined;\n\n\t\t/**\n\t\t * Gets a table row by its {@link TableSchema.IRow.id}.\n\t\t */\n\t\tgetRow(id: string): TreeNodeFromImplicitAllowedTypes<TRowSchema> | undefined;\n\n\t\t/**\n\t\t * Gets a cell in the table by column and row IDs.\n\t\t * @param key - A key that uniquely distinguishes a cell in the table, represented as a combination of the column ID and row ID.\n\t\t * @privateRemarks TODO: add overload that takes row and column nodes.\n\t\t */\n\t\tgetCell(key: CellKey): TreeNodeFromImplicitAllowedTypes<TCellSchema> | undefined;\n\n\t\t/**\n\t\t * Inserts a column into the table.\n\t\t * @throws Throws an error if the column is already in the tree, or if the specified index is out of range.\n\t\t */\n\t\tinsertColumn(\n\t\t\tparams: InsertColumnParameters<\n\t\t\t\tInsertableTreeNodeFromImplicitAllowedTypes<TColumnSchema>\n\t\t\t>,\n\t\t): TreeNodeFromImplicitAllowedTypes<TColumnSchema>;\n\n\t\t/**\n\t\t * Inserts 0 or more rows into the table.\n\t\t * @throws Throws an error if any of the rows are already in the tree, or if the specified index is out of range.\n\t\t */\n\t\tinsertRows(\n\t\t\tparams: InsertRowsParameters<InsertableTreeNodeFromImplicitAllowedTypes<TRowSchema>>,\n\t\t): TreeNodeFromImplicitAllowedTypes<TRowSchema>[];\n\n\t\t/**\n\t\t * Sets the cell at the specified location in the table.\n\t\t * @remarks To delete a cell, call {@link TableSchema.ITable.deleteCell} instead.\n\t\t * @privateRemarks TODO: add overload that takes column/row nodes?\n\t\t */\n\t\tsetCell(\n\t\t\tparams: SetCellParameters<InsertableTreeNodeFromImplicitAllowedTypes<TCellSchema>>,\n\t\t): void;\n\n\t\t/**\n\t\t * Removes the specified column from the table.\n\t\t * @remarks Note: this does not remove any cells from the table's rows.\n\t\t * @privateRemarks\n\t\t * TODO:\n\t\t * - Policy for when the column is not in the table.\n\t\t * - Actually remove corresponding cells from table rows.\n\t\t */\n\t\tremoveColumn: (column: TreeNodeFromImplicitAllowedTypes<TColumnSchema>) => void;\n\n\t\t/**\n\t\t * Deletes 0 or more rows from the table.\n\t\t * @privateRemarks TODO: policy for when 1 or more rows are not in the table.\n\t\t */\n\t\tdeleteRows: (rows: readonly TreeNodeFromImplicitAllowedTypes<TRowSchema>[]) => void;\n\n\t\t/**\n\t\t * Deletes all rows from the table.\n\t\t */\n\t\tdeleteAllRows: () => void;\n\n\t\t/**\n\t\t * Deletes the cell at the specified location in the table.\n\t\t * @privateRemarks TODO: add overload that takes column/row nodes?\n\t\t */\n\t\tdeleteCell: (key: CellKey) => void;\n\t}\n\n\t/**\n\t * Factory for creating new table schema.\n\t * @privateRemarks TODO: add overloads to make column/row schema optional.\n\t * @internal\n\t */\n\t// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is too complex to be reasonable to specify\n\texport function createTable<\n\t\tconst TInputScope extends string | undefined,\n\t\tconst TCell extends ImplicitAllowedTypes,\n\t\tconst TColumn extends ColumnSchemaBase<TInputScope> = ColumnSchemaBase<TInputScope>,\n\t\tconst TRow extends RowSchemaBase<TInputScope, TCell, TColumn> = RowSchemaBase<\n\t\t\tTInputScope,\n\t\t\tTCell,\n\t\t\tTColumn\n\t\t>,\n\t>(\n\t\tinputSchemaFactory: SchemaFactoryAlpha<TInputScope>,\n\t\t_cellSchema: TCell,\n\t\tcolumnSchema: TColumn,\n\t\trowSchema: TRow,\n\t) {\n\t\tconst schemaFactory = inputSchemaFactory.scopedFactory(tableSchemaFactorySubScope);\n\t\ttype Scope = ScopedSchemaName<TInputScope, typeof tableSchemaFactorySubScope>;\n\n\t\ttype CellValueType = TreeNodeFromImplicitAllowedTypes<TCell>;\n\t\ttype CellInsertableType = InsertableTreeNodeFromImplicitAllowedTypes<TCell>;\n\n\t\ttype ColumnValueType = TreeNodeFromImplicitAllowedTypes<TColumn>;\n\t\ttype ColumnInsertableType = InsertableTreeNodeFromImplicitAllowedTypes<TColumn>;\n\n\t\ttype RowValueType = TreeNodeFromImplicitAllowedTypes<TRow>;\n\t\ttype RowInsertableType = InsertableTreeNodeFromImplicitAllowedTypes<TRow>;\n\n\t\t/**\n\t\t * {@link Table} fields.\n\t\t * @remarks Extracted for re-use in returned type signature defined later in this function.\n\t\t * The implicit typing is intentional.\n\t\t */\n\t\tconst tableFields = {\n\t\t\trows: schemaFactory.array(\"Table.rows\", rowSchema),\n\t\t\tcolumns: schemaFactory.array(\"Table.columns\", columnSchema),\n\t\t} as const satisfies Record<string, ImplicitFieldSchema>;\n\n\t\t/**\n\t\t * The Table schema\n\t\t */\n\t\tclass Table\n\t\t\textends schemaFactory.object(\"Table\", tableFields)\n\t\t\timplements ITable<TCell, TColumn, TRow>\n\t\t{\n\t\t\tpublic getColumn(id: string): ColumnValueType | undefined {\n\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the casts.\n\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\treturn this.columns.find((column) => (column as ColumnValueType).id === id) as\n\t\t\t\t\t| ColumnValueType\n\t\t\t\t\t| undefined;\n\t\t\t}\n\n\t\t\tpublic getRow(id: string): RowValueType | undefined {\n\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the casts.\n\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\treturn this.rows.find((_row) => (_row as RowValueType).id === id) as\n\t\t\t\t\t| RowValueType\n\t\t\t\t\t| undefined;\n\t\t\t}\n\n\t\t\tpublic getCell(key: CellKey): CellValueType | undefined {\n\t\t\t\tconst { columnId, rowId } = key;\n\t\t\t\tconst row = this.getRow(rowId);\n\t\t\t\tif (row !== undefined) {\n\t\t\t\t\tconst column = this.getColumn(columnId);\n\t\t\t\t\tif (column !== undefined) {\n\t\t\t\t\t\treturn row.getCell(column);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// If the cell does not exist return undefined\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tpublic insertColumn({\n\t\t\t\tcolumn,\n\t\t\t\tindex,\n\t\t\t}: InsertColumnParameters<ColumnInsertableType>): ColumnValueType {\n\t\t\t\tif (index === undefined) {\n\t\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the cast.\n\t\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\tthis.columns.insertAtEnd(column as any);\n\t\t\t\t} else {\n\t\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the cast.\n\t\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\tthis.columns.insertAt(index, column as any);\n\t\t\t\t}\n\n\t\t\t\t// Inserting the input node into the tree hydrates it, making it usable as a node.\n\t\t\t\treturn column as ColumnValueType;\n\t\t\t}\n\n\t\t\tpublic insertRows({\n\t\t\t\tindex,\n\t\t\t\trows,\n\t\t\t}: InsertRowsParameters<RowInsertableType>): RowValueType[] {\n\t\t\t\tif (index === undefined) {\n\t\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the cast.\n\t\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\tthis.rows.insertAtEnd(TreeArrayNode.spread(rows) as any);\n\t\t\t\t} else {\n\t\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the cast.\n\t\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\tthis.rows.insertAt(index, TreeArrayNode.spread(rows) as any);\n\t\t\t\t}\n\n\t\t\t\t// Inserting the input nodes into the tree hydrates them, making them usable as nodes.\n\t\t\t\treturn rows as unknown as RowValueType[];\n\t\t\t}\n\n\t\t\tpublic setCell({ key, cell }: SetCellParameters<CellInsertableType>): void {\n\t\t\t\tconst { columnId, rowId } = key;\n\t\t\t\tconst row = this.getRow(rowId);\n\t\t\t\tif (row !== undefined) {\n\t\t\t\t\tconst column = this.getColumn(columnId);\n\t\t\t\t\tif (column !== undefined) {\n\t\t\t\t\t\trow.setCell(column, cell);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic removeColumn(column: ColumnValueType): void {\n\t\t\t\tconst index = this.columns.indexOf(column);\n\t\t\t\t// If the column is not in the table, do nothing\n\t\t\t\tif (index === -1) return;\n\t\t\t\tthis.columns.removeAt(index);\n\t\t\t}\n\n\t\t\tpublic deleteRows(rows: readonly RowValueType[]): void {\n\t\t\t\t// If there are no rows to delete, do nothing\n\t\t\t\tif (rows.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// If there is only one row to delete, delete it\n\t\t\t\tif (rows.length === 1) {\n\t\t\t\t\tconst index = this.rows.indexOf(rows[0] ?? oob());\n\t\t\t\t\tthis.rows.removeAt(index);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// If there are multiple rows to delete, delete them in a transaction\n\t\t\t\t// This is to avoid the performance issues of deleting multiple rows at once\n\t\t\t\tTree.runTransaction(this, () => {\n\t\t\t\t\t// Iterate over the rows and delete them\n\t\t\t\t\tfor (const row of rows) {\n\t\t\t\t\t\tconst index = this.rows.indexOf(row);\n\t\t\t\t\t\tthis.rows.removeAt(index);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tpublic deleteAllRows(): void {\n\t\t\t\tthis.rows.removeRange();\n\t\t\t}\n\n\t\t\tpublic deleteCell(key: CellKey): void {\n\t\t\t\tconst { columnId, rowId } = key;\n\t\t\t\tconst row = this.getRow(rowId);\n\t\t\t\tif (row !== undefined) {\n\t\t\t\t\tconst column = this.getColumn(columnId);\n\t\t\t\t\tif (column !== undefined) {\n\t\t\t\t\t\trow.deleteCell(column);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttype TableValueType = TreeNode &\n\t\t\tITable<TCell, TColumn, TRow> &\n\t\t\tWithType<ScopedSchemaName<Scope, \"Table\">>;\n\t\ttype TableInsertableType = InsertableObjectFromSchemaRecord<typeof tableFields>;\n\n\t\t// Returning SingletonSchema without a type conversion results in TypeScript generating something like `readonly \"__#124291@#brand\": unknown;`\n\t\t// for the private brand field of TreeNode.\n\t\t// This numeric id doesn't seem to be stable over incremental builds, and thus causes diffs in the API extractor reports.\n\t\t// This is avoided by doing this type conversion.\n\t\t// The conversion is done via assignment instead of `as` to get stronger type safety.\n\t\tconst TableSchemaType: TreeNodeSchemaClass<\n\t\t\t/* Name */ ScopedSchemaName<Scope, \"Table\">,\n\t\t\t/* Kind */ NodeKind.Object,\n\t\t\t/* TNode */ TableValueType,\n\t\t\t/* TInsertable */ object & TableInsertableType,\n\t\t\t/* ImplicitlyConstructable */ true,\n\t\t\t/* Info */ typeof tableFields\n\t\t> = Table;\n\n\t\t// Return the table schema\n\t\treturn TableSchemaType;\n\t}\n\n\t/**\n\t * Base row schema type.\n\t * @sealed @system @internal\n\t */\n\texport type TableSchemaBase<\n\t\tTScope extends string | undefined,\n\t\tTCell extends ImplicitAllowedTypes,\n\t\tTColumn extends ColumnSchemaBase<TScope> = ColumnSchemaBase<TScope>,\n\t\tTRow extends RowSchemaBase<TScope, TCell, TColumn> = RowSchemaBase<TScope, TCell, TColumn>,\n\t> = ReturnType<typeof createTable<TScope, TCell, TColumn, TRow>>;\n\n\t// #endregion\n}\n"]}
1
+ {"version":3,"file":"tableSchema.js","sourceRoot":"","sources":["../src/tableSchema.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { oob } from \"@fluidframework/core-utils/internal\";\n\nimport { Tree } from \"./shared-tree/index.js\";\nimport {\n\ttype ImplicitAllowedTypes,\n\ttype ImplicitFieldSchema,\n\ttype InsertableObjectFromSchemaRecord,\n\ttype InsertableTreeNodeFromImplicitAllowedTypes,\n\ttype NodeKind,\n\ttype SchemaFactoryAlpha,\n\ttype ScopedSchemaName,\n\tTreeArrayNode,\n\ttype TreeNode,\n\ttype TreeNodeFromImplicitAllowedTypes,\n\ttype TreeNodeSchema,\n\ttype TreeNodeSchemaClass,\n\ttype WithType,\n} from \"./simple-tree/index.js\";\n\n// Future improvement TODOs (ideally to be done before promoting these APIs to `@alpha`):\n// - Custom fields on Table/Row/Column (props pattern from Nick's demo)\n// - Overloads to make Column/Row schema optional when constructing Tables\n// - Record-like type parameters / input parameters?\n// - Move `@system` types into separate / sub scope?\n\n/**\n * Contains types and factories for creating schema to represent dynamic tabular data.\n * @privateRemarks TODO: document in more detail and add `@example`s.\n * @internal\n */\nexport namespace TableSchema {\n\tconst tableSchemaFactorySubScope = \"table\";\n\n\t// #region Column\n\n\t/**\n\t * A column in a table.\n\t * @remarks Implemented by the schema class returned from {@link TableSchema.createColumn}.\n\t * @sealed @internal\n\t */\n\texport interface IColumn {\n\t\t/**\n\t\t * The unique identifier of the column.\n\t\t * @remarks Uniquely identifies the node within the entire tree, not just the table.\n\t\t */\n\t\treadonly id: string;\n\t}\n\n\t/**\n\t * Factory for creating new table column schema.\n\t * @internal\n\t */\n\t// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is too complex to be reasonable to specify\n\texport function createColumn<const TInputScope extends string | undefined>(\n\t\tinputSchemaFactory: SchemaFactoryAlpha<TInputScope>,\n\t) {\n\t\tconst schemaFactory = inputSchemaFactory.scopedFactory(tableSchemaFactorySubScope);\n\t\ttype Scope = ScopedSchemaName<TInputScope, typeof tableSchemaFactorySubScope>;\n\n\t\t/**\n\t\t * {@link Column} fields.\n\t\t * @remarks Extracted for re-use in returned type signature defined later in this function.\n\t\t * The implicit typing is intentional.\n\t\t */\n\t\tconst columnFields = {\n\t\t\tid: schemaFactory.identifier,\n\t\t} as const satisfies Record<string, ImplicitFieldSchema>;\n\n\t\t/**\n\t\t * A column in a table.\n\t\t */\n\t\tclass Column extends schemaFactory.object(\"Column\", columnFields) implements IColumn {}\n\n\t\ttype ColumnValueType = TreeNode & IColumn & WithType<ScopedSchemaName<Scope, \"Column\">>;\n\t\ttype ColumnInsertableType = InsertableObjectFromSchemaRecord<typeof columnFields>;\n\n\t\t// Returning SingletonSchema without a type conversion results in TypeScript generating something like `readonly \"__#124291@#brand\": unknown;`\n\t\t// for the private brand field of TreeNode.\n\t\t// This numeric id doesn't seem to be stable over incremental builds, and thus causes diffs in the API extractor reports.\n\t\t// This is avoided by doing this type conversion.\n\t\t// The conversion is done via assignment instead of `as` to get stronger type safety.\n\t\tconst ColumnSchemaType: TreeNodeSchemaClass<\n\t\t\t/* Name */ ScopedSchemaName<Scope, \"Column\">,\n\t\t\t/* Kind */ NodeKind.Object,\n\t\t\t/* TNode */ ColumnValueType,\n\t\t\t/* TInsertable */ object & ColumnInsertableType,\n\t\t\t/* ImplicitlyConstructable */ true,\n\t\t\t/* Info */ typeof columnFields\n\t\t> = Column;\n\n\t\treturn ColumnSchemaType;\n\t}\n\n\t/**\n\t * Base column schema type.\n\t * @sealed @system @internal\n\t */\n\texport type ColumnSchemaBase<TScope extends string | undefined> = ReturnType<\n\t\ttypeof createColumn<TScope>\n\t>;\n\n\t// #endregion\n\n\t// #region Row\n\n\t/**\n\t * A row in a table.\n\t * @remarks Implemented by the schema class returned from {@link TableSchema.createRow}.\n\t * @sealed @internal\n\t */\n\texport interface IRow<\n\t\tTCellSchema extends ImplicitAllowedTypes,\n\t\tTColumnSchema extends ImplicitAllowedTypes,\n\t> {\n\t\t/**\n\t\t * The unique identifier of the row.\n\t\t * @remarks Uniquely identifies the node within the entire tree, not just the table.\n\t\t */\n\t\treadonly id: string;\n\n\t\t/**\n\t\t * Gets the cell in the specified column\n\t\t * @returns The cell if it exists, otherwise undefined.\n\t\t * @privateRemarks TODO: add overload that takes column ID.\n\t\t */\n\t\tgetCell(\n\t\t\tcolumn: TreeNodeFromImplicitAllowedTypes<TColumnSchema>,\n\t\t): TreeNodeFromImplicitAllowedTypes<TCellSchema> | undefined;\n\n\t\t/**\n\t\t * Sets the cell in the specified column.\n\t\t * @remarks To remove a cell, call {@link TableSchema.IRow.removeCell} instead.\n\t\t * @privateRemarks TODO: add overload that takes column ID.\n\t\t */\n\t\tsetCell(\n\t\t\tcolumn: TreeNodeFromImplicitAllowedTypes<TColumnSchema>,\n\t\t\tvalue: InsertableTreeNodeFromImplicitAllowedTypes<TCellSchema>,\n\t\t): void;\n\n\t\t/**\n\t\t * Removes the cell in the specified column.\n\t\t * @privateRemarks TODO: add overload that takes column ID.\n\t\t */\n\t\tremoveCell(column: TreeNodeFromImplicitAllowedTypes<TColumnSchema>): void;\n\t}\n\n\t/**\n\t * Factory for creating new table row schema.\n\t * @privateRemarks TODO: add overloads to make column schema optional.\n\t * @sealed @internal\n\t */\n\t// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is too complex to be reasonable to specify\n\texport function createRow<\n\t\tconst TInputScope extends string | undefined,\n\t\tconst TCellSchema extends ImplicitAllowedTypes,\n\t\tconst TColumnSchema extends ColumnSchemaBase<TInputScope> = ColumnSchemaBase<TInputScope>,\n\t>(\n\t\tinputSchemaFactory: SchemaFactoryAlpha<TInputScope>,\n\t\tcellSchema: TCellSchema,\n\t\t_columnSchema: TColumnSchema,\n\t) {\n\t\tconst schemaFactory = inputSchemaFactory.scopedFactory(tableSchemaFactorySubScope);\n\t\ttype Scope = ScopedSchemaName<TInputScope, typeof tableSchemaFactorySubScope>;\n\n\t\ttype CellValueType = TreeNodeFromImplicitAllowedTypes<TCellSchema>;\n\t\ttype CellInsertableType = InsertableTreeNodeFromImplicitAllowedTypes<TCellSchema>;\n\n\t\ttype ColumnValueType = TreeNodeFromImplicitAllowedTypes<TColumnSchema>;\n\n\t\t/**\n\t\t * {@link Row} fields.\n\t\t * @remarks Extracted for re-use in returned type signature defined later in this function.\n\t\t * The implicit typing is intentional.\n\t\t */\n\t\tconst rowFields = {\n\t\t\tid: schemaFactory.identifier,\n\t\t\tcells: schemaFactory.map(\"Row.cells\", cellSchema),\n\t\t} as const satisfies Record<string, ImplicitFieldSchema>;\n\n\t\t/**\n\t\t * The Row schema - this is a map of Cells where the key is the column id\n\t\t */\n\t\tclass Row\n\t\t\textends schemaFactory.object(\"Row\", rowFields)\n\t\t\timplements IRow<TCellSchema, TColumnSchema>\n\t\t{\n\t\t\tpublic getCell(column: ColumnValueType): CellValueType | undefined {\n\t\t\t\treturn this.cells.get(column.id) as CellValueType | undefined;\n\t\t\t}\n\n\t\t\tpublic setCell(column: ColumnValueType, value: CellInsertableType | undefined): void {\n\t\t\t\tthis.cells.set(column.id, value);\n\t\t\t}\n\n\t\t\tpublic removeCell(column: ColumnValueType): void {\n\t\t\t\tif (!this.cells.has(column.id)) return;\n\t\t\t\tthis.cells.delete(column.id);\n\t\t\t}\n\t\t}\n\n\t\ttype RowValueType = TreeNode &\n\t\t\tIRow<TCellSchema, TColumnSchema> &\n\t\t\tWithType<ScopedSchemaName<Scope, \"Row\">>;\n\t\ttype RowInsertableType = InsertableObjectFromSchemaRecord<typeof rowFields>;\n\n\t\t// Returning SingletonSchema without a type conversion results in TypeScript generating something like `readonly \"__#124291@#brand\": unknown;`\n\t\t// for the private brand field of TreeNode.\n\t\t// This numeric id doesn't seem to be stable over incremental builds, and thus causes diffs in the API extractor reports.\n\t\t// This is avoided by doing this type conversion.\n\t\t// The conversion is done via assignment instead of `as` to get stronger type safety.\n\t\tconst RowSchemaType: TreeNodeSchemaClass<\n\t\t\t/* Name */ ScopedSchemaName<Scope, \"Row\">,\n\t\t\t/* Kind */ NodeKind.Object,\n\t\t\t/* TNode */ RowValueType,\n\t\t\t/* TInsertable */ object & RowInsertableType,\n\t\t\t/* ImplicitlyConstructable */ true,\n\t\t\t/* Info */ typeof rowFields\n\t\t> = Row;\n\n\t\treturn RowSchemaType;\n\t}\n\n\t/**\n\t * Base row schema type.\n\t * @sealed @system @internal\n\t */\n\texport type RowSchemaBase<\n\t\tTScope extends string | undefined,\n\t\tTCellSchema extends ImplicitAllowedTypes,\n\t\tTColumnSchema extends ColumnSchemaBase<TScope> = ColumnSchemaBase<TScope>,\n\t> = ReturnType<typeof createRow<TScope, TCellSchema, TColumnSchema>>;\n\n\t// #endregion\n\n\t// #region Table\n\n\t/**\n\t * A key to uniquely identify a cell in a table.\n\t * @sealed @internal\n\t */\n\texport interface CellKey {\n\t\t/**\n\t\t * {@link TableSchema.IColumn.id} of the containing {@link TableSchema.IColumn}.\n\t\t */\n\t\treadonly columnId: string;\n\n\t\t/**\n\t\t * {@link TableSchema.IRow.id} of the containing {@link TableSchema.IRow}.\n\t\t */\n\t\treadonly rowId: string;\n\t}\n\n\t/**\n\t * {@link TableSchema.ITable.insertColumn} parameters.\n\t * @sealed @internal\n\t */\n\texport interface InsertColumnParameters<TInsertableColumn> {\n\t\t/**\n\t\t * The index at which to insert the new column.\n\t\t * @remarks If not provided, the column will be appended to the end of the table.\n\t\t */\n\t\treadonly index?: number | undefined;\n\n\t\t/**\n\t\t * The column to insert.\n\t\t */\n\t\treadonly column: TInsertableColumn;\n\t}\n\n\t/**\n\t * {@link TableSchema.ITable.insertRows} parameters.\n\t * @sealed @internal\n\t */\n\texport interface InsertRowsParameters<TInsertableRow> {\n\t\t/**\n\t\t * The index at which to insert the new rows.\n\t\t * @remarks If not provided, the rows will be appended to the end of the table.\n\t\t */\n\t\treadonly index?: number | undefined;\n\n\t\t/**\n\t\t * The rows to insert.\n\t\t */\n\t\treadonly rows: TInsertableRow[];\n\t}\n\n\t/**\n\t * {@link TableSchema.ITable.setCell} parameters.\n\t * @sealed @internal\n\t */\n\texport interface SetCellParameters<TInsertableCell> {\n\t\t/**\n\t\t * The key to uniquely identify a cell in a table.\n\t\t */\n\t\treadonly key: CellKey;\n\n\t\t/**\n\t\t * The cell to set.\n\t\t */\n\t\treadonly cell: TInsertableCell;\n\t}\n\n\t/**\n\t * A table.\n\t * @sealed @internal\n\t */\n\texport interface ITable<\n\t\tTCellSchema extends ImplicitAllowedTypes,\n\t\tTColumnSchema extends ImplicitAllowedTypes,\n\t\tTRowSchema extends ImplicitAllowedTypes,\n\t> {\n\t\t/**\n\t\t * The table's columns.\n\t\t */\n\t\treadonly columns: TreeArrayNode<TColumnSchema>;\n\n\t\t/**\n\t\t * The table's rows.\n\t\t */\n\t\treadonly rows: TreeArrayNode<TRowSchema>;\n\n\t\t/**\n\t\t * Gets a table column by its {@link TableSchema.IRow.id}.\n\t\t */\n\t\tgetColumn(id: string): TreeNodeFromImplicitAllowedTypes<TColumnSchema> | undefined;\n\n\t\t/**\n\t\t * Gets a table row by its {@link TableSchema.IRow.id}.\n\t\t */\n\t\tgetRow(id: string): TreeNodeFromImplicitAllowedTypes<TRowSchema> | undefined;\n\n\t\t/**\n\t\t * Gets a cell in the table by column and row IDs.\n\t\t * @param key - A key that uniquely distinguishes a cell in the table, represented as a combination of the column ID and row ID.\n\t\t * @privateRemarks TODO: add overload that takes row and column nodes.\n\t\t */\n\t\tgetCell(key: CellKey): TreeNodeFromImplicitAllowedTypes<TCellSchema> | undefined;\n\n\t\t/**\n\t\t * Inserts a column into the table.\n\t\t * @throws Throws an error if the column is already in the tree, or if the specified index is out of range.\n\t\t */\n\t\tinsertColumn(\n\t\t\tparams: InsertColumnParameters<\n\t\t\t\tInsertableTreeNodeFromImplicitAllowedTypes<TColumnSchema>\n\t\t\t>,\n\t\t): TreeNodeFromImplicitAllowedTypes<TColumnSchema>;\n\n\t\t/**\n\t\t * Inserts 0 or more rows into the table.\n\t\t * @throws Throws an error if any of the rows are already in the tree, or if the specified index is out of range.\n\t\t */\n\t\tinsertRows(\n\t\t\tparams: InsertRowsParameters<InsertableTreeNodeFromImplicitAllowedTypes<TRowSchema>>,\n\t\t): TreeNodeFromImplicitAllowedTypes<TRowSchema>[];\n\n\t\t/**\n\t\t * Sets the cell at the specified location in the table.\n\t\t * @remarks To remove a cell, call {@link TableSchema.ITable.removeCell} instead.\n\t\t * @privateRemarks TODO: add overload that takes column/row nodes?\n\t\t */\n\t\tsetCell(\n\t\t\tparams: SetCellParameters<InsertableTreeNodeFromImplicitAllowedTypes<TCellSchema>>,\n\t\t): void;\n\n\t\t/**\n\t\t * Removes the specified column from the table.\n\t\t * @remarks Note: this does not remove any cells from the table's rows.\n\t\t * @privateRemarks\n\t\t * TODO:\n\t\t * - Policy for when the column is not in the table.\n\t\t * - Actually remove corresponding cells from table rows.\n\t\t */\n\t\tremoveColumn: (column: TreeNodeFromImplicitAllowedTypes<TColumnSchema>) => void;\n\n\t\t/**\n\t\t * Removes 0 or more rows from the table.\n\t\t * @privateRemarks TODO: policy for when 1 or more rows are not in the table.\n\t\t */\n\t\tremoveRows: (rows: readonly TreeNodeFromImplicitAllowedTypes<TRowSchema>[]) => void;\n\n\t\t/**\n\t\t * Removes all rows from the table.\n\t\t */\n\t\tremoveAllRows: () => void;\n\n\t\t/**\n\t\t * Removes the cell at the specified location in the table.\n\t\t * @privateRemarks TODO: add overload that takes column/row nodes?\n\t\t */\n\t\tremoveCell: (key: CellKey) => void;\n\t}\n\n\t/**\n\t * Factory for creating new table schema without specifying row or column schema.\n\t * @internal\n\t */\n\texport function createTable<\n\t\tconst TInputScope extends string | undefined,\n\t\tconst TCell extends ImplicitAllowedTypes,\n\t>(\n\t\tinputSchemaFactory: SchemaFactoryAlpha<TInputScope>,\n\t\t_cellSchema: TCell,\n\t): ReturnType<typeof createTableInternal<TInputScope, TCell>>;\n\t/**\n\t * Factory for creating new table schema without specifyint row schema\n\t * @internal\n\t */\n\texport function createTable<\n\t\tconst TInputScope extends string | undefined,\n\t\tconst TCell extends ImplicitAllowedTypes,\n\t\tconst TColumn extends ColumnSchemaBase<TInputScope>,\n\t>(\n\t\tinputSchemaFactory: SchemaFactoryAlpha<TInputScope>,\n\t\t_cellSchema: TCell,\n\t\tcolumnSchema: TColumn,\n\t): ReturnType<typeof createTableInternal<TInputScope, TCell, TColumn>>;\n\t/**\n\t * Factory for creating new table schema.\n\t * @internal\n\t */\n\texport function createTable<\n\t\tconst TInputScope extends string | undefined,\n\t\tconst TCell extends ImplicitAllowedTypes,\n\t\tconst TColumn extends ColumnSchemaBase<TInputScope>,\n\t\tconst TRow extends RowSchemaBase<TInputScope, TCell, TColumn>,\n\t>(\n\t\tinputSchemaFactory: SchemaFactoryAlpha<TInputScope>,\n\t\t_cellSchema: TCell,\n\t\tcolumnSchema: TColumn,\n\t\trowSchema: TRow,\n\t): ReturnType<typeof createTableInternal<TInputScope, TCell, TColumn, TRow>>;\n\texport function createTable<\n\t\tconst TInputScope extends string | undefined,\n\t\tconst TCell extends ImplicitAllowedTypes,\n\t\tconst TColumn extends ColumnSchemaBase<TInputScope>,\n\t\tconst TRow extends RowSchemaBase<TInputScope, TCell, TColumn>,\n\t>(\n\t\tinputSchemaFactory: SchemaFactoryAlpha<TInputScope>,\n\t\t_cellSchema: TCell,\n\t\tcolumnSchema?: TColumn,\n\t\trowSchema?: TRow,\n\t): TreeNodeSchema {\n\t\tconst column = columnSchema ?? createColumn(inputSchemaFactory);\n\t\treturn createTableInternal(\n\t\t\tinputSchemaFactory,\n\t\t\t_cellSchema,\n\t\t\tcolumn as TColumn,\n\t\t\trowSchema ?? (createRow(inputSchemaFactory, _cellSchema, column) as TRow),\n\t\t);\n\t}\n\n\t/**\n\t * Factory for creating new table schema.\n\t * @system @internal\n\t */\n\t// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is too complex to be reasonable to specify\n\texport function createTableInternal<\n\t\tconst TInputScope extends string | undefined,\n\t\tconst TCell extends ImplicitAllowedTypes,\n\t\tconst TColumn extends ColumnSchemaBase<TInputScope> = ColumnSchemaBase<TInputScope>,\n\t\tconst TRow extends RowSchemaBase<TInputScope, TCell, TColumn> = RowSchemaBase<\n\t\t\tTInputScope,\n\t\t\tTCell,\n\t\t\tTColumn\n\t\t>,\n\t>(\n\t\tinputSchemaFactory: SchemaFactoryAlpha<TInputScope>,\n\t\t_cellSchema: TCell,\n\t\tcolumnSchema: TColumn,\n\t\trowSchema: TRow,\n\t) {\n\t\tconst schemaFactory = inputSchemaFactory.scopedFactory(tableSchemaFactorySubScope);\n\t\ttype Scope = ScopedSchemaName<TInputScope, typeof tableSchemaFactorySubScope>;\n\n\t\ttype CellValueType = TreeNodeFromImplicitAllowedTypes<TCell>;\n\t\ttype CellInsertableType = InsertableTreeNodeFromImplicitAllowedTypes<TCell>;\n\n\t\ttype ColumnValueType = TreeNodeFromImplicitAllowedTypes<TColumn>;\n\t\ttype ColumnInsertableType = InsertableTreeNodeFromImplicitAllowedTypes<TColumn>;\n\n\t\ttype RowValueType = TreeNodeFromImplicitAllowedTypes<TRow>;\n\t\ttype RowInsertableType = InsertableTreeNodeFromImplicitAllowedTypes<TRow>;\n\n\t\t/**\n\t\t * {@link Table} fields.\n\t\t * @remarks Extracted for re-use in returned type signature defined later in this function.\n\t\t * The implicit typing is intentional.\n\t\t */\n\t\tconst tableFields = {\n\t\t\trows: schemaFactory.array(\"Table.rows\", rowSchema),\n\t\t\tcolumns: schemaFactory.array(\"Table.columns\", columnSchema),\n\t\t} as const satisfies Record<string, ImplicitFieldSchema>;\n\n\t\t/**\n\t\t * The Table schema\n\t\t */\n\t\tclass Table\n\t\t\textends schemaFactory.object(\"Table\", tableFields)\n\t\t\timplements ITable<TCell, TColumn, TRow>\n\t\t{\n\t\t\tpublic getColumn(id: string): ColumnValueType | undefined {\n\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the casts.\n\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\treturn this.columns.find((column) => (column as ColumnValueType).id === id) as\n\t\t\t\t\t| ColumnValueType\n\t\t\t\t\t| undefined;\n\t\t\t}\n\n\t\t\tpublic getRow(id: string): RowValueType | undefined {\n\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the casts.\n\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\treturn this.rows.find((_row) => (_row as RowValueType).id === id) as\n\t\t\t\t\t| RowValueType\n\t\t\t\t\t| undefined;\n\t\t\t}\n\n\t\t\tpublic getCell(key: CellKey): CellValueType | undefined {\n\t\t\t\tconst { columnId, rowId } = key;\n\t\t\t\tconst row = this.getRow(rowId);\n\t\t\t\tif (row !== undefined) {\n\t\t\t\t\tconst column = this.getColumn(columnId);\n\t\t\t\t\tif (column !== undefined) {\n\t\t\t\t\t\treturn row.getCell(column);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// If the cell does not exist return undefined\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tpublic insertColumn({\n\t\t\t\tcolumn,\n\t\t\t\tindex,\n\t\t\t}: InsertColumnParameters<ColumnInsertableType>): ColumnValueType {\n\t\t\t\tif (index === undefined) {\n\t\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the cast.\n\t\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\tthis.columns.insertAtEnd(column as any);\n\t\t\t\t} else {\n\t\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the cast.\n\t\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\tthis.columns.insertAt(index, column as any);\n\t\t\t\t}\n\n\t\t\t\t// Inserting the input node into the tree hydrates it, making it usable as a node.\n\t\t\t\treturn column as ColumnValueType;\n\t\t\t}\n\n\t\t\tpublic insertRows({\n\t\t\t\tindex,\n\t\t\t\trows,\n\t\t\t}: InsertRowsParameters<RowInsertableType>): RowValueType[] {\n\t\t\t\tif (index === undefined) {\n\t\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the cast.\n\t\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\tthis.rows.insertAtEnd(TreeArrayNode.spread(rows) as any);\n\t\t\t\t} else {\n\t\t\t\t\t// TypeScript is unable to narrow the types correctly here, hence the cast.\n\t\t\t\t\t// See: https://github.com/microsoft/TypeScript/issues/52144\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t\tthis.rows.insertAt(index, TreeArrayNode.spread(rows) as any);\n\t\t\t\t}\n\n\t\t\t\t// Inserting the input nodes into the tree hydrates them, making them usable as nodes.\n\t\t\t\treturn rows as unknown as RowValueType[];\n\t\t\t}\n\n\t\t\tpublic setCell({ key, cell }: SetCellParameters<CellInsertableType>): void {\n\t\t\t\tconst { columnId, rowId } = key;\n\t\t\t\tconst row = this.getRow(rowId);\n\t\t\t\tif (row !== undefined) {\n\t\t\t\t\tconst column = this.getColumn(columnId);\n\t\t\t\t\tif (column !== undefined) {\n\t\t\t\t\t\trow.setCell(column, cell);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic removeColumn(column: ColumnValueType): void {\n\t\t\t\tconst index = this.columns.indexOf(column);\n\t\t\t\t// If the column is not in the table, do nothing\n\t\t\t\tif (index === -1) return;\n\t\t\t\tthis.columns.removeAt(index);\n\t\t\t}\n\n\t\t\tpublic removeRows(rows: readonly RowValueType[]): void {\n\t\t\t\t// If there are no rows to remove, do nothing\n\t\t\t\tif (rows.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// If there is only one row to remove, remove it\n\t\t\t\tif (rows.length === 1) {\n\t\t\t\t\tconst index = this.rows.indexOf(rows[0] ?? oob());\n\t\t\t\t\tthis.rows.removeAt(index);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// If there are multiple rows to remove, remove them in a transaction\n\t\t\t\t// This is to avoid the performance issues of deleting multiple rows at once\n\t\t\t\tTree.runTransaction(this, () => {\n\t\t\t\t\t// Iterate over the rows and remove them\n\t\t\t\t\tfor (const row of rows) {\n\t\t\t\t\t\tconst index = this.rows.indexOf(row);\n\t\t\t\t\t\tthis.rows.removeAt(index);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tpublic removeAllRows(): void {\n\t\t\t\tthis.rows.removeRange();\n\t\t\t}\n\n\t\t\tpublic removeCell(key: CellKey): void {\n\t\t\t\tconst { columnId, rowId } = key;\n\t\t\t\tconst row = this.getRow(rowId);\n\t\t\t\tif (row !== undefined) {\n\t\t\t\t\tconst column = this.getColumn(columnId);\n\t\t\t\t\tif (column !== undefined) {\n\t\t\t\t\t\trow.removeCell(column);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttype TableValueType = TreeNode &\n\t\t\tITable<TCell, TColumn, TRow> &\n\t\t\tWithType<ScopedSchemaName<Scope, \"Table\">>;\n\t\ttype TableInsertableType = InsertableObjectFromSchemaRecord<typeof tableFields>;\n\n\t\t// Returning SingletonSchema without a type conversion results in TypeScript generating something like `readonly \"__#124291@#brand\": unknown;`\n\t\t// for the private brand field of TreeNode.\n\t\t// This numeric id doesn't seem to be stable over incremental builds, and thus causes diffs in the API extractor reports.\n\t\t// This is avoided by doing this type conversion.\n\t\t// The conversion is done via assignment instead of `as` to get stronger type safety.\n\t\tconst TableSchemaType: TreeNodeSchemaClass<\n\t\t\t/* Name */ ScopedSchemaName<Scope, \"Table\">,\n\t\t\t/* Kind */ NodeKind.Object,\n\t\t\t/* TNode */ TableValueType,\n\t\t\t/* TInsertable */ object & TableInsertableType,\n\t\t\t/* ImplicitlyConstructable */ true,\n\t\t\t/* Info */ typeof tableFields\n\t\t> = Table;\n\n\t\t// Return the table schema\n\t\treturn TableSchemaType;\n\t}\n\n\t/**\n\t * Base row schema type.\n\t * @sealed @system @internal\n\t */\n\texport type TableSchemaBase<\n\t\tTScope extends string | undefined,\n\t\tTCell extends ImplicitAllowedTypes,\n\t\tTColumn extends ColumnSchemaBase<TScope> = ColumnSchemaBase<TScope>,\n\t\tTRow extends RowSchemaBase<TScope, TCell, TColumn> = RowSchemaBase<TScope, TCell, TColumn>,\n\t> = ReturnType<typeof createTable<TScope, TCell, TColumn, TRow>>;\n\n\t// #endregion\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/tree",
3
- "version": "2.32.0",
3
+ "version": "2.33.0-333010",
4
4
  "description": "Distributed tree",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -89,17 +89,17 @@
89
89
  "temp-directory": "nyc/.nyc_output"
90
90
  },
91
91
  "dependencies": {
92
- "@fluid-internal/client-utils": "~2.32.0",
93
- "@fluidframework/container-runtime": "~2.32.0",
94
- "@fluidframework/core-interfaces": "~2.32.0",
95
- "@fluidframework/core-utils": "~2.32.0",
96
- "@fluidframework/datastore-definitions": "~2.32.0",
97
- "@fluidframework/driver-definitions": "~2.32.0",
98
- "@fluidframework/id-compressor": "~2.32.0",
99
- "@fluidframework/runtime-definitions": "~2.32.0",
100
- "@fluidframework/runtime-utils": "~2.32.0",
101
- "@fluidframework/shared-object-base": "~2.32.0",
102
- "@fluidframework/telemetry-utils": "~2.32.0",
92
+ "@fluid-internal/client-utils": "2.33.0-333010",
93
+ "@fluidframework/container-runtime": "2.33.0-333010",
94
+ "@fluidframework/core-interfaces": "2.33.0-333010",
95
+ "@fluidframework/core-utils": "2.33.0-333010",
96
+ "@fluidframework/datastore-definitions": "2.33.0-333010",
97
+ "@fluidframework/driver-definitions": "2.33.0-333010",
98
+ "@fluidframework/id-compressor": "2.33.0-333010",
99
+ "@fluidframework/runtime-definitions": "2.33.0-333010",
100
+ "@fluidframework/runtime-utils": "2.33.0-333010",
101
+ "@fluidframework/shared-object-base": "2.33.0-333010",
102
+ "@fluidframework/telemetry-utils": "2.33.0-333010",
103
103
  "@sinclair/typebox": "^0.34.13",
104
104
  "@tylerbu/sorted-btree-es6": "^1.8.0",
105
105
  "@types/ungap__structured-clone": "^1.2.0",
@@ -109,19 +109,19 @@
109
109
  "devDependencies": {
110
110
  "@arethetypeswrong/cli": "^0.17.1",
111
111
  "@biomejs/biome": "~1.9.3",
112
- "@fluid-internal/mocha-test-setup": "~2.32.0",
113
- "@fluid-private/stochastic-test-utils": "~2.32.0",
114
- "@fluid-private/test-dds-utils": "~2.32.0",
115
- "@fluid-private/test-drivers": "~2.32.0",
112
+ "@fluid-internal/mocha-test-setup": "2.33.0-333010",
113
+ "@fluid-private/stochastic-test-utils": "2.33.0-333010",
114
+ "@fluid-private/test-dds-utils": "2.33.0-333010",
115
+ "@fluid-private/test-drivers": "2.33.0-333010",
116
116
  "@fluid-tools/benchmark": "^0.50.0",
117
117
  "@fluid-tools/build-cli": "^0.55.0",
118
118
  "@fluidframework/build-common": "^2.0.3",
119
119
  "@fluidframework/build-tools": "^0.55.0",
120
- "@fluidframework/container-definitions": "~2.32.0",
121
- "@fluidframework/container-loader": "~2.32.0",
120
+ "@fluidframework/container-definitions": "2.33.0-333010",
121
+ "@fluidframework/container-loader": "2.33.0-333010",
122
122
  "@fluidframework/eslint-config-fluid": "^5.7.3",
123
- "@fluidframework/test-runtime-utils": "~2.32.0",
124
- "@fluidframework/test-utils": "~2.32.0",
123
+ "@fluidframework/test-runtime-utils": "2.33.0-333010",
124
+ "@fluidframework/test-utils": "2.33.0-333010",
125
125
  "@fluidframework/tree-previous": "npm:@fluidframework/tree@2.31.0",
126
126
  "@microsoft/api-extractor": "7.50.1",
127
127
  "@types/diff": "^3.5.1",
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { assert } from "@fluidframework/core-utils/internal";
6
+ import { assert, debugAssert } from "@fluidframework/core-utils/internal";
7
7
 
8
8
  import {
9
9
  type ForestEvents,
@@ -43,6 +43,11 @@ export interface FlexTreeContext {
43
43
  * If false, this context was created for use in a unhydrated tree, and the full document schema is unknown.
44
44
  */
45
45
  isHydrated(): this is FlexTreeHydratedContext;
46
+
47
+ /**
48
+ * If true, none of the nodes in this context can be used.
49
+ */
50
+ isDisposed(): boolean;
46
51
  }
47
52
 
48
53
  /**
@@ -106,9 +111,14 @@ export class Context implements FlexTreeHydratedContext, IDisposable {
106
111
  }
107
112
 
108
113
  public isHydrated(): this is FlexTreeHydratedContext {
114
+ debugAssert(() => !this.disposed || "Disposed");
109
115
  return true;
110
116
  }
111
117
 
118
+ public isDisposed(): boolean {
119
+ return this.disposed;
120
+ }
121
+
112
122
  public get schema(): TreeStoredSchema {
113
123
  return this.checkout.storedSchema;
114
124
  }
@@ -94,6 +94,14 @@ export enum TreeStatus {
94
94
 
95
95
  /**
96
96
  * Is removed and cannot be added back to the original document tree.
97
+ * @remarks
98
+ * Nodes can enter this state for multiple reasons:
99
+ * - The node was removed and nothing (e.g. undo/redo history) kept it from being cleaned up.
100
+ * - The {@link TreeView} was disposed or had a schema change which made the tree incompatible.
101
+ * @privateRemarks
102
+ * There was planned work (AB#17948) to make the first reason a node could become "Deleted" impossible,
103
+ * at least as an opt in feature,
104
+ * by lifetime extending all nodes which are still possible to reach automatically.
97
105
  */
98
106
  Deleted = 2,
99
107
 
@@ -46,46 +46,47 @@ export interface NodeIdentifierManager {
46
46
  export function createNodeIdentifierManager(
47
47
  idCompressor?: IIdCompressor | undefined,
48
48
  ): NodeIdentifierManager {
49
- return {
50
- generateLocalNodeIdentifier: () => {
51
- assert(
52
- idCompressor !== undefined,
53
- 0x6e4 /* Runtime IdCompressor must be available to generate local node identifiers */,
54
- );
55
- return brand(idCompressor.generateCompressedId());
56
- },
57
-
58
- localizeNodeIdentifier: (identifier: StableNodeIdentifier) => {
59
- assert(
60
- idCompressor !== undefined,
61
- 0x6e5 /* Runtime IdCompressor must be available to convert node identifiers */,
62
- );
63
- return brand(idCompressor.recompress(identifier));
64
- },
49
+ return new DefaultNodeIdentifierManager(idCompressor);
50
+ }
65
51
 
66
- stabilizeNodeIdentifier: (identifier: LocalNodeIdentifier) => {
67
- assert(
68
- idCompressor !== undefined,
69
- 0x6e6 /* Runtime IdCompressor must be available to convert node identifiers */,
70
- );
71
- return brand(
72
- // TODO: The assert below is required for type safety but is maybe slow
73
- assertIsStableId(idCompressor.decompress(extractFromOpaque(identifier))),
74
- );
75
- },
76
- tryLocalizeNodeIdentifier: (identifier: string) => {
77
- assert(
78
- idCompressor !== undefined,
79
- 0x6e9 /* Runtime IdCompressor must be available to convert node identifiers */,
80
- );
81
- if (isStableNodeIdentifier(identifier)) {
82
- const compressedIdentifier = idCompressor.tryRecompress(identifier);
83
- if (compressedIdentifier !== undefined) {
84
- return brand(compressedIdentifier);
85
- }
52
+ class DefaultNodeIdentifierManager implements NodeIdentifierManager {
53
+ public constructor(private readonly idCompressor: IIdCompressor | undefined) {}
54
+ public generateLocalNodeIdentifier(): LocalNodeIdentifier {
55
+ assert(
56
+ this.idCompressor !== undefined,
57
+ 0x6e4 /* Runtime IdCompressor must be available to generate local node identifiers */,
58
+ );
59
+ return brand(this.idCompressor.generateCompressedId());
60
+ }
61
+ public localizeNodeIdentifier(identifier: StableNodeIdentifier): LocalNodeIdentifier {
62
+ assert(
63
+ this.idCompressor !== undefined,
64
+ 0x6e5 /* Runtime IdCompressor must be available to convert node identifiers */,
65
+ );
66
+ return brand(this.idCompressor.recompress(identifier));
67
+ }
68
+ public stabilizeNodeIdentifier(identifier: LocalNodeIdentifier): StableNodeIdentifier {
69
+ assert(
70
+ this.idCompressor !== undefined,
71
+ 0x6e6 /* Runtime IdCompressor must be available to convert node identifiers */,
72
+ );
73
+ return brand(
74
+ // TODO: The assert below is required for type safety but is maybe slow
75
+ assertIsStableId(this.idCompressor.decompress(extractFromOpaque(identifier))),
76
+ );
77
+ }
78
+ public tryLocalizeNodeIdentifier(identifier: string): LocalNodeIdentifier | undefined {
79
+ assert(
80
+ this.idCompressor !== undefined,
81
+ 0x6e9 /* Runtime IdCompressor must be available to convert node identifiers */,
82
+ );
83
+ if (isStableNodeIdentifier(identifier)) {
84
+ const compressedIdentifier = this.idCompressor.tryRecompress(identifier);
85
+ if (compressedIdentifier !== undefined) {
86
+ return brand(compressedIdentifier);
86
87
  }
87
- },
88
- };
88
+ }
89
+ }
89
90
  }
90
91
 
91
92
  export function isStableNodeIdentifier(
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/tree";
9
- export const pkgVersion = "2.32.0";
9
+ export const pkgVersion = "2.33.0-333010";
@@ -34,6 +34,8 @@ export class CheckoutFlexTreeView<out TCheckout extends ITreeCheckout = ITreeChe
34
34
  */
35
35
  public readonly flexTree: FlexTreeField;
36
36
 
37
+ private disposed = false;
38
+
37
39
  public constructor(
38
40
  /**
39
41
  * Access non-view schema specific aspects of this branch.
@@ -52,6 +54,9 @@ export class CheckoutFlexTreeView<out TCheckout extends ITreeCheckout = ITreeChe
52
54
  }
53
55
 
54
56
  public [disposeSymbol](): void {
57
+ assert(!this.disposed, "Double disposed");
58
+ this.disposed = true;
59
+
55
60
  for (const anchorNode of this.checkout.forest.anchors) {
56
61
  tryDisposeTreeNode(anchorNode);
57
62
  }
@@ -65,6 +70,7 @@ export class CheckoutFlexTreeView<out TCheckout extends ITreeCheckout = ITreeChe
65
70
  * Any mutations of the new view will not apply to this view until the new view is merged back into this view via `merge()`.
66
71
  */
67
72
  public fork(): CheckoutFlexTreeView<ITreeCheckout & ITreeCheckoutFork> {
73
+ assert(!this.disposed, "disposed");
68
74
  const branch = this.checkout.branch();
69
75
  return new CheckoutFlexTreeView(branch, this.schema, this.nodeKeyManager);
70
76
  }
@@ -3,7 +3,8 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { assert, Lazy, fail } from "@fluidframework/core-utils/internal";
6
+ import { assert, Lazy, fail, debugAssert } from "@fluidframework/core-utils/internal";
7
+ import { UsageError } from "@fluidframework/telemetry-utils/internal";
7
8
  import { createEmitter } from "@fluid-internal/client-utils";
8
9
  import type { Listenable, Off } from "@fluidframework/core-interfaces";
9
10
  import type { InternalTreeNode, TreeNode, Unhydrated } from "./types.js";
@@ -72,7 +73,7 @@ export function tryGetTreeNodeSchema(value: unknown): undefined | TreeNodeSchema
72
73
  /** The {@link HydrationState} of a {@link TreeNodeKernel} before the kernel is hydrated */
73
74
  interface UnhydratedState {
74
75
  off: Off;
75
- innerNode: UnhydratedFlexTreeNode;
76
+ readonly innerNode: UnhydratedFlexTreeNode;
76
77
  }
77
78
 
78
79
  /** The {@link HydrationState} of a {@link TreeNodeKernel} after the kernel is hydrated */
@@ -80,9 +81,9 @@ interface HydratedState {
80
81
  /** The flex node for this kernel (lazy - undefined if it has not yet been demanded) */
81
82
  innerNode?: FlexTreeNode;
82
83
  /** The {@link AnchorNode} that this node is associated with. */
83
- anchorNode: AnchorNode;
84
+ readonly anchorNode: AnchorNode;
84
85
  /** All {@link Off | event deregistration functions} that should be run when the kernel is disposed. */
85
- offAnchorNode: Set<Off>;
86
+ readonly offAnchorNode: Set<Off>;
86
87
  }
87
88
 
88
89
  /** State within a {@link TreeNodeKernel} that is related to the hydration process */
@@ -287,35 +288,46 @@ export class TreeNodeKernel {
287
288
  *
288
289
  * For hydrated nodes it returns a FlexTreeNode backed by the forest.
289
290
  * Note that for "marinated" nodes, this FlexTreeNode exists and returns it: it does not return the MapTreeNode which is the current InnerNode.
291
+ *
292
+ * If `allowDeleted` is false, this will throw a UsageError if the node is deleted.
290
293
  */
291
- public getOrCreateInnerNode(allowFreed = false): InnerNode {
294
+ public getOrCreateInnerNode(allowDeleted = false): InnerNode {
292
295
  if (!isHydrated(this.#hydrationState)) {
296
+ debugAssert(
297
+ () =>
298
+ this.#hydrationState.innerNode?.context.isDisposed() === false ||
299
+ "Unhydrated node should never be disposed",
300
+ );
293
301
  return this.#hydrationState.innerNode; // Unhydrated case
294
302
  }
295
303
 
296
- if (this.#hydrationState.innerNode !== undefined) {
297
- return this.#hydrationState.innerNode; // Cooked case
304
+ if (this.#hydrationState.innerNode === undefined) {
305
+ // Marinated case -> cooked
306
+ const anchorNode = this.#hydrationState.anchorNode;
307
+ // The proxy is bound to an anchor node, but it may or may not have an actual flex node yet
308
+ const flexNode = anchorNode.slots.get(flexTreeSlot);
309
+ if (flexNode !== undefined) {
310
+ // If the flex node already exists, use it...
311
+ this.#hydrationState.innerNode = flexNode;
312
+ } else {
313
+ // ...otherwise, the flex node must be created
314
+ const context =
315
+ anchorNode.anchorSet.slots.get(ContextSlot) ?? fail(0xb41 /* missing context */);
316
+ const cursor = context.checkout.forest.allocateCursor("getFlexNode");
317
+ context.checkout.forest.moveCursorToPath(anchorNode, cursor);
318
+ this.#hydrationState.innerNode = makeTree(context, cursor);
319
+ cursor.free();
320
+ // Calling this is a performance improvement, however, do this only after demand to avoid momentarily having no anchors to anchorNode
321
+ anchorForgetters?.get(this.node)?.();
322
+ if (!allowDeleted) {
323
+ assertFlexTreeEntityNotFreed(this.#hydrationState.innerNode);
324
+ }
325
+ }
298
326
  }
299
327
 
300
- // Marinated case -> cooked
301
- const anchorNode = this.#hydrationState.anchorNode;
302
- // The proxy is bound to an anchor node, but it may or may not have an actual flex node yet
303
- const flexNode = anchorNode.slots.get(flexTreeSlot);
304
- if (flexNode !== undefined) {
305
- // If the flex node already exists, use it...
306
- this.#hydrationState.innerNode = flexNode;
307
- } else {
308
- // ...otherwise, the flex node must be created
309
- const context =
310
- anchorNode.anchorSet.slots.get(ContextSlot) ?? fail(0xb41 /* missing context */);
311
- const cursor = context.checkout.forest.allocateCursor("getFlexNode");
312
- context.checkout.forest.moveCursorToPath(anchorNode, cursor);
313
- this.#hydrationState.innerNode = makeTree(context, cursor);
314
- cursor.free();
315
- // Calling this is a performance improvement, however, do this only after demand to avoid momentarily having no anchors to anchorNode
316
- anchorForgetters?.get(this.node)?.();
317
- if (!allowFreed) {
318
- assertFlexTreeEntityNotFreed(this.#hydrationState.innerNode);
328
+ if (!allowDeleted) {
329
+ if (this.#hydrationState.innerNode.context.isDisposed()) {
330
+ throw new UsageError("Cannot access a Deleted node.");
319
331
  }
320
332
  }
321
333
 
@@ -417,11 +429,15 @@ export const unhydratedFlexTreeNodeToTreeNode =
417
429
  */
418
430
  export const proxySlot = anchorSlot<TreeNode>();
419
431
 
432
+ /**
433
+ * Dispose a TreeNode (if any) for an existing anchor without disposing the anchor.
434
+ */
420
435
  export function tryDisposeTreeNode(anchorNode: AnchorNode): void {
421
436
  const treeNode = anchorNode.slots.get(proxySlot);
422
437
  if (treeNode !== undefined) {
423
438
  const kernel = getKernel(treeNode);
424
439
  kernel.dispose();
440
+ anchorNode.slots.delete(proxySlot);
425
441
  }
426
442
  }
427
443
 
@@ -454,10 +470,12 @@ export function getSimpleContextFromInnerNode(innerNode: InnerNode): Context {
454
470
  *
455
471
  * For hydrated nodes it returns a FlexTreeNode backed by the forest.
456
472
  * Note that for "marinated" nodes, this FlexTreeNode exists and returns it: it does not return the MapTreeNode which is the current InnerNode.
473
+ *
474
+ * If `allowDeleted` is false, this will throw a UsageError if the node is deleted.
457
475
  */
458
- export function getOrCreateInnerNode(treeNode: TreeNode, allowFreed = false): InnerNode {
476
+ export function getOrCreateInnerNode(treeNode: TreeNode, allowDeleted = false): InnerNode {
459
477
  const kernel = getKernel(treeNode);
460
- return kernel.getOrCreateInnerNode(allowFreed);
478
+ return kernel.getOrCreateInnerNode(allowDeleted);
461
479
  }
462
480
 
463
481
  /**
@@ -73,7 +73,7 @@ interface LocationInField {
73
73
  *
74
74
  * Create a `UnhydratedFlexTreeNode` by calling {@link getOrCreate}.
75
75
  */
76
- export class UnhydratedFlexTreeNode implements UnhydratedFlexTreeNode {
76
+ export class UnhydratedFlexTreeNode implements FlexTreeNode {
77
77
  public get schema(): TreeNodeSchemaIdentifier {
78
78
  return this.mapTree.type;
79
79
  }
@@ -277,6 +277,10 @@ export class UnhydratedContext implements FlexTreeContext {
277
277
  public readonly schema: TreeStoredSchema,
278
278
  ) {}
279
279
 
280
+ public isDisposed(): boolean {
281
+ return false;
282
+ }
283
+
280
284
  public isHydrated(): this is FlexTreeHydratedContext {
281
285
  return false;
282
286
  }
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { assert, Lazy, fail } from "@fluidframework/core-utils/internal";
6
+ import { assert, Lazy, fail, debugAssert } from "@fluidframework/core-utils/internal";
7
7
  import { UsageError } from "@fluidframework/telemetry-utils/internal";
8
8
 
9
9
  import type { FieldKey, SchemaPolicy } from "../core/index.js";
@@ -174,6 +174,8 @@ function createFlexKeyMapping(fields: Record<string, ImplicitFieldSchema>): Simp
174
174
  }
175
175
 
176
176
  /**
177
+ * Creates a proxy handler for the given schema.
178
+ *
177
179
  * @param allowAdditionalProperties - If true, setting of unexpected properties will be forwarded to the target object.
178
180
  * Otherwise setting of unexpected properties will error.
179
181
  * TODO: consider implementing this using `Object.preventExtension` instead.
@@ -196,9 +198,9 @@ function createProxyHandler(
196
198
  const handler: ProxyHandler<TreeNode> = {
197
199
  get(target, propertyKey, proxy): unknown {
198
200
  const fieldInfo = schema.flexKeyMap.get(propertyKey);
199
-
200
201
  if (fieldInfo !== undefined) {
201
202
  const flexNode = getOrCreateInnerNode(proxy);
203
+ debugAssert(() => !flexNode.context.isDisposed() || "FlexTreeNode is disposed");
202
204
  const field = flexNode.tryGetField(fieldInfo.storedKey);
203
205
  if (field !== undefined) {
204
206
  return getTreeNodeForField(field);