diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/InclusiveRequiredPropertiesSchema.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/InclusiveRequiredPropertiesSchema.tsx new file mode 100644 index 000000000..18e037f83 --- /dev/null +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/InclusiveRequiredPropertiesSchema.tsx @@ -0,0 +1,140 @@ +import React from 'react'; +import type { JSONSchema } from "json-schema-typed/draft-2020-12" +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; + +import { CreateNodes } from "@theme-original/JSONSchemaViewer/components" +import { + SchemaHierarchyContextProvider, + useSchemaHierarchyContext, +} from "@theme-original/JSONSchemaViewer/contexts" + +export interface Inclusions { + propertyNames: string[]; + schemasByPropertyName: { + [propertyName: string]: { + schema: Exclude; + index: number; + } + } +} + +export interface InclusiveRequiredPropertiesSchemaProps extends Inclusions { +} + +export default function InclusiveRequiredPropertiesSchema({ + propertyNames, + schemasByPropertyName +}: InclusiveRequiredPropertiesSchemaProps): JSX.Element { + const { jsonPointer: currentJsonPointer, level: currentLevel } = + useSchemaHierarchyContext() + + return ( +
+
+ independently-inclusive required properties  + This object may specify any of the following: + + + Depending on which required properties are used, the following + corresponding sub-schemas may apply: + + { + Object.entries(schemasByPropertyName) + .map(([propertyName, { schema, index }]) => ( + + + + + + )) + } + +
+ ); +} + +const isIfThen = ( + schema: JSONSchema +): schema is JSONSchema & { + if: JSONSchema; + then: JSONSchema; +} => + typeof schema !== "boolean" && + "if" in schema && "then" in schema; + +const isSingleRequiredProperty = ( + schema: JSONSchema +): schema is JSONSchema & { + required: [string] +} => + typeof schema !== "boolean" && + "required" in schema && schema.required?.length === 1; + +export function detectInclusiveRequiredProperties(schema: { + allOf: JSONSchema[] +}): Inclusions | undefined { + const { allOf } = schema; + + // every schema in the `allOf` should be structured as an if/then/else, + // where every `if` schema checks only for a single, unique required property + + if (!allOf.every(isIfThen)) { + return; + } + + const ifs = allOf.map(({ if: if_ }) => if_); + + if (!ifs.every(isSingleRequiredProperty)) { + return; + } + + const propertyNames = [...new Set( + ifs.map(({ required: [propertyName] }) => propertyName) + )]; + + // check that property names are unique + if (propertyNames.length !== ifs.length) { + console.debug("property names are not unique"); + return; + } + + + const schemasByPropertyName = ( + allOf as (JSONSchema & { if: { required: [string] }; then: Exclude; })[] + ) + .map( + ( + { + if: { required: [propertyName] }, + then + }, + index + ) => ({ + [propertyName]: { + schema: then, + index + } + }) + ) + .reduce((a, b) => ({ ...a, ...b }), {}); + + return { + propertyNames, + schemasByPropertyName + }; +} + diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/allOfSchema.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/allOfSchema.tsx index a052b8796..22b7174f8 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/allOfSchema.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/allOfSchema.tsx @@ -10,6 +10,10 @@ import ExclusiveRequiredPropertiesSchema, { detectExclusiveRequiredProperties } from "./ExclusiveRequiredPropertiesSchema"; +import InclusiveRequiredPropertiesSchema, { + detectInclusiveRequiredProperties +} from "./InclusiveRequiredPropertiesSchema"; + export default function allOfSchemaWrapper(props: { schema: Exclude & { allOf: JSONSchema[]; } }) { @@ -25,6 +29,11 @@ export default function allOfSchemaWrapper(props: { return } + const inclusions = detectInclusiveRequiredProperties(schema); + if (inclusions) { + return + } + return ( <> diff --git a/schemas/program/context.schema.yaml b/schemas/program/context.schema.yaml index b0dd142f5..18a67db48 100644 --- a/schemas/program/context.schema.yaml +++ b/schemas/program/context.schema.yaml @@ -3,15 +3,37 @@ $id: "schema:ethdebug/format/program/context" title: ethdebug/format/program/context description: | - A schema for representing the information known at compile-time about the - high-level language concerns at a particular point in code execution. + An **ethdebug/format/program/context** object represents compile-time + information about the high-level runtime execution state at a specific point + in a program's bytecode. + + This schema defines the structure for encoding compile-time knowledge about + the high-level runtime state. Contexts are treated as units of information + that may encompass multiple related or unrelated facts about the program's + state. This may include, e.g., source mapping information (via the `"code"` + property) or information about known variable allocations, etc. + + The interpretation of a context depends on its properties and its + relationship to program elements such as instructions or control flow + structures. For example, a context associated with an instruction may + indicate that the specified conditions hold true following the execution of + that instruction. type: object -anyOf: - - $ref: "schema:ethdebug/format/program/context/code" - - $ref: "schema:ethdebug/format/program/context/variables" - - $ref: "schema:ethdebug/format/program/context/remark" +allOf: + - if: + required: ["code"] + then: + $ref: "schema:ethdebug/format/program/context/code" + - if: + required: ["variables"] + then: + $ref: "schema:ethdebug/format/program/context/variables" + - if: + required: ["remark"] + then: + $ref: "schema:ethdebug/format/program/context/remark" unevaluatedProperties: false