From 07e6d8130069d8beac1f2ed897529a5511a2e32e Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Sat, 6 Jan 2024 03:32:19 -0500 Subject: [PATCH] Draft initial ethdebug/format/type - Define ethdebug/format/type as if/then/else - `if` the object is a known kind, - `then` the object must be a known elementary or complex type - `else` the object must be a valid base type with added constraints - Define ethdebug/format/type/elementary and ethdebug/format/type/elementary/{ uint, int, ufixed, fixed, bool, bytes, string, address, contract, enum } - Define ethdebug/format/type/complex and ethdebug/format/type/complex/{ alias, tuple, array, mapping, struct } - Define ethdebug/format/type/wrapper and ethdebug/format/type/reference to serve as more canonical forms that override the base schema equiv. - Add pages for all the type schemas - Move "key concepts" from base schema page to own page - Document schema overall - Test that all schemas have examples (except for permitted omissions) --- schemas/type.schema.yaml | 59 +++++ schemas/type/base.schema.yaml | 29 +-- schemas/type/complex.schema.yaml | 64 +++++ schemas/type/complex/alias.schema.yaml | 38 +++ schemas/type/complex/array.schema.yaml | 35 +++ schemas/type/complex/mapping.schema.yaml | 40 +++ schemas/type/complex/struct.schema.yaml | 54 ++++ schemas/type/complex/tuple.schema.yaml | 51 ++++ schemas/type/elementary.schema.yaml | 102 ++++++++ schemas/type/elementary/address.schema.yaml | 27 ++ schemas/type/elementary/bool.schema.yaml | 17 ++ schemas/type/elementary/bytes.schema.yaml | 28 ++ schemas/type/elementary/contract.schema.yaml | 51 ++++ schemas/type/elementary/enum.schema.yaml | 30 +++ schemas/type/elementary/fixed.schema.yaml | 33 +++ schemas/type/elementary/int.schema.yaml | 24 ++ schemas/type/elementary/string.schema.yaml | 22 ++ schemas/type/elementary/ufixed.schema.yaml | 34 +++ schemas/type/elementary/uint.schema.yaml | 24 ++ schemas/type/reference.schema.yaml | 16 ++ schemas/type/wrapper.schema.yaml | 41 +++ tests/schemas/examples.test.ts | 121 ++++++--- tests/src/schemas.ts | 110 ++++++-- web/spec/type/_category_.json | 2 +- web/spec/type/base.mdx | 253 ++++--------------- web/spec/type/complex/_category_.json | 8 + web/spec/type/complex/alias.mdx | 12 + web/spec/type/complex/array.mdx | 12 + web/spec/type/complex/mapping.mdx | 12 + web/spec/type/complex/struct.mdx | 12 + web/spec/type/complex/tuple.mdx | 12 + web/spec/type/concepts.mdx | 215 ++++++++++++++++ web/spec/type/elementary/_category_.json | 8 + web/spec/type/elementary/address.mdx | 12 + web/spec/type/elementary/bool.mdx | 12 + web/spec/type/elementary/bytes.mdx | 12 + web/spec/type/elementary/contract.mdx | 12 + web/spec/type/elementary/enum.mdx | 12 + web/spec/type/elementary/fixed.mdx | 12 + web/spec/type/elementary/int.mdx | 12 + web/spec/type/elementary/string.mdx | 12 + web/spec/type/elementary/ufixed.mdx | 12 + web/spec/type/elementary/uint.mdx | 12 + web/spec/type/overview.mdx | 81 +++--- web/spec/type/type.mdx | 24 +- web/src/schemas.ts | 81 ++++++ 46 files changed, 1579 insertions(+), 323 deletions(-) create mode 100644 schemas/type.schema.yaml create mode 100644 schemas/type/complex.schema.yaml create mode 100644 schemas/type/complex/alias.schema.yaml create mode 100644 schemas/type/complex/array.schema.yaml create mode 100644 schemas/type/complex/mapping.schema.yaml create mode 100644 schemas/type/complex/struct.schema.yaml create mode 100644 schemas/type/complex/tuple.schema.yaml create mode 100644 schemas/type/elementary.schema.yaml create mode 100644 schemas/type/elementary/address.schema.yaml create mode 100644 schemas/type/elementary/bool.schema.yaml create mode 100644 schemas/type/elementary/bytes.schema.yaml create mode 100644 schemas/type/elementary/contract.schema.yaml create mode 100644 schemas/type/elementary/enum.schema.yaml create mode 100644 schemas/type/elementary/fixed.schema.yaml create mode 100644 schemas/type/elementary/int.schema.yaml create mode 100644 schemas/type/elementary/string.schema.yaml create mode 100644 schemas/type/elementary/ufixed.schema.yaml create mode 100644 schemas/type/elementary/uint.schema.yaml create mode 100644 schemas/type/reference.schema.yaml create mode 100644 schemas/type/wrapper.schema.yaml create mode 100644 web/spec/type/complex/_category_.json create mode 100644 web/spec/type/complex/alias.mdx create mode 100644 web/spec/type/complex/array.mdx create mode 100644 web/spec/type/complex/mapping.mdx create mode 100644 web/spec/type/complex/struct.mdx create mode 100644 web/spec/type/complex/tuple.mdx create mode 100644 web/spec/type/concepts.mdx create mode 100644 web/spec/type/elementary/_category_.json create mode 100644 web/spec/type/elementary/address.mdx create mode 100644 web/spec/type/elementary/bool.mdx create mode 100644 web/spec/type/elementary/bytes.mdx create mode 100644 web/spec/type/elementary/contract.mdx create mode 100644 web/spec/type/elementary/enum.mdx create mode 100644 web/spec/type/elementary/fixed.mdx create mode 100644 web/spec/type/elementary/int.mdx create mode 100644 web/spec/type/elementary/string.mdx create mode 100644 web/spec/type/elementary/ufixed.mdx create mode 100644 web/spec/type/elementary/uint.mdx diff --git a/schemas/type.schema.yaml b/schemas/type.schema.yaml new file mode 100644 index 00000000..e8dc1899 --- /dev/null +++ b/schemas/type.schema.yaml @@ -0,0 +1,59 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type" + +title: ethdebug/format/type +description: + Canonical representation for all types. +type: object + +if: + type: object + title: Known kind + description: + If `kind` adheres to the set of known kinds defined by this format + properties: + kind: + anyOf: + - $ref: "schema:ethdebug/format/type/elementary#/$defs/Kind" + - $ref: "schema:ethdebug/format/type/complex#/$defs/Kind" + +then: + type: object + title: KnownType + description: + Then the object must adhere to exactly one known kind of type + oneOf: + - $ref: "schema:ethdebug/format/type/elementary" + - $ref: "schema:ethdebug/format/type/complex" + +else: + type: object + description: + Else the object must be a valid **ethdebug/format/type/base** with + additional constraints + allOf: + - $ref: "schema:ethdebug/format/type/base" + - title: Required `class` field + required: + - class + - title: Specialized complex type `contains` field + type: object + if: + description: + If this object is a complex type + properties: + class: + const: complex + then: + description: + Then the `contains` field must adhere to + **ethdebug/format/type/wrapper** schemas, not the + **ethdebug/format/type/base** equivalent. + + (i.e., these additional constraints must apply recursively) + properties: + contains: + oneOf: + - $ref: "schema:ethdebug/format/type/wrapper" + - $ref: "schema:ethdebug/format/type/wrapper#/$defs/Array" + - $ref: "schema:ethdebug/format/type/wrapper#/$defs/Object" diff --git a/schemas/type/base.schema.yaml b/schemas/type/base.schema.yaml index 88923c86..7e4cf577 100644 --- a/schemas/type/base.schema.yaml +++ b/schemas/type/base.schema.yaml @@ -13,7 +13,7 @@ oneOf: $defs: ElementaryType: - title: ElementaryType + title: Base elementary type description: Represents an elementary type (one that does not compose other types) type: object @@ -26,8 +26,8 @@ $defs: contains: not: description: - "**Elementary types must not specify a `contains` field - (to make it easier to discriminate elementary vs. complex)**" + "Elementary types **must not** specify a `contains` field + (to make it easier to discriminate elementary vs. complex)" required: - kind examples: @@ -35,7 +35,7 @@ $defs: bits: 256 ComplexType: - title: ComplexType + title: Base complex type description: Represents a complex type, one that composes other types (e.g., arrays, structs, mappings) @@ -49,7 +49,10 @@ $defs: type: string description: The specific kind of complex type, e.g., array or struct contains: - title: ComplexType.contains + title: Complex type `contains` field + description: + Either a type wrapper, an array of type wrappers, or an object + mapping to type wrappers. oneOf: - $ref: "#/$defs/TypeWrapper" - $ref: "#/$defs/TypeWrapperArray" @@ -84,19 +87,6 @@ $defs: 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: @@ -108,7 +98,8 @@ $defs: type: oneOf: - $ref: "schema:ethdebug/format/type/base" - - $ref: "#/$defs/TypeReference" + - $ref: "schema:ethdebug/format/type/reference" + required: - type diff --git a/schemas/type/complex.schema.yaml b/schemas/type/complex.schema.yaml new file mode 100644 index 00000000..1d0ad57b --- /dev/null +++ b/schemas/type/complex.schema.yaml @@ -0,0 +1,64 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/complex" + +title: ethdebug/format/type/complex +description: + Canonical representation of a complex type + +type: object +properties: + kind: + $ref: "#/$defs/Kind" +required: + - kind + +allOf: + - if: + properties: + kind: + const: alias + then: + $ref: "schema:ethdebug/format/type/complex/alias" + + - if: + properties: + kind: + const: tuple + then: + $ref: "schema:ethdebug/format/type/complex/tuple" + + - if: + properties: + kind: + const: array + then: + $ref: "schema:ethdebug/format/type/complex/array" + + - if: + properties: + kind: + const: mapping + then: + $ref: "schema:ethdebug/format/type/complex/mapping" + + - if: + properties: + kind: + const: struct + then: + $ref: "schema:ethdebug/format/type/complex/struct" + +$defs: + Kind: + title: Known complex kind + description: + A schema for the values of `kind` reserved for known complex types + included in ethdebug/format + type: string + enum: + - alias + - tuple + - array + - mapping + - struct + diff --git a/schemas/type/complex/alias.schema.yaml b/schemas/type/complex/alias.schema.yaml new file mode 100644 index 00000000..072f4697 --- /dev/null +++ b/schemas/type/complex/alias.schema.yaml @@ -0,0 +1,38 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/complex/alias" + +title: ethdebug/format/type/complex/alias +description: + Schema representing a type alias to another type + +type: object +properties: + class: + type: string + const: complex + kind: + type: string + const: alias + contains: + $ref: "schema:ethdebug/format/type/wrapper" + +required: + - kind + - contains + +examples: + - kind: alias + contains: + type: + kind: uint + bits: 256 + + - kind: alias + contains: + type: + kind: array + contains: + type: + class: elementary + kind: super-uint # unsupported type + blits: -256 diff --git a/schemas/type/complex/array.schema.yaml b/schemas/type/complex/array.schema.yaml new file mode 100644 index 00000000..6bdf8524 --- /dev/null +++ b/schemas/type/complex/array.schema.yaml @@ -0,0 +1,35 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/complex/array" + +title: ethdebug/format/type/complex/array +type: object +properties: + class: + type: string + const: complex + kind: + type: string + const: array + contains: + $ref: "schema:ethdebug/format/type/wrapper" + +required: + - kind + - contains + +examples: + - kind: array + contains: + type: + kind: uint + bits: 256 + + - kind: array + contains: + type: + kind: array + contains: + type: + class: elementary + kind: super-uint # unsupported type + blits: -256 diff --git a/schemas/type/complex/mapping.schema.yaml b/schemas/type/complex/mapping.schema.yaml new file mode 100644 index 00000000..3b10098d --- /dev/null +++ b/schemas/type/complex/mapping.schema.yaml @@ -0,0 +1,40 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/complex/mapping" + +title: ethdebug/format/type/complex/mapping +description: + Schema for representing mapping types + +type: object +properties: + class: + type: string + const: complex + kind: + type: string + const: mapping + contains: + type: object + properties: + key: + $ref: "schema:ethdebug/format/type/wrapper" + value: + $ref: "schema:ethdebug/format/type/wrapper" + required: + - key + - value + +required: + - kind + - contains + +examples: + - kind: mapping + contains: + key: + type: + kind: address + value: + type: + kind: uint + bits: 256 diff --git a/schemas/type/complex/struct.schema.yaml b/schemas/type/complex/struct.schema.yaml new file mode 100644 index 00000000..cd3837b0 --- /dev/null +++ b/schemas/type/complex/struct.schema.yaml @@ -0,0 +1,54 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/complex/struct" + +title: ethdebug/format/type/complex/struct +description: + Schema for representing struct types + +type: object +properties: + class: + type: string + const: complex + kind: + type: string + const: struct + contains: + type: array + items: + $ref: "#/$defs/MemberField" + +required: + - kind + - contains + +examples: + - kind: struct + contains: + - name: x + type: + kind: uint + bits: 128 + - name: y + type: + kind: uint + bits: 128 + +$defs: + MemberField: + type: object + title: MemberField + description: + A schema representing a member field inside a struct type. This is an + **ethdebug/format/type/wrapper** with additional fields. + allOf: + - $ref: "schema:ethdebug/format/type/wrapper" + - type: object + title: Additional fields + description: + An object with optional `name` property for identifying named struct + member fields. **Note** that this language does not specify that a + struct must be consistent in its use of naming for all fields or none + properties: + name: + type: string diff --git a/schemas/type/complex/tuple.schema.yaml b/schemas/type/complex/tuple.schema.yaml new file mode 100644 index 00000000..742ac656 --- /dev/null +++ b/schemas/type/complex/tuple.schema.yaml @@ -0,0 +1,51 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/complex/tuple" + +title: ethdebug/format/type/complex/tuple +description: + Schema for representing tuple types + +type: object +properties: + class: + type: string + const: complex + kind: + type: string + const: tuple + contains: + type: array + items: + title: '{ name?, type }' + allOf: + - $ref: "schema:ethdebug/format/type/wrapper" + - properties: + name: + type: string + description: + For tuple types where positional element types are identified + by name, this field **should** include this information. + + This schema makes no restriction on whether all-or-no elements + have names, and so this field may be sparse across elements of + the same tuple. + +required: + - kind + - contains + +examples: + - # empty tuple type + kind: tuple + contains: [] + + - kind: tuple + contains: + - name: x + type: + kind: uint + bits: 128 + - name: y + type: + kind: uint + bits: 128 diff --git a/schemas/type/elementary.schema.yaml b/schemas/type/elementary.schema.yaml new file mode 100644 index 00000000..e2ba1301 --- /dev/null +++ b/schemas/type/elementary.schema.yaml @@ -0,0 +1,102 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary" + +title: ethdebug/format/type/elementary +description: + Canonical representation of an elementary type + +type: object +properties: + kind: + $ref: "#/$defs/Kind" +required: + - kind + +allOf: + - if: + properties: + kind: + const: uint + then: + $ref: "schema:ethdebug/format/type/elementary/uint" + + - if: + properties: + kind: + const: int + then: + $ref: "schema:ethdebug/format/type/elementary/int" + + - if: + properties: + kind: + const: bool + then: + $ref: "schema:ethdebug/format/type/elementary/bool" + + - if: + properties: + kind: + const: bytes + then: + $ref: "schema:ethdebug/format/type/elementary/bytes" + + - if: + properties: + kind: + const: string + then: + $ref: "schema:ethdebug/format/type/elementary/string" + + - if: + properties: + kind: + const: ufixed + then: + $ref: "schema:ethdebug/format/type/elementary/ufixed" + + - if: + properties: + kind: + const: fixed + then: + $ref: "schema:ethdebug/format/type/elementary/fixed" + - if: + properties: + kind: + const: address + then: + $ref: "schema:ethdebug/format/type/elementary/address" + + - if: + properties: + kind: + const: contract + then: + $ref: "schema:ethdebug/format/type/elementary/contract" + + - if: + properties: + kind: + const: enum + then: + $ref: "schema:ethdebug/format/type/elementary/enum" + +$defs: + Kind: + title: Known elementary kind + description: + A schema for the values of `kind` reserved for known elementary types + included in ethdebug/format + type: string + enum: + - uint + - int + - bool + - bytes + - string + - ufixed + - fixed + - address + - contract + - enum diff --git a/schemas/type/elementary/address.schema.yaml b/schemas/type/elementary/address.schema.yaml new file mode 100644 index 00000000..0a09a5f7 --- /dev/null +++ b/schemas/type/elementary/address.schema.yaml @@ -0,0 +1,27 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary/address" + +title: ethdebug/format/type/elementary/address +description: + Schema describing the representation of an address type + +type: object +properties: + class: + const: elementary + kind: + const: address + payable: + type: boolean + description: + If this field is omitted, this type represents an address whose + payability is not known. +required: + - kind +examples: + - # a type for addresses of unknown payability + kind: address + + - # a type for payable addresses + kind: address + payable: true diff --git a/schemas/type/elementary/bool.schema.yaml b/schemas/type/elementary/bool.schema.yaml new file mode 100644 index 00000000..f19a3d82 --- /dev/null +++ b/schemas/type/elementary/bool.schema.yaml @@ -0,0 +1,17 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary/bool" + +title: ethdebug/format/type/elementary/bool +description: + Schema describing the representation of the boolean type + +type: object +properties: + class: + const: elementary + kind: + const: bool +required: + - kind +examples: + - kind: bool diff --git a/schemas/type/elementary/bytes.schema.yaml b/schemas/type/elementary/bytes.schema.yaml new file mode 100644 index 00000000..e397b028 --- /dev/null +++ b/schemas/type/elementary/bytes.schema.yaml @@ -0,0 +1,28 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary/bytes" + +title: ethdebug/format/type/elementary/bytes +description: + Schema describing the representation of a type of bytes string + (either dynamic or static) + +type: object +properties: + class: + const: elementary + kind: + const: bytes + size: + type: number + description: + The number of bytes in the bytes string. If this field is omitted, this + type is the dynamic bytes string type. + minimum: 1 +required: + - kind +examples: + - # example static bytes type + kind: bytes + size: 32 + - # example dynamic bytes type + kind: bytes diff --git a/schemas/type/elementary/contract.schema.yaml b/schemas/type/elementary/contract.schema.yaml new file mode 100644 index 00000000..10f90a72 --- /dev/null +++ b/schemas/type/elementary/contract.schema.yaml @@ -0,0 +1,51 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary/contract" + +title: ethdebug/format/type/elementary/contract +description: + Schema describing the representation of a contract type + +type: object +properties: + class: + const: elementary + kind: + const: contract + payable: + type: boolean + description: + If this field is omitted, this type represents an address whose + payability is not known. +oneOf: + - properties: + library: + const: false + interface: + const: false + + - properties: + library: + const: true + description: + Indicates that this is a type representing a library + required: + - library + + - properties: + interface: + const: true + description: + Indicates that this is a type representing an interface + required: + - interface + +required: + - kind + +examples: + - kind: contract + + - kind: contract + library: false + interface: false + payable: true diff --git a/schemas/type/elementary/enum.schema.yaml b/schemas/type/elementary/enum.schema.yaml new file mode 100644 index 00000000..10915751 --- /dev/null +++ b/schemas/type/elementary/enum.schema.yaml @@ -0,0 +1,30 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary/enum" + +title: ethdebug/format/type/elementary/enum +description: + Schema describing the representation of an enumerated type + +type: object +properties: + class: + const: elementary + kind: + const: enum + values: + description: + The allowed values of an enum. This format makes no restriction on which + values are allowed here. + type: array + items: true + +required: + - kind + - values + +examples: + - kind: enum + values: + - A + - B + - C diff --git a/schemas/type/elementary/fixed.schema.yaml b/schemas/type/elementary/fixed.schema.yaml new file mode 100644 index 00000000..7506c3da --- /dev/null +++ b/schemas/type/elementary/fixed.schema.yaml @@ -0,0 +1,33 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary/fixed" + +title: ethdebug/format/type/elementary/fixed +description: + Schema describing the representation of a signed fixed decimal type + +type: object +properties: + class: + const: elementary + kind: + const: fixed + bits: + type: number + multipleOf: 8 + minimum: 8 + maximum: 256 + places: + type: number + description: + How many decimal places, implying that a raw value `v` of this type + should be interpreted as `v / (10**places)` + minimum: 1 + maximum: 80 +required: + - kind + - bits + - places +examples: + - kind: fixed + bits: 256 + places: 10 diff --git a/schemas/type/elementary/int.schema.yaml b/schemas/type/elementary/int.schema.yaml new file mode 100644 index 00000000..00ea4ac0 --- /dev/null +++ b/schemas/type/elementary/int.schema.yaml @@ -0,0 +1,24 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary/int" + +title: ethdebug/format/type/elementary/int +description: + Schema describing the representation of a signed integer type + +type: object +properties: + class: + const: elementary + kind: + const: int + bits: + type: number + multipleOf: 8 + minimum: 8 + maximum: 256 +required: + - kind + - bits +examples: + - kind: int + bits: 256 diff --git a/schemas/type/elementary/string.schema.yaml b/schemas/type/elementary/string.schema.yaml new file mode 100644 index 00000000..5b9383f0 --- /dev/null +++ b/schemas/type/elementary/string.schema.yaml @@ -0,0 +1,22 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary/string" + +title: ethdebug/format/type/elementary/string +description: + Schema describing the representation of a string type + +type: object +properties: + class: + const: elementary + kind: + const: string + encoding: + type: string + default: utf-8 +required: + - kind +examples: + - kind: string + - kind: string + encoding: utf-16 diff --git a/schemas/type/elementary/ufixed.schema.yaml b/schemas/type/elementary/ufixed.schema.yaml new file mode 100644 index 00000000..1c6d89b4 --- /dev/null +++ b/schemas/type/elementary/ufixed.schema.yaml @@ -0,0 +1,34 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary/ufixed" + +title: ethdebug/format/type/elementary/ufixed +description: + Schema describing the representation of an unsigned fixed decimal type + +type: object +properties: + class: + const: elementary + kind: + const: ufixed + bits: + type: number + multipleOf: 8 + minimum: 8 + maximum: 256 + places: + type: number + description: + How many decimal places, implying that a raw value `v` of this type + should be interpreted as `v / (10**places)` + minimum: 1 + maximum: 80 +required: + - kind + - bits + - places +examples: + - kind: ufixed + bits: 256 + places: 10 + diff --git a/schemas/type/elementary/uint.schema.yaml b/schemas/type/elementary/uint.schema.yaml new file mode 100644 index 00000000..bbc38375 --- /dev/null +++ b/schemas/type/elementary/uint.schema.yaml @@ -0,0 +1,24 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/elementary/uint" + +title: ethdebug/format/type/elementary/uint +description: + Schema describing the representation of an unsigned integer type + +type: object +properties: + class: + const: elementary + kind: + const: uint + bits: + type: number + multipleOf: 8 + minimum: 8 + maximum: 256 +required: + - kind + - bits +examples: + - kind: uint + bits: 256 diff --git a/schemas/type/reference.schema.yaml b/schemas/type/reference.schema.yaml new file mode 100644 index 00000000..a14933c5 --- /dev/null +++ b/schemas/type/reference.schema.yaml @@ -0,0 +1,16 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/reference" + +title: ethdebug/format/type/reference +description: A reference to a known type by ID +type: object +properties: + id: + type: + - string + - number +additionalProperties: false +required: + - id +examples: + - id: 5 diff --git a/schemas/type/wrapper.schema.yaml b/schemas/type/wrapper.schema.yaml new file mode 100644 index 00000000..4a5cadfb --- /dev/null +++ b/schemas/type/wrapper.schema.yaml @@ -0,0 +1,41 @@ +$schema: "https://json-schema.org/draft/2020-12/schema" +$id: "schema:ethdebug/format/type/wrapper" + +title: ethdebug/format/type/wrapper +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" + - $ref: "schema:ethdebug/format/type/reference" + +required: + - type + +examples: + - name: beneficiary + type: + kind: address + payable: true + - type: + id: "" + +$defs: + Array: + title: '{ "type": ... }[]' + description: A list of wrapped types, where the wrapper may add fields + type: array + items: + $ref: "schema:ethdebug/format/type/wrapper" + + Object: + title: '{ "key": { "type": ... }, ... }' + description: + A key-value mapping of wrapped types, where the wrapper may add fields + type: object + additionalProperties: + $ref: "schema:ethdebug/format/type/wrapper" diff --git a/tests/schemas/examples.test.ts b/tests/schemas/examples.test.ts index 475a65bd..3343418c 100644 --- a/tests/schemas/examples.test.ts +++ b/tests/schemas/examples.test.ts @@ -10,46 +10,103 @@ import printErrors from "../src/printErrors.js"; // loads schemas into global hyperjump json schema validator import "../src/loadSchemas.js"; +const idsOfSchemasAllowedToOmitExamples = new Set([ + "schema:ethdebug/format/type", + "schema:ethdebug/format/type/complex", + "schema:ethdebug/format/type/elementary", +]); + describe("Examples", () => { for (const [id, schema] of Object.entries(schemas)) { - const exampledDefinitionNames = definitionsWithExamples(schema); + testSchema({ id, schema }); + } +}); + +function testSchema(options: { + id: string; + schema: JSONSchema +}): void { + const { id, schema } = options; + + const { title } = schema; + + const exampledDefinitionNames = definitionsWithExamples(schema); + + const hasOwnExamples = schema.examples && schema.examples.length > 0; + const hasDefinitionsWithExamples = exampledDefinitionNames.length > 0; - if (exampledDefinitionNames.length > 0) { - describe(id, () => { + const hasExamples = hasOwnExamples || hasDefinitionsWithExamples; + const allowedToOmitExamples = idsOfSchemasAllowedToOmitExamples.has(id); + + describe(title || id, () => { + ( + allowedToOmitExamples + ? it.skip + : it + )("has examples", () => { + expect(hasExamples).toBe(true); + }); + + if (!hasExamples) { + return; + }; + + testExamples({ id, schema }); + + if (hasDefinitionsWithExamples) { + describe("$defs", () => { for (const name of exampledDefinitionNames) { - const definitionSchemaId = `${id}#/$defs/${name}`; - - describe(`#/$defs/${name}`, () => { - const { - examples = [] - } = (schema!.$defs![name] as JSONSchema); - - for (const [index, example] of examples.entries()) { - describe(`example #${index}`, () => { - it(`is a valid ${name}`, async () => { - const output = await validate(definitionSchemaId, example); - expect(output.valid).toBe(true); - }) - - const { - extends: parentSchemaIds = new Set([]) - } = (schemaExtensions[id] || {})[name]; - - // NOTE this is currently not recursive (it probably should be) - for (const parentSchemaId of parentSchemaIds) { - it(`is also a valid ${parentSchemaId}`, async () => { - const output = await validate(parentSchemaId, example); - expect(output.valid).toBe(true); - }); - } - }); - } - }); + testSchema({ + id: `${id}#/$defs/${name}`, + schema: schema!.$defs![name] as JSONSchema + }) } }); } + }); +} + +function testExamples(options: { + id: string; + schema: JSONSchema +}): void { + const { id, schema } = options; + const { examples = [] } = schema; + + for (const [index, example] of examples.entries()) { + describe(`example #${index}`, () => { + it(`is a valid ${schema.title || id}`, async () => { + const output = await validate(id, example); + expect(output.valid).toBe(true); + }) + + const testedParentSchemas = new Set(); + + // function to test parent schemas recursively + const testParentSchemas = (schemaId: string) => { + testedParentSchemas.add(schemaId); + + const parentSchemaIds = schemaExtensions[schemaId]?.extends || new Set(); + + for (const parentSchemaId of parentSchemaIds) { + if (testedParentSchemas.has(parentSchemaId)) { + continue; + } + + it(`is also a valid ${parentSchemaId}`, async () => { + const output = await validate(parentSchemaId, example); + expect(output.valid).toBe(true); + }); + + // recurse to ancestors + testParentSchemas(parentSchemaId); + } + }; + + testParentSchemas(id); + }); } -}); +} function definitionsWithExamples(schema: JSONSchema): string[] { if (!("$defs" in schema) || !schema.$defs) { diff --git a/tests/src/schemas.ts b/tests/src/schemas.ts index ebcfdbdf..f4060dba 100644 --- a/tests/src/schemas.ts +++ b/tests/src/schemas.ts @@ -12,7 +12,27 @@ const readSchemas = (): { [id: string]: JSONSchema } => { const schemaPaths = [ - "type/base.schema.yaml" + "type/base.schema.yaml", + "type/wrapper.schema.yaml", + "type/reference.schema.yaml", + "type/elementary/uint.schema.yaml", + "type/elementary/int.schema.yaml", + "type/elementary/bool.schema.yaml", + "type/elementary/bytes.schema.yaml", + "type/elementary/string.schema.yaml", + "type/elementary/ufixed.schema.yaml", + "type/elementary/fixed.schema.yaml", + "type/elementary/address.schema.yaml", + "type/elementary/contract.schema.yaml", + "type/elementary/enum.schema.yaml", + "type/elementary.schema.yaml", + "type/complex/alias.schema.yaml", + "type/complex/tuple.schema.yaml", + "type/complex/array.schema.yaml", + "type/complex/mapping.schema.yaml", + "type/complex/struct.schema.yaml", + "type/complex.schema.yaml", + "type.schema.yaml", ]; const schemas = schemaPaths @@ -36,23 +56,81 @@ const readSchemas = (): { export const schemaExtensions: { [schemaId: string]: { - [definitionName: string]: { - extends: Set; - } + extends: Set; } } = { - "schema:ethdebug/format/type/base": { - "ElementaryType": { - extends: new Set([ - "schema:ethdebug/format/type/base" - ]) - }, - "ComplexType": { - extends: new Set([ - "schema:ethdebug/format/type/base" - ]) - }, - } + "schema:ethdebug/format/type/base#/$defs/ElementaryType": { + extends: new Set([ + "schema:ethdebug/format/type/base" + ]) + }, + "schema:ethdebug/format/type/base#/$defs/ComplexType": { + extends: new Set([ + "schema:ethdebug/format/type/base" + ]) + }, + "schema:ethdebug/format/type": { + extends: new Set([ + "schema:ethdebug/format/type/base" + ]) + }, + "schema:ethdebug/format/type/elementary": { + extends: new Set([ + "schema:ethdebug/format/type", + "schema:ethdebug/format/type/base#/$defs/ElementaryType" + ]) + }, + "schema:ethdebug/format/type/elementary/uint": { + extends: new Set(["schema:ethdebug/format/type/elementary"]) + }, + "schema:ethdebug/format/type/elementary/int": { + extends: new Set(["schema:ethdebug/format/type/elementary"]) + }, + "schema:ethdebug/format/type/elementary/bool": { + extends: new Set(["schema:ethdebug/format/type/elementary"]) + }, + "schema:ethdebug/format/type/elementary/bytes": { + extends: new Set(["schema:ethdebug/format/type/elementary"]) + }, + "schema:ethdebug/format/type/elementary/string": { + extends: new Set(["schema:ethdebug/format/type/elementary"]) + }, + "schema:ethdebug/format/type/elementary/ufixed": { + extends: new Set(["schema:ethdebug/format/type/elementary"]) + }, + "schema:ethdebug/format/type/elementary/fixed": { + extends: new Set(["schema:ethdebug/format/type/elementary"]) + }, + "schema:ethdebug/format/type/elementary/address": { + extends: new Set(["schema:ethdebug/format/type/elementary"]) + }, + "schema:ethdebug/format/type/elementary/contract": { + extends: new Set(["schema:ethdebug/format/type/elementary"]) + }, + "schema:ethdebug/format/type/elementary/enum": { + extends: new Set(["schema:ethdebug/format/type/elementary"]) + }, + "schema:ethdebug/format/type/complex": { + extends: new Set([ + "schema:ethdebug/format/type", + "schema:ethdebug/format/type/base#/$defs/ComplexType" + ]) + }, + "schema:ethdebug/format/type/complex/alias": { + extends: new Set(["schema:ethdebug/format/type/complex"]) + }, + "schema:ethdebug/format/type/complex/tuple": { + extends: new Set(["schema:ethdebug/format/type/complex"]) + }, + "schema:ethdebug/format/type/complex/array": { + extends: new Set(["schema:ethdebug/format/type/complex"]) + }, + "schema:ethdebug/format/type/complex/mapping": { + extends: new Set(["schema:ethdebug/format/type/complex"]) + }, + "schema:ethdebug/format/type/complex/struct": { + extends: new Set(["schema:ethdebug/format/type/complex"]) + }, } const schemas = readSchemas(); diff --git a/web/spec/type/_category_.json b/web/spec/type/_category_.json index d3684fa3..8aa65ef5 100644 --- a/web/spec/type/_category_.json +++ b/web/spec/type/_category_.json @@ -1,5 +1,5 @@ { - "label": "Type schemas", + "label": "ethdebug/format/type", "position": 3, "link": { "type": "generated-index", diff --git a/web/spec/type/base.mdx b/web/spec/type/base.mdx index a1d11ce3..a68e6f83 100644 --- a/web/spec/type/base.mdx +++ b/web/spec/type/base.mdx @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 6 --- import SchemaViewer from "@site/src/components/SchemaViewer"; @@ -8,7 +8,7 @@ import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import yaml from "yaml-template"; -# ethdebug/format/type/base +# Base schema :::warning The schema on this page is extended by other, more specific schemas as part of @@ -22,7 +22,7 @@ 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 +This format defines the **ethdebug/format/type/base** schema 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 @@ -30,238 +30,75 @@ 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). +format, namely **ethdebug/format/type**. 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 +## Differences from **ethdebug/format/type** -The **ethdebug/format/type/base** schema includes definitions for a few -concepts that are worth highlighting here. +This base schema defines the structure of a type representation without respect +to any known kind of type. -### Types are organized by `kind` +### Unconstrained `kind` field -:::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. +As described in key concepts +[Types are organized by `kind`](/spec/type/concepts#types-are-organized-by-kind) +and +[Known vs. unknown kinds](/spec/type/concepts#known-vs-unknown-kinds), +**ethdebug/format/type** imposes constraints on type representations' `kind` +field. This base schema makes no restriction on the value of this field +(other than it **must** be defined and **must** be a string). -`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. +:::note[Note to implementers] +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 +When extending this schema, there **should** exist exactly one corresponding +schema for each `kind` value. +::: -```javascript -{ - "type": { - "id": "" - } -} -``` +### The `class` field is always optional -
+Although **ethdebug/format/type** does not require the `class` field to be +defined for known types, it does require this field for representations of +unknown types. +The **ethdebug/format/type/base** schema does not ever require this field. -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. +### A complex base type `contains` other base types -#### Type reference schema +As described in key concepts +[Elementary vs. complex types](/spec/type/concepts#elementary-vs-complex-types), +this format allows the representation of types whose definition +includes other types. Both the primary schema and this base schema +require type composition to be represented via complex types' `contains` field. -A type reference is an object containing the single `"id"` field. This field -must be a string or a number. +These two schemas differ by which type schema this field is +permitted to compose. Naturally, **ethdebug/format/type**'s `contains` field +composes **ethdebug/format/type** representations, and +**ethdebug/format/type/base**'s `contains` field composes +**ethdebug/format/type/base** representations. - +As a result of this, **ethdebug/format/type/base** defines its own type wrapper +schema. -#### Type wrapper schema +#### Base 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 @@ -322,7 +159,7 @@ correspond to the canonical **ethdebug/format/type** schema._ type: object properties: type: - $ref: "schema:ethdebug/format/type/base#/$defs/Type" + $ref: "schema:ethdebug/format/type/base" required: - type required: @@ -359,14 +196,14 @@ correspond to the canonical **ethdebug/format/type** schema._ type: object properties: type: - $ref: "schema:ethdebug/format/type/base#/$defs/Type" + $ref: "schema:ethdebug/format/type/base" required: - type value: type: object properties: type: - $ref: "schema:ethdebug/format/type/base#/$defs/Type" + $ref: "schema:ethdebug/format/type/base" required: - type required: diff --git a/web/spec/type/complex/_category_.json b/web/spec/type/complex/_category_.json new file mode 100644 index 00000000..a5919364 --- /dev/null +++ b/web/spec/type/complex/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Complex types", + "position": 5, + "link": { + "type": "generated-index", + "description": "Schemas for known complex types" + } +} diff --git a/web/spec/type/complex/alias.mdx b/web/spec/type/complex/alias.mdx new file mode 100644 index 00000000..b29fe6b6 --- /dev/null +++ b/web/spec/type/complex/alias.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 1 +description: Alias types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `alias` + + diff --git a/web/spec/type/complex/array.mdx b/web/spec/type/complex/array.mdx new file mode 100644 index 00000000..a99fe26b --- /dev/null +++ b/web/spec/type/complex/array.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 3 +description: Array types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `array` + + diff --git a/web/spec/type/complex/mapping.mdx b/web/spec/type/complex/mapping.mdx new file mode 100644 index 00000000..828cc3e9 --- /dev/null +++ b/web/spec/type/complex/mapping.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 4 +description: Mapping types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `mapping` + + diff --git a/web/spec/type/complex/struct.mdx b/web/spec/type/complex/struct.mdx new file mode 100644 index 00000000..54d437fb --- /dev/null +++ b/web/spec/type/complex/struct.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 5 +description: Struct types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `struct` + + diff --git a/web/spec/type/complex/tuple.mdx b/web/spec/type/complex/tuple.mdx new file mode 100644 index 00000000..091f78c9 --- /dev/null +++ b/web/spec/type/complex/tuple.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 2 +description: Tuple types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `tuple` + + diff --git a/web/spec/type/concepts.mdx b/web/spec/type/concepts.mdx new file mode 100644 index 00000000..ffd52db7 --- /dev/null +++ b/web/spec/type/concepts.mdx @@ -0,0 +1,215 @@ +--- +sidebar_position: 2 +--- + +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"; + +# Key concepts + +The **ethdebug/format/type** 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** type representation is a JSON object with a +`kind` field containing a string value. + +`kind` is a required field for all type representations and is used to +discriminate type objects into the appropriate corresponding subschema for a +well-understood family of type. + +## Known vs. unknown kinds + +**ethdebug/format/type** defines specific subschemas for known kinds of types. +Known types correspond 1-to-1 with a reserved constant string value for the +`kind` field. + +Type representations **should** adhere to the specific corresponding subschema +when representing a known type. Type representations **must not** use any of +the reserved values for `kind` for any purpose other than adhering to the +corresponding subschema. + +This schema makes no restriction on values for the `kind` field other than +these reservations. For custom variations on known types and to represent kinds +of types not supported by this format, type representations **may** use other +values for `kind` that correspond to associated external subschemas. + +Note that this format defines a +[base type schema (**ethdebug/format/type/base**)](/spec/type/base), to which +all representations of unknown (and known) types **must** conform. +For unknown types, [**ethdebug/format/type**](/spec/type) +places additional constraints in addition to what the base schema specifies. + +## 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. + +## Complex types' `"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 + +All three forms of composition polymorphically use the `"contains"` field. + +As described in +[Type wrappers and type references](#type-wrappers-and-type-references) +below, complex types compose +other types by way of wrapper objects of the form `{ "type": ... }`, which +possibly includes other fields alongside `"type"`. + +
+ 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 + } + } + } + } + ``` + + +
+## 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 +{ + "name": "beneficiary", + "type": { + "kind": "address" + } +} +``` +
+ +
+Example type wrapper with reference by ID + +```javascript +{ + "type": { + "id": "" + } +} +``` + +
+ + +Note that **ethdebug/format/type** 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 wrapper schema + + + +### Type reference schema + +A type reference is an object containing the single `"id"` field. This field +must be a string or a number. + + diff --git a/web/spec/type/elementary/_category_.json b/web/spec/type/elementary/_category_.json new file mode 100644 index 00000000..39afc422 --- /dev/null +++ b/web/spec/type/elementary/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Elementary types", + "position": 4, + "link": { + "type": "generated-index", + "description": "Schemas for known elementary types" + } +} diff --git a/web/spec/type/elementary/address.mdx b/web/spec/type/elementary/address.mdx new file mode 100644 index 00000000..c1701060 --- /dev/null +++ b/web/spec/type/elementary/address.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 8 +description: Address types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `address` + + diff --git a/web/spec/type/elementary/bool.mdx b/web/spec/type/elementary/bool.mdx new file mode 100644 index 00000000..dffc65f4 --- /dev/null +++ b/web/spec/type/elementary/bool.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 5 +description: Boolean type schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `bool` + + diff --git a/web/spec/type/elementary/bytes.mdx b/web/spec/type/elementary/bytes.mdx new file mode 100644 index 00000000..cd876801 --- /dev/null +++ b/web/spec/type/elementary/bytes.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 6 +description: Bytes string types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `bytes` + + diff --git a/web/spec/type/elementary/contract.mdx b/web/spec/type/elementary/contract.mdx new file mode 100644 index 00000000..3db7926a --- /dev/null +++ b/web/spec/type/elementary/contract.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 9 +description: Contract types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `contract` + + diff --git a/web/spec/type/elementary/enum.mdx b/web/spec/type/elementary/enum.mdx new file mode 100644 index 00000000..6ee77496 --- /dev/null +++ b/web/spec/type/elementary/enum.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 10 +description: Enumerated values types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `enum` + + diff --git a/web/spec/type/elementary/fixed.mdx b/web/spec/type/elementary/fixed.mdx new file mode 100644 index 00000000..846329b7 --- /dev/null +++ b/web/spec/type/elementary/fixed.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 4 +description: Signed decimal fixed point types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `fixed` + + diff --git a/web/spec/type/elementary/int.mdx b/web/spec/type/elementary/int.mdx new file mode 100644 index 00000000..4b64f665 --- /dev/null +++ b/web/spec/type/elementary/int.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 2 +description: Signed integer types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `int` + + diff --git a/web/spec/type/elementary/string.mdx b/web/spec/type/elementary/string.mdx new file mode 100644 index 00000000..c1eb679b --- /dev/null +++ b/web/spec/type/elementary/string.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 7 +description: String types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `string` + + diff --git a/web/spec/type/elementary/ufixed.mdx b/web/spec/type/elementary/ufixed.mdx new file mode 100644 index 00000000..85845244 --- /dev/null +++ b/web/spec/type/elementary/ufixed.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 3 +description: Unsigned decimal fixed point types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `ufixed` + + diff --git a/web/spec/type/elementary/uint.mdx b/web/spec/type/elementary/uint.mdx new file mode 100644 index 00000000..4db8af59 --- /dev/null +++ b/web/spec/type/elementary/uint.mdx @@ -0,0 +1,12 @@ +--- +sidebar_position: 1 +description: Unsigned integer types schema +--- + +import SchemaViewer from "@site/src/components/SchemaViewer"; + +# `uint` + + diff --git a/web/spec/type/overview.mdx b/web/spec/type/overview.mdx index cb7bfbf2..a35e0053 100644 --- a/web/spec/type/overview.mdx +++ b/web/spec/type/overview.mdx @@ -2,6 +2,11 @@ sidebar_position: 1 --- +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import { describeSchema } from "@site/src/schemas"; +import CodeBlock from "@theme/CodeBlock"; + # Overview :::tip @@ -36,10 +41,8 @@ JSON values: - +for a sample of valid type representations according to this schema. ::: @@ -51,48 +54,52 @@ JSON values that adhere to this schema may (for example) represent a particular 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. +## Reading this schema -2. A base Type schema - ([**ethdebug/format/type/base**](/spec/type)), which specifies a - minimal definition of any type, known or unknown. +The **ethdebug/format/type** schema is a root schema that conditionally defers +to one or more other related schemas in the ethdebug/format/type/* namespace. - When adhering to this format, this schema is considered **necessary** for - representing any supported type. +These schemas (like all schemas in this format) are specified as +[JSON Schema](https://json-schema.org), draft 2020-12. -In other words: +Please refer to one or more of the following resources in this section: -- Compilers adhering to this format **should** use the canonical - **ethdebug/format/type** schema when representing known types - (e.g., uints, arrays, structs, etc.). +- [Key concepts](/spec/type/concepts) introduces how types are represented in + this schema. -- Compilers **must** still adhere to the **ethdebug/format/type/base** schema - when representing types not known to this format. +- [Schema](/spec/type) presents the root **ethdebug/format/type** schema, which + aggregates links to all relevant subschemas. -:::note -Any representation adhering to the former also adheres to the latter, -since **ethdebug/format/type** extends **ethdebug/format/type/base**. -::: +- The categories [Elementary types](/spec/category/elementary-types) + and [Complex types](/spec/category/complex-types) comprise individual + subschemas for all known kinds of types. -:::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. -::: +- The [Base schema](/spec/type/base) defines the mimimum overall structure of + **ethdebug/format/type** objects for purposes of schema extension. - +Here are some example **ethdebug/format/type** type representations. + +{ + [ + "ethdebug/format/type/elementary/address", + "ethdebug/format/type/complex/mapping", + "ethdebug/format/type/complex/struct" + ].map((id, index) => { + const { schema } = describeSchema({ schema: { id: `schema:${id}` } }); + return + { + JSON.stringify(schema.examples[0], undefined, 2) + } + + }) +} diff --git a/web/spec/type/type.mdx b/web/spec/type/type.mdx index ccab15d8..7ad3a02e 100644 --- a/web/spec/type/type.mdx +++ b/web/spec/type/type.mdx @@ -1,20 +1,24 @@ --- -sidebar_position: 2 +sidebar_position: 3 --- import SchemaViewer from "@site/src/components/SchemaViewer"; import { Collapsible, CreateTypes } from "@theme/JSONSchemaViewer/components"; -# ethdebug/format/type [placeholder] +# Schema -:::note + -This schema remains unspecified. Please see the Type schemas -[Overview](/spec/type/overview) for more information on how these -schemas will be organized, and/or please review the -[**ethdebug/format/type/base** schema](/spec/type/base) that is intended -to serve as base subschema for **ethdebug/format/type**. +## Elementary type schema -We appreciate your interest in these developing efforts. + -::: +## Complex type schema + + diff --git a/web/src/schemas.ts b/web/src/schemas.ts index 19052856..de7bc485 100644 --- a/web/src/schemas.ts +++ b/web/src/schemas.ts @@ -1,9 +1,49 @@ import YAML from "yaml"; import typeBaseSchemaYaml from "../../schemas/type/base.schema.yaml"; +import typeWrapperSchemaYaml from "../../schemas/type/wrapper.schema.yaml"; +import typeReferenceSchemaYaml from "../../schemas/type/reference.schema.yaml"; +import typeElementaryUintSchemaYaml from "../../schemas/type/elementary/uint.schema.yaml"; +import typeElementaryIntSchemaYaml from "../../schemas/type/elementary/int.schema.yaml"; +import typeElementaryBoolSchemaYaml from "../../schemas/type/elementary/bool.schema.yaml"; +import typeElementaryBytesSchemaYaml from "../../schemas/type/elementary/bytes.schema.yaml"; +import typeElementaryStringSchemaYaml from "../../schemas/type/elementary/string.schema.yaml"; +import typeElementaryUfixedSchemaYaml from "../../schemas/type/elementary/ufixed.schema.yaml"; +import typeElementaryFixedSchemaYaml from "../../schemas/type/elementary/fixed.schema.yaml"; +import typeElementaryAddressSchemaYaml from "../../schemas/type/elementary/address.schema.yaml"; +import typeElementaryContractSchemaYaml from "../../schemas/type/elementary/contract.schema.yaml"; +import typeElementaryEnumSchemaYaml from "../../schemas/type/elementary/enum.schema.yaml"; +import typeElementarySchemaYaml from "../../schemas/type/elementary.schema.yaml"; +import typeComplexAliasSchemaYaml from "../../schemas/type/complex/alias.schema.yaml"; +import typeComplexArraySchemaYaml from "../../schemas/type/complex/array.schema.yaml"; +import typeComplexMappingSchemaYaml from "../../schemas/type/complex/mapping.schema.yaml"; +import typeComplexStructSchemaYaml from "../../schemas/type/complex/struct.schema.yaml"; +import typeComplexTupleSchemaYaml from "../../schemas/type/complex/tuple.schema.yaml"; +import typeComplexSchemaYaml from "../../schemas/type/complex.schema.yaml"; +import typeSchemaYaml from "../../schemas/type.schema.yaml"; export const schemaYamls = [ typeBaseSchemaYaml, + typeWrapperSchemaYaml, + typeReferenceSchemaYaml, + typeElementaryUintSchemaYaml, + typeElementaryIntSchemaYaml, + typeElementaryUfixedSchemaYaml, + typeElementaryFixedSchemaYaml, + typeElementaryBoolSchemaYaml, + typeElementaryBytesSchemaYaml, + typeElementaryStringSchemaYaml, + typeElementaryAddressSchemaYaml, + typeElementaryContractSchemaYaml, + typeElementaryEnumSchemaYaml, + typeElementarySchemaYaml, + typeComplexAliasSchemaYaml, + typeComplexArraySchemaYaml, + typeComplexMappingSchemaYaml, + typeComplexStructSchemaYaml, + typeComplexTupleSchemaYaml, + typeComplexSchemaYaml, + typeSchemaYaml, ].map(schema => ({ [YAML.parse(schema).$id]: schema })).reduce((a, b) => ({ ...a, ...b }), {}); @@ -24,6 +64,47 @@ export const schemaIndex: SchemaIndex = { title: "Base type wrapper schema", href: "/spec/type/base#base-type-wrapper-schema", }, + "schema:ethdebug/format/type/wrapper": { + title: "Type wrapper schema", + href: "/spec/type/concepts#type-wrapper-schema", + }, + "schema:ethdebug/format/type/reference": { + title: "Type reference schema", + href: "/spec/type/concepts#type-reference-schema" + }, + "schema:ethdebug/format/type": { + href: "/spec/type" + }, + "schema:ethdebug/format/type/elementary": { + href: "/spec/type#elementary-type-schema" + }, + "schema:ethdebug/format/type/complex": { + href: "/spec/type#complex-type-schema" + }, + ...( + [ + "uint", "int", "ufixed", "fixed", "bool", "bytes", "string", "address", + "contract", "enum" + ].map(kind => ({ + [`schema:ethdebug/format/type/elementary/${kind}`]: { + href: `/spec/type/elementary/${kind}` + } + })) + .reduce((a, b) => ({ ...a, ...b }), {}) + ), + ...( + [ + "alias", "tuple", "array", "mapping", "struct" + ].map(kind => ({ + [`schema:ethdebug/format/type/complex/${kind}`]: { + href: `/spec/type/complex/${kind}` + } + })) + .reduce((a, b) => ({ ...a, ...b }), {}) + ) + + + }; export interface DescribeSchemaOptions<