Skip to content

Commit

Permalink
Merge pull request #85 from ethdebug/better-schema-extensions
Browse files Browse the repository at this point in the history
Improve schema extension rendering
  • Loading branch information
gnidan committed Apr 11, 2024
2 parents 574bac6 + 2465a29 commit 0568ebc
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 13 deletions.
11 changes: 11 additions & 0 deletions packages/web/src/contexts/SchemaContext.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import { useContext, createContext } from "react";
import type { JSONSchema } from "json-schema-typed/draft-2020-12";

import type { SchemaInfo } from "@ethdebug/format";
import type { SchemaIndex } from "@site/src/schemas";

export type JSONSchemaWithInternalIdKeys =
| boolean
| (
& Exclude<JSONSchema, boolean>
& {
[internalIdKey]: string;
}
);

export interface SchemaContextValue {
rootSchemaInfo?: SchemaInfo;
schemaIndex: SchemaIndex;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import React from 'react';
import CreateTypes from "@theme-original/JSONSchemaViewer/components/CreateTypes";
import CreateNodes from '@theme-original/JSONSchemaViewer/components/CreateNodes';
import type { JSONSchema } from "json-schema-typed/draft-2020-12";
import { useSchemaHierarchyContext } from "@theme-original/JSONSchemaViewer/contexts";
import { useSchemaContext, internalIdKey } from "@site/src/contexts/SchemaContext";
import {
useSchemaContext,
internalIdKey,
type JSONSchemaWithInternalIdKeys as JSONSchema
} from "@site/src/contexts/SchemaContext";
import Link from "@docusaurus/Link";

import UnnecessaryCompositionSchema, {
detectUnnecessaryComposition
} from "./UnnecessaryComposition";

export default function CreateNodesWrapper(props: {
schema: Exclude<JSONSchema, boolean> & {
[internalIdKey]: string
}
schema: Exclude<JSONSchema, boolean>
}) {
const { level } = useSchemaHierarchyContext();
const { schemaIndex } = useSchemaContext();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import React from "react";
import type { JSONSchema } from "json-schema-typed/draft-2020-12";
import Link from "@docusaurus/Link";
import CreateNodes from "@theme/JSONSchemaViewer/components/CreateNodes";
import CreateEdge from "@theme-original/JSONSchemaViewer/components/CreateEdge";
import { SchemaHierarchyComponent } from "@theme-original/JSONSchemaViewer/contexts"
import { Collapsible } from "@theme/JSONSchemaViewer/components";
import { GenerateFriendlyName, QualifierMessages } from "@theme/JSONSchemaViewer/utils";
import { internalIdKey } from "@site/src/contexts/SchemaContext";
import {
useSchemaContext,
internalIdKey,
type JSONSchemaWithInternalIdKeys
} from "@site/src/contexts/SchemaContext";
import type { JSONSchema } from "json-schema-typed/draft-2020-12";
import { CreateDescription } from "@theme/JSONSchemaViewer/JSONSchemaElements";
import { useJSVOptionsContext } from "@theme/JSONSchemaViewer/contexts"

export interface UnnecessaryComposition {
schemaWithoutUnnecessaryComposition: Exclude<JSONSchema, boolean>;
schemaWithoutUnnecessaryComposition: Exclude<JSONSchemaWithInternalIdKeys, boolean>;
unnecessaryCompositionKeyword: "allOf" | "oneOf" | "anyOf";
unnecessarilyComposedSchema: JSONSchema;
unnecessarilyComposedSchema: JSONSchemaWithInternalIdKeys;
}

export function detectUnnecessaryComposition(
schema: JSONSchema
schema: JSONSchemaWithInternalIdKeys
): UnnecessaryComposition | undefined {
if (typeof schema === "boolean") {
return;
Expand All @@ -37,7 +42,7 @@ export function detectUnnecessaryComposition(
} = schema;

const [unnecessarilyComposedSchema] =
composition as [JSONSchema] /* (we know this from filter above) */;
composition as [JSONSchemaWithInternalIdKeys] /* (we know this from filter above) */;

return {
unnecessarilyComposedSchema,
Expand All @@ -55,6 +60,7 @@ export default function UnnecessaryCompositionSchema({
unnecessarilyComposedSchema
}: UnnecessaryCompositionSchemaProps): JSX.Element {
const jsvOptions = useJSVOptionsContext();
const { schemaIndex } = useSchemaContext();

// treat the unnecessary composition to represent the extension of a base
// schema, where the unnecessarily composed schema is the base
Expand All @@ -65,7 +71,31 @@ export default function UnnecessaryCompositionSchema({
semantics
} = separateDocumentationFromSemantics(extensionSchema);

if (Object.keys(semantics).length === 0) {
// due to a limitation of docusaurus-json-schema-plugin, use of the `type`
// field is necessary in order for the plugin to display schema descriptions.
//
// for a given extension schema, check whether the use of the `type` field
// is actually a semantic difference vs. the base schema
const onlyExtendsDocumentation = Object.keys(semantics).length === 0 || (
Object.keys(semantics).length === 1 &&
"type" in semantics &&
typeof baseSchema === "object" &&
"type" in baseSchema &&
((
typeof semantics.type === "string" &&
semantics.type === baseSchema.type
) || (
semantics.type instanceof Array &&
baseSchema.type instanceof Array &&
semantics.type.length === baseSchema.type.length &&
(semantics.type as string[]).every(
type_ =>
(baseSchema.type as string[]).includes(type_)
)
))
);

if (onlyExtendsDocumentation) {
const { description } = documentation;

return <>
Expand All @@ -81,6 +111,29 @@ export default function UnnecessaryCompositionSchema({
</>;
}

const { [internalIdKey]: id } = baseSchema;

if (id && id in schemaIndex) {
const {
href,
title = `${
id.startsWith("schema:")
? id.slice("schema:".length)
: id
} schema`
} = schemaIndex[id as keyof typeof schemaIndex];

return (
<>
<span className="badge badge--info">extensions</span>&nbsp;
This schema extends the <Link to={href}>{title}</Link>.
<p>
<CreateNodes schema={extensionSchema} />
</p>
</>
);
}

return (
<>
<span className="badge badge--info">extensions</span>&nbsp;
Expand Down Expand Up @@ -113,7 +166,7 @@ export default function UnnecessaryCompositionSchema({

function separateDocumentationFromSemantics(schema: JSONSchema): {
documentation: Exclude<JSONSchema, boolean>,
semantics: JSONSchema
semantics: Exclude<JSONSchema, boolean>
} {
if (typeof schema === "boolean") {
return {
Expand Down

0 comments on commit 0568ebc

Please sign in to comment.