You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Cleanup related to allowUnknownOptionalFields (microsoft#25074)
## Description
Change and clarify limitations related to alpha features
allowUnknownOptionalFields and importVerbose
See changeset for user facing details.
Internally this cleans up some debt where schema policy was being used
in ways that it was not intended.
## Breaking Changes
See changeset.
Change and clarify limitations related to alpha features allowUnknownOptionalFields and importVerbose
7
+
8
+
[allowUnknownOptionalFields](https://fluidframework.com/docs/api/fluid-framework/schemafactoryobjectoptions-interface#allowunknownoptionalfields-propertysignature) currently has some limitations.
9
+
To mitigate some bugs, [importVerbose](https://fluidframework.com/docs/api/fluid-framework/treealpha-interface#importverbose-methodsignature) has dropped support for unknown optional fields.
10
+
Previously `importVerbose` would tolerate some unknown optional fields, but could not validate they comply with the document stored schema.
11
+
This could cause some crashes, and likely document corruption.
12
+
This support has been removed: now trying to create nodes containing unknown optional fields via `importVerbose` will throw a `UsageError`.
13
+
There is no longer a way to create and insert nodes which contain subtrees for which there is no schema.
14
+
15
+
Ideally `exportVerbose` and `importVerbose` could be used to round trip data while optionally preserving unknown optional fields, but this is currently not working and thus not supported.
16
+
17
+
If exporting using [useStoredKeys](https://fluidframework.com/docs/api/fluid-framework/treeencodingoptions-interface#usestoredkeys-propertysignature), the unknown optional fields will be preserved but may not be able to be imported.
18
+
If exporting not using `useStoredKeys`, a known bug currently causes an assertion to fail.
Copy file name to clipboardExpand all lines: packages/dds/tree/src/feature-libraries/default-schema/schemaChecker.ts
+5-8Lines changed: 5 additions & 8 deletions
Original file line number
Diff line number
Diff line change
@@ -79,14 +79,11 @@ export function isNodeInSchema(
79
79
}
80
80
uncheckedFieldsFromNode.delete(fieldKey);
81
81
}
82
-
// The node has fields that we did not check as part of looking at every field defined in the node's schema
83
-
if(
84
-
uncheckedFieldsFromNode.size!==0&&
85
-
// TODO: AB#43547: This check is wrong. If a given view schema allows an unknown optional field, that does NOT mean the stored schema should allow unknown:
86
-
// In-fact, any data the view schema does not know about must still comply with the stored schema:
87
-
// if this were not the case schema evolution could not add any fields since they might already have out of schema data.
// The node has fields that we did not check as part of looking at every field defined in the node's schema.
83
+
// Since this is testing compatibility with a stored schema (not view schema), "allowUnknownOptionalFields" does not exist at this layer.
84
+
// Code using this with a stored schema derived from a view schema rather than the document can be problematic because it may be missing unknown fields that the actual document has.
85
+
// Other schema evolution features like "staged" allowed types will likely cause similar issues elsewhere in this checker.
Copy file name to clipboardExpand all lines: packages/dds/tree/src/shared-tree/treeAlpha.ts
+8Lines changed: 8 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -263,6 +263,14 @@ export interface TreeAlpha {
263
263
* Construct tree content compatible with a field defined by the provided `schema`.
264
264
* @param schema - The schema for what to construct. As this is an {@link ImplicitFieldSchema}, a {@link FieldSchema}, {@link TreeNodeSchema} or {@link AllowedTypes} array can be provided.
265
265
* @param data - The data used to construct the field content. See {@link (TreeAlpha:interface).(exportVerbose:1)}.
266
+
* @remarks
267
+
* This currently does not support input containing {@link SchemaFactoryObjectOptions.allowUnknownOptionalFields| unknown optional fields}.
268
+
* @privateRemarks
269
+
* See TODOs in {@link TreeEncodingOptions}.
270
+
*
271
+
* TODO: clarify how this handles out of schema data.
272
+
* Does it robustly validate? How do you use it with schema evolution features like staged allowed types and allowUnknownOptionalFields? Which errors are deferred until insertion/hydration?
273
+
* Ensure whatever policy is chosen is documented, enforces, tested and applied consistently to all import code paths.
// TODO: AB#43548: Using a stored schema from the possibly unhydrated flex tree context does not handle schema evolution features like "allowUnknownOptionalFields".
60
61
constmaybeError=isFieldInSchema(
61
62
mapTrees,
62
63
flexSchema.rootFieldSchema,
@@ -80,27 +81,45 @@ export function createFromCursor<const TSchema extends ImplicitFieldSchema>(
80
81
/**
81
82
* Construct an {@link UnhydratedFlexTreeNode} from a cursor in Nodes mode.
82
83
* @remarks
83
-
* This does not validate the node is in schema.
84
+
* This does not fully validate the node is in schema, but does throw UsageErrors for some cases of out-of-schema content.
85
+
*
86
+
* Does not support unknown optional fields: will throw a UsageError if the field is not in schema.
87
+
* This cannot easily be fixed as this code requires a schema for each subtree to process, and none is available for unknown optional fields.
// Check for unexpected fields before recursing into children:
104
+
// Code which hits this case is very likely to also use an unknown type in the unexpected field, which would give a more confusing error message.
105
+
// This case is detected here to improve error quality.
106
+
// Also note that if using the view schema from above to suppress this error for unknownOptionalFields, that would not provide a way to handle unknown types in those fields:
107
+
// they would still error, but with that more confusing message about unknown types.
108
+
thrownewUsageError(
109
+
// Using JSON.stringify to handle quoting and escaping since both key and identifier can technically contain quotes themselves.
110
+
`Field ${JSON.stringify(cursor.getFieldKey())} is not defined in the schema ${JSON.stringify(schema.identifier)}.`,
0 commit comments