Skip to content

Commit 69a755e

Browse files
Deprecate types in tree (#23313)
Add a changeset to deprecate types from @fluidframework/tree. Modify fluid-framework to re-export the non-deprecated APIs from core-interfaces. Added basic test cases which covers importing a type from the three packages: tree, core-interfaces, and fluid-framework. These tests are added under examples. Prior PR: #23183 [ADO#25440](https://dev.azure.com/fluidframework/internal/_workitems/edit/25440)
1 parent 7366d2b commit 69a755e

File tree

11 files changed

+249
-34
lines changed

11 files changed

+249
-34
lines changed

.changeset/ready-seas-ask.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
"@fluidframework/tree": minor
3+
---
4+
---
5+
"section": deprecation
6+
---
7+
8+
Deprecation Notice: Events Interfaces Migrated to `@fluidframework/core-interfaces`
9+
10+
The following interfaces and types are now deprecated in `@fluidframework/tree`. It is recommended to import them from either `@fluidframework/core-interfaces` or `fluid-framework`.
11+
12+
- Listeners
13+
- IsListener
14+
- Listenable
15+
- Off
16+
17+
These deprecated interfaces are planned for removal from `@fluidframework/tree` package in Fluid Framework 3.0 release.

examples/utils/import-testing/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@
3737
"tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist"
3838
},
3939
"dependencies": {
40+
"@fluid-internal/client-utils": "workspace:~",
4041
"@fluidframework/core-interfaces": "workspace:~",
4142
"@fluidframework/runtime-utils": "workspace:~",
42-
"@fluidframework/tree": "workspace:~"
43+
"@fluidframework/tree": "workspace:~",
44+
"fluid-framework": "workspace:~"
4345
},
4446
"devDependencies": {
4547
"@biomejs/biome": "~1.9.3",
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*!
2+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3+
* Licensed under the MIT License.
4+
*/
5+
6+
/**
7+
* The test cases below ensure that type can be successfully imported from all three packages — tree, core-interfaces, and fluid-framework and validate that the imports work as expected.
8+
* The plan is to remove types {@link @fluidframework/tree#Listenable}, {@link @fluidframework/tree#IsListener}, {@link @fluidframework/tree#Listeners} and {@link @fluidframework/tree#Off}
9+
* from `@fluidframework/tree` in Fluid Framework 3.0 and instead import them from `fluid-framework` or `@fluidframework/core-interfaces`,
10+
*/
11+
12+
import { strict as assert } from "node:assert";
13+
14+
import { createEmitter } from "@fluid-internal/client-utils";
15+
import type { Listenable as Listenable_Interfaces } from "@fluidframework/core-interfaces";
16+
import type { Listenable as Listenable_Tree } from "@fluidframework/tree";
17+
import type { Listenable as Listenable_Framework } from "fluid-framework";
18+
19+
describe("Test events type imports", () => {
20+
it("Trigger loaded event using core-interfaces import", async () => {
21+
const emitter = new MyCompositionClassInterfaces();
22+
let count = 0;
23+
emitter.on("loaded", () => {
24+
count += 1;
25+
});
26+
27+
emitter.triggerLoad();
28+
assert.strictEqual(count, 1);
29+
});
30+
31+
it("Trigger loaded event using tree import", async () => {
32+
const emitter = new MyCompositionClassTree();
33+
let count = 1;
34+
emitter.on("loaded", () => {
35+
count += 1;
36+
});
37+
38+
emitter.triggerLoad();
39+
assert.strictEqual(count, 2);
40+
});
41+
42+
it("Trigger loaded event using fluid-framework import", async () => {
43+
const emitter = new MyCompositionClassFramework();
44+
let count = 2;
45+
emitter.on("loaded", () => {
46+
count += 1;
47+
});
48+
49+
emitter.triggerLoad();
50+
assert.strictEqual(count, 3);
51+
});
52+
});
53+
54+
/**
55+
* A set of events with their handlers.
56+
*/
57+
interface MyEvents {
58+
loaded: () => void;
59+
computed: () => number;
60+
}
61+
62+
/**
63+
* Example of composing over {@link CustomEventEmitter}.
64+
*/
65+
export class MyCompositionClassTree implements Listenable_Tree<MyEvents> {
66+
private readonly events = createEmitter<MyEvents>();
67+
68+
private load(): number[] {
69+
this.events.emit("loaded");
70+
const results: number[] = this.events.emitAndCollect("computed");
71+
return results;
72+
}
73+
74+
public triggerLoad(): void {
75+
this.load();
76+
}
77+
78+
public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {
79+
return this.events.on(eventName, listener);
80+
}
81+
82+
public off<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): void {
83+
return this.events.off(eventName, listener);
84+
}
85+
}
86+
87+
/**
88+
* Example of composing over {@link CustomEventEmitter}.
89+
*/
90+
export class MyCompositionClassFramework implements Listenable_Framework<MyEvents> {
91+
private readonly events = createEmitter<MyEvents>();
92+
93+
private load(): number[] {
94+
this.events.emit("loaded");
95+
const results: number[] = this.events.emitAndCollect("computed");
96+
return results;
97+
}
98+
99+
public triggerLoad(): void {
100+
this.load();
101+
}
102+
103+
public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {
104+
return this.events.on(eventName, listener);
105+
}
106+
107+
public off<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): void {
108+
return this.events.off(eventName, listener);
109+
}
110+
}
111+
112+
/**
113+
* Example of composing over {@link CustomEventEmitter}.
114+
*/
115+
export class MyCompositionClassInterfaces implements Listenable_Interfaces<MyEvents> {
116+
private readonly events = createEmitter<MyEvents>();
117+
118+
private load(): number[] {
119+
this.events.emit("loaded");
120+
const results: number[] = this.events.emitAndCollect("computed");
121+
return results;
122+
}
123+
124+
public triggerLoad(): void {
125+
this.load();
126+
}
127+
128+
public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {
129+
return this.events.on(eventName, listener);
130+
}
131+
132+
public off<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): void {
133+
return this.events.off(eventName, listener);
134+
}
135+
}

