@fluidframework/tree 2.1.0-274160 → 2.1.0-276985
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.
- package/README.md +93 -34
- package/api-report/tree.alpha.api.md +0 -3
- package/dist/core/tree/anchorSet.js +2 -2
- package/dist/core/tree/anchorSet.js.map +1 -1
- package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts +1 -1
- package/dist/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
- package/dist/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
- package/dist/feature-libraries/flex-tree/lazyField.d.ts +1 -1
- package/dist/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
- package/dist/feature-libraries/flex-tree/lazyField.js.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeCodecs.js +4 -0
- package/dist/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeFormat.d.ts +4 -0
- package/dist/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +1 -1
- package/dist/feature-libraries/modular-schema/modularChangeFormat.js +4 -0
- package/dist/feature-libraries/modular-schema/modularChangeFormat.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/shared-tree/index.d.ts +1 -1
- package/dist/shared-tree/index.d.ts.map +1 -1
- package/dist/shared-tree/index.js.map +1 -1
- package/dist/shared-tree/schematizingTreeView.d.ts +4 -6
- package/dist/shared-tree/schematizingTreeView.d.ts.map +1 -1
- package/dist/shared-tree/schematizingTreeView.js +7 -9
- package/dist/shared-tree/schematizingTreeView.js.map +1 -1
- package/dist/shared-tree/sharedTree.d.ts +3 -3
- package/dist/shared-tree/sharedTree.d.ts.map +1 -1
- package/dist/shared-tree/sharedTree.js +0 -10
- package/dist/shared-tree/sharedTree.js.map +1 -1
- package/dist/shared-tree/treeApi.js.map +1 -1
- package/dist/shared-tree/treeView.d.ts +13 -6
- package/dist/shared-tree/treeView.d.ts.map +1 -1
- package/dist/shared-tree/treeView.js +0 -2
- package/dist/shared-tree/treeView.js.map +1 -1
- package/dist/simple-tree/arrayNode.d.ts.map +1 -1
- package/dist/simple-tree/arrayNode.js +23 -22
- package/dist/simple-tree/arrayNode.js.map +1 -1
- package/dist/simple-tree/index.d.ts +2 -2
- package/dist/simple-tree/index.d.ts.map +1 -1
- package/dist/simple-tree/index.js +2 -3
- package/dist/simple-tree/index.js.map +1 -1
- package/dist/simple-tree/objectNode.d.ts.map +1 -1
- package/dist/simple-tree/objectNode.js +4 -0
- package/dist/simple-tree/objectNode.js.map +1 -1
- package/dist/simple-tree/proxies.d.ts.map +1 -1
- package/dist/simple-tree/proxies.js +13 -16
- package/dist/simple-tree/proxies.js.map +1 -1
- package/dist/simple-tree/schemaFactory.d.ts +8 -0
- package/dist/simple-tree/schemaFactory.d.ts.map +1 -1
- package/dist/simple-tree/schemaFactory.js +10 -24
- package/dist/simple-tree/schemaFactory.js.map +1 -1
- package/dist/simple-tree/toFlexSchema.d.ts +0 -15
- package/dist/simple-tree/toFlexSchema.d.ts.map +1 -1
- package/dist/simple-tree/toFlexSchema.js +1 -35
- package/dist/simple-tree/toFlexSchema.js.map +1 -1
- package/dist/simple-tree/tree.d.ts +0 -29
- package/dist/simple-tree/tree.d.ts.map +1 -1
- package/dist/simple-tree/tree.js +1 -24
- package/dist/simple-tree/tree.js.map +1 -1
- package/dist/treeFactory.d.ts +1 -1
- package/dist/treeFactory.js +1 -1
- package/dist/treeFactory.js.map +1 -1
- package/dist/util/brandedMap.d.ts +9 -2
- package/dist/util/brandedMap.d.ts.map +1 -1
- package/dist/util/brandedMap.js +3 -4
- package/dist/util/brandedMap.js.map +1 -1
- package/dist/util/nestedMap.d.ts +7 -1
- package/dist/util/nestedMap.d.ts.map +1 -1
- package/dist/util/nestedMap.js +17 -6
- package/dist/util/nestedMap.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/main/compatibility.md +1 -1
- package/docs/main/stored-and-view-schema.md +1 -1
- package/lib/core/tree/anchorSet.js +2 -2
- package/lib/core/tree/anchorSet.js.map +1 -1
- package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts +1 -1
- package/lib/feature-libraries/flex-tree/flexTreeTypes.d.ts.map +1 -1
- package/lib/feature-libraries/flex-tree/flexTreeTypes.js.map +1 -1
- package/lib/feature-libraries/flex-tree/lazyField.d.ts +1 -1
- package/lib/feature-libraries/flex-tree/lazyField.d.ts.map +1 -1
- package/lib/feature-libraries/flex-tree/lazyField.js.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeCodecs.js +4 -0
- package/lib/feature-libraries/modular-schema/modularChangeCodecs.js.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeFormat.d.ts +4 -0
- package/lib/feature-libraries/modular-schema/modularChangeFormat.d.ts.map +1 -1
- package/lib/feature-libraries/modular-schema/modularChangeFormat.js +4 -0
- package/lib/feature-libraries/modular-schema/modularChangeFormat.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/shared-tree/index.d.ts +1 -1
- package/lib/shared-tree/index.d.ts.map +1 -1
- package/lib/shared-tree/index.js +1 -1
- package/lib/shared-tree/index.js.map +1 -1
- package/lib/shared-tree/schematizingTreeView.d.ts +4 -6
- package/lib/shared-tree/schematizingTreeView.d.ts.map +1 -1
- package/lib/shared-tree/schematizingTreeView.js +9 -11
- package/lib/shared-tree/schematizingTreeView.js.map +1 -1
- package/lib/shared-tree/sharedTree.d.ts +3 -3
- package/lib/shared-tree/sharedTree.d.ts.map +1 -1
- package/lib/shared-tree/sharedTree.js +0 -10
- package/lib/shared-tree/sharedTree.js.map +1 -1
- package/lib/shared-tree/treeApi.js.map +1 -1
- package/lib/shared-tree/treeView.d.ts +13 -6
- package/lib/shared-tree/treeView.d.ts.map +1 -1
- package/lib/shared-tree/treeView.js +0 -2
- package/lib/shared-tree/treeView.js.map +1 -1
- package/lib/simple-tree/arrayNode.d.ts.map +1 -1
- package/lib/simple-tree/arrayNode.js +23 -22
- package/lib/simple-tree/arrayNode.js.map +1 -1
- package/lib/simple-tree/index.d.ts +2 -2
- package/lib/simple-tree/index.d.ts.map +1 -1
- package/lib/simple-tree/index.js +2 -2
- package/lib/simple-tree/index.js.map +1 -1
- package/lib/simple-tree/objectNode.d.ts.map +1 -1
- package/lib/simple-tree/objectNode.js +4 -0
- package/lib/simple-tree/objectNode.js.map +1 -1
- package/lib/simple-tree/proxies.d.ts.map +1 -1
- package/lib/simple-tree/proxies.js +14 -17
- package/lib/simple-tree/proxies.js.map +1 -1
- package/lib/simple-tree/schemaFactory.d.ts +8 -0
- package/lib/simple-tree/schemaFactory.d.ts.map +1 -1
- package/lib/simple-tree/schemaFactory.js +11 -25
- package/lib/simple-tree/schemaFactory.js.map +1 -1
- package/lib/simple-tree/toFlexSchema.d.ts +0 -15
- package/lib/simple-tree/toFlexSchema.d.ts.map +1 -1
- package/lib/simple-tree/toFlexSchema.js +0 -33
- package/lib/simple-tree/toFlexSchema.js.map +1 -1
- package/lib/simple-tree/tree.d.ts +0 -29
- package/lib/simple-tree/tree.d.ts.map +1 -1
- package/lib/simple-tree/tree.js +0 -22
- package/lib/simple-tree/tree.js.map +1 -1
- package/lib/treeFactory.d.ts +1 -1
- package/lib/treeFactory.js +1 -1
- package/lib/treeFactory.js.map +1 -1
- package/lib/util/brandedMap.d.ts +9 -2
- package/lib/util/brandedMap.d.ts.map +1 -1
- package/lib/util/brandedMap.js +3 -4
- package/lib/util/brandedMap.js.map +1 -1
- package/lib/util/nestedMap.d.ts +7 -1
- package/lib/util/nestedMap.d.ts.map +1 -1
- package/lib/util/nestedMap.js +17 -6
- package/lib/util/nestedMap.js.map +1 -1
- package/package.json +22 -22
- package/src/core/tree/anchorSet.ts +3 -3
- package/src/feature-libraries/flex-tree/flexTreeTypes.ts +5 -1
- package/src/feature-libraries/flex-tree/lazyField.ts +8 -5
- package/src/feature-libraries/modular-schema/modularChangeCodecs.ts +5 -0
- package/src/feature-libraries/modular-schema/modularChangeFormat.ts +4 -0
- package/src/index.ts +1 -0
- package/src/packageVersion.ts +1 -1
- package/src/shared-tree/index.ts +6 -1
- package/src/shared-tree/schematizingTreeView.ts +14 -21
- package/src/shared-tree/sharedTree.ts +1 -20
- package/src/shared-tree/treeApi.ts +2 -2
- package/src/shared-tree/treeView.ts +14 -8
- package/src/simple-tree/arrayNode.ts +28 -24
- package/src/simple-tree/index.ts +1 -2
- package/src/simple-tree/objectNode.ts +6 -0
- package/src/simple-tree/proxies.ts +22 -20
- package/src/simple-tree/schemaFactory.ts +13 -41
- package/src/simple-tree/toFlexSchema.ts +0 -47
- package/src/simple-tree/tree.ts +0 -37
- package/src/treeFactory.ts +1 -1
- package/src/util/brandedMap.ts +18 -11
- package/src/util/nestedMap.ts +17 -9
|
@@ -20,19 +20,18 @@ import {
|
|
|
20
20
|
defaultSchemaPolicy,
|
|
21
21
|
ContextSlot,
|
|
22
22
|
cursorForMapTreeNode,
|
|
23
|
+
type FlexTreeSchema,
|
|
23
24
|
} from "../feature-libraries/index.js";
|
|
24
25
|
import {
|
|
25
26
|
type FieldSchema,
|
|
26
27
|
type ImplicitFieldSchema,
|
|
27
28
|
type SchemaCompatibilityStatus,
|
|
28
29
|
type InsertableTreeFieldFromImplicitField,
|
|
29
|
-
// eslint-disable-next-line import/no-deprecated
|
|
30
|
-
type TreeConfiguration,
|
|
31
30
|
type TreeFieldFromImplicitField,
|
|
32
31
|
type TreeView,
|
|
33
32
|
type TreeViewEvents,
|
|
34
33
|
getProxyForField,
|
|
35
|
-
|
|
34
|
+
toFlexSchema,
|
|
36
35
|
setField,
|
|
37
36
|
normalizeFieldSchema,
|
|
38
37
|
type InsertableContent,
|
|
@@ -42,12 +41,7 @@ import {
|
|
|
42
41
|
} from "../simple-tree/index.js";
|
|
43
42
|
import { disposeSymbol } from "../util/index.js";
|
|
44
43
|
|
|
45
|
-
import {
|
|
46
|
-
type TreeContent,
|
|
47
|
-
canInitialize,
|
|
48
|
-
ensureSchema,
|
|
49
|
-
initialize,
|
|
50
|
-
} from "./schematizeTree.js";
|
|
44
|
+
import { canInitialize, ensureSchema, initialize } from "./schematizeTree.js";
|
|
51
45
|
import type { TreeCheckout } from "./treeCheckout.js";
|
|
52
46
|
import { CheckoutFlexTreeView } from "./treeView.js";
|
|
53
47
|
|
|
@@ -68,7 +62,7 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
|
|
|
68
62
|
* Undefined iff uninitialized or disposed.
|
|
69
63
|
*/
|
|
70
64
|
private currentCompatibility: SchemaCompatibilityStatus | undefined;
|
|
71
|
-
private readonly
|
|
65
|
+
private readonly flexSchema: FlexTreeSchema;
|
|
72
66
|
public readonly events: Listenable<TreeViewEvents> &
|
|
73
67
|
IEmitter<TreeViewEvents> &
|
|
74
68
|
HasListeners<TreeViewEvents> = createEmitter();
|
|
@@ -90,8 +84,7 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
|
|
|
90
84
|
|
|
91
85
|
public constructor(
|
|
92
86
|
public readonly checkout: TreeCheckout,
|
|
93
|
-
public readonly config:
|
|
94
|
-
TreeConfiguration<TRootSchema> | TreeViewConfiguration<TRootSchema>,
|
|
87
|
+
public readonly config: TreeViewConfiguration<TRootSchema>,
|
|
95
88
|
public readonly nodeKeyManager: NodeKeyManager,
|
|
96
89
|
) {
|
|
97
90
|
const policy = {
|
|
@@ -99,11 +92,9 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
|
|
|
99
92
|
validateSchema: config.enableSchemaValidation,
|
|
100
93
|
};
|
|
101
94
|
this.rootFieldSchema = normalizeFieldSchema(config.schema);
|
|
102
|
-
this.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
});
|
|
106
|
-
this.viewSchema = new ViewSchema(policy, {}, this.flexConfig.schema);
|
|
95
|
+
this.flexSchema = toFlexSchema(config.schema);
|
|
96
|
+
|
|
97
|
+
this.viewSchema = new ViewSchema(policy, {}, this.flexSchema);
|
|
107
98
|
// This must be initialized before `update` can be called.
|
|
108
99
|
this.currentCompatibility = {
|
|
109
100
|
canView: false,
|
|
@@ -144,7 +135,7 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
|
|
|
144
135
|
|
|
145
136
|
prepareContentForHydration(mapTree, this.checkout.forest);
|
|
146
137
|
initialize(this.checkout, {
|
|
147
|
-
schema: this.
|
|
138
|
+
schema: this.flexSchema,
|
|
148
139
|
initialTree: mapTree === undefined ? undefined : cursorForMapTreeNode(mapTree),
|
|
149
140
|
});
|
|
150
141
|
});
|
|
@@ -168,10 +159,12 @@ export class SchematizingSimpleTreeView<in out TRootSchema extends ImplicitField
|
|
|
168
159
|
this.runSchemaEdit(() => {
|
|
169
160
|
const result = ensureSchema(
|
|
170
161
|
this.viewSchema,
|
|
171
|
-
|
|
172
|
-
AllowedUpdateType.SchemaCompatible | AllowedUpdateType.Initialize,
|
|
162
|
+
AllowedUpdateType.SchemaCompatible,
|
|
173
163
|
this.checkout,
|
|
174
|
-
|
|
164
|
+
{
|
|
165
|
+
schema: this.flexSchema,
|
|
166
|
+
initialTree: undefined,
|
|
167
|
+
},
|
|
175
168
|
);
|
|
176
169
|
assert(result, 0x8bf /* Schema upgrade should always work if canUpgrade is set. */);
|
|
177
170
|
});
|
|
@@ -53,9 +53,6 @@ import {
|
|
|
53
53
|
import type {
|
|
54
54
|
ITree,
|
|
55
55
|
ImplicitFieldSchema,
|
|
56
|
-
// eslint-disable-next-line import/no-deprecated
|
|
57
|
-
TreeConfiguration,
|
|
58
|
-
TreeView,
|
|
59
56
|
TreeViewConfiguration,
|
|
60
57
|
} from "../simple-tree/index.js";
|
|
61
58
|
|
|
@@ -322,25 +319,9 @@ export class SharedTree
|
|
|
322
319
|
);
|
|
323
320
|
}
|
|
324
321
|
|
|
325
|
-
public schematize<TRoot extends ImplicitFieldSchema>(
|
|
326
|
-
// eslint-disable-next-line import/no-deprecated
|
|
327
|
-
config: TreeConfiguration<TRoot>,
|
|
328
|
-
): TreeView<TRoot> {
|
|
329
|
-
const view = new SchematizingSimpleTreeView(
|
|
330
|
-
this.checkout,
|
|
331
|
-
config,
|
|
332
|
-
createNodeKeyManager(this.runtime.idCompressor),
|
|
333
|
-
);
|
|
334
|
-
// As a subjective API design choice, we initialize the tree here if it is not already initialized.
|
|
335
|
-
if (view.compatibility.canInitialize === true) {
|
|
336
|
-
view.initialize(config.initialTree());
|
|
337
|
-
}
|
|
338
|
-
return view;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
322
|
public viewWith<TRoot extends ImplicitFieldSchema>(
|
|
342
323
|
config: TreeViewConfiguration<TRoot>,
|
|
343
|
-
):
|
|
324
|
+
): SchematizingSimpleTreeView<TRoot> {
|
|
344
325
|
return new SchematizingSimpleTreeView(
|
|
345
326
|
this.checkout,
|
|
346
327
|
config,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { fail } from "../util/index.js";
|
|
18
18
|
|
|
19
19
|
import { SchematizingSimpleTreeView } from "./schematizingTreeView.js";
|
|
20
|
-
import type {
|
|
20
|
+
import type { ITreeCheckout } from "./treeCheckout.js";
|
|
21
21
|
import { contextToTreeView } from "./treeView.js";
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -445,7 +445,7 @@ export function runTransaction<
|
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
function runTransactionInCheckout<TResult>(
|
|
448
|
-
checkout:
|
|
448
|
+
checkout: ITreeCheckout,
|
|
449
449
|
transaction: () => TResult | typeof rollback,
|
|
450
450
|
preconditions: readonly TransactionConstraint[],
|
|
451
451
|
): TResult | typeof rollback {
|
|
@@ -17,14 +17,12 @@ import { type IDisposable, disposeSymbol } from "../util/index.js";
|
|
|
17
17
|
import type { ITreeCheckout, ITreeCheckoutFork, TreeCheckout } from "./treeCheckout.js";
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* The portion of {@link FlexTreeView} that does not depend on the schema's type.
|
|
21
21
|
* @privateRemarks
|
|
22
|
-
*
|
|
23
|
-
* 1. Once ISharedTreeView is renamed this can become ISharedTreeView.
|
|
24
|
-
* 2. This object should be combined with or accessible from the TreeContext to allow easy access to thinks like branching.
|
|
22
|
+
* Since {@link FlexTreeView}'s schema is invariant, `FlexTreeView<FlexFieldSchema>` does not cover this use case.
|
|
25
23
|
* @internal
|
|
26
24
|
*/
|
|
27
|
-
export interface
|
|
25
|
+
export interface FlexTreeViewGeneric extends IDisposable {
|
|
28
26
|
/**
|
|
29
27
|
* Context for controlling the FlexTree nodes produced from {@link FlexTreeView.flexTree}.
|
|
30
28
|
*
|
|
@@ -40,7 +38,17 @@ export interface FlexTreeView<in out TRoot extends FlexFieldSchema> extends IDis
|
|
|
40
38
|
* This is a non-owning reference: disposing of this view does not impact the branch.
|
|
41
39
|
*/
|
|
42
40
|
readonly checkout: ITreeCheckout;
|
|
41
|
+
}
|
|
43
42
|
|
|
43
|
+
/**
|
|
44
|
+
* An editable view of a (version control style) branch of a shared tree.
|
|
45
|
+
* @privateRemarks
|
|
46
|
+
* TODO:
|
|
47
|
+
* If schema aware APIs are removed from flex tree, this can be combined with {@link FlexTreeViewGeneric}.
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
export interface FlexTreeView<in out TRoot extends FlexFieldSchema>
|
|
51
|
+
extends FlexTreeViewGeneric {
|
|
44
52
|
/**
|
|
45
53
|
* Get a typed view of the tree content using the flex-tree API.
|
|
46
54
|
*/
|
|
@@ -100,6 +108,4 @@ export class CheckoutFlexTreeView<
|
|
|
100
108
|
* Maps the context of every {@link CheckoutFlexTreeView} to the view.
|
|
101
109
|
* In practice, this allows the view or checkout to be obtained from a flex node by first getting the context from the flex node and then using this map.
|
|
102
110
|
*/
|
|
103
|
-
|
|
104
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
105
|
-
export const contextToTreeView = new WeakMap<Context, CheckoutFlexTreeView<any>>();
|
|
111
|
+
export const contextToTreeView = new WeakMap<Context, FlexTreeViewGeneric>();
|
|
@@ -774,22 +774,27 @@ abstract class CustomArrayNodeBase<const T extends ImplicitAllowedTypes>
|
|
|
774
774
|
}
|
|
775
775
|
public moveToStart(sourceIndex: number, source?: TreeArrayNode): void {
|
|
776
776
|
const sourceArray = source ?? this;
|
|
777
|
-
const
|
|
778
|
-
validateIndex(sourceIndex,
|
|
777
|
+
const sourceField = getSequenceField(sourceArray);
|
|
778
|
+
validateIndex(sourceIndex, sourceField, "moveToStart");
|
|
779
779
|
this.moveRangeToIndex(0, sourceIndex, sourceIndex + 1, source);
|
|
780
780
|
}
|
|
781
781
|
public moveToEnd(sourceIndex: number, source?: TreeArrayNode): void {
|
|
782
782
|
const sourceArray = source ?? this;
|
|
783
|
-
const
|
|
784
|
-
validateIndex(sourceIndex,
|
|
783
|
+
const sourceField = getSequenceField(sourceArray);
|
|
784
|
+
validateIndex(sourceIndex, sourceField, "moveToEnd");
|
|
785
785
|
this.moveRangeToIndex(this.length, sourceIndex, sourceIndex + 1, source);
|
|
786
786
|
}
|
|
787
|
-
public moveToIndex(
|
|
787
|
+
public moveToIndex(
|
|
788
|
+
destinationIndex: number,
|
|
789
|
+
sourceIndex: number,
|
|
790
|
+
source?: TreeArrayNode,
|
|
791
|
+
): void {
|
|
788
792
|
const sourceArray = source ?? this;
|
|
789
|
-
const
|
|
790
|
-
|
|
791
|
-
validateIndex(
|
|
792
|
-
|
|
793
|
+
const sourceField = getSequenceField(sourceArray);
|
|
794
|
+
const destinationField = getSequenceField(this);
|
|
795
|
+
validateIndex(destinationIndex, destinationField, "moveToIndex", true);
|
|
796
|
+
validateIndex(sourceIndex, sourceField, "moveToIndex");
|
|
797
|
+
this.moveRangeToIndex(destinationIndex, sourceIndex, sourceIndex + 1, source);
|
|
793
798
|
}
|
|
794
799
|
public moveRangeToStart(
|
|
795
800
|
sourceStart: number,
|
|
@@ -814,41 +819,40 @@ abstract class CustomArrayNodeBase<const T extends ImplicitAllowedTypes>
|
|
|
814
819
|
this.moveRangeToIndex(this.length, sourceStart, sourceEnd, source);
|
|
815
820
|
}
|
|
816
821
|
public moveRangeToIndex(
|
|
817
|
-
|
|
822
|
+
destinationIndex: number,
|
|
818
823
|
sourceStart: number,
|
|
819
824
|
sourceEnd: number,
|
|
820
825
|
source?: TreeArrayNode,
|
|
821
826
|
): void {
|
|
822
|
-
const
|
|
823
|
-
validateIndex(
|
|
824
|
-
validateIndexRange(sourceStart, sourceEnd, source ??
|
|
827
|
+
const destinationField = getSequenceField(this);
|
|
828
|
+
validateIndex(destinationIndex, destinationField, "moveRangeToIndex", true);
|
|
829
|
+
validateIndexRange(sourceStart, sourceEnd, source ?? destinationField, "moveRangeToIndex");
|
|
825
830
|
const sourceField =
|
|
826
831
|
source !== undefined
|
|
827
|
-
?
|
|
828
|
-
?
|
|
832
|
+
? destinationField.isSameAs(getSequenceField(source))
|
|
833
|
+
? destinationField
|
|
829
834
|
: getSequenceField(source)
|
|
830
|
-
:
|
|
835
|
+
: destinationField;
|
|
831
836
|
|
|
832
837
|
// TODO: determine support for move across different sequence types
|
|
833
|
-
if (
|
|
838
|
+
if (destinationField.schema.types !== undefined && sourceField !== destinationField) {
|
|
834
839
|
for (let i = sourceStart; i < sourceEnd; i++) {
|
|
835
|
-
const sourceNode =
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
throw new Error("Type in source sequence is not allowed in destination.");
|
|
840
|
+
const sourceNode = sourceField.boxedAt(i) ?? fail("impossible out of bounds index");
|
|
841
|
+
if (!destinationField.schema.types.has(sourceNode.schema.name)) {
|
|
842
|
+
throw new UsageError("Type in source sequence is not allowed in destination.");
|
|
839
843
|
}
|
|
840
844
|
}
|
|
841
845
|
}
|
|
842
846
|
const movedCount = sourceEnd - sourceStart;
|
|
843
847
|
const sourceFieldPath = sourceField.getFieldPath();
|
|
844
848
|
|
|
845
|
-
const destinationFieldPath =
|
|
846
|
-
|
|
849
|
+
const destinationFieldPath = destinationField.getFieldPath();
|
|
850
|
+
destinationField.context.checkout.editor.move(
|
|
847
851
|
sourceFieldPath,
|
|
848
852
|
sourceStart,
|
|
849
853
|
movedCount,
|
|
850
854
|
destinationFieldPath,
|
|
851
|
-
|
|
855
|
+
destinationIndex,
|
|
852
856
|
);
|
|
853
857
|
}
|
|
854
858
|
}
|
package/src/simple-tree/index.ts
CHANGED
|
@@ -7,7 +7,6 @@ export {
|
|
|
7
7
|
type ITree,
|
|
8
8
|
type TreeView,
|
|
9
9
|
type TreeViewEvents,
|
|
10
|
-
TreeConfiguration,
|
|
11
10
|
TreeViewConfiguration,
|
|
12
11
|
type ITreeViewConfiguration,
|
|
13
12
|
type SchemaCompatibilityStatus,
|
|
@@ -42,7 +41,7 @@ export {
|
|
|
42
41
|
export { SchemaFactory, type ScopedSchemaName } from "./schemaFactory.js";
|
|
43
42
|
export { getFlexNode } from "./proxyBinding.js";
|
|
44
43
|
export { treeNodeApi, type TreeNodeApi, type TreeChangeEvents } from "./treeNodeApi.js";
|
|
45
|
-
export {
|
|
44
|
+
export { toFlexSchema, cursorFromUnhydratedRoot } from "./toFlexSchema.js";
|
|
46
45
|
export type {
|
|
47
46
|
FieldHasDefaultUnsafe,
|
|
48
47
|
ObjectFromSchemaRecordUnsafe,
|
|
@@ -200,6 +200,12 @@ function createProxyHandler(
|
|
|
200
200
|
setField(flexNode.getBoxed(fieldInfo.storedKey), fieldInfo.schema, value);
|
|
201
201
|
return true;
|
|
202
202
|
},
|
|
203
|
+
deleteProperty(target, viewKey): boolean {
|
|
204
|
+
// TODO: supporting delete when it makes sense (custom local fields, and optional field) could be added as a feature in the future.
|
|
205
|
+
throw new UsageError(
|
|
206
|
+
`Object nodes do not support the delete operator. Optional fields can be assigned to undefined instead.`,
|
|
207
|
+
);
|
|
208
|
+
},
|
|
203
209
|
has: (target, viewKey) => {
|
|
204
210
|
return (
|
|
205
211
|
flexKeyMap.has(viewKey) ||
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
type MapTreeNode,
|
|
26
26
|
tryGetMapTreeNode,
|
|
27
27
|
typeNameSymbol,
|
|
28
|
+
isFlexTreeNode,
|
|
28
29
|
} from "../feature-libraries/index.js";
|
|
29
30
|
import { type Mutable, fail, isReadonlyArray } from "../util/index.js";
|
|
30
31
|
|
|
@@ -55,27 +56,28 @@ export function isTreeNode(candidate: unknown): candidate is TreeNode | Unhydrat
|
|
|
55
56
|
* Retrieve the associated proxy for the given field.
|
|
56
57
|
* */
|
|
57
58
|
export function getProxyForField(field: FlexTreeField): TreeNode | TreeValue | undefined {
|
|
59
|
+
function tryToUnboxLeaves(
|
|
60
|
+
flexField: FlexTreeTypedField<
|
|
61
|
+
FlexFieldSchema<typeof FieldKinds.required | typeof FieldKinds.optional>
|
|
62
|
+
>,
|
|
63
|
+
): TreeNode | TreeValue | undefined {
|
|
64
|
+
const maybeUnboxedContent = flexField.content;
|
|
65
|
+
return isFlexTreeNode(maybeUnboxedContent)
|
|
66
|
+
? getOrCreateNodeProxy(maybeUnboxedContent)
|
|
67
|
+
: maybeUnboxedContent;
|
|
68
|
+
}
|
|
58
69
|
switch (field.schema.kind) {
|
|
59
70
|
case FieldKinds.required: {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// inner field.
|
|
65
|
-
return getOrCreateNodeProxy(asValue.boxedContent);
|
|
71
|
+
const typedField = field as FlexTreeTypedField<
|
|
72
|
+
FlexFieldSchema<typeof FieldKinds.required>
|
|
73
|
+
>;
|
|
74
|
+
return tryToUnboxLeaves(typedField);
|
|
66
75
|
}
|
|
67
76
|
case FieldKinds.optional: {
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// inner field.
|
|
73
|
-
|
|
74
|
-
const maybeContent = asValue.boxedContent;
|
|
75
|
-
|
|
76
|
-
// Normally, empty fields are unreachable due to the behavior of 'tryGetField'. However, the
|
|
77
|
-
// root field is a special case where the field is always present (even if empty).
|
|
78
|
-
return maybeContent === undefined ? undefined : getOrCreateNodeProxy(maybeContent);
|
|
77
|
+
const typedField = field as FlexTreeTypedField<
|
|
78
|
+
FlexFieldSchema<typeof FieldKinds.optional>
|
|
79
|
+
>;
|
|
80
|
+
return tryToUnboxLeaves(typedField);
|
|
79
81
|
}
|
|
80
82
|
// TODO: Remove if/when 'FieldNode' is removed.
|
|
81
83
|
case FieldKinds.sequence: {
|
|
@@ -84,9 +86,9 @@ export function getProxyForField(field: FlexTreeField): TreeNode | TreeValue | u
|
|
|
84
86
|
fail("'sequence' field is unexpected.");
|
|
85
87
|
}
|
|
86
88
|
case FieldKinds.identifier: {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
// Identifier fields are just value fields that hold strings
|
|
90
|
+
return (field as FlexTreeTypedField<FlexFieldSchema<typeof FieldKinds.required>>)
|
|
91
|
+
.content as string;
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
default:
|
|
@@ -10,13 +10,7 @@ import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
|
|
|
10
10
|
import type { IFluidHandle as _dummyImport } from "@fluidframework/core-interfaces";
|
|
11
11
|
|
|
12
12
|
import type { TreeValue } from "../core/index.js";
|
|
13
|
-
import {
|
|
14
|
-
type FlexTreeNode,
|
|
15
|
-
type NodeKeyManager,
|
|
16
|
-
type Unenforced,
|
|
17
|
-
isFlexTreeNode,
|
|
18
|
-
isLazy,
|
|
19
|
-
} from "../feature-libraries/index.js";
|
|
13
|
+
import { type NodeKeyManager, type Unenforced, isLazy } from "../feature-libraries/index.js";
|
|
20
14
|
import {
|
|
21
15
|
type RestrictiveReadonlyRecord,
|
|
22
16
|
getOrCreate,
|
|
@@ -170,6 +164,14 @@ export class SchemaFactory<
|
|
|
170
164
|
private readonly structuralTypes: Map<string, TreeNodeSchema> = new Map();
|
|
171
165
|
|
|
172
166
|
/**
|
|
167
|
+
* Construct a SchemaFactory with a given scope.
|
|
168
|
+
* @remarks
|
|
169
|
+
* There are no restrictions on mixing schema from different schema factories:
|
|
170
|
+
* this is encouraged when a single schema references schema from different libraries.
|
|
171
|
+
* If each library exporting schema picks its own globally unique scope for its SchemaFactory,
|
|
172
|
+
* then all schema an application might depend on, directly or transitively,
|
|
173
|
+
* will end up with a unique fully qualified name which is required to refer to it in persisted data and errors.
|
|
174
|
+
*
|
|
173
175
|
* @param scope - Prefix appended to the identifiers of all {@link TreeNodeSchema} produced by this builder.
|
|
174
176
|
* Use of [Reverse domain name notation](https://en.wikipedia.org/wiki/Reverse_domain_name_notation) or a UUIDv4 is recommended to avoid collisions.
|
|
175
177
|
* You may opt out of using a scope by passing `undefined`, but note that this increases the risk of collisions.
|
|
@@ -641,26 +643,12 @@ export class SchemaFactory<
|
|
|
641
643
|
const Name extends TName,
|
|
642
644
|
const T extends Unenforced<ImplicitAllowedTypes>,
|
|
643
645
|
>(name: Name, allowedTypes: T) {
|
|
644
|
-
|
|
646
|
+
const RecursiveArray = this.namedArray(
|
|
645
647
|
name,
|
|
646
648
|
allowedTypes as T & ImplicitAllowedTypes,
|
|
647
649
|
true,
|
|
648
650
|
false,
|
|
649
|
-
)
|
|
650
|
-
public constructor(
|
|
651
|
-
data:
|
|
652
|
-
| Iterable<InsertableTreeNodeFromImplicitAllowedTypes<T & ImplicitAllowedTypes>>
|
|
653
|
-
| FlexTreeNode,
|
|
654
|
-
) {
|
|
655
|
-
if (isFlexTreeNode(data)) {
|
|
656
|
-
// TODO: use something other than `any`
|
|
657
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
658
|
-
super(data as any);
|
|
659
|
-
} else {
|
|
660
|
-
super(data);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
}
|
|
651
|
+
);
|
|
664
652
|
|
|
665
653
|
return RecursiveArray as TreeNodeSchemaClass<
|
|
666
654
|
ScopedSchemaName<TScope, Name>,
|
|
@@ -697,28 +685,12 @@ export class SchemaFactory<
|
|
|
697
685
|
name: Name,
|
|
698
686
|
allowedTypes: T,
|
|
699
687
|
) {
|
|
700
|
-
|
|
688
|
+
const MapSchema = this.namedMap(
|
|
701
689
|
name,
|
|
702
690
|
allowedTypes as T & ImplicitAllowedTypes,
|
|
703
691
|
true,
|
|
704
692
|
false,
|
|
705
|
-
)
|
|
706
|
-
public constructor(
|
|
707
|
-
data:
|
|
708
|
-
| Iterable<
|
|
709
|
-
[string, InsertableTreeNodeFromImplicitAllowedTypes<T & ImplicitAllowedTypes>]
|
|
710
|
-
>
|
|
711
|
-
| FlexTreeNode,
|
|
712
|
-
) {
|
|
713
|
-
if (isFlexTreeNode(data)) {
|
|
714
|
-
// TODO: use something other than `any`
|
|
715
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
716
|
-
super(data as any);
|
|
717
|
-
} else {
|
|
718
|
-
super(new Map(data));
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
}
|
|
693
|
+
);
|
|
722
694
|
|
|
723
695
|
return MapSchema as TreeNodeSchemaClass<
|
|
724
696
|
ScopedSchemaName<TScope, Name>,
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
schemaIsLeaf,
|
|
28
28
|
} from "../feature-libraries/index.js";
|
|
29
29
|
import { normalizeFlexListEager } from "../feature-libraries/typed-schema/flexList.js";
|
|
30
|
-
import type { TreeContent } from "../shared-tree/index.js";
|
|
31
30
|
import { brand, fail, isReadonlyArray, mapIterable } from "../util/index.js";
|
|
32
31
|
|
|
33
32
|
import type { InsertableContent } from "./proxies.js";
|
|
@@ -48,8 +47,6 @@ import {
|
|
|
48
47
|
getStoredKey,
|
|
49
48
|
} from "./schemaTypes.js";
|
|
50
49
|
import { cursorFromNodeData } from "./toMapTree.js";
|
|
51
|
-
// eslint-disable-next-line import/no-deprecated
|
|
52
|
-
import { TreeConfiguration, type TreeViewConfiguration } from "./tree.js";
|
|
53
50
|
|
|
54
51
|
/**
|
|
55
52
|
* Returns a cursor (in nodes mode) for the root node.
|
|
@@ -77,50 +74,6 @@ export function cursorFromUnhydratedRoot(
|
|
|
77
74
|
);
|
|
78
75
|
}
|
|
79
76
|
|
|
80
|
-
/* eslint-disable import/no-deprecated */
|
|
81
|
-
function isTreeConfiguration(
|
|
82
|
-
config: TreeViewConfiguration | TreeConfiguration,
|
|
83
|
-
): config is TreeConfiguration {
|
|
84
|
-
return config instanceof TreeConfiguration;
|
|
85
|
-
}
|
|
86
|
-
/* eslint-enable import/no-deprecated */
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Generates a configuration object (schema + initial tree) for a FlexTree.
|
|
90
|
-
* @param config - Configuration for how to {@link ITree.schematize|schematize} a tree.
|
|
91
|
-
* @param nodeKeyManager - See {@link NodeKeyManager}.
|
|
92
|
-
* @param schemaValidationPolicy - Stored schema and policy for the tree. If the policy specifies
|
|
93
|
-
* `{@link SchemaPolicy.validateSchema} === true`, new content inserted into the tree will be validated using this
|
|
94
|
-
* object.
|
|
95
|
-
* @returns A configuration object for a FlexTree.
|
|
96
|
-
*
|
|
97
|
-
* @privateremarks
|
|
98
|
-
* I wrote these docs without a ton of context, they can probably be improved.
|
|
99
|
-
*/
|
|
100
|
-
export function toFlexConfig(
|
|
101
|
-
// eslint-disable-next-line import/no-deprecated
|
|
102
|
-
config: TreeViewConfiguration | TreeConfiguration,
|
|
103
|
-
nodeKeyManager: NodeKeyManager,
|
|
104
|
-
schemaValidationPolicy: SchemaAndPolicy | undefined = undefined,
|
|
105
|
-
): TreeContent {
|
|
106
|
-
const unhydrated = isTreeConfiguration(config) ? config.initialTree() : undefined;
|
|
107
|
-
const initialTree =
|
|
108
|
-
unhydrated === undefined
|
|
109
|
-
? undefined
|
|
110
|
-
: [
|
|
111
|
-
cursorFromUnhydratedRoot(
|
|
112
|
-
config.schema,
|
|
113
|
-
unhydrated,
|
|
114
|
-
nodeKeyManager,
|
|
115
|
-
schemaValidationPolicy,
|
|
116
|
-
),
|
|
117
|
-
];
|
|
118
|
-
return {
|
|
119
|
-
schema: toFlexSchema(config.schema),
|
|
120
|
-
initialTree,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
77
|
interface SchemaInfo {
|
|
125
78
|
toFlex: () => FlexTreeNodeSchema;
|
|
126
79
|
original: TreeNodeSchema;
|
package/src/simple-tree/tree.ts
CHANGED
|
@@ -133,43 +133,6 @@ export class TreeViewConfiguration<TSchema extends ImplicitFieldSchema = Implici
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
/**
|
|
137
|
-
* Configuration for how to {@link ITree.schematize | schematize} a tree.
|
|
138
|
-
* @sealed @public
|
|
139
|
-
* @deprecated Please migrate to use {@link TreeViewConfiguration} with {@link ITree.viewWith} instead.
|
|
140
|
-
*/
|
|
141
|
-
export class TreeConfiguration<TSchema extends ImplicitFieldSchema = ImplicitFieldSchema> {
|
|
142
|
-
/**
|
|
143
|
-
* If `true`, the tree will validate new content against its stored schema at insertion time
|
|
144
|
-
* and throw an error if the new content doesn't match the expected schema.
|
|
145
|
-
*
|
|
146
|
-
* @defaultValue `false`.
|
|
147
|
-
*
|
|
148
|
-
* @remarks Enabling schema validation has a performance penalty when inserting new content into the tree because
|
|
149
|
-
* additional checks are done. Enable this option only in scenarios where you are ok with that operation being a
|
|
150
|
-
* bit slower.
|
|
151
|
-
*/
|
|
152
|
-
public readonly enableSchemaValidation: boolean;
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* @param schema - The schema which the application wants to view the tree with.
|
|
156
|
-
* @param initialTree - A function that returns the default tree content to initialize the tree with iff the tree is uninitialized
|
|
157
|
-
* (meaning it does not even have any schema set at all).
|
|
158
|
-
* If `initialTree` returns any actual node instances, they should be recreated each time `initialTree` runs.
|
|
159
|
-
* This is because if the config is used a second time any nodes that were not recreated could error since nodes cannot be inserted into the tree multiple times.
|
|
160
|
-
* @param options - Additional options that can be specified when {@link ITree.schematize | schematizing } a tree.
|
|
161
|
-
*/
|
|
162
|
-
public constructor(
|
|
163
|
-
public readonly schema: TSchema,
|
|
164
|
-
public readonly initialTree: () => InsertableTreeFieldFromImplicitField<TSchema>,
|
|
165
|
-
options?: ITreeConfigurationOptions,
|
|
166
|
-
) {
|
|
167
|
-
this.enableSchemaValidation =
|
|
168
|
-
options?.enableSchemaValidation ??
|
|
169
|
-
defaultTreeConfigurationOptions.enableSchemaValidation;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
136
|
/**
|
|
174
137
|
* An editable view of a (version control style) branch of a shared tree based on some schema.
|
|
175
138
|
*
|
package/src/treeFactory.ts
CHANGED
|
@@ -56,7 +56,7 @@ export class TreeFactory implements IChannelFactory<ITree> {
|
|
|
56
56
|
/**
|
|
57
57
|
* SharedTree is a hierarchical data structure for collaboratively editing strongly typed JSON-like trees
|
|
58
58
|
* of objects, arrays, and other data types.
|
|
59
|
-
* @
|
|
59
|
+
* @internal
|
|
60
60
|
*/
|
|
61
61
|
export const SharedTree = configuredSharedTree({});
|
|
62
62
|
|
package/src/util/brandedMap.ts
CHANGED
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import type { Brand } from "./brand.js";
|
|
7
|
+
import type { Opaque } from "./opaque.js";
|
|
6
8
|
import type { Invariant } from "./typeCheck.js";
|
|
7
9
|
import { getOrCreate } from "./utils.js";
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Key in a {@link BrandedMapSubset}.
|
|
13
|
+
* @remarks
|
|
14
|
+
* Due to the `TContent` type parameter being invariant (which it has to be since keys are used to both read and write data),
|
|
15
|
+
* generic collections end up needing to constrain their key's `TContent` to `any`.
|
|
11
16
|
* @internal
|
|
12
17
|
*/
|
|
13
18
|
export type BrandedKey<TKey, TContent> = TKey & Invariant<TContent>;
|
|
@@ -49,16 +54,15 @@ export interface BrandedMapSubset<K extends BrandedKey<unknown, any>> {
|
|
|
49
54
|
|
|
50
55
|
/**
|
|
51
56
|
* Version of {@link getOrCreate} with better typing for {@link BrandedMapSubset}.
|
|
57
|
+
* @privateRemarks
|
|
58
|
+
* Only infers type from key to avoid inferring `any` from map's key.
|
|
52
59
|
*/
|
|
53
|
-
export function getOrCreateSlotContent<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
>(map
|
|
59
|
-
const result: BrandedKeyContent<K> = getOrCreate(map, key, defaultValue);
|
|
60
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
61
|
-
return result;
|
|
60
|
+
export function getOrCreateSlotContent<K, V>(
|
|
61
|
+
map: NoInfer<BrandedMapSubset<BrandedKey<K, V>>>,
|
|
62
|
+
key: BrandedKey<K, V>,
|
|
63
|
+
defaultValue: NoInfer<(key: BrandedKey<K, V>) => V>,
|
|
64
|
+
): V {
|
|
65
|
+
return getOrCreate<BrandedKey<K, V>, V>(map, key, defaultValue);
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
/**
|
|
@@ -72,7 +76,10 @@ let slotCounter = 0;
|
|
|
72
76
|
* Define a strongly typed slot in which data can be stored in a {@link BrandedMapSubset}.
|
|
73
77
|
* @internal
|
|
74
78
|
*/
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
export function brandedSlot<
|
|
80
|
+
// See note on BrandedKey.
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
82
|
+
TSlot extends BrandedKey<number | Opaque<Brand<number, string>>, any>,
|
|
83
|
+
>(): TSlot {
|
|
77
84
|
return slotCounter++ as TSlot;
|
|
78
85
|
}
|