Skip to content

Commit

Permalink
improvement(tree): Simpler JSON schema in non-polymorphic field cases (
Browse files Browse the repository at this point in the history
…microsoft#22538)

Simplifies the JSON Schema output of `getJsonSchema` for non-polymorphic
field cases from

```json
"anyOf": [
	{
		"$ref": "foo"
	}
]
```

to

```json
"$ref": "foo"
```
  • Loading branch information
Josmithr authored Sep 17, 2024
1 parent ba93cde commit 5f3dc05
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 137 deletions.
12 changes: 5 additions & 7 deletions packages/dds/tree/api-report/tree.alpha.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,15 +200,13 @@ export interface ITreeViewConfiguration<TSchema extends ImplicitFieldSchema = Im

// @alpha @sealed
export interface JsonArrayNodeSchema extends JsonNodeSchemaBase<NodeKind.Array, "array"> {
readonly items: {
anyOf: JsonSchemaRef[];
};
readonly items: JsonFieldSchema;
}

// @alpha @sealed
export interface JsonFieldSchema {
export type JsonFieldSchema = {
readonly anyOf: JsonSchemaRef[];
}
} | JsonSchemaRef;

// @alpha @sealed
export interface JsonLeafNodeSchema extends JsonNodeSchemaBase<NodeKind.Leaf, JsonLeafSchemaType> {
Expand Down Expand Up @@ -256,9 +254,9 @@ export interface JsonSchemaRef {
export type JsonSchemaType = "object" | "array" | JsonLeafSchemaType;

// @alpha @sealed
export interface JsonTreeSchema extends JsonFieldSchema {
export type JsonTreeSchema = JsonFieldSchema & {
readonly $defs: Record<JsonSchemaId, JsonNodeSchema>;
}
};

// @public
export type LazyItem<Item = unknown> = Item | (() => Item);
Expand Down
32 changes: 13 additions & 19 deletions packages/dds/tree/src/simple-tree/api/jsonSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,10 @@ export interface JsonObjectNodeSchema extends JsonNodeSchemaBase<NodeKind.Object
export interface JsonArrayNodeSchema extends JsonNodeSchemaBase<NodeKind.Array, "array"> {
/**
* The kinds of items allowed under the array.
* @remarks Always represented via references to {@link JsonTreeSchema.$defs}.
*
* @see {@link https://json-schema.org/draft/2020-12/json-schema-core#name-items}.
*/
readonly items: {
/**
* The kinds of items allowed under the array.
* @remarks Always represented via references to {@link JsonTreeSchema.$defs}.
* @see {@link https://json-schema.org/draft/2020-12/json-schema-core#name-anyof}.
*/
anyOf: JsonSchemaRef[];
};
readonly items: JsonFieldSchema;
}

/**
Expand Down Expand Up @@ -191,14 +183,16 @@ export type JsonNodeSchema =
* @sealed
* @alpha
*/
export interface JsonFieldSchema {
/**
* The kinds of items allowed under the field.
* @remarks Always represented via references to {@link JsonTreeSchema.$defs}.
* @see {@link https://json-schema.org/draft/2020-12/json-schema-core#name-anyof}.
*/
readonly anyOf: JsonSchemaRef[];
}
export type JsonFieldSchema =
| {
/**
* The kinds of items allowed under the field, for polymorphic types.
* @remarks Always represented via references to {@link JsonTreeSchema.$defs}.
* @see {@link https://json-schema.org/draft/2020-12/json-schema-core#name-anyof}.
*/
readonly anyOf: JsonSchemaRef[];
}
| JsonSchemaRef;

/**
* {@link https://json-schema.org/draft/2020-12/json-schema-core | JSON Schema} representation of a tree schema.
Expand All @@ -221,10 +215,10 @@ export interface JsonFieldSchema {
* @sealed
* @alpha
*/
export interface JsonTreeSchema extends JsonFieldSchema {
export type JsonTreeSchema = JsonFieldSchema & {
/**
* The set of definitions reachable from this schema's root.
* @see {@link https://json-schema.org/draft/2020-12/json-schema-core#name-schema-re-use-with-defs}
*/
readonly $defs: Record<JsonSchemaId, JsonNodeSchema>;
}
};
49 changes: 31 additions & 18 deletions packages/dds/tree/src/simple-tree/api/simpleSchemaToJsonSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License.
*/

import { unreachableCase } from "@fluidframework/core-utils/internal";
import { oob, unreachableCase } from "@fluidframework/core-utils/internal";
import { UsageError } from "@fluidframework/telemetry-utils/internal";
import { ValueSchema } from "../../core/index.js";
import { getOrCreate } from "../../util/index.js";
Expand Down Expand Up @@ -37,15 +37,20 @@ import { NodeKind } from "../core/index.js";
export function toJsonSchema(schema: SimpleTreeSchema): JsonTreeSchema {
const definitions = convertDefinitions(schema.definitions);

const anyOf: JsonSchemaRef[] = [];
const allowedTypes: JsonSchemaRef[] = [];
for (const allowedType of schema.allowedTypes) {
anyOf.push(createSchemaRef(allowedType));
allowedTypes.push(createSchemaRef(allowedType));
}

return {
$defs: definitions,
anyOf,
};
return allowedTypes.length === 1
? {
...(allowedTypes[0] ?? oob()),
$defs: definitions,
}
: {
$defs: definitions,
anyOf: allowedTypes,
};
}

function convertDefinitions(
Expand Down Expand Up @@ -90,12 +95,14 @@ function convertArrayNodeSchema(schema: SimpleArrayNodeSchema): JsonArrayNodeSch
schema.allowedTypes.forEach((type) => {
allowedTypes.push(createSchemaRef(type));
});

const items: JsonFieldSchema =
allowedTypes.length === 1 ? allowedTypes[0] ?? oob() : { anyOf: allowedTypes };

return {
type: "array",
_treeNodeSchemaKind: NodeKind.Array,
items: {
anyOf: allowedTypes,
},
items,
};
}

Expand Down Expand Up @@ -130,14 +137,17 @@ function convertObjectNodeSchema(schema: SimpleObjectNodeSchema): JsonObjectNode
const properties: Record<string, JsonFieldSchema> = {};
const required: string[] = [];
for (const [key, value] of Object.entries(schema.fields)) {
const anyOf: JsonSchemaRef[] = [];
const allowedTypes: JsonSchemaRef[] = [];
for (const allowedType of value.allowedTypes) {
anyOf.push(createSchemaRef(allowedType));
allowedTypes.push(createSchemaRef(allowedType));
}

properties[key] = {
anyOf,
};
properties[key] =
allowedTypes.length === 1
? allowedTypes[0] ?? oob()
: {
anyOf: allowedTypes,
};
if (value.kind === FieldKind.Required) {
required.push(key);
}
Expand All @@ -160,9 +170,12 @@ function convertMapNodeSchema(schema: SimpleMapNodeSchema): JsonMapNodeSchema {
type: "object",
_treeNodeSchemaKind: NodeKind.Map,
patternProperties: {
"^.*$": {
anyOf: allowedTypes,
},
"^.*$":
allowedTypes.length === 1
? allowedTypes[0] ?? oob()
: {
anyOf: allowedTypes,
},
},
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,7 @@ describe("simpleSchemaToJsonSchema", () => {
_treeNodeSchemaKind: NodeKind.Leaf,
},
},
anyOf: [
{
$ref: "#/$defs/test.string",
},
],
$ref: "#/$defs/test.string",
};
assert.deepEqual(actual, expected);

Expand Down Expand Up @@ -83,19 +79,15 @@ describe("simpleSchemaToJsonSchema", () => {
type: "array",
_treeNodeSchemaKind: NodeKind.Array,
items: {
anyOf: [{ $ref: "#/$defs/test.string" }],
$ref: "#/$defs/test.string",
},
},
"test.string": {
type: "string",
_treeNodeSchemaKind: NodeKind.Leaf,
},
},
anyOf: [
{
$ref: "#/$defs/test.array",
},
],
$ref: "#/$defs/test.array",
};
assert.deepEqual(actual, expected);

Expand Down Expand Up @@ -128,19 +120,15 @@ describe("simpleSchemaToJsonSchema", () => {
type: "object",
_treeNodeSchemaKind: NodeKind.Map,
patternProperties: {
"^.*$": { anyOf: [{ $ref: "#/$defs/test.string" }] },
"^.*$": { $ref: "#/$defs/test.string" },
},
},
"test.string": {
type: "string",
_treeNodeSchemaKind: NodeKind.Leaf,
},
},
anyOf: [
{
$ref: "#/$defs/test.map",
},
],
$ref: "#/$defs/test.map",
};
assert.deepEqual(actual, expected);

Expand Down Expand Up @@ -201,12 +189,8 @@ describe("simpleSchemaToJsonSchema", () => {
type: "object",
_treeNodeSchemaKind: NodeKind.Object,
properties: {
foo: {
anyOf: [{ $ref: "#/$defs/test.number" }],
},
bar: {
anyOf: [{ $ref: "#/$defs/test.string" }],
},
foo: { $ref: "#/$defs/test.number" },
bar: { $ref: "#/$defs/test.string" },
},
required: ["bar"],
additionalProperties: false,
Expand All @@ -220,11 +204,7 @@ describe("simpleSchemaToJsonSchema", () => {
_treeNodeSchemaKind: NodeKind.Leaf,
},
},
anyOf: [
{
$ref: "#/$defs/test.object",
},
],
$ref: "#/$defs/test.object",
};
assert.deepEqual(actual, expected);

Expand Down Expand Up @@ -292,9 +272,7 @@ describe("simpleSchemaToJsonSchema", () => {
type: "object",
_treeNodeSchemaKind: NodeKind.Object,
properties: {
id: {
anyOf: [{ $ref: "#/$defs/test.identifier" }],
},
id: { $ref: "#/$defs/test.identifier" },
},
required: [],
additionalProperties: false,
Expand All @@ -304,11 +282,7 @@ describe("simpleSchemaToJsonSchema", () => {
_treeNodeSchemaKind: NodeKind.Leaf,
},
},
anyOf: [
{
$ref: "#/$defs/test.object",
},
],
$ref: "#/$defs/test.object",
};
assert.deepEqual(actual, expected);
});
Expand Down Expand Up @@ -358,11 +332,7 @@ describe("simpleSchemaToJsonSchema", () => {
_treeNodeSchemaKind: NodeKind.Leaf,
},
},
anyOf: [
{
$ref: "#/$defs/test.object",
},
],
$ref: "#/$defs/test.object",
};
assert.deepEqual(actual, expected);
});
Expand Down Expand Up @@ -409,11 +379,7 @@ describe("simpleSchemaToJsonSchema", () => {
_treeNodeSchemaKind: NodeKind.Leaf,
},
},
anyOf: [
{
$ref: "#/$defs/test.recursive-object",
},
],
$ref: "#/$defs/test.recursive-object",
};
assert.deepEqual(actual, expected);

Expand Down
Loading

0 comments on commit 5f3dc05

Please sign in to comment.