packages/dds/tree/api-report/tree.alpha.api.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,8 @@ declare namespace InternalTypes {
335335
}
336336
export { InternalTypes }
337337

338-
export { IsListener }
338+
// @public @deprecated
339+
export type IsListener<T> = IsListener_2<T>;
339340

340341
// @alpha
341342
export type IsUnion<T, T2 = T> = T extends unknown ? [T2] extends [T] ? false : true : "error";
@@ -439,9 +440,11 @@ export interface JsonValidator {
439440
// @public
440441
export type LazyItem<Item = unknown> = Item | (() => Item);
441442

442-
export { Listenable }
443+
// @public @deprecated
444+
export type Listenable<T extends object> = Listenable_2<T>;
443445

444-
export { Listeners }
446+
// @public @deprecated
447+
export type Listeners<T extends object> = Listeners_2<T>;
445448

446449
// @public @sealed
447450
export interface MakeNominal {
@@ -507,7 +510,8 @@ type ObjectFromSchemaRecordUnsafe<T extends Unenforced<RestrictiveStringRecord<I
507510
-readonly [Property in keyof T]: TreeFieldFromImplicitFieldUnsafe<T[Property]>;
508511
};
509512

510-
export { Off }
513+
// @public @deprecated
514+
export type Off = Off_2;
511515

512516
// @alpha
513517
export interface ParseOptions<TCustom> {
@@ -810,7 +814,7 @@ export const TreeBeta: {
810814
// @alpha @sealed
811815
export interface TreeBranch extends IDisposable {
812816
dispose(error?: Error): void;
813-
readonly events: Listenable<TreeBranchEvents>;
817+
readonly events: Listenable_2<TreeBranchEvents>;
814818
fork(): TreeBranch;
815819
hasRootSchema<TSchema extends ImplicitFieldSchema>(schema: TSchema): this is TreeViewAlpha<TSchema>;
816820
merge(branch: TreeBranch, disposeMerged?: boolean): void;
@@ -971,7 +975,7 @@ export enum TreeStatus {
971975
// @public @sealed
972976
export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends IDisposable {
973977
readonly compatibility: SchemaCompatibilityStatus;
974-
readonly events: Listenable<TreeViewEvents>;
978+
readonly events: Listenable_2<TreeViewEvents>;
975979
initialize(content: InsertableTreeFieldFromImplicitField<TSchema>): void;
976980
get root(): TreeFieldFromImplicitField<TSchema>;
977981
set root(newRoot: InsertableTreeFieldFromImplicitField<TSchema>);
@@ -982,7 +986,7 @@ export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends ID
982986
// @alpha @sealed
983987
export interface TreeViewAlpha<in out TSchema extends ImplicitFieldSchema | UnsafeUnknownSchema> extends Omit<TreeView<ReadSchema<TSchema>>, "root" | "initialize">, TreeBranch {
984988
// (undocumented)
985-
readonly events: Listenable<TreeViewEvents & TreeBranchEvents>;
989+
readonly events: Listenable_2<TreeViewEvents & TreeBranchEvents>;
986990
// (undocumented)
987991
fork(): ReturnType<TreeBranch["fork"]> & TreeViewAlpha<TSchema>;
988992
// (undocumented)

packages/dds/tree/api-report/tree.beta.api.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ declare namespace InternalTypes {
197197
}
198198
export { InternalTypes }
199199

200-
export { IsListener }
200+
// @public @deprecated
201+
export type IsListener<T> = IsListener_2<T>;
201202

202203
// @public @sealed
203204
export class IterableTreeArrayContent<T> implements Iterable<T> {
@@ -222,9 +223,11 @@ export interface ITreeViewConfiguration<TSchema extends ImplicitFieldSchema = Im
222223
// @public
223224
export type LazyItem<Item = unknown> = Item | (() => Item);
224225

225-
export { Listenable }
226+
// @public @deprecated
227+
export type Listenable<T extends object> = Listenable_2<T>;
226228

227-
export { Listeners }
229+
// @public @deprecated
230+
export type Listeners<T extends object> = Listeners_2<T>;
228231

229232
// @public @sealed
230233
export interface MakeNominal {
@@ -287,7 +290,8 @@ type ObjectFromSchemaRecordUnsafe<T extends Unenforced<RestrictiveStringRecord<I
287290
-readonly [Property in keyof T]: TreeFieldFromImplicitFieldUnsafe<T[Property]>;
288291
};
289292

290-
export { Off }
293+
// @public @deprecated
294+
export type Off = Off_2;
291295

292296
// @public @sealed
293297
export interface ReadonlyArrayNode<out T = TreeNode | TreeLeafValue> extends ReadonlyArray<T>, Awaited<TreeNode & WithType<string, NodeKind.Array>> {
@@ -577,7 +581,7 @@ export enum TreeStatus {
577581
// @public @sealed
578582
export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends IDisposable {
579583
readonly compatibility: SchemaCompatibilityStatus;
580-
readonly events: Listenable<TreeViewEvents>;
584+
readonly events: Listenable_2<TreeViewEvents>;
581585
initialize(content: InsertableTreeFieldFromImplicitField<TSchema>): void;
582586
get root(): TreeFieldFromImplicitField<TSchema>;
583587
set root(newRoot: InsertableTreeFieldFromImplicitField<TSchema>);

packages/dds/tree/api-report/tree.legacy.alpha.api.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ declare namespace InternalTypes {
197197
}
198198
export { InternalTypes }
199199

200-
export { IsListener }
200+
// @public @deprecated
201+
export type IsListener<T> = IsListener_2<T>;
201202

202203
// @public @sealed
203204
export class IterableTreeArrayContent<T> implements Iterable<T> {
@@ -222,9 +223,11 @@ export interface ITreeViewConfiguration<TSchema extends ImplicitFieldSchema = Im
222223
// @public
223224
export type LazyItem<Item = unknown> = Item | (() => Item);
224225

225-
export { Listenable }
226+
// @public @deprecated
227+
export type Listenable<T extends object> = Listenable_2<T>;
226228

227-
export { Listeners }
229+
// @public @deprecated
230+
export type Listeners<T extends object> = Listeners_2<T>;
228231

229232
// @public @sealed
230233
export interface MakeNominal {
@@ -282,7 +285,8 @@ type ObjectFromSchemaRecordUnsafe<T extends Unenforced<RestrictiveStringRecord<I
282285
-readonly [Property in keyof T]: TreeFieldFromImplicitFieldUnsafe<T[Property]>;
283286
};
284287

285-
export { Off }
288+
// @public @deprecated
289+
export type Off = Off_2;
286290

287291
// @public @sealed
288292
export interface ReadonlyArrayNode<out T = TreeNode | TreeLeafValue> extends ReadonlyArray<T>, Awaited<TreeNode & WithType<string, NodeKind.Array>> {
@@ -564,7 +568,7 @@ export enum TreeStatus {
564568
// @public @sealed
565569
export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends IDisposable {
566570
readonly compatibility: SchemaCompatibilityStatus;
567-
readonly events: Listenable<TreeViewEvents>;
571+
readonly events: Listenable_2<TreeViewEvents>;
568572
initialize(content: InsertableTreeFieldFromImplicitField<TSchema>): void;
569573
get root(): TreeFieldFromImplicitField<TSchema>;
570574
set root(newRoot: InsertableTreeFieldFromImplicitField<TSchema>);

packages/dds/tree/api-report/tree.legacy.public.api.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ declare namespace InternalTypes {
197197
}
198198
export { InternalTypes }
199199

200-
export { IsListener }
200+
// @public @deprecated
201+
export type IsListener<T> = IsListener_2<T>;
201202

202203
// @public @sealed
203204
export class IterableTreeArrayContent<T> implements Iterable<T> {
@@ -222,9 +223,11 @@ export interface ITreeViewConfiguration<TSchema extends ImplicitFieldSchema = Im
222223
// @public
223224
export type LazyItem<Item = unknown> = Item | (() => Item);
224225

225-
export { Listenable }
226+
// @public @deprecated
227+
export type Listenable<T extends object> = Listenable_2<T>;
226228

227-
export { Listeners }
229+
// @public @deprecated
230+
export type Listeners<T extends object> = Listeners_2<T>;
228231

229232
// @public @sealed
230233
export interface MakeNominal {
@@ -282,7 +285,8 @@ type ObjectFromSchemaRecordUnsafe<T extends Unenforced<RestrictiveStringRecord<I
282285
-readonly [Property in keyof T]: TreeFieldFromImplicitFieldUnsafe<T[Property]>;
283286
};
284287

285-
export { Off }
288+
// @public @deprecated
289+
export type Off = Off_2;
286290

287291
// @public @sealed
288292
export interface ReadonlyArrayNode<out T = TreeNode | TreeLeafValue> extends ReadonlyArray<T>, Awaited<TreeNode & WithType<string, NodeKind.Array>> {
@@ -561,7 +565,7 @@ export enum TreeStatus {
561565
// @public @sealed
562566
export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends IDisposable {
563567
readonly compatibility: SchemaCompatibilityStatus;
564-
readonly events: Listenable<TreeViewEvents>;
568+
readonly events: Listenable_2<TreeViewEvents>;
565569
initialize(content: InsertableTreeFieldFromImplicitField<TSchema>): void;
566570
get root(): TreeFieldFromImplicitField<TSchema>;
567571
set root(newRoot: InsertableTreeFieldFromImplicitField<TSchema>);

packages/dds/tree/api-report/tree.public.api.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ declare namespace InternalTypes {
197197
}
198198
export { InternalTypes }
199199

200-
export { IsListener }
200+
// @public @deprecated
201+
export type IsListener<T> = IsListener_2<T>;
201202

202203
// @public @sealed
203204
export class IterableTreeArrayContent<T> implements Iterable<T> {
@@ -222,9 +223,11 @@ export interface ITreeViewConfiguration<TSchema extends ImplicitFieldSchema = Im
222223
// @public
223224
export type LazyItem<Item = unknown> = Item | (() => Item);
224225

225-
export { Listenable }
226+
// @public @deprecated
227+
export type Listenable<T extends object> = Listenable_2<T>;
226228

227-
export { Listeners }
229+
// @public @deprecated
230+
export type Listeners<T extends object> = Listeners_2<T>;
228231

229232
// @public @sealed
230233
export interface MakeNominal {
@@ -282,7 +285,8 @@ type ObjectFromSchemaRecordUnsafe<T extends Unenforced<RestrictiveStringRecord<I
282285
-readonly [Property in keyof T]: TreeFieldFromImplicitFieldUnsafe<T[Property]>;
283286
};
284287

285-
export { Off }
288+
// @public @deprecated
289+
export type Off = Off_2;
286290

287291
// @public @sealed
288292
export interface ReadonlyArrayNode<out T = TreeNode | TreeLeafValue> extends ReadonlyArray<T>, Awaited<TreeNode & WithType<string, NodeKind.Array>> {
@@ -561,7 +565,7 @@ export enum TreeStatus {
561565
// @public @sealed
562566
export interface TreeView<in out TSchema extends ImplicitFieldSchema> extends IDisposable {
563567
readonly compatibility: SchemaCompatibilityStatus;
564-
readonly events: Listenable<TreeViewEvents>;
568+
readonly events: Listenable_2<TreeViewEvents>;
565569
initialize(content: InsertableTreeFieldFromImplicitField<TSchema>): void;
566570
get root(): TreeFieldFromImplicitField<TSchema>;
567571
set root(newRoot: InsertableTreeFieldFromImplicitField<TSchema>);

0 commit comments

Comments
 (0)