diff --git a/schemas/type/base.schema.yaml b/schemas/type/base.schema.yaml
new file mode 100644
index 00000000..88923c86
--- /dev/null
+++ b/schemas/type/base.schema.yaml
@@ -0,0 +1,128 @@
+$schema: "https://json-schema.org/draft/2020-12/schema"
+$id: "schema:ethdebug/format/type/base"
+
+title: ethdebug/format/type/base
+description:
+ Defines the minimally necessary schema for a data type.
+ Types belong to a particular `class` (`"elementary"` or `"complex"`),
+ and are further identified by a particular `kind`.
+type: object
+oneOf:
+ - $ref: "#/$defs/ElementaryType"
+ - $ref: "#/$defs/ComplexType"
+
+$defs:
+ ElementaryType:
+ title: ElementaryType
+ description:
+ Represents an elementary type (one that does not compose other types)
+ type: object
+ properties:
+ class:
+ type: string
+ const: elementary
+ kind:
+ type: string
+ contains:
+ not:
+ description:
+ "**Elementary types must not specify a `contains` field
+ (to make it easier to discriminate elementary vs. complex)**"
+ required:
+ - kind
+ examples:
+ - kind: uint
+ bits: 256
+
+ ComplexType:
+ title: ComplexType
+ description:
+ Represents a complex type, one that composes other types (e.g., arrays,
+ structs, mappings)
+ type: object
+ properties:
+ class:
+ type: string
+ const: complex
+ description: Indicates that this is a complex type
+ kind:
+ type: string
+ description: The specific kind of complex type, e.g., array or struct
+ contains:
+ title: ComplexType.contains
+ oneOf:
+ - $ref: "#/$defs/TypeWrapper"
+ - $ref: "#/$defs/TypeWrapperArray"
+ - $ref: "#/$defs/TypeWrapperObject"
+ required:
+ - kind
+ - contains
+ examples:
+ - kind: array
+ contains:
+ type:
+ kind: uint
+ bits: 256
+ - kind: struct
+ contains:
+ - member: x
+ type:
+ kind: uint
+ bits: 256
+ - member: y
+ type:
+ kind: uint
+ bits: 256
+ - kind: mapping
+ contains:
+ key:
+ type:
+ kind: address
+ payable: true
+ value:
+ type:
+ kind: uint
+ bits: 256
+
+ TypeReference:
+ title: '{ "id": ... }'
+ description: A reference to a known type by ID
+ type: object
+ properties:
+ id:
+ type:
+ - string
+ - number
+ additionalProperties: false
+ required:
+ - id
+
+ TypeWrapper:
+ title: '{ "type": ... }'
+ description:
+ A wrapper around a type. Defines a `"type"` field that may include a full
+ Type representation or a reference to a known Type by ID. Note that this
+ schema permits additional properties on the same object.
+ type: object
+ properties:
+ type:
+ oneOf:
+ - $ref: "schema:ethdebug/format/type/base"
+ - $ref: "#/$defs/TypeReference"
+ required:
+ - type
+
+ TypeWrapperArray:
+ title: '{ "type": ... }[]'
+ description: A list of wrapped types, where the wrapper may add fields
+ type: array
+ items:
+ $ref: "#/$defs/TypeWrapper"
+
+ TypeWrapperObject:
+ title: '{ "key": { "type": ... }, ... }'
+ description:
+ A key-value mapping of wrapped types, where the wrapper may add fields
+ type: object
+ additionalProperties:
+ $ref: "#/$defs/TypeWrapper"
diff --git a/web/docusaurus.config.ts b/web/docusaurus.config.ts
index 92a6eb20..0c4b127b 100644
--- a/web/docusaurus.config.ts
+++ b/web/docusaurus.config.ts
@@ -1,4 +1,5 @@
import {themes as prismThemes} from 'prism-react-renderer';
+import path from "path";
import type {Config} from '@docusaurus/types';
import type * as Preset from '@docusaurus/preset-classic';
import type { Configuration } from "webpack";
@@ -53,6 +54,25 @@ const config: Config = {
};
},
+ async function ignoreBuffer(context, options) {
+ return {
+ name: "ignore-buffer",
+ configureWebpack(config: Configuration) {
+ return {
+ resolve: {
+ alias: {
+ react: path.resolve('./node_modules/react'),
+ },
+ fallback: {
+ buffer: false
+ }
+ }
+ };
+ }
+ }
+
+ },
+
// Used to maintain separate spec/ directory, outside the core docs/
[
'@docusaurus/plugin-content-docs',
@@ -157,6 +177,9 @@ const config: Config = {
prism: {
theme: prismThemes.github,
darkTheme: prismThemes.dracula,
+ additionalLanguages: [
+ "json"
+ ],
},
} satisfies Preset.ThemeConfig,
};
diff --git a/web/spec/schema/_category_.json b/web/spec/type/_category_.json
similarity index 83%
rename from web/spec/schema/_category_.json
rename to web/spec/type/_category_.json
index facdbe72..d3684fa3 100644
--- a/web/spec/schema/_category_.json
+++ b/web/spec/type/_category_.json
@@ -1,5 +1,5 @@
{
- "label": "Schema",
+ "label": "Type schemas",
"position": 3,
"link": {
"type": "generated-index",
diff --git a/web/spec/type/base.mdx b/web/spec/type/base.mdx
new file mode 100644
index 00000000..50fb6272
--- /dev/null
+++ b/web/spec/type/base.mdx
@@ -0,0 +1,400 @@
+---
+sidebar_position: 3
+---
+
+import SchemaViewer from "@site/src/components/SchemaViewer";
+import TOCInline from '@theme/TOCInline';
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+import yaml from "yaml-template";
+
+# ethdebug/format/type/base
+
+:::warning
+The schema on this page is extended by other, more specific schemas as part of
+the larger **ethdebug/format** specification. These other schemas specify the
+representation of many common kinds of types (e.g. including signed/unsigned
+integers, arrays, structs, mappings, etc.). In order to adhere to this format
+fully, compilers that represent known types **should** do so with the
+appropriate more-specific schema.
+
+Please see the [**ethdebug/format/type**](/spec/type) schema for representing
+these supported types.
+:::
+
+This format defines this base schema (**ethdebug/format/type/base**) for
+representing data types from high-level languages. These types may be
+user-defined or supplied as native data types in a language. This schema
+affords the representation of complex/parametric types, whose definition
+composes other types (e.g., arrays and structs, which contain at least one
+underlying type).
+
+This base schema itself is designed to be extended by other schemas in this
+format. It serves to specify what is _minimally necessary_ for a type to be
+a valid representation (i.e., all type representations **must** adhere to at
+least this base schema).
+
+
+
+## Key concepts
+
+The **ethdebug/format/type/base** schema includes definitions for a few
+concepts that are worth highlighting here.
+
+### Types are organized by `kind`
+
+:::info[Example: Boolean type]
+```json
+{
+ "kind": "bool"
+}
+```
+:::
+
+An **ethdebug/format/type/base** type representation is a JSON object with a
+`kind` field containing a string value.
+
+This field is intended for use by other **ethdebug/format** schemas, which
+reserve specific string values for the various `kind`s of types that
+this format supports, and for use by implementers of compilers and debuggers
+in situations where coordinating outside this specification is necessary or
+beneficial.
+
+`kind` is a required field for all type representations.
+
+The primary purpose for the `kind` field is to discriminate type objects into
+the appropriate corresponding subschema for a well-understood family of type.
+Although **ethdebug/format/type/base** does not impose any constraints on
+objects based on the `kind` field, it includes this field so as to encourage
+the one-to-one pairing between values for this field and corresponding
+subschemas.
+
+In other words: when extending this schema, ensure there exists exactly one
+corresponding subschema for each defined value of `kind`.
+
+### Elementary vs. complex types
+
+Type representations in this schema fall into one of two `class`es: either
+`"elementary"` or `"complex"`. Type representations express this disinction in
+two ways (the optional `"class"` field, and the absence or existence of a
+`"contains"` field).
+
+- Elementary types do not compose any other types. For example, `uint256` is an
+ elementary type. `string` may be an elementary type for languages that whose
+ semantics treat strings differently than simply an array of characters (like
+ Solidity does).
+
+- Complex types compose at least one other type. For instance, `uint256[]` is
+ an array type that composes an elementary type. Complex types in this schema
+ are polymorphic in how they represent this composition; see
+ [below](#complextypes-contains-field) for information about complex types'
+ `"contains"` field.
+
+### Type wrappers and type references
+
+This schema defines the concept of a type wrapper and the related concept of a
+type reference.
+
+Type wrappers serve to encapsulate a type representation alongside other fields
+in the same object, and to facilitate discriminating which polymorphic form is
+used for a particular complex type.
+
+Type wrappers are any object of the form
+`{ "type": , ...otherProperties }`, where `` is either a complete
+type representation or a reference to another type by ID.
+
+
+Example type wrapper with complete type representation
+
+```javascript
+// from a struct type (which defines member types)
+{
+ "member": "beneficiary",
+ "type": {
+ "kind": "address"
+ }
+}
+```
+
+
+
+Example type wrapper with reference by ID
+
+```javascript
+{
+ "type": {
+ "id": ""
+ }
+}
+```
+
+
+
+
+Note that **ethdebug/format/type/base** places no restriction on IDs other than
+that they must be either a number or a string. Other components of this format
+at-large may impose restrictions, however.
+
+#### Type reference schema
+
+A type reference is an object containing the single `"id"` field. This field
+must be a string or a number.
+
+
+
+#### Type wrapper schema
+
+
+ typeof item === "object" &&
+ !("$schema" in item) &&
+ item["$ref"] === "#/$defs/Type"}
+ transform={
+ ({ $ref, ...rest }, root) => ({
+ ...rest,
+ type: "object",
+ title: root.$defs.Type.title + " [RECURSIVE]",
+ description: "The root Type schema"
+ })
+ }
+ />
+
+### ComplexType's `"contains"` field
+
+Complex types inherently compose at least one other type and may do so in one
+of three forms:
+- Complex types may compose exactly one other type
+- Complex types may compose an ordered list of other types
+- Complex types may compose an object mapping of specific other types by key
+As described [above](#type-wrappers-and-type-references), complex types compose
+other types. This composition occurs inside the `"contains"` field for all
+complex types.
+
+#### Example complex types to show different forms
+
+
+
+ This is an example array type, which composes exactly one other type.
+
+ ```json
+ {
+ "kind": "array",
+ "contains": {
+ "type": {
+ "kind": "uint",
+ "bits": 256
+ }
+ }
+ }
+ ```
+
+
+ This is an example array type, which composes an ordered list of member
+ types.
+
+ ```json
+ {
+ "kind": "struct",
+ "contains": [{
+ "member": "balance",
+ "type": {
+ "kind": "uint",
+ "bits": 256
+ }
+ }, {
+ "member": "scoreSheet",
+ "type": {
+ "id": ""
+ }
+ }]
+ }
+ ```
+
+ In this example, please note how this struct type represents member names
+ with a `"member"` field alongside the `"type"` field, and note how the
+ value of `"type"` can be either a complete representation or a reference
+ object in the form of `{ id }`.
+
+
+ This is an example mapping type, which composes an object mapping of types
+ by key.
+ ```json
+ {
+ "kind": "mapping",
+ "contains": {
+ "key": {
+ "type": {
+ "kind": "address"
+ }
+ },
+ "value": {
+ "type": {
+ "kind": "uint",
+ "bits": 256
+ }
+ }
+ }
+ }
+ ```
+
+
+
+## Full base schema
+
+
+ typeof item === "object" &&
+ !("$schema" in item) &&
+ item["$ref"] === "schema:ethdebug/format/type/base"}
+ transform={
+ ({ $ref, ...rest }, root) => ({
+ ...rest,
+ type: "object",
+ title: root.title + " [RECURSIVE]",
+ description: "The root Type schema"
+ })
+ }
+ />
+## Example schema extensions for particular types
+
+These examples show valid schemas that extend **ethdebug/format/types/base**
+for particular kinds of types.
+
+_**Note**: These are just examples and may not
+correspond to the canonical **ethdebug/format/type** schema._
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/spec/type/overview.mdx b/web/spec/type/overview.mdx
new file mode 100644
index 00000000..cb7bfbf2
--- /dev/null
+++ b/web/spec/type/overview.mdx
@@ -0,0 +1,98 @@
+---
+sidebar_position: 1
+---
+
+# Overview
+
+:::tip
+**ethdebug/format/type** defines how to write data types as JSON.
+
+Debuggers critically rely on having representations of the data types
+used by a piece of code. This information is used to highlight code display,
+offer links to where user-defined types are defined, and to render runtime
+values correctly.
+
+For a quick introduction to type representations, please see these example
+JSON values:
+
+
+A valid type representation
+
+```json
+{
+ "kind": "uint",
+ "bits": 256
+}
+```
+
+
+
+
+An invalid type representation
+
+```json
+"uh, some kind of number"
+```
+
+
+
+
+:::
+
+
+This format defines schemas for representing the data types allowable in a
+supporting high-level language.
+
+JSON values that adhere to this schema may (for example) represent a particular
+`uint` type (like `uint256`), a `struct` type with a particular set of member
+fields, a particular `mapping` type from a certain key type to a certain value
+type, and so on.
+
+This schema is broadly divided into two sections:
+1. A canonical Type schema
+ ([**ethdebug/format/type**](/spec/type)), which includes
+ subschemas for included known types.
+
+ When adhering to this format, this schema is considered **sufficient** for
+ representing any supported type.
+
+2. A base Type schema
+ ([**ethdebug/format/type/base**](/spec/type)), which specifies a
+ minimal definition of any type, known or unknown.
+
+ When adhering to this format, this schema is considered **necessary** for
+ representing any supported type.
+
+In other words:
+
+- Compilers adhering to this format **should** use the canonical
+ **ethdebug/format/type** schema when representing known types
+ (e.g., uints, arrays, structs, etc.).
+
+- Compilers **must** still adhere to the **ethdebug/format/type/base** schema
+ when representing types not known to this format.
+
+:::note
+Any representation adhering to the former also adheres to the latter,
+since **ethdebug/format/type** extends **ethdebug/format/type/base**.
+:::
+
+:::info
+To highlight one purpose behind this separation, consider that this format
+seeks to be complete enough to be useful _and_ flexible enough to afford
+extension.
+
+While **ethdebug/format/type** aims to cover all of the available kinds of
+types available in EVM languages today, languages in the future may offer
+additional kinds of types. **ethdebug/format/type/base** serves to address
+this concern.
+:::
+
+
diff --git a/web/spec/type/type.mdx b/web/spec/type/type.mdx
new file mode 100644
index 00000000..99c17d99
--- /dev/null
+++ b/web/spec/type/type.mdx
@@ -0,0 +1,21 @@
+---
+sidebar_position: 2
+---
+
+import SchemaViewer from "@site/src/components/SchemaViewer";
+import { Collapsible, CreateTypes } from "@theme/JSONSchemaViewer/components";
+import { schemas } from "@site/src/loadSchema";
+
+# ethdebug/format/type [placeholder]
+
+:::note
+
+This schema remains unspecified. Please see the Type schemas
+[Overview](/spec/schema/type/overview) for more information on how these
+schemas will be organized, and/or please review the
+[**ethdebug/format/type/base** schema](/spec/schema/type/base) that is intended
+to serve as base subschema for **ethdebug/format/type**.
+
+We appreciate your interest in these developing efforts.
+
+:::
diff --git a/web/src/components/SchemaViewer.tsx b/web/src/components/SchemaViewer.tsx
index c06a1129..08cbc7ef 100644
--- a/web/src/components/SchemaViewer.tsx
+++ b/web/src/components/SchemaViewer.tsx
@@ -1,23 +1,96 @@
import JSONSchemaViewer from "@theme/JSONSchemaViewer";
+import CodeBlock from "@theme/CodeBlock";
import { loadSchema } from "@site/src/loadSchema";
+import ReactMarkdown from "react-markdown";
export interface SchemaViewerProps {
- schema: string;
+ schema: string | object;
pointer?: string;
+ detect?: (item: object) => boolean;
+ transform?: (item: object, root: object) => object;
+}
+
+
+export const transformObject = (
+ obj: object,
+ predicate: (item: object) => boolean,
+ transform: (item: object, root: object) => object
+): object => {
+ const process = (currentObj: object): object => {
+ if (predicate(currentObj)) {
+ return transform(currentObj, obj);
+ }
+
+ if (typeof currentObj !== 'object' || currentObj === null) {
+ return currentObj;
+ }
+
+ // Using Array.isArray to differentiate between array and object
+ if (Array.isArray(currentObj)) {
+ return currentObj.map(item => process(item));
+ } else {
+ return Object.keys(currentObj).reduce((acc, key) => {
+ acc[key] = process(currentObj[key]);
+ return acc;
+ }, {});
+ }
+ };
+
+ return process(obj);
}
export default function SchemaViewer({
- schema,
- pointer = ""
+ schema: schemaName,
+ pointer = "",
+ detect = () => false,
+ transform = (x) => x
}: SchemaViewerProps): JSX.Element {
+ const rawSchema = typeof schemaName === "string"
+ ? loadSchema(schemaName)
+ : schemaName;
+ const schema = transformObject(
+ rawSchema,
+ detect,
+ transform
+ );
+
return (
{
+ const schema = loadSchema(uri.toString());
+ return schema;
+
+ }
+ }
+ }
}}
viewerOptions={{
- showExamples: true
+ showExamples: true,
+ ValueComponent: ({ value }) => {
+ // deal with simple types first
+ if ([
+ "string",
+ "number",
+ "bigint",
+ "boolean"
+ ].includes(typeof value)) {
+ return {
+ (value as string | number | bigint | boolean).toString()
+ }
;
+ }
+
+ // for complex types use a whole CodeBlock
+ return {`${
+ JSON.stringify(value, undefined, 2)
+ }`};
+ },
+ DescriptionComponent: ({description}) =>
+
}} />
);
}
diff --git a/web/src/loadSchema.ts b/web/src/loadSchema.ts
index 8ba99f1e..7dcff92f 100644
--- a/web/src/loadSchema.ts
+++ b/web/src/loadSchema.ts
@@ -1,4 +1,8 @@
+import typeBaseSchemaYaml from "../../schemas/type/base.schema.yaml";
+
+
export const schemas = [
+ typeBaseSchemaYaml,
].map(schema => ({
[schema.$id]: schema
})).reduce((a, b) => ({ ...a, ...b }), {});