From 73cf8684cbb8308c4ebe64f7a59c1449f211e529 Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 00:22:32 -0500 Subject: [PATCH 01/11] Add Prettier configuration --- .prettierignore | 14 ++++++++++++++ .prettierrc.json | 4 ++++ package.json | 5 ++++- yarn.lock | 36 +++++++++++++++++++++++++++++++++--- 4 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc.json diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..0909188c0 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,14 @@ +node_modules/ +dist/ +coverage/ +*.log +.DS_Store +yarn.lock +package-lock.json + +# Auto-generated files +packages/format/src/schemas/yamls.ts + +# Docusaurus build output +packages/web/.docusaurus/ +packages/web/build/ diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..218fcf926 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "printWidth": 80, + "singleQuote": false +} diff --git a/package.json b/package.json index a4a5dd0ac..bc99f8361 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,15 @@ "test": "vitest", "start": "./bin/start", "lerna": "lerna", - "postinstall": "lerna run prepare" + "postinstall": "lerna run prepare", + "format": "prettier --write .", + "format:check": "prettier --check ." }, "devDependencies": { "@vitest/ui": "^3.0.5", "concurrently": "^8.2.2", "lerna": "^8.0.2", + "prettier": "^3.4.2", "tsx": "^4.16.2", "vitest": "^3.0.5" } diff --git a/yarn.lock b/yarn.lock index 343f68acb..47c570808 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11378,6 +11378,11 @@ postcss@^8.5.1: picocolors "^1.1.1" source-map-js "^1.2.1" +prettier@^3.4.2: + version "3.7.4" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.7.4.tgz#d2f8335d4b1cec47e1c8098645411b0c9dff9c0f" + integrity sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA== + pretty-error@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz" @@ -12824,7 +12829,16 @@ std-env@^3.8.0: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.0.tgz#b56ffc1baf1a29dcc80a3bdf11d7fca7c315e7d5" integrity sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w== -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -12873,7 +12887,14 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -13945,7 +13966,7 @@ wordwrap@^1.0.0: resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -13963,6 +13984,15 @@ wrap-ansi@^6.0.1: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" From d42ac838468820243ce5bfaed89bfd686f296bee Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 00:23:33 -0500 Subject: [PATCH 02/11] Apply Prettier formatting --- .github/workflows/ci.yml | 2 +- .github/workflows/gh-pages.yml | 6 +- README.md | 12 +- bin/bundle-schema.ts | 4 +- jest.config.ts | 2 +- lerna.json | 4 +- packages/format/bin/generate-schema-yamls.js | 14 +- packages/format/src/describe.ts | 77 ++-- packages/format/src/schemas/examples.test.ts | 45 +- packages/format/src/schemas/index.ts | 4 +- packages/format/src/schemas/validity.test.ts | 32 +- packages/format/src/types/data/index.test.ts | 6 +- packages/format/src/types/data/index.ts | 6 +- .../format/src/types/materials/index.test.ts | 10 +- packages/format/src/types/materials/index.ts | 121 +++--- .../format/src/types/pointer/pointer.test.ts | 44 +- packages/format/src/types/pointer/pointer.ts | 359 ++++++++-------- .../format/src/types/program/context.test.ts | 14 +- packages/format/src/types/program/context.ts | 93 ++-- .../src/types/program/instruction.test.ts | 2 +- .../format/src/types/program/instruction.ts | 26 +- .../format/src/types/program/program.test.ts | 2 +- packages/format/src/types/program/program.ts | 47 +-- packages/format/src/types/type/base.test.ts | 6 +- packages/format/src/types/type/base.ts | 67 ++- packages/format/src/types/type/index.test.ts | 37 +- packages/format/src/types/type/index.ts | 398 +++++++++--------- packages/format/test/extensions.ts | 56 ++- packages/format/test/guards.ts | 6 +- packages/format/test/hyperjump.ts | 45 +- packages/format/tsconfig.json | 8 +- packages/format/vitest.config.ts | 4 +- packages/format/vitest.setup.ts | 49 +-- packages/pointers/bin/run-example.ts | 37 +- packages/pointers/src/cursor.ts | 32 +- packages/pointers/src/data.test.ts | 4 +- packages/pointers/src/data.ts | 21 +- packages/pointers/src/dereference/cursor.ts | 22 +- packages/pointers/src/dereference/generate.ts | 15 +- .../pointers/src/dereference/index.test.ts | 296 +++++++------ packages/pointers/src/dereference/index.ts | 21 +- packages/pointers/src/dereference/memo.ts | 57 +-- packages/pointers/src/dereference/process.ts | 74 ++-- packages/pointers/src/dereference/region.ts | 45 +- packages/pointers/src/evaluate.test.ts | 167 ++++---- packages/pointers/src/evaluate.ts | 135 +++--- packages/pointers/src/integration.test.ts | 8 +- packages/pointers/src/machine.ts | 6 +- packages/pointers/src/read.test.ts | 162 +++---- packages/pointers/src/read.ts | 90 ++-- packages/pointers/src/test-cases.ts | 46 +- packages/pointers/test/deploy.ts | 38 +- packages/pointers/test/examples.ts | 9 +- packages/pointers/test/ganache.ts | 53 +-- packages/pointers/test/index.ts | 14 +- packages/pointers/test/observe.ts | 8 +- packages/pointers/test/solc.ts | 38 +- packages/pointers/tsconfig.json | 2 +- packages/pointers/vitest.config.ts | 3 +- packages/web/babel.config.js | 2 +- packages/web/docs/goals.mdx | 1 + .../implementation-guides.mdx | 16 +- .../dereference-logic/dereference-logic.mdx | 8 +- .../dereference-logic/generating-regions.mdx | 37 +- .../making-regions-concrete.mdx | 13 +- .../pointers/evaluating-expressions.mdx | 87 ++-- .../pointers/pointers.mdx | 1 - .../pointers/reading-from-regions.mdx | 5 +- .../pointers/testing/example-pointers.mdx | 7 +- .../testing/test-cases/TestedPointer.tsx | 13 +- .../testing/test-cases/string-storage.mdx | 8 +- .../testing/test-cases/struct-storage.mdx | 8 +- .../testing/test-cases/test-cases.mdx | 13 +- .../test-cases/uint256-array-memory.mdx | 10 +- .../pointers/types/cursors.mdx | 28 +- .../pointers/types/data-and-machines.mdx | 20 +- .../pointers/types/pointer-types.mdx | 7 +- packages/web/docs/known-challenges.mdx | 56 +-- packages/web/docs/sketches/layout.mdx | 236 ++++++----- packages/web/docs/sketches/prototype.mdx | 223 +++++----- packages/web/docusaurus.config.ts | 142 +++---- packages/web/plugins/project-code-plugin.ts | 36 +- packages/web/sidebars.ts | 4 +- packages/web/spec/data/hex.mdx | 4 +- packages/web/spec/data/unsigned.mdx | 4 +- packages/web/spec/data/value.mdx | 4 +- packages/web/spec/info/info.mdx | 4 +- packages/web/spec/info/overview.mdx | 1 + packages/web/spec/info/resources.mdx | 4 +- packages/web/spec/materials/compilation.mdx | 4 +- packages/web/spec/materials/id.mdx | 8 +- packages/web/spec/materials/source-range.mdx | 2 +- packages/web/spec/materials/source.mdx | 4 +- packages/web/spec/overview.mdx | 24 +- .../spec/pointer/collection/collection.mdx | 4 +- .../spec/pointer/collection/conditional.mdx | 2 +- .../web/spec/pointer/collection/group.mdx | 2 +- packages/web/spec/pointer/collection/list.mdx | 2 +- .../web/spec/pointer/collection/reference.mdx | 2 +- .../web/spec/pointer/collection/scope.mdx | 2 +- .../web/spec/pointer/collection/templates.mdx | 2 +- packages/web/spec/pointer/concepts.mdx | 84 ++-- packages/web/spec/pointer/expression.mdx | 22 +- packages/web/spec/pointer/overview.mdx | 3 +- packages/web/spec/pointer/pointer.mdx | 4 +- packages/web/spec/pointer/region/base.mdx | 4 +- .../spec/pointer/region/location/calldata.mdx | 2 +- .../web/spec/pointer/region/location/code.mdx | 4 +- .../spec/pointer/region/location/memory.mdx | 4 +- .../pointer/region/location/returndata.mdx | 2 +- .../spec/pointer/region/location/stack.mdx | 4 +- .../spec/pointer/region/location/storage.mdx | 2 +- .../pointer/region/location/transient.mdx | 2 +- packages/web/spec/pointer/region/region.mdx | 4 +- .../spec/pointer/region/scheme/segment.mdx | 2 +- .../web/spec/pointer/region/scheme/slice.mdx | 4 +- packages/web/spec/pointer/template.mdx | 4 +- packages/web/spec/program/concepts.mdx | 4 +- packages/web/spec/program/context/code.mdx | 4 +- packages/web/spec/program/context/context.mdx | 4 +- packages/web/spec/program/context/frame.mdx | 4 +- packages/web/spec/program/context/gather.mdx | 2 +- packages/web/spec/program/context/pick.mdx | 4 +- packages/web/spec/program/context/remark.mdx | 2 +- .../web/spec/program/context/variables.mdx | 2 +- packages/web/spec/program/example.mdx | 205 ++++----- packages/web/spec/program/instruction.mdx | 4 +- packages/web/spec/program/overview.mdx | 13 +- packages/web/spec/program/program.mdx | 4 +- packages/web/spec/type/base.mdx | 8 +- packages/web/spec/type/complex/alias.mdx | 4 +- packages/web/spec/type/complex/array.mdx | 4 +- packages/web/spec/type/complex/function.mdx | 7 +- packages/web/spec/type/complex/mapping.mdx | 4 +- packages/web/spec/type/complex/struct.mdx | 4 +- packages/web/spec/type/complex/tuple.mdx | 4 +- packages/web/spec/type/concepts.mdx | 18 +- packages/web/spec/type/elementary/address.mdx | 2 +- packages/web/spec/type/elementary/bool.mdx | 4 +- packages/web/spec/type/elementary/bytes.mdx | 4 +- .../web/spec/type/elementary/contract.mdx | 2 +- packages/web/spec/type/elementary/enum.mdx | 4 +- packages/web/spec/type/elementary/fixed.mdx | 4 +- packages/web/spec/type/elementary/int.mdx | 4 +- packages/web/spec/type/elementary/string.mdx | 2 +- packages/web/spec/type/elementary/ufixed.mdx | 2 +- packages/web/spec/type/elementary/uint.mdx | 4 +- packages/web/spec/type/overview.mdx | 33 +- packages/web/spec/type/type.mdx | 12 +- packages/web/src/components/CodeListing.tsx | 41 +- .../web/src/components/LinkedCodeBlock.tsx | 38 +- packages/web/src/components/Playground.tsx | 2 +- packages/web/src/components/SchemaListing.tsx | 56 +-- packages/web/src/components/SchemaViewer.tsx | 126 +++--- packages/web/src/components/StatusBadge.tsx | 5 +- packages/web/src/components/StatusBanner.tsx | 5 +- .../src/components/StatusLevelExplainer.tsx | 5 +- packages/web/src/contexts/SchemaContext.tsx | 11 +- packages/web/src/hooks/useProjectCode.ts | 2 +- packages/web/src/pages/home/index.tsx | 77 ++-- packages/web/src/schemas.ts | 200 ++++----- packages/web/src/status/status-config.ts | 22 +- .../SchemaConditional/schemaConditional.tsx | 23 +- .../schemaComposition/DiscriminatorSchema.tsx | 95 ++--- .../ExclusiveRequiredPropertiesSchema.tsx | 103 ++--- .../InclusiveRequiredPropertiesSchema.tsx | 100 +++-- .../schemaComposition/allOfSchema.tsx | 21 +- .../components/CreateNodes.tsx | 25 +- .../components/UnnecessaryComposition.tsx | 169 ++++---- packages/web/src/theme/MDXComponents.tsx | 32 +- .../web/src/theme/ProgramExample/Details.tsx | 90 ++-- .../ProgramExample/HighlightedInstruction.tsx | 16 +- .../web/src/theme/ProgramExample/Opcodes.css | 5 +- .../web/src/theme/ProgramExample/Opcodes.tsx | 103 ++--- .../ProgramExample/ProgramExampleContext.tsx | 80 ++-- .../theme/ProgramExample/SourceContents.css | 1 - .../theme/ProgramExample/SourceContents.tsx | 65 ++- .../src/theme/ProgramExample/Variables.tsx | 96 +++-- .../web/src/theme/ProgramExample/Viewer.css | 4 +- .../web/src/theme/ProgramExample/Viewer.tsx | 31 +- .../web/src/theme/ProgramExample/dynamic.ts | 41 +- .../web/src/theme/ProgramExample/index.ts | 1 - .../web/src/theme/ProgramExample/offsets.ts | 37 +- .../theme/ShikiCodeBlock/ShikiCodeBlock.tsx | 2 +- .../theme/ShikiCodeBlock/useHighlighter.ts | 16 +- packages/web/tsconfig.json | 8 +- schemas/info.schema.yaml | 5 +- schemas/info/resources.schema.yaml | 1 - schemas/pointer.schema.yaml | 8 +- schemas/pointer/collection.schema.yaml | 1 - schemas/pointer/collection/list.schema.yaml | 1 - schemas/pointer/expression.schema.yaml | 10 +- schemas/pointer/region.schema.yaml | 3 - schemas/pointer/region/calldata.schema.yaml | 1 - schemas/pointer/region/code.schema.yaml | 1 - schemas/pointer/region/memory.schema.yaml | 1 - schemas/pointer/region/returndata.schema.yaml | 1 - schemas/pointer/region/stack.schema.yaml | 1 - schemas/pointer/region/storage.schema.yaml | 1 - schemas/pointer/region/transient.schema.yaml | 1 - schemas/program/context/gather.schema.yaml | 42 +- schemas/program/context/pick.schema.yaml | 24 +- schemas/type.schema.yaml | 15 +- schemas/type/base.schema.yaml | 12 +- schemas/type/complex.schema.yaml | 3 +- schemas/type/complex/alias.schema.yaml | 3 +- schemas/type/complex/mapping.schema.yaml | 3 +- schemas/type/complex/struct.schema.yaml | 3 +- schemas/type/complex/tuple.schema.yaml | 6 +- schemas/type/elementary.schema.yaml | 3 +- schemas/type/elementary/address.schema.yaml | 6 +- schemas/type/elementary/bool.schema.yaml | 3 +- schemas/type/elementary/bytes.schema.yaml | 3 +- schemas/type/elementary/contract.schema.yaml | 12 +- schemas/type/elementary/enum.schema.yaml | 3 +- schemas/type/elementary/fixed.schema.yaml | 3 +- schemas/type/elementary/int.schema.yaml | 3 +- schemas/type/elementary/string.schema.yaml | 3 +- schemas/type/elementary/ufixed.schema.yaml | 4 +- schemas/type/elementary/uint.schema.yaml | 3 +- schemas/type/wrapper.schema.yaml | 3 +- tsconfig.base.json | 18 +- vitest.config.ts | 4 +- 223 files changed, 3187 insertions(+), 3389 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c42db767d..5f34e63fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,6 @@ name: Continuous integration checks on: -- pull_request + - pull_request jobs: run-tests: diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index f66657b7f..9f95d8627 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -29,10 +29,8 @@ jobs: folder: ./packages/web/build branch: gh-pages # default deployer - git-config-name: 'github-actions[bot]' - git-config-email: 'github-actions[bot]@users.noreply.github.com' + git-config-name: "github-actions[bot]" + git-config-email: "github-actions[bot]@users.noreply.github.com" # don't break preview deployments clean-exclude: pr-preview force: false - - diff --git a/README.md b/README.md index aec7d3989..9bb3c1429 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ This repository contains a with the formal JSON Schemas defined by this project (in YAML format). This repository also contains the source materials for the following NPM packages: + - **@ethdebug/format** in [`packages/format/`](https://github.com/ethdebug/format/tree/main/packages/format) distributes the formal schemas for use in TypeScript @@ -75,6 +76,7 @@ To build and run the site locally, please ensure you have Node.js (LTS or better) and `yarn` installed globally. First, clone this repo and install the Node.js dependencies: + ```console git clone https://github.com/ethdebug/format.git cd format @@ -96,10 +98,12 @@ This project uses a dual-license approach: - All other code and documentation in this repository is licensed under the [MIT License](LICENSE). -[^1]: See [Debugging data format - - Wikipedia](https://en.wikipedia.org/wiki/Debugging_data_format) +[^1]: + See [Debugging data format - + Wikipedia](https://en.wikipedia.org/wiki/Debugging_data_format) [^2]: See [DWARF - Wikipedia](https://en.wikipedia.org/wiki/DWARF) -[^3]: See [Using type predicates](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) - section from TypeScript's Narrowing documentation. +[^3]: + See [Using type predicates](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates) + section from TypeScript's Narrowing documentation. diff --git a/bin/bundle-schema.ts b/bin/bundle-schema.ts index 90bf6f03a..f9aea366f 100644 --- a/bin/bundle-schema.ts +++ b/bin/bundle-schema.ts @@ -1,14 +1,14 @@ import { addSchema } from "@hyperjump/json-schema/draft-2020-12"; import { bundle as bundleSchema } from "@hyperjump/json-schema/bundle"; import { schemas, describeSchema } from "@ethdebug/format"; -import type { JSONSchema } from "json-schema-typed/draft-2020-12" +import type { JSONSchema } from "json-schema-typed/draft-2020-12"; async function main() { const schema = { id: process.argv[2] }; // a bit brittle if (!schema.id) { console.error( - "Please provide a schema ID, e.g. `schema:ethdebug/format/pointer`" + "Please provide a schema ID, e.g. `schema:ethdebug/format/pointer`", ); process.exit(1); } diff --git a/jest.config.ts b/jest.config.ts index 41defa7de..08f5f97ab 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -5,7 +5,7 @@ const config: Config = { rootDir: "./", extensionsToTreatAsEsm: [".ts"], transform: { - "^.+\\.tsx?$": ['ts-jest', { useESM: true, }], + "^.+\\.tsx?$": ["ts-jest", { useESM: true }], }, projects: ["/packages/*"], }; diff --git a/lerna.json b/lerna.json index bbe540cf6..877244c11 100644 --- a/lerna.json +++ b/lerna.json @@ -2,8 +2,6 @@ "$schema": "node_modules/lerna/schemas/lerna-schema.json", "version": "independent", "npmClient": "yarn", - "packages": [ - "packages/*" - ], + "packages": ["packages/*"], "rejectCycles": true } diff --git a/packages/format/bin/generate-schema-yamls.js b/packages/format/bin/generate-schema-yamls.js index 63bb9c8ad..5f42c890f 100644 --- a/packages/format/bin/generate-schema-yamls.js +++ b/packages/format/bin/generate-schema-yamls.js @@ -26,7 +26,7 @@ const readSchemaYamls = (directory) => { } return schemaYamls; -} +}; const schemaYamls = readSchemaYamls(schemasRoot); const rawSchemas = Object.entries(schemaYamls) @@ -40,13 +40,13 @@ export type SchemaYamlsById = { [id: string]: string; }; -export const schemaYamls: SchemaYamlsById = ${ - JSON.stringify(schemaYamls, undefined, 2) -}; +export const schemaYamls: SchemaYamlsById = ${JSON.stringify( + schemaYamls, + undefined, + 2, +)}; -const rawSchemas = ${ - JSON.stringify(rawSchemas, undefined, 2) -} as const; +const rawSchemas = ${JSON.stringify(rawSchemas, undefined, 2)} as const; export type Schema = (typeof rawSchemas)[Id]; diff --git a/packages/format/src/describe.ts b/packages/format/src/describe.ts index e0e34b1f3..1f7e6ed17 100644 --- a/packages/format/src/describe.ts +++ b/packages/format/src/describe.ts @@ -2,16 +2,16 @@ import * as YAML from "yaml"; import { schemaYamls } from "./schemas/yamls"; -import type { JSONSchema as JSONSchemaTyped } from "json-schema-typed/draft-2020-12" +import type { JSONSchema as JSONSchemaTyped } from "json-schema-typed/draft-2020-12"; export type JSONSchema = Exclude; export interface DescribeSchemaOptions< - S extends SchemaReference = SchemaReference + S extends SchemaReference = SchemaReference, > { schema: S; pointer?: SchemaPointer; -}; +} export interface SchemaInfo { id?: string; // root ID only @@ -23,46 +23,42 @@ export interface SchemaInfo { const parseOptions = { // merge keys were removed from YAML 1.2 spec but used by these schemas - merge: true + merge: true, }; export function describeSchema({ schema, - pointer + pointer, }: DescribeSchemaOptions): SchemaInfo { if (typeof pointer === "string" && !pointer.startsWith("#")) { throw new Error("`pointer` option must start with '#'"); } - const pointerOptions = pointer - ? { pointer } - : {}; + const pointerOptions = pointer ? { pointer } : {}; if (referencesId(schema)) { return describeSchemaById({ - schema: typeof schema === "object" - ? schema - : { id: schema }, - ...pointerOptions + schema: typeof schema === "object" ? schema : { id: schema }, + ...pointerOptions, }); } if (referencesYaml(schema)) { return describeSchemaByYaml({ schema, - ...pointerOptions + ...pointerOptions, }); } return describeSchemaByObject({ schema, - ...pointerOptions + ...pointerOptions, }); } function describeSchemaById({ schema: { id: referencedId }, - pointer: relativePointer + pointer: relativePointer, }: DescribeSchemaOptions): SchemaInfo { // we need to handle the case where the schema is referenced by an ID // with a pointer specified, possibly with a separate `pointer` field too @@ -72,7 +68,7 @@ function describeSchemaById({ ? joinSchemaPointers([`#${rawReferencedPointer}`, relativePointer]) : relativePointer; - const rootYaml = schemaYamls[id] + const rootYaml = schemaYamls[id]; if (!rootYaml) { throw new Error(`Unknown schema with $id "${id}"`); } @@ -87,13 +83,13 @@ function describeSchemaById({ ...(pointer ? { pointer } : {}), yaml, schema, - rootSchema - } + rootSchema, + }; } function describeSchemaByYaml({ schema: { yaml: referencedYaml }, - pointer + pointer, }: DescribeSchemaOptions): SchemaInfo { const yaml = pointToYaml(referencedYaml, pointer); @@ -108,21 +104,21 @@ function describeSchemaByYaml({ ...(pointer ? { pointer } : {}), yaml, schema, - rootSchema - } + rootSchema, + }; } else { return { ...(pointer ? { pointer } : {}), yaml, schema, - rootSchema - } + rootSchema, + }; } } function describeSchemaByObject({ schema: rootSchema, - pointer + pointer, }: DescribeSchemaOptions): SchemaInfo { const rootYaml = YAML.stringify(rootSchema); @@ -138,24 +134,24 @@ function describeSchemaByObject({ ...(pointer ? { pointer } : {}), yaml, schema, - rootSchema - } + rootSchema, + }; } else { return { ...(pointer ? { pointer } : {}), yaml, schema, - rootSchema - } + rootSchema, + }; } } function joinSchemaPointers( - pointers: (SchemaPointer | undefined)[] + pointers: (SchemaPointer | undefined)[], ): SchemaPointer | undefined { const joined = pointers .filter((pointer): pointer is SchemaPointer => typeof pointer === "string") - .map(pointer => pointer.slice(1)) + .map((pointer) => pointer.slice(1)) .join(""); if (joined.length === 0) { @@ -165,10 +161,7 @@ function joinSchemaPointers( return `#${joined}`; } -function pointToYaml( - yaml: string, - pointer?: SchemaPointer -): string { +function pointToYaml(yaml: string, pointer?: SchemaPointer): string { if (!pointer) { return yaml; } @@ -192,9 +185,8 @@ type Impossible = { [P in K]: never; }; -type NoExtraProperties = - & U - & Impossible>; +type NoExtraProperties = U & + Impossible>; export type SchemaPointer = `#${string}`; @@ -215,7 +207,7 @@ export type SchemaByYaml = NoExtraProperties<{ }>; export function referencesId( - schema: SchemaReference + schema: SchemaReference, ): schema is SchemaId | SchemaById { return ( typeof schema === "string" || @@ -224,8 +216,11 @@ export function referencesId( } export function referencesYaml( - schema: SchemaReference + schema: SchemaReference, ): schema is SchemaByYaml { - return typeof schema === "object" && - Object.keys(schema).length === 1 && "yaml" in schema; + return ( + typeof schema === "object" && + Object.keys(schema).length === 1 && + "yaml" in schema + ); } diff --git a/packages/format/src/schemas/examples.test.ts b/packages/format/src/schemas/examples.test.ts index de01410e1..c4cc5e1fc 100644 --- a/packages/format/src/schemas/examples.test.ts +++ b/packages/format/src/schemas/examples.test.ts @@ -21,10 +21,7 @@ describe("Examples", () => { } }); -function testSchema(options: { - id: string; - schema: JSONSchema -}): void { +function testSchema(options: { id: string; schema: JSONSchema }): void { const { id, schema } = options; const { title } = schema; @@ -38,17 +35,13 @@ function testSchema(options: { const allowedToOmitExamples = idsOfSchemasAllowedToOmitExamples.has(id); describe(title || id, () => { - ( - allowedToOmitExamples - ? it.skip - : it - )("has examples", () => { + (allowedToOmitExamples ? it.skip : it)("has examples", () => { expect(hasExamples).toBe(true); }); if (!hasExamples) { return; - }; + } testExamples({ id, schema }); @@ -57,18 +50,15 @@ function testSchema(options: { for (const name of exampledDefinitionNames) { testSchema({ id: `${id}#/$defs/${name}`, - schema: schema!.$defs![name] as JSONSchema - }) + schema: schema!.$defs![name] as JSONSchema, + }); } }); } }); } -function testExamples(options: { - id: string; - schema: JSONSchema -}): void { +function testExamples(options: { id: string; schema: JSONSchema }): void { const { id, schema } = options; const { examples = [] } = schema; @@ -76,7 +66,7 @@ function testExamples(options: { describe(`example #${index}`, () => { it(`is a valid ${schema.title || id}`, async () => { await expect(example).toValidate({ schema: { id } }); - }) + }); const testedParentSchemas = new Set(); @@ -84,7 +74,8 @@ function testExamples(options: { const testParentSchemas = (schemaId: string) => { testedParentSchemas.add(schemaId); - const parentSchemaIds = schemaExtensions[schemaId]?.extends || new Set(); + const parentSchemaIds = + schemaExtensions[schemaId]?.extends || new Set(); for (const parentSchemaId of parentSchemaIds) { if (testedParentSchemas.has(parentSchemaId)) { @@ -93,7 +84,7 @@ function testExamples(options: { it(`is also a valid ${parentSchemaId}`, async () => { await expect(example).toValidate({ - schema: { id: parentSchemaId } + schema: { id: parentSchemaId }, }); }); @@ -112,14 +103,12 @@ function definitionsWithExamples(schema: JSONSchema): string[] { return []; } - return Object.entries(schema.$defs) - .flatMap(([name, definition]) => ( - typeof definition !== "boolean" && - "examples" in definition && - definition.examples && - definition.examples.length > 0 - ) + return Object.entries(schema.$defs).flatMap(([name, definition]) => + typeof definition !== "boolean" && + "examples" in definition && + definition.examples && + definition.examples.length > 0 ? [name] - : [] - ) + : [], + ); } diff --git a/packages/format/src/schemas/index.ts b/packages/format/src/schemas/index.ts index 0644a9560..2d2c9c972 100644 --- a/packages/format/src/schemas/index.ts +++ b/packages/format/src/schemas/index.ts @@ -4,7 +4,7 @@ export type { Schema } from "./yamls"; export const schemaIds: string[] = Object.keys(schemaYamls); export const schemas = schemaIds - .map(id => ({ - [id]: describeSchema({ schema: { id } }).schema + .map((id) => ({ + [id]: describeSchema({ schema: { id } }).schema, })) .reduce((a, b) => ({ ...a, ...b }), {}); diff --git a/packages/format/src/schemas/validity.test.ts b/packages/format/src/schemas/validity.test.ts index d006a3fb5..89ba2d514 100644 --- a/packages/format/src/schemas/validity.test.ts +++ b/packages/format/src/schemas/validity.test.ts @@ -10,19 +10,18 @@ import { schemas } from "."; // loads schemas into global hyperjump json schema validator import "../../test/hyperjump"; -const printErrors = (output: OutputUnit): string => output.errors! - .map((error) => { - if (!error.valid && !error.keyword.endsWith("#validate")) { - return `${ - error.instanceLocation - } fails schema constraint ${ - error.absoluteKeywordLocation - }`; - } - }) - .filter((message): message is string => !!message) - .map(message => ` - ${message}`) - .join("\n"); +const printErrors = (output: OutputUnit): string => + output + .errors!.map((error) => { + if (!error.valid && !error.keyword.endsWith("#validate")) { + return `${error.instanceLocation} fails schema constraint ${ + error.absoluteKeywordLocation + }`; + } + }) + .filter((message): message is string => !!message) + .map((message) => ` - ${message}`) + .join("\n"); describe("Valid schemas", () => { for (const [id, schema] of Object.entries(schemas)) { @@ -34,11 +33,10 @@ describe("Valid schemas", () => { throw error; } - throw new Error(`Invalid schema. Errors:\n${ - printErrors(error.output) - }`); + throw new Error( + `Invalid schema. Errors:\n${printErrors(error.output)}`, + ); } - }); } }); diff --git a/packages/format/src/types/data/index.test.ts b/packages/format/src/types/data/index.test.ts index 8729c20d4..05f09b70c 100644 --- a/packages/format/src/types/data/index.test.ts +++ b/packages/format/src/types/data/index.test.ts @@ -5,14 +5,14 @@ import { Data } from "./index.js"; testSchemaGuards("ethdebug/format/data", [ { schema: "schema:ethdebug/format/data/value", - guard: Data.isValue + guard: Data.isValue, }, { schema: "schema:ethdebug/format/data/unsigned", - guard: Data.isUnsigned + guard: Data.isUnsigned, }, { schema: "schema:ethdebug/format/data/hex", - guard: Data.isHex + guard: Data.isHex, }, ]); diff --git a/packages/format/src/types/data/index.ts b/packages/format/src/types/data/index.ts index 69e27d280..cc2662191 100644 --- a/packages/format/src/types/data/index.ts +++ b/packages/format/src/types/data/index.ts @@ -1,10 +1,8 @@ export namespace Data { - export type Value = - | Unsigned - | Hex; + export type Value = Unsigned | Hex; export const isValue = (value: unknown): value is Value => - [isUnsigned, isHex].some(guard => guard(value)); + [isUnsigned, isHex].some((guard) => guard(value)); export type Unsigned = number; diff --git a/packages/format/src/types/materials/index.test.ts b/packages/format/src/types/materials/index.test.ts index df1884ef5..6174af469 100644 --- a/packages/format/src/types/materials/index.test.ts +++ b/packages/format/src/types/materials/index.test.ts @@ -4,22 +4,22 @@ import { Materials } from "./index"; testSchemaGuards("ethdebug/format/materials", [ { schema: "schema:ethdebug/format/materials/id", - guard: Materials.isId + guard: Materials.isId, }, { schema: "schema:ethdebug/format/materials/reference", - guard: Materials.isReference + guard: Materials.isReference, }, { schema: "schema:ethdebug/format/materials/compilation", - guard: Materials.isCompilation + guard: Materials.isCompilation, }, { schema: "schema:ethdebug/format/materials/source", - guard: Materials.isSource + guard: Materials.isSource, }, { schema: "schema:ethdebug/format/materials/source-range", - guard: Materials.isSourceRange + guard: Materials.isSourceRange, }, ]); diff --git a/packages/format/src/types/materials/index.ts b/packages/format/src/types/materials/index.ts index 899e44e26..80d837ebf 100644 --- a/packages/format/src/types/materials/index.ts +++ b/packages/format/src/types/materials/index.ts @@ -1,64 +1,54 @@ import { Data } from "../data"; export namespace Materials { - export type Id = - | number - | string; + export type Id = number | string; export const isId = (value: unknown): value is Id => ["number", "string"].includes(typeof value); // this and `toReference` are a bit janky to ensure Reference can't // be assigned to Reference unless X can be assigned to Y - export type Reference = OmitNever< - & OmitNever<{ - [K in keyof O]-?: K extends "id" ? O[K] : never; - }> - & ( - Reference.Type extends string - ? { type?: Reference.Type; } - : { type?: string;} - ) + export type Reference = OmitNever< + OmitNever<{ + [K in keyof O]-?: K extends "id" ? O[K] : never; + }> & + (Reference.Type extends string + ? { type?: Reference.Type } + : { type?: string }) >; - export const isReference = ( - value: unknown + export const isReference = ( + value: unknown, ): value is Reference => - typeof value === "object" && !!value && - "id" in value && isId(value.id); + typeof value === "object" && !!value && "id" in value && isId(value.id); - export function toReference(object: O): Reference { + export function toReference(object: O): Reference { return { id: object.id, - ...( - ([ + ...(( + [ [isCompilation, "compilation"], - [isSource, "source"] - ] as const) - .filter(([guard]) => guard(object)) - .map(([_, type]) => ({ type })) - [0] || {} + [isSource, "source"], + ] as const ) + .filter(([guard]) => guard(object)) + .map(([_, type]) => ({ type }))[0] || {}), } as unknown as Reference; } - type OmitNever = { - [K in keyof T as T[K] extends never ? never : K]: T[K] + [K in keyof T as T[K] extends never ? never : K]: T[K]; }; - export namespace Reference { - export type Type = { + export type Type = { [T in keyof Types]: O extends Types[T] ? T : never; }[keyof Types]; - type Types = { - "compilation": Compilation, - "source": Source + compilation: Compilation; + source: Source; }; - } export interface Compilation { @@ -72,13 +62,20 @@ export namespace Materials { } export const isCompilation = (value: unknown): value is Compilation => - typeof value === "object" && !!value && - "id" in value && isId(value.id) && - "compiler" in value && typeof value.compiler === "object" && !!value.compiler && - "name" in value.compiler && typeof value.compiler.name === "string" && - "version" in value.compiler && typeof value.compiler.version === "string" && - "sources" in value && value.sources instanceof Array && - value.sources.every(isSource); + typeof value === "object" && + !!value && + "id" in value && + isId(value.id) && + "compiler" in value && + typeof value.compiler === "object" && + !!value.compiler && + "name" in value.compiler && + typeof value.compiler.name === "string" && + "version" in value.compiler && + typeof value.compiler.version === "string" && + "sources" in value && + value.sources instanceof Array && + value.sources.every(isSource); export interface Source { id: Id; @@ -89,15 +86,17 @@ export namespace Materials { } export const isSource = (value: unknown): value is Source => - typeof value === "object" && !!value && - "id" in value && isId(value.id) && - "path" in value && typeof value.path === "string" && - "contents" in value && typeof value.contents === "string" && - "language" in value && typeof value.language === "string" && - ( - !("encoding" in value) || typeof value.encoding === "string" - ); - + typeof value === "object" && + !!value && + "id" in value && + isId(value.id) && + "path" in value && + typeof value.path === "string" && + "contents" in value && + typeof value.contents === "string" && + "language" in value && + typeof value.language === "string" && + (!("encoding" in value) || typeof value.encoding === "string"); export interface SourceRange { compilation?: Reference; @@ -109,18 +108,16 @@ export namespace Materials { } export const isSourceRange = (value: unknown): value is SourceRange => - typeof value === "object" && !!value && - "source" in value && isReference(value.source) && - ( - !("range" in value) || - ( - typeof value.range === "object" && !!value.range && - "offset" in value.range && Data.isValue(value.range.offset) && - "length" in value.range && Data.isValue(value.range.length) - ) - ) && - ( - !("compilation" in value) || isReference(value.compilation) - ); - + typeof value === "object" && + !!value && + "source" in value && + isReference(value.source) && + (!("range" in value) || + (typeof value.range === "object" && + !!value.range && + "offset" in value.range && + Data.isValue(value.range.offset) && + "length" in value.range && + Data.isValue(value.range.length))) && + (!("compilation" in value) || isReference(value.compilation)); } diff --git a/packages/format/src/types/pointer/pointer.test.ts b/packages/format/src/types/pointer/pointer.test.ts index e367033b1..49dc73bfe 100644 --- a/packages/format/src/types/pointer/pointer.test.ts +++ b/packages/format/src/types/pointer/pointer.test.ts @@ -6,99 +6,99 @@ const expressionSchema = "schema:ethdebug/format/pointer/expression"; testSchemaGuards("ethdebug/format/pointer", [ { schema: expressionSchema, - guard: Pointer.isExpression + guard: Pointer.isExpression, }, { schema: expressionSchema, pointer: "#/$defs/Literal", - guard: Pointer.Expression.isLiteral + guard: Pointer.Expression.isLiteral, }, { schema: expressionSchema, pointer: "#/$defs/Constant", - guard: Pointer.Expression.isConstant + guard: Pointer.Expression.isConstant, }, { schema: expressionSchema, pointer: "#/$defs/Variable", - guard: Pointer.Expression.isVariable + guard: Pointer.Expression.isVariable, }, { schema: expressionSchema, pointer: "#/$defs/Arithmetic", - guard: Pointer.Expression.isArithmetic + guard: Pointer.Expression.isArithmetic, }, { schema: expressionSchema, pointer: "#/$defs/Lookup", - guard: Pointer.Expression.isLookup + guard: Pointer.Expression.isLookup, }, { schema: expressionSchema, pointer: "#/$defs/Read", - guard: Pointer.Expression.isRead + guard: Pointer.Expression.isRead, }, { schema: expressionSchema, pointer: "#/$defs/Reference", - guard: Pointer.Expression.isReference + guard: Pointer.Expression.isReference, }, { schema: expressionSchema, pointer: "#/$defs/Keccak256", - guard: Pointer.Expression.isKeccak256 + guard: Pointer.Expression.isKeccak256, }, { schema: expressionSchema, pointer: "#/$defs/Resize", - guard: Pointer.Expression.isResize + guard: Pointer.Expression.isResize, }, { schema: "schema:ethdebug/format/pointer/region", - guard: Pointer.isRegion + guard: Pointer.isRegion, }, { schema: "schema:ethdebug/format/pointer/region/stack", - guard: Pointer.Region.isStack + guard: Pointer.Region.isStack, }, { schema: "schema:ethdebug/format/pointer/region/memory", - guard: Pointer.Region.isMemory + guard: Pointer.Region.isMemory, }, { schema: "schema:ethdebug/format/pointer/region/storage", - guard: Pointer.Region.isStorage + guard: Pointer.Region.isStorage, }, { schema: "schema:ethdebug/format/pointer/region/calldata", - guard: Pointer.Region.isCalldata + guard: Pointer.Region.isCalldata, }, { schema: "schema:ethdebug/format/pointer/region/returndata", - guard: Pointer.Region.isReturndata + guard: Pointer.Region.isReturndata, }, { schema: "schema:ethdebug/format/pointer/region/transient", - guard: Pointer.Region.isTransient + guard: Pointer.Region.isTransient, }, { schema: "schema:ethdebug/format/pointer/region/code", - guard: Pointer.Region.isCode + guard: Pointer.Region.isCode, }, { schema: "schema:ethdebug/format/pointer/collection/group", - guard: Pointer.Collection.isGroup + guard: Pointer.Collection.isGroup, }, { schema: "schema:ethdebug/format/pointer/collection/list", - guard: Pointer.Collection.isList + guard: Pointer.Collection.isList, }, { schema: "schema:ethdebug/format/pointer", - guard: isPointer + guard: isPointer, }, { schema: "schema:ethdebug/format/pointer/template", - guard: Pointer.isTemplate + guard: Pointer.isTemplate, }, ] as const); diff --git a/packages/format/src/types/pointer/pointer.ts b/packages/format/src/types/pointer/pointer.ts index 94aba4108..23f030518 100644 --- a/packages/format/src/types/pointer/pointer.ts +++ b/packages/format/src/types/pointer/pointer.ts @@ -1,12 +1,7 @@ -export type Pointer = - | Pointer.Region - | Pointer.Collection; +export type Pointer = Pointer.Region | Pointer.Collection; export const isPointer = (value: unknown): value is Pointer => - [ - Pointer.isRegion, - Pointer.isCollection - ].some(guard => guard(value)); + [Pointer.isRegion, Pointer.isCollection].some((guard) => guard(value)); export namespace Pointer { export type Identifier = string; @@ -30,8 +25,8 @@ export namespace Pointer { Region.isCalldata, Region.isReturndata, Region.isTransient, - Region.isCode - ].some(guard => guard(value)); + Region.isCode, + ].some((guard) => guard(value)); export namespace Region { export interface Base { @@ -40,59 +35,40 @@ export namespace Pointer { } export const isBase = (value: unknown): value is Base => !!value && - typeof value === "object" && - (!("name" in value) || typeof value.name === "string") && - "location" in value && - typeof value.location === "string"; + typeof value === "object" && + (!("name" in value) || typeof value.name === "string") && + "location" in value && + typeof value.location === "string"; export type Name = Base["name"]; - export type Stack = - & Base - & Scheme.Segment - & { location: "stack" }; + export type Stack = Base & Scheme.Segment & { location: "stack" }; export const isStack = (value: unknown): value is Stack => isBase(value) && Scheme.isSegment(value) && value.location === "stack"; - export type Memory = - & Base - & Scheme.Slice - & { location: "memory" }; + export type Memory = Base & Scheme.Slice & { location: "memory" }; export const isMemory = (value: unknown): value is Memory => isBase(value) && Scheme.isSlice(value) && value.location === "memory"; - export type Storage = - & Base - & Scheme.Segment - & { location: "storage" }; + export type Storage = Base & Scheme.Segment & { location: "storage" }; export const isStorage = (value: unknown): value is Storage => isBase(value) && Scheme.isSegment(value) && value.location === "storage"; - export type Calldata = - & Base - & Scheme.Slice - & { location: "calldata" }; + export type Calldata = Base & Scheme.Slice & { location: "calldata" }; export const isCalldata = (value: unknown): value is Calldata => isBase(value) && Scheme.isSlice(value) && value.location === "calldata"; - export type Returndata = - & Base - & Scheme.Slice - & { location: "returndata" }; + export type Returndata = Base & Scheme.Slice & { location: "returndata" }; export const isReturndata = (value: unknown): value is Returndata => isBase(value) && Scheme.isSlice(value) && value.location === "returndata"; - export type Transient = - & Base - & Scheme.Segment - & { location: "transient" }; + export type Transient = Base & Scheme.Segment & { location: "transient" }; export const isTransient = (value: unknown): value is Transient => - isBase(value) && Scheme.isSegment(value) && value.location === "transient"; + isBase(value) && + Scheme.isSegment(value) && + value.location === "transient"; - export type Code = - & Base - & Scheme.Slice - & { location: "code" }; + export type Code = Base & Scheme.Slice & { location: "code" }; export const isCode = (value: unknown): value is Code => isBase(value) && Scheme.isSlice(value) && value.location === "code"; } @@ -105,11 +81,11 @@ export namespace Pointer { } export const isSegment = (value: unknown): value is Segment => !!value && - typeof value === "object" && - "slot" in value && - isExpression(value.slot) && - (!("offset" in value) || isExpression(value.offset)) && - (!("length" in value) || isExpression(value.length)); + typeof value === "object" && + "slot" in value && + isExpression(value.slot) && + (!("offset" in value) || isExpression(value.offset)) && + (!("length" in value) || isExpression(value.length)); export interface Slice { offset: Expression; @@ -118,11 +94,11 @@ export namespace Pointer { export const isSlice = (value: unknown): value is Slice => !!value && - typeof value === "object" && - "offset" in value && - isExpression(value.offset) && - "length" in value && - isExpression(value.length); + typeof value === "object" && + "offset" in value && + isExpression(value.offset) && + "length" in value && + isExpression(value.length); } export type Collection = @@ -140,8 +116,8 @@ export namespace Pointer { Collection.isConditional, Collection.isScope, Collection.isReference, - Collection.isTemplates - ].some(guard => guard(value)); + Collection.isTemplates, + ].some((guard) => guard(value)); export namespace Collection { export interface Group { @@ -149,34 +125,34 @@ export namespace Pointer { } export const isGroup = (value: unknown): value is Group => !!value && - typeof value === "object" && - Object.keys(value).length === 1 && - "group" in value && - value.group instanceof Array && - value.group.length >= 1 && - value.group.every(isPointer); + typeof value === "object" && + Object.keys(value).length === 1 && + "group" in value && + value.group instanceof Array && + value.group.length >= 1 && + value.group.every(isPointer); export interface List { list: { count: Expression; each: Identifier; is: Pointer; - } + }; } export const isList = (value: unknown): value is List => !!value && - typeof value === "object" && - Object.keys(value).length === 1 && - "list" in value && - !!value.list && - typeof value.list === "object" && - Object.keys(value.list).length === 3 && - "count" in value.list && - isExpression(value.list.count) && - "each" in value.list && - isIdentifier(value.list.each) && - "is" in value.list && - isPointer(value.list.is); + typeof value === "object" && + Object.keys(value).length === 1 && + "list" in value && + !!value.list && + typeof value.list === "object" && + Object.keys(value.list).length === 3 && + "count" in value.list && + isExpression(value.list.count) && + "each" in value.list && + isIdentifier(value.list.each) && + "is" in value.list && + isPointer(value.list.is); export interface Conditional { if: Expression; @@ -185,28 +161,29 @@ export namespace Pointer { } export const isConditional = (value: unknown): value is Conditional => !!value && - typeof value === "object" && - "if" in value && - isExpression(value.if) && - "then" in value && - isPointer(value.then) && - (!("else" in value) || isPointer(value.else)); + typeof value === "object" && + "if" in value && + isExpression(value.if) && + "then" in value && + isPointer(value.then) && + (!("else" in value) || isPointer(value.else)); export interface Scope { define: { [identifier: string]: Expression; - } + }; in: Pointer; } export const isScope = (value: unknown): value is Scope => !!value && - typeof value === "object" && - "define" in value && - typeof value.define === "object" && !!value.define && - Object.keys(value.define).every(key => isIdentifier(key)) && - "in" in value && - isPointer(value.in); + typeof value === "object" && + "define" in value && + typeof value.define === "object" && + !!value.define && + Object.keys(value.define).every((key) => isIdentifier(key)) && + "in" in value && + isPointer(value.in); export interface Reference { template: string; @@ -215,16 +192,16 @@ export namespace Pointer { export const isReference = (value: unknown): value is Reference => !!value && - typeof value === "object" && - "template" in value && - typeof value.template === "string" && !!value.template && - (!("yields" in value) || ( - typeof value.yields === "object" && + typeof value === "object" && + "template" in value && + typeof value.template === "string" && + !!value.template && + (!("yields" in value) || + (typeof value.yields === "object" && value.yields !== null && Object.entries(value.yields as Record).every( - ([k, v]) => isIdentifier(k) && isIdentifier(v) - ) - )) + ([k, v]) => isIdentifier(k) && isIdentifier(v), + ))); export interface Templates { templates: { @@ -235,13 +212,14 @@ export namespace Pointer { export const isTemplates = (value: unknown): value is Templates => !!value && - typeof value === "object" && - "templates" in value && - typeof value.templates === "object" && !!value.templates && - Object.keys(value.templates).every(isIdentifier) && - Object.values(value.templates).every(isTemplate) && - "in" in value && - isPointer(value.in); + typeof value === "object" && + "templates" in value && + typeof value.templates === "object" && + !!value.templates && + Object.keys(value.templates).every(isIdentifier) && + Object.values(value.templates).every(isTemplate) && + "in" in value && + isPointer(value.in); } export type Expression = @@ -265,17 +243,16 @@ export namespace Pointer { Expression.isRead, Expression.isKeccak256, Expression.isConcat, - Expression.isResize - ].some(guard => guard(value)); + Expression.isResize, + ].some((guard) => guard(value)); export namespace Expression { export type Literal = number | `0x${string}`; export const isLiteral = (value: unknown): value is Literal => typeof value === "number" || - typeof value === "string" && /^0x[0-9a-fA-F]+$/.test(value); + (typeof value === "string" && /^0x[0-9a-fA-F]+$/.test(value)); - export type Constant = - | "$wordsize"; + export type Constant = "$wordsize"; export const isConstant = (value: unknown): value is Constant => typeof value === "string" && ["$wordsize"].includes(value); @@ -296,26 +273,24 @@ export namespace Pointer { Arithmetic.isDifference, Arithmetic.isProduct, Arithmetic.isQuotient, - Arithmetic.isRemainder - ].some(guard => guard(value)); - - const makeIsOperation = < - O extends string, - T extends { [K in O]: any; } - >( - operation: O, - checkOperands: (operands: unknown) => operands is T[O] - ) => (value: unknown): value is T => - !!value && + Arithmetic.isRemainder, + ].some((guard) => guard(value)); + + const makeIsOperation = + ( + operation: O, + checkOperands: (operands: unknown) => operands is T[O], + ) => + (value: unknown): value is T => + !!value && typeof value === "object" && Object.keys(value).length === 1 && operation in value && checkOperands(value[operation as keyof typeof value]); export type Operands = Expression[]; - export const isOperands = - (value: unknown): value is Expression[] => - value instanceof Array && value.every(isExpression); + export const isOperands = (value: unknown): value is Expression[] => + value instanceof Array && value.every(isExpression); export namespace Arithmetic { export type Operation = @@ -325,132 +300,137 @@ export namespace Pointer { | keyof Quotient | keyof Remainder; - export const isTwoOperands = - (value: unknown): value is [Expression, Expression] => - isOperands(value) && value.length === 2; + export const isTwoOperands = ( + value: unknown, + ): value is [Expression, Expression] => + isOperands(value) && value.length === 2; export interface Sum { $sum: Expression[]; } - export const isSum = - makeIsOperation<"$sum", Sum>("$sum", isOperands); + export const isSum = makeIsOperation<"$sum", Sum>("$sum", isOperands); export interface Difference { $difference: [Expression, Expression]; } - export const isDifference = - makeIsOperation<"$difference", Difference>("$difference", isTwoOperands); + export const isDifference = makeIsOperation<"$difference", Difference>( + "$difference", + isTwoOperands, + ); export interface Product { $product: Expression[]; } - export const isProduct = - makeIsOperation<"$product", Product>("$product", isOperands); + export const isProduct = makeIsOperation<"$product", Product>( + "$product", + isOperands, + ); export interface Quotient { $quotient: [Expression, Expression]; } - export const isQuotient = - makeIsOperation<"$quotient", Quotient>("$quotient", isTwoOperands); + export const isQuotient = makeIsOperation<"$quotient", Quotient>( + "$quotient", + isTwoOperands, + ); export interface Remainder { $remainder: [Expression, Expression]; } - export const isRemainder = - makeIsOperation<"$remainder", Remainder>("$remainder", isTwoOperands); + export const isRemainder = makeIsOperation<"$remainder", Remainder>( + "$remainder", + isTwoOperands, + ); } - export type Reference = - | Identifier - | "$this"; + export type Reference = Identifier | "$this"; export const isReference = (value: unknown): value is Reference => isIdentifier(value) || value === "$this"; - export type Lookup = - | Lookup.Offset - | Lookup.Length - | Lookup.Slot; + export type Lookup = Lookup.Offset | Lookup.Length | Lookup.Slot; export const isLookup = (value: unknown): value is Lookup => - [ - Lookup.isOffset, - Lookup.isLength, - Lookup.isSlot - ].some(guard => guard(value)); + [Lookup.isOffset, Lookup.isLength, Lookup.isSlot].some((guard) => + guard(value), + ); export namespace Lookup { - export type Operation = - | keyof Offset - | keyof Length - | keyof Slot; + export type Operation = keyof Offset | keyof Length | keyof Slot; - export type ForOperation = - & Lookup - & { [K in O]: any }; + export type ForOperation = Lookup & { + [K in O]: any; + }; export const propertyFrom = ( - operation: O + operation: O, ): "slot" | "offset" | "length" => { return operation.slice(1) as "slot" | "offset" | "length"; - } + }; export interface Offset { ".offset": Reference; } - export const isOffset = - makeIsOperation<".offset", Offset>(".offset", isReference); + export const isOffset = makeIsOperation<".offset", Offset>( + ".offset", + isReference, + ); export interface Length { ".length": Reference; } - export const isLength = - makeIsOperation<".length", Length>(".length", isReference); + export const isLength = makeIsOperation<".length", Length>( + ".length", + isReference, + ); export interface Slot { ".slot": Reference; } - export const isSlot = - makeIsOperation<".slot", Slot>(".slot", isReference); + export const isSlot = makeIsOperation<".slot", Slot>( + ".slot", + isReference, + ); } export interface Read { - $read: Reference + $read: Reference; } export const isRead = makeIsOperation<"$read", Read>("$read", isReference); export interface Keccak256 { $keccak256: Expression[]; } - export const isKeccak256 = - makeIsOperation<"$keccak256", Keccak256>("$keccak256", isOperands); + export const isKeccak256 = makeIsOperation<"$keccak256", Keccak256>( + "$keccak256", + isOperands, + ); export interface Concat { $concat: Expression[]; } - export const isConcat = - makeIsOperation<"$concat", Concat>("$concat", isOperands); + export const isConcat = makeIsOperation<"$concat", Concat>( + "$concat", + isOperands, + ); export type Resize = | Resize.ToNumber | Resize.ToWordsize; export const isResize = ( - value: unknown + value: unknown, ): value is Resize => - [ - Resize.isToWordsize, - Resize.isToNumber, - ].some(guard => guard(value)); + [Resize.isToWordsize, Resize.isToNumber].some((guard) => guard(value)); export namespace Resize { export type ToNumber = { [K in `$sized${N}`]: Expression; }; export const isToNumber = ( - value: unknown + value: unknown, ): value is ToNumber => { if ( !value || - typeof value !== "object" || - Object.keys(value).length !== 1 + typeof value !== "object" || + Object.keys(value).length !== 1 ) { return false; } @@ -461,14 +441,14 @@ export namespace Pointer { export type ToWordsize = { $wordsized: Expression; - } + }; export const isToWordsize = (value: unknown): value is ToWordsize => !!value && - typeof value === "object" && - Object.keys(value).length === 1 && - "$wordsized" in value && - typeof value.$wordsized !== "undefined" && - isExpression(value.$wordsized); + typeof value === "object" && + Object.keys(value).length === 1 && + "$wordsized" in value && + typeof value.$wordsized !== "undefined" && + isExpression(value.$wordsized); } } @@ -478,9 +458,9 @@ export namespace Pointer { export const isTemplates = (value: unknown): value is Templates => !!value && - typeof value === "object" && - Object.keys(value).every(isIdentifier) && - Object.values(value).every(isTemplate); + typeof value === "object" && + Object.keys(value).every(isIdentifier) && + Object.values(value).every(isTemplate); export interface Template { expect: string[]; @@ -489,12 +469,11 @@ export namespace Pointer { export const isTemplate = (value: unknown): value is Template => !!value && - typeof value === "object" && - Object.keys(value).length === 2 && - "expect" in value && - value.expect instanceof Array && - value.expect.every(isIdentifier) && - "for" in value && - isPointer(value.for); - + typeof value === "object" && + Object.keys(value).length === 2 && + "expect" in value && + value.expect instanceof Array && + value.expect.every(isIdentifier) && + "for" in value && + isPointer(value.for); } diff --git a/packages/format/src/types/program/context.test.ts b/packages/format/src/types/program/context.test.ts index 65cee6de3..a8c6a6d9a 100644 --- a/packages/format/src/types/program/context.test.ts +++ b/packages/format/src/types/program/context.test.ts @@ -4,30 +4,30 @@ import { Context, isContext } from "./context"; testSchemaGuards("ethdebug/format/program/context", [ { schema: "schema:ethdebug/format/program/context", - guard: isContext + guard: isContext, }, { schema: "schema:ethdebug/format/program/context/code", - guard: Context.isCode + guard: Context.isCode, }, { schema: "schema:ethdebug/format/program/context/variables", - guard: Context.isVariables + guard: Context.isVariables, }, { schema: "schema:ethdebug/format/program/context/remark", - guard: Context.isRemark + guard: Context.isRemark, }, { schema: "schema:ethdebug/format/program/context/pick", - guard: Context.isPick + guard: Context.isPick, }, { schema: "schema:ethdebug/format/program/context/gather", - guard: Context.isGather + guard: Context.isGather, }, { schema: "schema:ethdebug/format/program/context/frame", - guard: Context.isFrame + guard: Context.isFrame, }, ] as const); diff --git a/packages/format/src/types/program/context.ts b/packages/format/src/types/program/context.ts index 74b2bde29..34de5899e 100644 --- a/packages/format/src/types/program/context.ts +++ b/packages/format/src/types/program/context.ts @@ -10,14 +10,15 @@ export type Context = | Context.Gather | Context.Frame; -export const isContext = (value: unknown): value is Context => [ - Context.isCode, - Context.isVariables, - Context.isRemark, - Context.isPick, - Context.isFrame, - Context.isGather, -].some(guard => guard(value)); +export const isContext = (value: unknown): value is Context => + [ + Context.isCode, + Context.isVariables, + Context.isRemark, + Context.isPick, + Context.isFrame, + Context.isGather, + ].some((guard) => guard(value)); export namespace Context { export interface Code { @@ -25,18 +26,22 @@ export namespace Context { } export const isCode = (value: unknown): value is Code => - typeof value === "object" && !!value && - "code" in value && Materials.isSourceRange(value.code); + typeof value === "object" && + !!value && + "code" in value && + Materials.isSourceRange(value.code); export interface Variables { - variables: Variables.Variable[] + variables: Variables.Variable[]; } export const isVariables = (value: unknown): value is Variables => - typeof value === "object" && !!value && - "variables" in value && value.variables instanceof Array && - value.variables.length > 0 && - value.variables.every(Variables.isVariable); + typeof value === "object" && + !!value && + "variables" in value && + value.variables instanceof Array && + value.variables.length > 0 && + value.variables.every(Variables.isVariable); export namespace Variables { export interface Variable { @@ -50,29 +55,19 @@ export namespace Context { "identifier", "declaration", "type", - "pointer" + "pointer", ]); export const isVariable = (value: unknown): value is Variable => - typeof value === "object" && !!value && - Object.keys(value).length > 0 && - Object.keys(value).every(key => allowedKeys.has(key)) && - ( - !("identifier" in value) || - typeof value.identifier === "string" - ) && - ( - !("declaration" in value) || - Materials.isSourceRange(value.declaration) - ) && - ( - !("type" in value) || - isType(value.type) - ) && - ( - !("pointer" in value) || - isPointer(value.pointer) - ); + typeof value === "object" && + !!value && + Object.keys(value).length > 0 && + Object.keys(value).every((key) => allowedKeys.has(key)) && + (!("identifier" in value) || typeof value.identifier === "string") && + (!("declaration" in value) || + Materials.isSourceRange(value.declaration)) && + (!("type" in value) || isType(value.type)) && + (!("pointer" in value) || isPointer(value.pointer)); } export interface Remark { @@ -80,32 +75,40 @@ export namespace Context { } export const isRemark = (value: unknown): value is Remark => - typeof value === "object" && !!value && - "remark" in value && typeof value.remark === "string"; + typeof value === "object" && + !!value && + "remark" in value && + typeof value.remark === "string"; export interface Pick { pick: Context[]; } export const isPick = (value: unknown): value is Pick => - typeof value === "object" && !!value && - "pick" in value && Array.isArray(value.pick) && - value.pick.every(isContext); + typeof value === "object" && + !!value && + "pick" in value && + Array.isArray(value.pick) && + value.pick.every(isContext); export interface Gather { gather: Context[]; } export const isGather = (value: unknown): value is Gather => - typeof value === "object" && !!value && - "gather" in value && Array.isArray(value.gather) && - value.gather.every(isContext); + typeof value === "object" && + !!value && + "gather" in value && + Array.isArray(value.gather) && + value.gather.every(isContext); export interface Frame { frame: string; } export const isFrame = (value: unknown): value is Frame => - typeof value === "object" && !!value && - "frame" in value && typeof value.frame === "string"; + typeof value === "object" && + !!value && + "frame" in value && + typeof value.frame === "string"; } diff --git a/packages/format/src/types/program/instruction.test.ts b/packages/format/src/types/program/instruction.test.ts index 1784a7053..ee4139af5 100644 --- a/packages/format/src/types/program/instruction.test.ts +++ b/packages/format/src/types/program/instruction.test.ts @@ -4,6 +4,6 @@ import { Instruction, isInstruction } from "./instruction"; testSchemaGuards("ethdebug/format/program/instruction", [ { schema: "schema:ethdebug/format/program/instruction", - guard: isInstruction + guard: isInstruction, }, ] as const); diff --git a/packages/format/src/types/program/instruction.ts b/packages/format/src/types/program/instruction.ts index 6edc36a24..f8e10db1f 100644 --- a/packages/format/src/types/program/instruction.ts +++ b/packages/format/src/types/program/instruction.ts @@ -9,11 +9,12 @@ export interface Instruction { } export const isInstruction = (value: unknown): value is Instruction => - typeof value === "object" && !!value && - "offset" in value && Data.isValue(value.offset) && - (!("context" in value) || isContext(value.context)) && - (!("operation" in value) || Instruction.isOperation(value.operation)); - + typeof value === "object" && + !!value && + "offset" in value && + Data.isValue(value.offset) && + (!("context" in value) || isContext(value.context)) && + (!("operation" in value) || Instruction.isOperation(value.operation)); export namespace Instruction { export interface Operation { @@ -22,12 +23,11 @@ export namespace Instruction { } export const isOperation = (value: unknown): value is Operation => - typeof value === "object" && !!value && - "mnemonic" in value && typeof value.mnemonic === "string" && - ( - !("arguments" in value) || ( - value.arguments instanceof Array && - value.arguments.every(Data.isValue) - ) - ) + typeof value === "object" && + !!value && + "mnemonic" in value && + typeof value.mnemonic === "string" && + (!("arguments" in value) || + (value.arguments instanceof Array && + value.arguments.every(Data.isValue))); } diff --git a/packages/format/src/types/program/program.test.ts b/packages/format/src/types/program/program.test.ts index 5f4228715..7fdff788c 100644 --- a/packages/format/src/types/program/program.test.ts +++ b/packages/format/src/types/program/program.test.ts @@ -4,6 +4,6 @@ import { Program, isProgram } from "./program"; testSchemaGuards("ethdebug/format/program", [ { schema: "schema:ethdebug/format/program", - guard: isProgram + guard: isProgram, }, ] as const); diff --git a/packages/format/src/types/program/program.ts b/packages/format/src/types/program/program.ts index 663adc202..0bb9d6a75 100644 --- a/packages/format/src/types/program/program.ts +++ b/packages/format/src/types/program/program.ts @@ -1,13 +1,10 @@ import { Materials } from "../materials"; -import { - Context as _Context, - isContext as _isContext -} from "./context"; +import { Context as _Context, isContext as _isContext } from "./context"; import { Instruction as _Instruction, - isInstruction as _isInstruction + isInstruction as _isInstruction, } from "./instruction"; export interface Program { @@ -19,32 +16,28 @@ export interface Program { } export const isProgram = (value: unknown): value is Program => - typeof value === "object" && !!value && - "contract" in value && Program.isContract(value.contract) && - "environment" in value && Program.isEnvironment(value.environment) && - "instructions" in value && value.instructions instanceof Array && - value.instructions.every(Program.isInstruction) && - ( - !("compilation" in value) || - Materials.isReference(value.compilation) - ) && - ( - !("context" in value) || - Program.isContext(value.context) - ); + typeof value === "object" && + !!value && + "contract" in value && + Program.isContract(value.contract) && + "environment" in value && + Program.isEnvironment(value.environment) && + "instructions" in value && + value.instructions instanceof Array && + value.instructions.every(Program.isInstruction) && + (!("compilation" in value) || + Materials.isReference(value.compilation)) && + (!("context" in value) || Program.isContext(value.context)); export namespace Program { export import Context = _Context; export const isContext = _isContext; export import Instruction = _Instruction; export const isInstruction = _isInstruction; - export type Environment = - | "call" - | "create"; + export type Environment = "call" | "create"; export const isEnvironment = (value: unknown): value is Environment => - typeof value === "string" && - ["call", "create"].includes(value); + typeof value === "string" && ["call", "create"].includes(value); export interface Contract { name?: string; @@ -52,7 +45,9 @@ export namespace Program { } export const isContract = (value: unknown): value is Contract => - typeof value === "object" && !!value && - "definition" in value && Materials.isSourceRange(value.definition) && - (!("name" in value) || typeof value.name === "string"); + typeof value === "object" && + !!value && + "definition" in value && + Materials.isSourceRange(value.definition) && + (!("name" in value) || typeof value.name === "string"); } diff --git a/packages/format/src/types/type/base.test.ts b/packages/format/src/types/type/base.test.ts index c7600e7a6..e131b3b14 100644 --- a/packages/format/src/types/type/base.test.ts +++ b/packages/format/src/types/type/base.test.ts @@ -5,16 +5,16 @@ testSchemaGuards("ethdebug/format/type/base", [ { schema: "schema:ethdebug/format/type/base", pointer: "#/$defs/ElementaryType", - guard: Base.isElementary + guard: Base.isElementary, }, { schema: "schema:ethdebug/format/type/base", pointer: "#/$defs/ComplexType", - guard: Base.isComplex + guard: Base.isComplex, }, { schema: "schema:ethdebug/format/type/base", pointer: "#/$defs/TypeWrapper", - guard: Base.isWrapper + guard: Base.isWrapper, }, ] as const); diff --git a/packages/format/src/types/type/base.ts b/packages/format/src/types/type/base.ts index ecf72f52e..add55ef48 100644 --- a/packages/format/src/types/type/base.ts +++ b/packages/format/src/types/type/base.ts @@ -1,12 +1,7 @@ -export type Type = - | Elementary - | Complex; +export type Type = Elementary | Complex; export const isType = (value: unknown): value is Type => - [ - isElementary, - isComplex - ].some(guard => guard(value)); + [isElementary, isComplex].some((guard) => guard(value)); export interface Elementary { class?: "elementary"; @@ -14,12 +9,12 @@ export interface Elementary { } export const isElementary = (value: unknown): value is Elementary => - typeof value === "object" && !!value && - "kind" in value && typeof value.kind === "string" && - ( - !("class" in value) || value.class === "elementary" - ) && - !("contains" in value); + typeof value === "object" && + !!value && + "kind" in value && + typeof value.kind === "string" && + (!("class" in value) || value.class === "elementary") && + !("contains" in value); export interface Complex { class?: "complex"; @@ -28,40 +23,30 @@ export interface Complex { | Wrapper | Wrapper[] | { - [key: string]: Wrapper + [key: string]: Wrapper; }; } export const isComplex = (value: unknown): value is Complex => - typeof value === "object" && !!value && - "kind" in value && typeof value.kind === "string" && - ( - !("class" in value) || value.class === "complex" - ) && - "contains" in value && !!value.contains && ( - isWrapper(value.contains) || - ( - value.contains instanceof Array && - value.contains.every(isWrapper) - ) || - ( - typeof value.contains === "object" && - Object.values(value.contains).every(isWrapper) - ) - ); + typeof value === "object" && + !!value && + "kind" in value && + typeof value.kind === "string" && + (!("class" in value) || value.class === "complex") && + "contains" in value && + !!value.contains && + (isWrapper(value.contains) || + (value.contains instanceof Array && value.contains.every(isWrapper)) || + (typeof value.contains === "object" && + Object.values(value.contains).every(isWrapper))); export interface Wrapper { - type: - | Type - | { id: any; }; + type: Type | { id: any }; } export const isWrapper = (value: unknown): value is Wrapper => - typeof value === "object" && !!value && - "type" in value && ( - isType(value.type) || - ( - typeof value.type === "object" && !!value.type && - "id" in value.type - ) - ); + typeof value === "object" && + !!value && + "type" in value && + (isType(value.type) || + (typeof value.type === "object" && !!value.type && "id" in value.type)); diff --git a/packages/format/src/types/type/index.test.ts b/packages/format/src/types/type/index.test.ts index a8aa42b0c..6480b85ca 100644 --- a/packages/format/src/types/type/index.test.ts +++ b/packages/format/src/types/type/index.test.ts @@ -1,84 +1,83 @@ import { testSchemaGuards } from "../../../test/guards"; import { Type, isType } from "./index"; - testSchemaGuards("ethdebug/format/type", [ { schema: "schema:ethdebug/format/type", - guard: isType + guard: isType, }, // elementary types { schema: "schema:ethdebug/format/type/elementary", - guard: Type.isElementary + guard: Type.isElementary, }, { schema: "schema:ethdebug/format/type/elementary/uint", - guard: Type.Elementary.isUint + guard: Type.Elementary.isUint, }, { schema: "schema:ethdebug/format/type/elementary/int", - guard: Type.Elementary.isInt + guard: Type.Elementary.isInt, }, { schema: "schema:ethdebug/format/type/elementary/ufixed", - guard: Type.Elementary.isUfixed + guard: Type.Elementary.isUfixed, }, { schema: "schema:ethdebug/format/type/elementary/fixed", - guard: Type.Elementary.isFixed + guard: Type.Elementary.isFixed, }, { schema: "schema:ethdebug/format/type/elementary/bool", - guard: Type.Elementary.isBool + guard: Type.Elementary.isBool, }, { schema: "schema:ethdebug/format/type/elementary/bytes", - guard: Type.Elementary.isBytes + guard: Type.Elementary.isBytes, }, { schema: "schema:ethdebug/format/type/elementary/string", - guard: Type.Elementary.isString + guard: Type.Elementary.isString, }, { schema: "schema:ethdebug/format/type/elementary/address", - guard: Type.Elementary.isAddress + guard: Type.Elementary.isAddress, }, { schema: "schema:ethdebug/format/type/elementary/contract", - guard: Type.Elementary.isContract + guard: Type.Elementary.isContract, }, { schema: "schema:ethdebug/format/type/elementary/enum", - guard: Type.Elementary.isEnum + guard: Type.Elementary.isEnum, }, // complex types { schema: "schema:ethdebug/format/type/complex", - guard: Type.isComplex + guard: Type.isComplex, }, { schema: "schema:ethdebug/format/type/complex/alias", - guard: Type.Complex.isAlias + guard: Type.Complex.isAlias, }, { schema: "schema:ethdebug/format/type/complex/tuple", - guard: Type.Complex.isTuple + guard: Type.Complex.isTuple, }, { schema: "schema:ethdebug/format/type/complex/array", - guard: Type.Complex.isArray + guard: Type.Complex.isArray, }, { schema: "schema:ethdebug/format/type/complex/mapping", - guard: Type.Complex.isMapping + guard: Type.Complex.isMapping, }, { schema: "schema:ethdebug/format/type/complex/struct", - guard: Type.Complex.isStruct + guard: Type.Complex.isStruct, }, ] as const); diff --git a/packages/format/src/types/type/index.ts b/packages/format/src/types/type/index.ts index 0df86d2b3..32d31e882 100644 --- a/packages/format/src/types/type/index.ts +++ b/packages/format/src/types/type/index.ts @@ -3,62 +3,45 @@ import { Materials } from "../materials"; import * as _Base from "./base"; -export type Type = - | Type.Known - | Type.Unknown; +export type Type = Type.Known | Type.Unknown; export const isType = (value: unknown): value is Type => - (Type.hasElementaryKind(value) || Type.hasComplexKind(value)) + Type.hasElementaryKind(value) || Type.hasComplexKind(value) ? Type.isKnown(value) : Type.isUnknown(value); export namespace Type { export import Base = _Base; - export type Known = - | Elementary - | Complex; + export type Known = Elementary | Complex; export const isKnown = (value: unknown): value is Known => - [ - isElementary, - isComplex - ].some(guard => guard(value)); + [isElementary, isComplex].some((guard) => guard(value)); - export type Unknown = - & Base.Type - & { class: Exclude }; + export type Unknown = Base.Type & { + class: Exclude; + }; export const isUnknown = (value: unknown): value is Unknown => Base.isType(value) && - "class" in value && - ( - !("contains" in value) || Type.isWrapper(value.contains) || - ( - value.contains instanceof Array && - value.contains.every(Type.isWrapper) - ) || - ( - typeof value.contains === "object" && - Object.values(value.contains).every(Type.isWrapper) - ) - ); + "class" in value && + (!("contains" in value) || + Type.isWrapper(value.contains) || + (value.contains instanceof Array && + value.contains.every(Type.isWrapper)) || + (typeof value.contains === "object" && + Object.values(value.contains).every(Type.isWrapper))); export interface Wrapper { - type: - | Type - | { id: any; } + type: Type | { id: any }; } export const isWrapper = (value: unknown): value is Wrapper => - typeof value === "object" && !!value && - "type" in value && ( - isType(value.type) || - ( - typeof value.type === "object" && !!value.type && - "id" in value.type - ) - ); + typeof value === "object" && + !!value && + "type" in value && + (isType(value.type) || + (typeof value.type === "object" && !!value.type && "id" in value.type)); export type Elementary = | Elementary.Uint @@ -72,23 +55,27 @@ export namespace Type { | Elementary.Contract | Elementary.Enum; - export const hasElementaryKind = (value: unknown): value is { - kind: Elementary["kind"] + export const hasElementaryKind = ( + value: unknown, + ): value is { + kind: Elementary["kind"]; } => - typeof value === "object" && !!value && - "kind" in value && typeof value.kind === "string" && - [ - "uint", - "int", - "ufixed", - "fixed", - "bool", - "bytes", - "string", - "address", - "contract", - "enum" - ].includes(value.kind); + typeof value === "object" && + !!value && + "kind" in value && + typeof value.kind === "string" && + [ + "uint", + "int", + "ufixed", + "fixed", + "bool", + "bytes", + "string", + "address", + "contract", + "enum", + ].includes(value.kind); export const isElementary = (value: unknown): value is Elementary => [ @@ -101,8 +88,8 @@ export namespace Type { Elementary.isString, Elementary.isAddress, Elementary.isContract, - Elementary.isEnum - ].some(guard => guard(value)); + Elementary.isEnum, + ].some((guard) => guard(value)); export namespace Elementary { export interface Uint { @@ -112,11 +99,15 @@ export namespace Type { } export const isUint = (value: unknown): value is Uint => - typeof value === "object" && !!value && - mayHaveClass(value, "elementary") && - hasKind(value, "uint") && - "bits" in value && typeof value.bits === "number" && - value.bits >= 8 && value.bits <= 256 && value.bits % 8 === 0; + typeof value === "object" && + !!value && + mayHaveClass(value, "elementary") && + hasKind(value, "uint") && + "bits" in value && + typeof value.bits === "number" && + value.bits >= 8 && + value.bits <= 256 && + value.bits % 8 === 0; export interface Int { class?: "elementary"; @@ -125,11 +116,15 @@ export namespace Type { } export const isInt = (value: unknown): value is Int => - typeof value === "object" && !!value && - mayHaveClass(value, "elementary") && - hasKind(value, "int") && - "bits" in value && typeof value.bits === "number" && - value.bits >= 8 && value.bits <= 256 && value.bits % 8 === 0; + typeof value === "object" && + !!value && + mayHaveClass(value, "elementary") && + hasKind(value, "int") && + "bits" in value && + typeof value.bits === "number" && + value.bits >= 8 && + value.bits <= 256 && + value.bits % 8 === 0; export interface Ufixed { class?: "elementary"; @@ -139,13 +134,19 @@ export namespace Type { } export const isUfixed = (value: unknown): value is Ufixed => - typeof value === "object" && !!value && - mayHaveClass(value, "elementary") && - hasKind(value, "ufixed") && - "bits" in value && typeof value.bits === "number" && - value.bits >= 8 && value.bits <= 256 && value.bits % 8 === 0 && - "places" in value && typeof value.places === "number" && - value.places >= 1 && value.places <= 80; + typeof value === "object" && + !!value && + mayHaveClass(value, "elementary") && + hasKind(value, "ufixed") && + "bits" in value && + typeof value.bits === "number" && + value.bits >= 8 && + value.bits <= 256 && + value.bits % 8 === 0 && + "places" in value && + typeof value.places === "number" && + value.places >= 1 && + value.places <= 80; export interface Fixed { class?: "elementary"; @@ -155,13 +156,19 @@ export namespace Type { } export const isFixed = (value: unknown): value is Fixed => - typeof value === "object" && !!value && - mayHaveClass(value, "elementary") && - hasKind(value, "fixed") && - "bits" in value && typeof value.bits === "number" && - value.bits >= 8 && value.bits <= 256 && value.bits % 8 === 0 && - "places" in value && typeof value.places === "number" && - value.places >= 1 && value.places <= 80; + typeof value === "object" && + !!value && + mayHaveClass(value, "elementary") && + hasKind(value, "fixed") && + "bits" in value && + typeof value.bits === "number" && + value.bits >= 8 && + value.bits <= 256 && + value.bits % 8 === 0 && + "places" in value && + typeof value.places === "number" && + value.places >= 1 && + value.places <= 80; export interface Bool { class?: "elementary"; @@ -169,9 +176,10 @@ export namespace Type { } export const isBool = (value: unknown): value is Bool => - typeof value === "object" && !!value && - mayHaveClass(value, "elementary") && - hasKind(value, "bool"); + typeof value === "object" && + !!value && + mayHaveClass(value, "elementary") && + hasKind(value, "bool"); export interface Bytes { class?: "elementary"; @@ -180,12 +188,11 @@ export namespace Type { } export const isBytes = (value: unknown): value is Bytes => - typeof value === "object" && !!value && - mayHaveClass(value, "elementary") && - hasKind(value, "bytes") && - ( - !("size" in value) || Data.isUnsigned(value.size) - ); + typeof value === "object" && + !!value && + mayHaveClass(value, "elementary") && + hasKind(value, "bytes") && + (!("size" in value) || Data.isUnsigned(value.size)); export interface String { class?: "elementary"; @@ -194,12 +201,11 @@ export namespace Type { } export const isString = (value: unknown): value is String => - typeof value === "object" && !!value && - mayHaveClass(value, "elementary") && - hasKind(value, "string") && - ( - !("encoding" in value) || typeof value.encoding === "string" - ); + typeof value === "object" && + !!value && + mayHaveClass(value, "elementary") && + hasKind(value, "string") && + (!("encoding" in value) || typeof value.encoding === "string"); export interface Address { class?: "elementary"; @@ -208,12 +214,11 @@ export namespace Type { } export const isAddress = (value: unknown): value is Address => - typeof value === "object" && !!value && - mayHaveClass(value, "elementary") && - hasKind(value, "address") && - ( - !("payable" in value) || typeof value.payable === "boolean" - ); + typeof value === "object" && + !!value && + mayHaveClass(value, "elementary") && + hasKind(value, "address") && + (!("payable" in value) || typeof value.payable === "boolean"); export interface Contract { class?: "elementary"; @@ -223,15 +228,12 @@ export namespace Type { } export const isContract = (value: unknown): value is Contract => - typeof value === "object" && !!value && - mayHaveClass(value, "elementary") && - hasKind(value, "contract") && - ( - !("payable" in value) || typeof value.payable === "boolean" - ) && - ( - !("definition" in value) || isDefinition(value.definition) - ); + typeof value === "object" && + !!value && + mayHaveClass(value, "elementary") && + hasKind(value, "contract") && + (!("payable" in value) || typeof value.payable === "boolean") && + (!("definition" in value) || isDefinition(value.definition)); export interface Enum { class?: "elementary"; @@ -241,13 +243,13 @@ export namespace Type { } export const isEnum = (value: unknown): value is Enum => - typeof value === "object" && !!value && - mayHaveClass(value, "elementary") && - hasKind(value, "enum") && - "values" in value && value.values instanceof Array && - ( - !("definition" in value) || isDefinition(value.definition) - ); + typeof value === "object" && + !!value && + mayHaveClass(value, "elementary") && + hasKind(value, "enum") && + "values" in value && + value.values instanceof Array && + (!("definition" in value) || isDefinition(value.definition)); } export type Complex = @@ -255,22 +257,26 @@ export namespace Type { | Complex.Tuple | Complex.Array | Complex.Mapping - | Complex.Struct - /* currently unsupported: | Complex.Function */; + | Complex.Struct; + /* currently unsupported: | Complex.Function */ - export const hasComplexKind = (value: unknown): value is { - kind: Complex["kind"] + export const hasComplexKind = ( + value: unknown, + ): value is { + kind: Complex["kind"]; } => - typeof value === "object" && !!value && - "kind" in value && typeof value.kind === "string" && - [ - "alias", - "tuple", - "array", - "mapping", - "struct", - // "function" - ].includes(value.kind); + typeof value === "object" && + !!value && + "kind" in value && + typeof value.kind === "string" && + [ + "alias", + "tuple", + "array", + "mapping", + "struct", + // "function" + ].includes(value.kind); export const isComplex = (value: unknown): value is Complex => [ @@ -279,7 +285,7 @@ export namespace Type { Complex.isArray, Complex.isMapping, Complex.isStruct, - ].some(guard => guard(value)); + ].some((guard) => guard(value)); export namespace Complex { export interface Alias { @@ -290,35 +296,32 @@ export namespace Type { } export const isAlias = (value: unknown): value is Alias => - typeof value === "object" && !!value && - mayHaveClass(value, "complex") && - hasKind(value, "alias") && - "contains" in value && isWrapper(value.contains) && - ( - !("definition" in value) || isDefinition(value.definition) - ); + typeof value === "object" && + !!value && + mayHaveClass(value, "complex") && + hasKind(value, "alias") && + "contains" in value && + isWrapper(value.contains) && + (!("definition" in value) || isDefinition(value.definition)); export interface Tuple { class?: "complex"; kind: "tuple"; - contains: ( - & Wrapper - & { name?: string } - )[]; + contains: (Wrapper & { name?: string })[]; } export const isTuple = (value: unknown): value is Tuple => - typeof value === "object" && !!value && - mayHaveClass(value, "complex") && - hasKind(value, "tuple") && - "contains" in value && value.contains instanceof Array && - value.contains.every( - (element) => - isWrapper(element) && - ( - !("name" in element) || typeof element.name === "string" - ) - ); + typeof value === "object" && + !!value && + mayHaveClass(value, "complex") && + hasKind(value, "tuple") && + "contains" in value && + value.contains instanceof Array && + value.contains.every( + (element) => + isWrapper(element) && + (!("name" in element) || typeof element.name === "string"), + ); export interface Array { class?: "complex"; @@ -327,54 +330,55 @@ export namespace Type { } export const isArray = (value: unknown): value is Array => - typeof value === "object" && !!value && - mayHaveClass(value, "complex") && - hasKind(value, "array") && - "contains" in value && isWrapper(value.contains); + typeof value === "object" && + !!value && + mayHaveClass(value, "complex") && + hasKind(value, "array") && + "contains" in value && + isWrapper(value.contains); export interface Mapping { class?: "complex"; kind: "mapping"; contains: { - key: Wrapper - value: Wrapper + key: Wrapper; + value: Wrapper; }; } export const isMapping = (value: unknown): value is Mapping => - typeof value === "object" && !!value && - mayHaveClass(value, "complex") && - hasKind(value, "mapping") && - "contains" in value && - typeof value.contains === "object" && !!value.contains && - "key" in value.contains && isWrapper(value.contains.key) && - "value" in value.contains && isWrapper(value.contains.value); + typeof value === "object" && + !!value && + mayHaveClass(value, "complex") && + hasKind(value, "mapping") && + "contains" in value && + typeof value.contains === "object" && + !!value.contains && + "key" in value.contains && + isWrapper(value.contains.key) && + "value" in value.contains && + isWrapper(value.contains.value); export interface Struct { class?: "complex"; kind: "struct"; - contains: ( - & Wrapper - & { name?: string } - )[]; + contains: (Wrapper & { name?: string })[]; definition?: Definition; } export const isStruct = (value: unknown): value is Struct => - typeof value === "object" && !!value && - mayHaveClass(value, "complex") && - hasKind(value, "struct") && - "contains" in value && value.contains instanceof Array && - value.contains.every( - (field) => - isWrapper(field) && - ( - !("name" in field) || typeof field.name === "string" - ) - ) && - ( - !("definition" in value) || isDefinition(value.definition) - ); + typeof value === "object" && + !!value && + mayHaveClass(value, "complex") && + hasKind(value, "struct") && + "contains" in value && + value.contains instanceof Array && + value.contains.every( + (field) => + isWrapper(field) && + (!("name" in field) || typeof field.name === "string"), + ) && + (!("definition" in value) || isDefinition(value.definition)); } export interface Definition { @@ -383,29 +387,21 @@ export namespace Type { } export const isDefinition = (value: unknown): value is Definition => - typeof value === "object" && !!value && - ( - !("name" in value) || typeof value.name === "string" - ) && - ( - !("location" in value) || Materials.isSourceRange(value.location) - ) && - ( - Object.keys(value).includes("name") || - Object.keys(value).includes("location") - ); - + typeof value === "object" && + !!value && + (!("name" in value) || typeof value.name === "string") && + (!("location" in value) || Materials.isSourceRange(value.location)) && + (Object.keys(value).includes("name") || + Object.keys(value).includes("location")); } export const mayHaveClass = ( object: object, - class_: Class + class_: Class, ): object is { class: Class } => !("class" in object) || object.class === class_; - export const hasKind = ( object: object, - kind: Kind -): object is { kind: Kind } => - "kind" in object && object.kind === kind; + kind: Kind, +): object is { kind: Kind } => "kind" in object && object.kind === kind; diff --git a/packages/format/test/extensions.ts b/packages/format/test/extensions.ts index 5cba4df4f..0e55322a4 100644 --- a/packages/format/test/extensions.ts +++ b/packages/format/test/extensions.ts @@ -3,81 +3,75 @@ import { schemas } from "../src"; export const schemaExtensions: { [schemaId: string]: { extends: Set; - } + }; } = { "schema:ethdebug/format/type/base#/$defs/ElementaryType": { - extends: new Set([ - "schema:ethdebug/format/type/base" - ]) + extends: new Set(["schema:ethdebug/format/type/base"]), }, "schema:ethdebug/format/type/base#/$defs/ComplexType": { - extends: new Set([ - "schema:ethdebug/format/type/base" - ]) + extends: new Set(["schema:ethdebug/format/type/base"]), }, "schema:ethdebug/format/type": { - extends: new Set([ - "schema:ethdebug/format/type/base" - ]) + 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/base#/$defs/ElementaryType", + ]), }, "schema:ethdebug/format/type/elementary/uint": { - extends: new Set(["schema:ethdebug/format/type/elementary"]) + extends: new Set(["schema:ethdebug/format/type/elementary"]), }, "schema:ethdebug/format/type/elementary/int": { - extends: new Set(["schema:ethdebug/format/type/elementary"]) + extends: new Set(["schema:ethdebug/format/type/elementary"]), }, "schema:ethdebug/format/type/elementary/bool": { - extends: new Set(["schema:ethdebug/format/type/elementary"]) + extends: new Set(["schema:ethdebug/format/type/elementary"]), }, "schema:ethdebug/format/type/elementary/bytes": { - extends: new Set(["schema:ethdebug/format/type/elementary"]) + extends: new Set(["schema:ethdebug/format/type/elementary"]), }, "schema:ethdebug/format/type/elementary/string": { - extends: new Set(["schema:ethdebug/format/type/elementary"]) + extends: new Set(["schema:ethdebug/format/type/elementary"]), }, "schema:ethdebug/format/type/elementary/ufixed": { - extends: new Set(["schema:ethdebug/format/type/elementary"]) + extends: new Set(["schema:ethdebug/format/type/elementary"]), }, "schema:ethdebug/format/type/elementary/fixed": { - extends: new Set(["schema:ethdebug/format/type/elementary"]) + extends: new Set(["schema:ethdebug/format/type/elementary"]), }, "schema:ethdebug/format/type/elementary/address": { - extends: new Set(["schema:ethdebug/format/type/elementary"]) + extends: new Set(["schema:ethdebug/format/type/elementary"]), }, "schema:ethdebug/format/type/elementary/contract": { - extends: new Set(["schema:ethdebug/format/type/elementary"]) + extends: new Set(["schema:ethdebug/format/type/elementary"]), }, "schema:ethdebug/format/type/elementary/enum": { - extends: new Set(["schema:ethdebug/format/type/elementary"]) + 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/base#/$defs/ComplexType", + ]), }, "schema:ethdebug/format/type/complex/alias": { - extends: new Set(["schema:ethdebug/format/type/complex"]) + extends: new Set(["schema:ethdebug/format/type/complex"]), }, "schema:ethdebug/format/type/complex/tuple": { - extends: new Set(["schema:ethdebug/format/type/complex"]) + extends: new Set(["schema:ethdebug/format/type/complex"]), }, "schema:ethdebug/format/type/complex/array": { - extends: new Set(["schema:ethdebug/format/type/complex"]) + extends: new Set(["schema:ethdebug/format/type/complex"]), }, "schema:ethdebug/format/type/complex/mapping": { - extends: new Set(["schema:ethdebug/format/type/complex"]) + extends: new Set(["schema:ethdebug/format/type/complex"]), }, "schema:ethdebug/format/type/complex/struct": { - extends: new Set(["schema:ethdebug/format/type/complex"]) + extends: new Set(["schema:ethdebug/format/type/complex"]), }, "schema:ethdebug/format/type/complex/function": { - extends: new Set(["schema:ethdebug/format/type/complex"]) + extends: new Set(["schema:ethdebug/format/type/complex"]), }, -} +}; diff --git a/packages/format/test/guards.ts b/packages/format/test/guards.ts index 17bad95c0..470a3cefc 100644 --- a/packages/format/test/guards.ts +++ b/packages/format/test/guards.ts @@ -8,16 +8,14 @@ export interface SchemaGuard extends DescribeSchemaOptions { export const testSchemaGuards = ( namespace: string, - schemaGuards: SchemaGuard[] + schemaGuards: SchemaGuard[], ) => { describe(`type guards for ${namespace} schemas`, () => { for (const { guard, ...describeSchemaOptions } of schemaGuards) { const { id, pointer, - schema: { - examples = [] - } + schema: { examples = [] }, } = describeSchema(describeSchemaOptions); const schemaName = `${id?.slice("schema:".length) || ""}${pointer || ""}`; diff --git a/packages/format/test/hyperjump.ts b/packages/format/test/hyperjump.ts index 304dfd8bc..1c6aee7ac 100644 --- a/packages/format/test/hyperjump.ts +++ b/packages/format/test/hyperjump.ts @@ -11,10 +11,7 @@ import * as YAML from "yaml"; import indentString from "indent-string"; import { highlight } from "cli-highlight"; -import { - describeSchema, - type DescribeSchemaOptions -} from "../src/describe"; +import { describeSchema, type DescribeSchemaOptions } from "../src/describe"; import { schemas } from "../src/schemas"; @@ -33,14 +30,9 @@ const main = () => { throw new Error("Schema is not known to validator by ID"); } - const schemaReference = pointer - ? `${id}${pointer}` - : id; + const schemaReference = pointer ? `${id}${pointer}` : id; - const schemaName = - schema.title - ? schema.title - : schemaReference; + const schemaName = schema.title ? schema.title : schemaReference; const output = await validate(schemaReference, received, BASIC); @@ -48,28 +40,21 @@ const main = () => { return { pass, - message: () => `expected input:\n${ - indentString( + message: () => + `expected input:\n${indentString( highlight(YAML.stringify(received), { language: "yaml" }), - 2 - ) - }\n${ - pass - ? "not to be" - : "to be" - } valid ${schemaName}.${ - pass - ? "" - : `\noutput:\n${ - indentString( + 2, + )}\n${pass ? "not to be" : "to be"} valid ${schemaName}.${ + pass + ? "" + : `\noutput:\n${indentString( highlight(YAML.stringify(output), { language: "yaml" }), - 2 - ) - }` - }` + 2, + )}` + }`, }; - } + }, }); -} +}; main(); diff --git a/packages/format/tsconfig.json b/packages/format/tsconfig.json index 2739d3471..ec5998010 100644 --- a/packages/format/tsconfig.json +++ b/packages/format/tsconfig.json @@ -6,11 +6,7 @@ "moduleResolution": "node10", "exactOptionalPropertyTypes": true, "rootDir": "./", - "outDir": "./dist/", + "outDir": "./dist/" }, - "include": [ - "./src/**/*.ts", - "vitest.d.ts", - "yamls.ts" - ] + "include": ["./src/**/*.ts", "vitest.d.ts", "yamls.ts"] } diff --git a/packages/format/vitest.config.ts b/packages/format/vitest.config.ts index 09576069a..58ad168d0 100644 --- a/packages/format/vitest.config.ts +++ b/packages/format/vitest.config.ts @@ -2,6 +2,6 @@ import { defineProject } from "vitest/config"; export default defineProject({ test: { - setupFiles: ["./vitest.setup.ts"] - } + setupFiles: ["./vitest.setup.ts"], + }, }); diff --git a/packages/format/vitest.setup.ts b/packages/format/vitest.setup.ts index 1bf3a7d19..3b099a359 100644 --- a/packages/format/vitest.setup.ts +++ b/packages/format/vitest.setup.ts @@ -4,49 +4,44 @@ import chalk from "chalk"; expect.extend({ toSatisfy value is T>( predicate: P, - received: any + received: any, ) { const pass = predicate(received); return { pass, - message: () => `expected ${ - JSON.stringify(received) - } ${ - pass - ? "not to satisfy" - : "to satisfy" - } the predicate ${predicate.name}` + message: () => + `expected ${JSON.stringify(received)} ${ + pass ? "not to satisfy" : "to satisfy" + } the predicate ${predicate.name}`, }; }, toSatisfyAll value is T>( predicate: P, - values: any[] + values: any[], ) { - const results = values.map(value => ({ + const results = values.map((value) => ({ value, - pass: predicate(value) + pass: predicate(value), })); - const pass = results.every(result => result.pass); + const pass = results.every((result) => result.pass); return { pass, - message: () => `expected the predicate ${predicate.name} ${ - pass - ? "not to be satisfied by all" - : "to be satisfied by all" - } of the following values:\n${ - results.map(result => ` ${ - result.pass - ? chalk.green("✓") - : chalk.red("✗") - } ${ - // @ts-ignore - this.utils.printReceived(result.value) - }`).join("\n") - }` + message: () => + `expected the predicate ${predicate.name} ${ + pass ? "not to be satisfied by all" : "to be satisfied by all" + } of the following values:\n${results + .map( + (result) => + ` ${result.pass ? chalk.green("✓") : chalk.red("✗")} ${ + // @ts-ignore + this.utils.printReceived(result.value) + }`, + ) + .join("\n")}`, }; - } + }, }); diff --git a/packages/pointers/bin/run-example.ts b/packages/pointers/bin/run-example.ts index db9b7ed41..7a2dccb47 100644 --- a/packages/pointers/bin/run-example.ts +++ b/packages/pointers/bin/run-example.ts @@ -2,26 +2,22 @@ import chalk from "chalk"; import { highlight } from "cli-highlight"; import { describeSchema } from "@ethdebug/format"; -import { - type Cursor, - Data -} from "../src/index.js"; +import { type Cursor, Data } from "../src/index.js"; import { observeTrace } from "../test/index.js"; import { observeTraceTests } from "../src/test-cases.js"; export async function run() { - const { - pointer, - compileOptions, - observe - } = observeTraceTests["string storage"]; + const { pointer, compileOptions, observe } = + observeTraceTests["string storage"]; console.log( - chalk.bold(chalk.cyan( - "demo: run compiled solidity and watch a changing ethdebug/format pointer\n" - )) + chalk.bold( + chalk.cyan( + "demo: run compiled solidity and watch a changing ethdebug/format pointer\n", + ), + ), ); console.group(chalk.bold("ethdebug/format pointer used by demo")); @@ -29,25 +25,26 @@ export async function run() { highlight( describeSchema({ schema: { id: "schema:ethdebug/format/pointer" }, - pointer: "#/examples/4" + pointer: "#/examples/4", }).yaml, - { language: "yaml" } - ).trim() + { language: "yaml" }, + ).trim(), ); console.groupEnd(); console.log(""); console.group(chalk.bold("solidity source code used by demo")); - console.log( - compileOptions.sources["StringStorage.sol"].content.trim() - ); + console.log(compileOptions.sources["StringStorage.sol"].content.trim()); console.groupEnd(); console.log(""); console.group(chalk.bold("observing deployment trace")); - const observedValues = - await observeTrace({ pointer, compileOptions, observe }); + const observedValues = await observeTrace({ + pointer, + compileOptions, + observe, + }); console.groupEnd(); console.log(""); diff --git a/packages/pointers/src/cursor.ts b/packages/pointers/src/cursor.ts index 61b5ac855..4abb45320 100644 --- a/packages/pointers/src/cursor.ts +++ b/packages/pointers/src/cursor.ts @@ -40,7 +40,7 @@ export namespace Cursor { ? Data | undefined : R[K] : R[K]; - } + }; /** * A collection of concrete regions. @@ -51,21 +51,19 @@ export namespace Cursor { * It also provides a couple interfaces of its own for accessing regions by * name. */ - export type Regions = - & Cursor.Region[] - & { - /** - * Obtain an ordered list of all regions with a particular name. - * - * This is useful, e.g., when looking to concatenate a series of - * sequential regions that were generated by index from a list - * collection - */ - named(name: string): Cursor.Region[]; + export type Regions = Cursor.Region[] & { + /** + * Obtain an ordered list of all regions with a particular name. + * + * This is useful, e.g., when looking to concatenate a series of + * sequential regions that were generated by index from a list + * collection + */ + named(name: string): Cursor.Region[]; - /** - * Retrieve the last concrete region generated with a particular name - */ - lookup: { [name: string]: Cursor.Region }; - }; + /** + * Retrieve the last concrete region generated with a particular name + */ + lookup: { [name: string]: Cursor.Region }; + }; } diff --git a/packages/pointers/src/data.test.ts b/packages/pointers/src/data.test.ts index 9427c022f..b8c32362b 100644 --- a/packages/pointers/src/data.test.ts +++ b/packages/pointers/src/data.test.ts @@ -56,7 +56,9 @@ describe("Data", () => { }); it("throws an error for invalid hex string format", () => { - expect(() => Data.fromHex("ff")).toThrow("Invalid hex string format. Expected \"0x\" prefix."); + expect(() => Data.fromHex("ff")).toThrow( + 'Invalid hex string format. Expected "0x" prefix.', + ); }); }); }); diff --git a/packages/pointers/src/data.ts b/packages/pointers/src/data.ts index 937a4de06..470e83d12 100644 --- a/packages/pointers/src/data.ts +++ b/packages/pointers/src/data.ts @@ -37,7 +37,7 @@ export class Data extends Uint8Array { } static fromHex(hex: string): Data { - if (!hex.startsWith('0x')) { + if (!hex.startsWith("0x")) { throw new Error('Invalid hex string format. Expected "0x" prefix.'); } const bytes = new Uint8Array((hex.length - 2) / 2 + 0.5); @@ -56,8 +56,8 @@ export class Data extends Uint8Array { let value = 0n; for (const byte of this.values()) { - const byteValue = BigInt(byte) - value = (value << bits) + byteValue + const byteValue = BigInt(byte); + value = (value << bits) + byteValue; } return value; } @@ -95,7 +95,7 @@ export class Data extends Uint8Array { concat(...others: Data[]): Data { // HACK concatenate via string representation const concatenatedHex = [this, ...others] - .map(data => data.toHex().slice(2)) + .map((data) => data.toHex().slice(2)) .reduce((accumulator, hex) => `${accumulator}${hex}`, "0x"); return Data.fromHex(concatenatedHex); @@ -104,21 +104,18 @@ export class Data extends Uint8Array { inspect( depth: number, options: Util.InspectOptionsStylized, - inspect: typeof Util.inspect + inspect: typeof Util.inspect, ): string { return `Data[${options.stylize(this.toHex(), "number")}]`; } - [ - util && "inspect" in util && typeof util.inspect === "object" - ? util.inspect.custom - : "_inspect" - ]( + [util && "inspect" in util && typeof util.inspect === "object" + ? util.inspect.custom + : "_inspect"]( depth: number, options: Util.InspectOptionsStylized, - inspect: typeof Util.inspect + inspect: typeof Util.inspect, ): string { return this.inspect(depth, options, inspect); } - } diff --git a/packages/pointers/src/dereference/cursor.ts b/packages/pointers/src/dereference/cursor.ts index 4ef5a5b77..7b0b68b90 100644 --- a/packages/pointers/src/dereference/cursor.ts +++ b/packages/pointers/src/dereference/cursor.ts @@ -3,7 +3,7 @@ import type { Cursor } from "../cursor.js"; import { read } from "../read.js"; export function createCursor( - simpleCursor: (state: Machine.State) => AsyncIterable + simpleCursor: (state: Machine.State) => AsyncIterable, ): Cursor { return { async view(state: Machine.State) { @@ -18,14 +18,14 @@ export function createCursor( const propertyFlags = { writable: false, enumerable: false, - configurable: false + configurable: false, } as const; const regions: Cursor.Regions = Object.create(Array.prototype, { length: { value: list.length, - ...propertyFlags - } + ...propertyFlags, + }, }); for (const [index, region] of list.entries()) { @@ -47,29 +47,29 @@ export function createCursor( for (const [name, region] of Object.entries(current)) { Object.defineProperty(regions, name, { value: region, - ...propertyFlags + ...propertyFlags, }); } Object.defineProperties(regions, { named: { value: (name: string) => named[name] || [], - ...propertyFlags + ...propertyFlags, }, lookup: { value: { - ...current + ...current, }, - ...propertyFlags - } + ...propertyFlags, + }, }); return { regions, async read(region: Cursor.Region) { return await read(region, { state }); - } + }, }; - } + }, }; } diff --git a/packages/pointers/src/dereference/generate.ts b/packages/pointers/src/dereference/generate.ts index eccdf0cfc..96d823fe3 100644 --- a/packages/pointers/src/dereference/generate.ts +++ b/packages/pointers/src/dereference/generate.ts @@ -25,15 +25,12 @@ export interface GenerateRegionsOptions { */ export async function* generateRegions( pointer: Pointer, - generateRegionsOptions: GenerateRegionsOptions + generateRegionsOptions: GenerateRegionsOptions, ): AsyncIterable { const options = await initializeProcessOptions(generateRegionsOptions); // extract records for mutation - const { - regions, - variables - } = options; + const { regions, variables } = options; // Stack of rename mappings for template references with yields const renameStack: Array> = []; @@ -51,13 +48,13 @@ export async function* generateRegions( // Merge inline templates with base templates (inline takes precedence) const currentTemplates = templatesStack.reduce( (acc, templates) => ({ ...acc, ...templates }), - options.templates + options.templates, ); // Process the pointer, intercepting yielded regions to apply renames const process = processPointer(memo.pointer, { ...options, - templates: currentTemplates + templates: currentTemplates, }); let result = await process.next(); while (!result.done) { @@ -126,7 +123,7 @@ export async function* generateRegions( async function initializeProcessOptions({ templates, state, - initialStackLength + initialStackLength, }: GenerateRegionsOptions): Promise { const currentStackLength = await state.stack.length; const stackLengthChange = currentStackLength - initialStackLength; @@ -139,6 +136,6 @@ async function initializeProcessOptions({ state, stackLengthChange, regions, - variables + variables, }; } diff --git a/packages/pointers/src/dereference/index.test.ts b/packages/pointers/src/dereference/index.test.ts index dffcde333..2799b752e 100644 --- a/packages/pointers/src/dereference/index.test.ts +++ b/packages/pointers/src/dereference/index.test.ts @@ -11,25 +11,39 @@ describe("dereference", () => { state = { stack: { length: Promise.resolve(10n), - peek: vitest.fn(async () => Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44]))), + peek: vitest.fn(async () => + Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), + ), }, memory: { - read: vitest.fn(async () => Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88]))), + read: vitest.fn(async () => + Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88])), + ), }, storage: { - read: vitest.fn(async () => Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]))), + read: vitest.fn(async () => + Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])), + ), }, calldata: { - read: vitest.fn(async () => Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44]))), + read: vitest.fn(async () => + Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), + ), }, returndata: { - read: vitest.fn(async () => Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88]))), + read: vitest.fn(async () => + Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88])), + ), }, transient: { - read: vitest.fn(async () => Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]))), + read: vitest.fn(async () => + Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])), + ), }, code: { - read: vitest.fn(async () => Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44]))), + read: vitest.fn(async () => + Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), + ), }, } as unknown as Machine.State; }); @@ -38,9 +52,9 @@ describe("dereference", () => { const pointer: Pointer = { location: "memory", offset: { - $sum: [0x40, 0x20] + $sum: [0x40, 0x20], }, - length: 0x20 + length: 0x20, }; const cursor = await dereference(pointer); @@ -51,29 +65,29 @@ describe("dereference", () => { expect(regions[0]).toEqual({ location: "memory", offset: Data.fromNumber(0x60), - length: Data.fromNumber(0x20) + length: Data.fromNumber(0x20), }); }); it("works for a group of regions", async () => { const pointer: Pointer = { - group: [{ - name: "a", - location: "memory", - offset: { - $sum: [0x40, 0x20] + group: [ + { + name: "a", + location: "memory", + offset: { + $sum: [0x40, 0x20], + }, + length: 0x20, }, - length: 0x20 - }, { - location: "memory", - offset: { - $sum: [ - { ".offset": "a" }, - { ".length": "a" } - ] + { + location: "memory", + offset: { + $sum: [{ ".offset": "a" }, { ".length": "a" }], + }, + length: { ".length": "a" }, }, - length: { ".length": "a" } - }] + ], }; const cursor = await dereference(pointer); @@ -85,12 +99,12 @@ describe("dereference", () => { name: "a", location: "memory", offset: Data.fromNumber(0x60), - length: Data.fromNumber(0x20) + length: Data.fromNumber(0x20), }); expect(regions[1]).toEqual({ location: "memory", offset: Data.fromNumber(0x80), - length: Data.fromNumber(0x20) + length: Data.fromNumber(0x20), }); }); @@ -105,7 +119,7 @@ describe("dereference", () => { offset: { $product: ["i", 32], }, - length: 32 + length: 32, }, }, }; @@ -122,10 +136,10 @@ describe("dereference", () => { name: "item", location: "memory", offset: Data.fromUint( - Data.fromNumber(index).asUint() * 32n + Data.fromNumber(index).asUint() * 32n, ).padUntilAtLeast(1), length: Data.fromNumber(32), - }) + }); } }); @@ -133,7 +147,7 @@ describe("dereference", () => { const pointer: Pointer = { location: "memory", offset: 32, - length: { ".offset": "$this" } + length: { ".offset": "$this" }, }; const cursor = await dereference(pointer); @@ -144,7 +158,7 @@ describe("dereference", () => { expect(regions[0]).toEqual({ location: "memory", offset: Data.fromNumber(32), - length: Data.fromNumber(32) + length: Data.fromNumber(32), }); }); @@ -152,7 +166,7 @@ describe("dereference", () => { const pointer: Pointer = { location: "memory", offset: { ".length": "$this" }, - length: 32 + length: 32, }; const cursor = await dereference(pointer); @@ -163,7 +177,7 @@ describe("dereference", () => { expect(regions[0]).toEqual({ location: "memory", offset: Data.fromNumber(32), - length: Data.fromNumber(32) + length: Data.fromNumber(32), }); }); @@ -172,7 +186,7 @@ describe("dereference", () => { location: "storage", slot: { ".offset": "$this" }, offset: { ".length": "$this" }, - length: 32 + length: 32, }; const cursor = await dereference(pointer); @@ -184,7 +198,7 @@ describe("dereference", () => { location: "storage", slot: Data.fromNumber(32), offset: Data.fromNumber(32), - length: Data.fromNumber(32) + length: Data.fromNumber(32), }); }); @@ -198,27 +212,27 @@ describe("dereference", () => { const cursor = await dereference(pointer); await expect(cursor.view(state)).rejects.toThrow( - "Circular reference detected: $this.offset" + "Circular reference detected: $this.offset", ); }); it("works for conditionals", async () => { const pointer: Pointer = { if: { - $difference: [5, 5] + $difference: [5, 5], }, then: { name: "a", location: "memory", offset: 0, - length: 0 + length: 0, }, else: { name: "b", location: "memory", offset: 0, - length: 0 - } + length: 0, + }, }; const cursor = await dereference(pointer); @@ -233,13 +247,13 @@ describe("dereference", () => { const pointer: Pointer = { define: { "example-offset": 0, - "example-length": 32 + "example-length": 32, }, in: { location: "memory", offset: "example-offset", - length: "example-length" - } + length: "example-length", + }, }; const cursor = await dereference(pointer); @@ -258,19 +272,19 @@ describe("dereference", () => { for: { location: "memory", offset: "offset", - length: "length" - } - } + length: "length", + }, + }, }; const pointer: Pointer = { define: { - "offset": 0, - "length": 32 + offset: 0, + length: 32, }, in: { - template: "memory-range" - } + template: "memory-range", + }, }; const cursor = await dereference(pointer, { templates }); @@ -289,21 +303,21 @@ describe("dereference", () => { for: { name: "data", location: "storage", - slot: "slot" - } - } + slot: "slot", + }, + }, }; const pointer: Pointer = { define: { - "slot": 0 + slot: 0, }, in: { template: "named-region", yields: { - "data": "my-data" - } - } + data: "my-data", + }, + }, }; const cursor = await dereference(pointer, { templates }); @@ -322,28 +336,28 @@ describe("dereference", () => { for: { name: "value", location: "storage", - slot: "slot" - } - } + slot: "slot", + }, + }, }; const pointer: Pointer = { group: [ { - define: { "slot": 0 }, + define: { slot: 0 }, in: { template: "slot-region", - yields: { "value": "first-value" } - } + yields: { value: "first-value" }, + }, }, { - define: { "slot": 1 }, + define: { slot: 1 }, in: { template: "slot-region", - yields: { "value": "second-value" } - } - } - ] + yields: { value: "second-value" }, + }, + }, + ], }; const cursor = await dereference(pointer, { templates }); @@ -363,18 +377,18 @@ describe("dereference", () => { for: { group: [ { name: "a", location: "storage", slot: "slot" }, - { name: "b", location: "storage", slot: { $sum: ["slot", 1] } } - ] - } - } + { name: "b", location: "storage", slot: { $sum: ["slot", 1] } }, + ], + }, + }, }; const pointer: Pointer = { - define: { "slot": 0 }, + define: { slot: 0 }, in: { template: "two-regions", - yields: { "a": "renamed-a" } // only rename "a", leave "b" as-is - } + yields: { a: "renamed-a" }, // only rename "a", leave "b" as-is + }, }; const cursor = await dereference(pointer, { templates }); @@ -382,7 +396,7 @@ describe("dereference", () => { expect(regions).toHaveLength(2); expect(regions[0].name).toEqual("renamed-a"); - expect(regions[1].name).toEqual("b"); // unchanged + expect(regions[1].name).toEqual("b"); // unchanged expect(regions.lookup["renamed-a"]).toBeDefined(); expect(regions.lookup["b"]).toBeDefined(); }); @@ -397,28 +411,30 @@ describe("dereference", () => { name: "first", location: "memory", offset: "base", - length: 32 + length: 32, }, { name: "second", location: "memory", - offset: { $sum: [{ ".offset": "first" }, { ".length": "first" }] }, - length: { ".length": "first" } - } - ] - } - } + offset: { + $sum: [{ ".offset": "first" }, { ".length": "first" }], + }, + length: { ".length": "first" }, + }, + ], + }, + }, }; const pointer: Pointer = { - define: { "base": 64 }, + define: { base: 64 }, in: { template: "dependent-regions", yields: { - "first": "my-first", - "second": "my-second" - } - } + first: "my-first", + second: "my-second", + }, + }, }; const cursor = await dereference(pointer, { templates }); @@ -431,43 +447,43 @@ describe("dereference", () => { // Second region depends on first via internal reference expect(regions[1].name).toEqual("my-second"); - expect(regions[1].offset).toEqual(Data.fromNumber(96)); // 64 + 32 + expect(regions[1].offset).toEqual(Data.fromNumber(96)); // 64 + 32 expect(regions[1].length).toEqual(Data.fromNumber(32)); }); it("works for nested template references with yields", async () => { const templates: Pointer.Templates = { - "inner": { + inner: { expect: ["slot"], for: { name: "inner-data", location: "storage", - slot: "slot" - } + slot: "slot", + }, }, - "outer": { + outer: { expect: ["base-slot"], for: { group: [ { - define: { "slot": "base-slot" }, - in: { template: "inner" } + define: { slot: "base-slot" }, + in: { template: "inner" }, }, { - define: { "slot": { $sum: ["base-slot", 1] } }, - in: { template: "inner" } - } - ] - } - } + define: { slot: { $sum: ["base-slot", 1] } }, + in: { template: "inner" }, + }, + ], + }, + }, }; const pointer: Pointer = { define: { "base-slot": 10 }, in: { template: "outer", - yields: { "inner-data": "outer-data" } - } + yields: { "inner-data": "outer-data" }, + }, }; const cursor = await dereference(pointer, { templates }); @@ -488,19 +504,19 @@ describe("dereference", () => { for: { location: "memory", offset: "offset", - length: "length" - } - } + length: "length", + }, + }, }, in: { define: { - "offset": 0, - "length": 32 + offset: 0, + length: 32, }, in: { - template: "memory-range" - } - } + template: "memory-range", + }, + }, }; const cursor = await dereference(pointer); @@ -519,9 +535,9 @@ describe("dereference", () => { for: { name: "external", location: "storage", - slot: "value" - } - } + slot: "value", + }, + }, }; // Inline template overrides with memory-based region @@ -533,16 +549,16 @@ describe("dereference", () => { name: "inline", location: "memory", offset: "value", - length: 32 - } - } + length: 32, + }, + }, }, in: { - define: { "value": 64 }, + define: { value: 64 }, in: { - template: "my-region" - } - } + template: "my-region", + }, + }, }; const cursor = await dereference(pointer, { templates: externalTemplates }); @@ -566,21 +582,21 @@ describe("dereference", () => { name: "data", location: "memory", offset: "offset", - length: 32 - } - } + length: 32, + }, + }, }, in: { - define: { "offset": "base" }, - in: { template: "inner-template" } - } - } - } + define: { offset: "base" }, + in: { template: "inner-template" }, + }, + }, + }, }, in: { - define: { "base": 128 }, - in: { template: "outer-template" } - } + define: { base: 128 }, + in: { template: "outer-template" }, + }, }; const cursor = await dereference(pointer); @@ -599,17 +615,17 @@ describe("dereference", () => { for: { name: "value", location: "storage", - slot: "slot" - } - } + slot: "slot", + }, + }, }, in: { - define: { "slot": 5 }, + define: { slot: 5 }, in: { template: "named-slot", - yields: { "value": "my-slot-value" } - } - } + yields: { value: "my-slot-value" }, + }, + }, }; const cursor = await dereference(pointer); diff --git a/packages/pointers/src/dereference/index.ts b/packages/pointers/src/dereference/index.ts index 793b34c57..cd3cd75d9 100644 --- a/packages/pointers/src/dereference/index.ts +++ b/packages/pointers/src/dereference/index.ts @@ -11,7 +11,7 @@ export interface DereferenceOptions { * Required for any pointers that reference the stack. */ state?: Machine.State; - templates?: Pointer.Templates + templates?: Pointer.Templates; } /** @@ -23,18 +23,19 @@ export interface DereferenceOptions { */ export async function dereference( pointer: Pointer, - dereferenceOptions: DereferenceOptions = {} + dereferenceOptions: DereferenceOptions = {}, ): Promise { const options = await initializeGenerateRegionsOptions(dereferenceOptions); // use a closure to build a simple Cursor-like interface for accepting // a machine state and producing a collection of regions. - const simpleCursor = - (state: Machine.State): AsyncIterable => ({ - async *[Symbol.asyncIterator]() { - yield* generateRegions(pointer, { ...options, state }); - } - }); + const simpleCursor = ( + state: Machine.State, + ): AsyncIterable => ({ + async *[Symbol.asyncIterator]() { + yield* generateRegions(pointer, { ...options, state }); + }, + }); return createCursor(simpleCursor); } @@ -45,7 +46,7 @@ export async function dereference( */ async function initializeGenerateRegionsOptions({ templates = {}, - state: initialState + state: initialState, }: DereferenceOptions): Promise> { const initialStackLength = initialState ? await initialState.stack.length @@ -53,6 +54,6 @@ async function initializeGenerateRegionsOptions({ return { templates, - initialStackLength + initialStackLength, }; } diff --git a/packages/pointers/src/dereference/memo.ts b/packages/pointers/src/dereference/memo.ts index c65268357..18e6194e2 100644 --- a/packages/pointers/src/dereference/memo.ts +++ b/packages/pointers/src/dereference/memo.ts @@ -26,11 +26,10 @@ export namespace Memo { /** * Initialize a DereferencePointer memo */ - export const dereferencePointer = - (pointer: Pointer): DereferencePointer => ({ - kind: "dereference-pointer", - pointer - }); + export const dereferencePointer = (pointer: Pointer): DereferencePointer => ({ + kind: "dereference-pointer", + pointer, + }); /** * A request to modify the stateful map of regions by name with a @@ -47,11 +46,12 @@ export namespace Memo { /** * Initialize a SaveRegions memo */ - export const saveRegions = - (regions: Record): SaveRegions => ({ - kind: "save-regions", - regions - }); + export const saveRegions = ( + regions: Record, + ): SaveRegions => ({ + kind: "save-regions", + regions, + }); /** * A request to modify the stateful map of variable values with a @@ -68,11 +68,12 @@ export namespace Memo { /** * Initialize a SaveVariables memo */ - export const saveVariables = - (variables: Record): SaveVariables => ({ - kind: "save-variables", - variables - }); + export const saveVariables = ( + variables: Record, + ): SaveVariables => ({ + kind: "save-variables", + variables, + }); /** * A request to push a region rename mapping onto the context stack. @@ -88,11 +89,12 @@ export namespace Memo { /** * Initialize a PushRegionRenames memo */ - export const pushRegionRenames = - (mapping: Record): PushRegionRenames => ({ - kind: "push-region-renames", - mapping - }); + export const pushRegionRenames = ( + mapping: Record, + ): PushRegionRenames => ({ + kind: "push-region-renames", + mapping, + }); /** * A request to pop the current region rename mapping from the context stack. @@ -105,7 +107,7 @@ export namespace Memo { * Initialize a PopRegionRenames memo */ export const popRegionRenames = (): PopRegionRenames => ({ - kind: "pop-region-renames" + kind: "pop-region-renames", }); /** @@ -121,11 +123,12 @@ export namespace Memo { /** * Initialize a PushTemplates memo */ - export const pushTemplates = - (templates: Pointer.Templates): PushTemplates => ({ - kind: "push-templates", - templates - }); + export const pushTemplates = ( + templates: Pointer.Templates, + ): PushTemplates => ({ + kind: "push-templates", + templates, + }); /** * A request to pop the current template definitions from the context stack. @@ -138,6 +141,6 @@ export namespace Memo { * Initialize a PopTemplates memo */ export const popTemplates = (): PopTemplates => ({ - kind: "pop-templates" + kind: "pop-templates", }); } diff --git a/packages/pointers/src/dereference/process.ts b/packages/pointers/src/dereference/process.ts index 7e84d19dd..963992622 100644 --- a/packages/pointers/src/dereference/process.ts +++ b/packages/pointers/src/dereference/process.ts @@ -7,7 +7,6 @@ import { evaluate } from "../evaluate.js"; import { Memo } from "./memo.js"; import { adjustStackLength, evaluateRegion } from "./region.js"; - /** * Contextual information for use within a pointer dereference process */ @@ -31,7 +30,7 @@ export type Process = AsyncGenerator; */ export async function* processPointer( pointer: Pointer, - options: ProcessOptions + options: ProcessOptions, ): Process { if (Pointer.isRegion(pointer)) { const region = pointer; @@ -71,11 +70,11 @@ export async function* processPointer( async function* processRegion( region: Pointer.Region, - { stackLengthChange, ...options}: ProcessOptions + { stackLengthChange, ...options }: ProcessOptions, ): Process { const evaluatedRegion = await evaluateRegion( adjustStackLength(region, stackLengthChange), - options + options, ); yield evaluatedRegion; @@ -89,7 +88,7 @@ async function* processRegion( async function* processGroup( collection: Pointer.Collection.Group, - options: ProcessOptions + options: ProcessOptions, ): Process { const { group } = collection; return group.map(Memo.dereferencePointer); @@ -97,7 +96,7 @@ async function* processGroup( async function* processList( collection: Pointer.Collection.List, - options: ProcessOptions + options: ProcessOptions, ): Process { const { list } = collection; const { count: countExpression, each, is } = list; @@ -106,9 +105,11 @@ async function* processList( const memos: Memo[] = []; for (let index = 0n; index < count; index++) { - memos.push(Memo.saveVariables({ - [each]: Data.fromUint(index) - })); + memos.push( + Memo.saveVariables({ + [each]: Data.fromUint(index), + }), + ); memos.push(Memo.dereferencePointer(is)); } @@ -118,7 +119,7 @@ async function* processList( async function* processConditional( collection: Pointer.Collection.Conditional, - options: ProcessOptions + options: ProcessOptions, ): Process { const { if: ifExpression, then: then_, else: else_ } = collection; @@ -129,40 +130,35 @@ async function* processConditional( } // otherwise, return the else clause if it exists (it is optional) - return else_ - ? [Memo.dereferencePointer(else_)] - : []; + return else_ ? [Memo.dereferencePointer(else_)] : []; } async function* processScope( collection: Pointer.Collection.Scope, - options: ProcessOptions + options: ProcessOptions, ): Process { const { define: variableExpressions, in: in_ } = collection; const allVariables = { - ...options.variables + ...options.variables, }; const newVariables: { [identifier: string]: Data } = {}; for (const [identifier, expression] of Object.entries(variableExpressions)) { const data = await evaluate(expression, { ...options, - variables: allVariables + variables: allVariables, }); allVariables[identifier] = data; newVariables[identifier] = data; } - return [ - Memo.saveVariables(newVariables), - Memo.dereferencePointer(in_) - ]; + return [Memo.saveVariables(newVariables), Memo.dereferencePointer(in_)]; } async function* processReference( collection: Pointer.Collection.Reference, - options: ProcessOptions + options: ProcessOptions, ): Process { const { template: templateName, yields } = collection; @@ -171,26 +167,24 @@ async function* processReference( const template = templates[templateName]; if (!template) { - throw new Error( - `Unknown pointer template named ${templateName}` - ); + throw new Error(`Unknown pointer template named ${templateName}`); } - const { - expect: expectedVariables, - for: pointer - } = template; + const { expect: expectedVariables, for: pointer } = template; const definedVariables = new Set(Object.keys(variables)); - const missingVariables = expectedVariables - .filter(identifier => !definedVariables.has(identifier)); + const missingVariables = expectedVariables.filter( + (identifier) => !definedVariables.has(identifier), + ); if (missingVariables.length > 0) { - throw new Error([ - `Invalid reference to template named ${templateName}; missing expected `, - `variables with identifiers: ${missingVariables.join(", ")}. `, - `Please ensure these variables are defined prior to this reference.` - ].join("")); + throw new Error( + [ + `Invalid reference to template named ${templateName}; missing expected `, + `variables with identifiers: ${missingVariables.join(", ")}. `, + `Please ensure these variables are defined prior to this reference.`, + ].join(""), + ); } // If yields is specified with mappings, wrap the dereference with @@ -199,24 +193,22 @@ async function* processReference( return [ Memo.pushRegionRenames(yields), Memo.dereferencePointer(pointer), - Memo.popRegionRenames() + Memo.popRegionRenames(), ]; } - return [ - Memo.dereferencePointer(pointer) - ]; + return [Memo.dereferencePointer(pointer)]; } async function* processTemplates( collection: Pointer.Collection.Templates, - options: ProcessOptions + options: ProcessOptions, ): Process { const { templates, in: in_ } = collection; return [ Memo.pushTemplates(templates), Memo.dereferencePointer(in_), - Memo.popTemplates() + Memo.popTemplates(), ]; } diff --git a/packages/pointers/src/dereference/region.ts b/packages/pointers/src/dereference/region.ts index 672ae837e..3dca9df9a 100644 --- a/packages/pointers/src/dereference/region.ts +++ b/packages/pointers/src/dereference/region.ts @@ -18,13 +18,13 @@ import { evaluate, type EvaluateOptions } from "../evaluate.js"; */ export async function evaluateRegion( region: R, - options: EvaluateOptions + options: EvaluateOptions, ): Promise> { const evaluatedProperties: { - [K in keyof R]?: Data + [K in keyof R]?: Data; } = {}; const propertyAttempts: { - [K in keyof R]?: number + [K in keyof R]?: number; } = {}; const partialRegion: Cursor.Region = new Proxy( @@ -34,19 +34,22 @@ export async function evaluateRegion( if (property in evaluatedProperties) { return evaluatedProperties[property as keyof R]; } - throw new Error(`Property not evaluated yet: $this.${property.toString()}`) + throw new Error( + `Property not evaluated yet: $this.${property.toString()}`, + ); }, - } + }, ); const propertiesRequiringEvaluation = ["slot", "offset", "length"] as const; const expressionQueue: [keyof R, Pointer.Expression][] = propertiesRequiringEvaluation - .filter(property => property in region) - .map( - property => [property, region[property as keyof R]] - ) as [keyof R, Pointer.Expression][]; + .filter((property) => property in region) + .map((property) => [property, region[property as keyof R]]) as [ + keyof R, + Pointer.Expression, + ][]; while (expressionQueue.length > 0) { const [property, expression] = expressionQueue.shift()!; @@ -70,7 +73,9 @@ export async function evaluateRegion( // fields may reference each other, but the chain of references // should not exceed the number of fields minus 1 if (attempts > propertiesRequiringEvaluation.length - 1) { - throw new Error(`Circular reference detected: $this.${property.toString()}`); + throw new Error( + `Circular reference detected: $this.${property.toString()}`, + ); } propertyAttempts[property] = attempts + 1; @@ -94,18 +99,24 @@ export async function evaluateRegion( */ export function adjustStackLength( region: R, - stackLengthChange: bigint + stackLengthChange: bigint, ): R { if (Pointer.Region.isStack(region)) { - const slot: Pointer.Expression = stackLengthChange === 0n - ? region.slot - : stackLengthChange > 0n - ? { $sum: [region.slot, `0x${stackLengthChange.toString(16)}`] } - : { $difference: [region.slot, `0x${-stackLengthChange.toString(16)}`] }; + const slot: Pointer.Expression = + stackLengthChange === 0n + ? region.slot + : stackLengthChange > 0n + ? { $sum: [region.slot, `0x${stackLengthChange.toString(16)}`] } + : { + $difference: [ + region.slot, + `0x${-stackLengthChange.toString(16)}`, + ], + }; return { ...region, - slot + slot, }; } diff --git a/packages/pointers/src/evaluate.test.ts b/packages/pointers/src/evaluate.test.ts index 57be50513..82be6529b 100644 --- a/packages/pointers/src/evaluate.test.ts +++ b/packages/pointers/src/evaluate.test.ts @@ -16,7 +16,7 @@ const state: Machine.State = { opcode: Promise.resolve("PUSH1"), programCounter: Promise.resolve(10n), stack: { - length: 50n + length: 50n, } as any, memory: {} as any, storage: {} as any, @@ -44,145 +44,149 @@ describe("evaluate", () => { location: "stack", slot: Data.fromNumber(42), offset: Data.fromNumber(0x60), - length: Data.fromNumber(0x1f / 2) + length: Data.fromNumber(0x1f / 2), }, memory: { name: "memory", location: "memory", offset: Data.fromNumber(0x20 * 0x05), - length: Data.fromNumber(42 - 0x1f) - } - } ; + length: Data.fromNumber(42 - 0x1f), + }, + }; options = { state, variables, - regions - } + regions, + }; }); it("evaluates literal expressions", async () => { - expect(await evaluate(42, options)) - .toEqual(Data.fromNumber(42)); + expect(await evaluate(42, options)).toEqual(Data.fromNumber(42)); - expect(await evaluate("0x1f", options)) - .toEqual(Data.fromHex("0x1f")); + expect(await evaluate("0x1f", options)).toEqual(Data.fromHex("0x1f")); }); it("evaluates constant expressions", async () => { - expect(await evaluate("$wordsize", options)) - .toEqual(Data.fromHex("0x20")); + expect(await evaluate("$wordsize", options)).toEqual(Data.fromHex("0x20")); }); it("evaluates variable expressions", async () => { - expect(await evaluate("foo", options)) - .toEqual(Data.fromNumber(42)); + expect(await evaluate("foo", options)).toEqual(Data.fromNumber(42)); - expect(await evaluate("bar", options)) - .toEqual(Data.fromHex("0x1f")); + expect(await evaluate("bar", options)).toEqual(Data.fromHex("0x1f")); }); it("evaluates sum expressions", async () => { const expression: Pointer.Expression = { - $sum: [42, "0x1f", "foo", "bar"] + $sum: [42, "0x1f", "foo", "bar"], }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromUint(42n + 0x1fn + 42n + 0x1fn)); + expect(await evaluate(expression, options)).toEqual( + Data.fromUint(42n + 0x1fn + 42n + 0x1fn), + ); }); it("evaluates difference expressions", async () => { const expression: Pointer.Expression = { - $difference: ["foo", "bar"] + $difference: ["foo", "bar"], }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromUint(42n - 0x1fn)); + expect(await evaluate(expression, options)).toEqual( + Data.fromUint(42n - 0x1fn), + ); }); it("evaluates product expressions", async () => { const expression: Pointer.Expression = { - $product: [42, "0x1f", "foo", "bar"] + $product: [42, "0x1f", "foo", "bar"], }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromUint(42n * 0x1fn * 42n * 0x1fn)); + expect(await evaluate(expression, options)).toEqual( + Data.fromUint(42n * 0x1fn * 42n * 0x1fn), + ); }); it("evaluates quotient expressions", async () => { const expression: Pointer.Expression = { - $quotient: ["foo", "bar"] + $quotient: ["foo", "bar"], }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromUint(42n / 0x1fn)); + expect(await evaluate(expression, options)).toEqual( + Data.fromUint(42n / 0x1fn), + ); }); it("evaluates remainder expressions", async () => { const expression: Pointer.Expression = { - $remainder: ["foo", "bar"] + $remainder: ["foo", "bar"], }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromUint(42n % 0x1fn)); + expect(await evaluate(expression, options)).toEqual( + Data.fromUint(42n % 0x1fn), + ); }); describe("evaluates concat expressions", () => { it("concatenates hex literals", async () => { const expression: Pointer.Expression = { - $concat: ["0x00", "0x00"] + $concat: ["0x00", "0x00"], }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromHex("0x0000")); + expect(await evaluate(expression, options)).toEqual( + Data.fromHex("0x0000"), + ); }); it("concatenates multiple values preserving byte widths", async () => { const expression: Pointer.Expression = { - $concat: ["0xdead", "0xbeef"] + $concat: ["0xdead", "0xbeef"], }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromHex("0xdeadbeef")); + expect(await evaluate(expression, options)).toEqual( + Data.fromHex("0xdeadbeef"), + ); }); it("returns empty data for empty operand list", async () => { const expression: Pointer.Expression = { - $concat: [] + $concat: [], }; - expect(await evaluate(expression, options)) - .toEqual(Data.zero()); + expect(await evaluate(expression, options)).toEqual(Data.zero()); }); it("preserves single operand unchanged", async () => { const expression: Pointer.Expression = { - $concat: ["0xabcdef"] + $concat: ["0xabcdef"], }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromHex("0xabcdef")); + expect(await evaluate(expression, options)).toEqual( + Data.fromHex("0xabcdef"), + ); }); it("concatenates variables", async () => { const expression: Pointer.Expression = { - $concat: ["foo", "bar"] + $concat: ["foo", "bar"], }; // foo = 0x2a (42), bar = 0x1f - expect(await evaluate(expression, options)) - .toEqual(Data.fromHex("0x2a1f")); + expect(await evaluate(expression, options)).toEqual( + Data.fromHex("0x2a1f"), + ); }); it("concatenates nested expressions", async () => { const expression: Pointer.Expression = { $concat: [ - { $sum: [1, 2] }, // 3 = 0x03 - "0xff" - ] + { $sum: [1, 2] }, // 3 = 0x03 + "0xff", + ], }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromHex("0x03ff")); + expect(await evaluate(expression, options)).toEqual( + Data.fromHex("0x03ff"), + ); }); it("preserves leading zeros in hex literals", async () => { const expression: Pointer.Expression = { - $concat: ["0x0001", "0x0002"] + $concat: ["0x0001", "0x0002"], }; const result = await evaluate(expression, options); expect(result).toEqual(Data.fromHex("0x00010002")); @@ -193,42 +197,42 @@ describe("evaluate", () => { // skipped because test does not perform proper padding it.skip("evaluates keccak256 expressions", async () => { const expression: Pointer.Expression = { - $keccak256: ["foo", "bar", 42, "0x1f"] + $keccak256: ["foo", "bar", 42, "0x1f"], }; const expectedHash = keccak256( Buffer.from( toHex(Data.fromNumber(42)).slice(2) + - toHex(Data.fromHex("0x1f")).slice(2) + - toHex(variables.foo).slice(2) + - toHex(variables.bar).slice(2), - "hex" - ) + toHex(Data.fromHex("0x1f")).slice(2) + + toHex(variables.foo).slice(2) + + toHex(variables.bar).slice(2), + "hex", + ), ); - expect(await evaluate(expression, options)) - .toEqual(Data.fromBytes(expectedHash)); + expect(await evaluate(expression, options)).toEqual( + Data.fromBytes(expectedHash), + ); }); it("evaluates offset lookup expressions", async () => { const expression: Pointer.Expression = { - ".offset": "stack" + ".offset": "stack", }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromUint(0x60n)); + expect(await evaluate(expression, options)).toEqual(Data.fromUint(0x60n)); }); it("evaluates offset lookup expressions with $this", async () => { const expression: Pointer.Expression = { - ".offset": "$this" + ".offset": "$this", }; const $this = { name: "$this", location: "memory", offset: Data.fromNumber(0x120), - length: Data.fromNumber(0x40) + length: Data.fromNumber(0x40), } as const; expect( @@ -236,28 +240,26 @@ describe("evaluate", () => { ...options, regions: { ...regions, - $this - } - }) + $this, + }, + }), ).toEqual(Data.fromUint(0x120n)); }); it("evaluates length lookup expressions", async () => { const expression: Pointer.Expression = { - ".length": "memory" + ".length": "memory", }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromUint(11n)); + expect(await evaluate(expression, options)).toEqual(Data.fromUint(11n)); }); it("evaluates slot lookup expressions", async () => { const expression: Pointer.Expression = { - ".slot": "stack" + ".slot": "stack", }; - expect(await evaluate(expression, options)) - .toEqual(Data.fromNumber(42)); + expect(await evaluate(expression, options)).toEqual(Data.fromNumber(42)); }); describe("resulting bytes widths", () => { @@ -271,16 +273,19 @@ describe("evaluate", () => { it("uses at least the largest bytes width amongst arithmetic operands", async () => { expect(await evaluate({ $sum: [0, 0] }, options)).toHaveLength(0); - expect(await evaluate({ $difference: ["0x00", "0x00"] }, options)) - .toHaveLength(1); + expect( + await evaluate({ $difference: ["0x00", "0x00"] }, options), + ).toHaveLength(1); - expect(await evaluate({ $remainder: ["0x0001", "0x01"] }, options)) - .toHaveLength(2); + expect( + await evaluate({ $remainder: ["0x0001", "0x01"] }, options), + ).toHaveLength(2); }); it("uses exactly as many bytes necessary to avoid arithmetic overflow", async () => { - expect(await evaluate({ $product: ["0xffff", "0xff"] }, options)) - .toHaveLength(3); + expect( + await evaluate({ $product: ["0xffff", "0xff"] }, options), + ).toHaveLength(3); }); }); diff --git a/packages/pointers/src/evaluate.ts b/packages/pointers/src/evaluate.ts index eb2519ca8..e819d48e4 100644 --- a/packages/pointers/src/evaluate.ts +++ b/packages/pointers/src/evaluate.ts @@ -18,7 +18,7 @@ export interface EvaluateOptions { export async function evaluate( expression: Pointer.Expression, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { if (Pointer.Expression.isLiteral(expression)) { return evaluateLiteral(expression); @@ -85,14 +85,14 @@ export async function evaluate( } throw new Error( - `Unexpected runtime failure to recognize kind of expression: ${ - JSON.stringify(expression) - }` + `Unexpected runtime failure to recognize kind of expression: ${JSON.stringify( + expression, + )}`, ); } async function evaluateLiteral( - literal: Pointer.Expression.Literal + literal: Pointer.Expression.Literal, ): Promise { switch (typeof literal) { case "string": @@ -103,7 +103,7 @@ async function evaluateLiteral( } async function evaluateConstant( - constant: Pointer.Expression.Constant + constant: Pointer.Expression.Constant, ): Promise { switch (constant) { case "$wordsize": @@ -113,7 +113,7 @@ async function evaluateConstant( async function evaluateVariable( identifier: Pointer.Expression.Variable, - { variables }: EvaluateOptions + { variables }: EvaluateOptions, ): Promise { const data = variables[identifier]; if (typeof data === "undefined") { @@ -125,35 +125,42 @@ async function evaluateVariable( async function evaluateArithmeticSum( expression: Pointer.Expression.Arithmetic.Sum, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { - const operands = await Promise.all(expression.$sum.map( - async expression => await evaluate(expression, options) - )); + const operands = await Promise.all( + expression.$sum.map( + async (expression) => await evaluate(expression, options), + ), + ); - const maxLength = operands - .reduce((max, { length }) => length > max ? length : max, 0); + const maxLength = operands.reduce( + (max, { length }) => (length > max ? length : max), + 0, + ); - const data = Data - .fromUint(operands.reduce((sum, data) => sum + data.asUint(), 0n)) - .padUntilAtLeast(maxLength); + const data = Data.fromUint( + operands.reduce((sum, data) => sum + data.asUint(), 0n), + ).padUntilAtLeast(maxLength); return data; } async function evaluateArithmeticDifference( expression: Pointer.Expression.Arithmetic.Difference, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { - const [a, b] = await Promise.all(expression.$difference.map( - async expression => await evaluate(expression, options) - )); + const [a, b] = await Promise.all( + expression.$difference.map( + async (expression) => await evaluate(expression, options), + ), + ); const maxLength = a.length > b.length ? a.length : b.length; - const unpadded = a.asUint() > b.asUint() - ? Data.fromUint(a.asUint() - b.asUint()) - : Data.fromNumber(0); + const unpadded = + a.asUint() > b.asUint() + ? Data.fromUint(a.asUint() - b.asUint()) + : Data.fromNumber(0); const data = unpadded.padUntilAtLeast(maxLength); return data; @@ -161,61 +168,71 @@ async function evaluateArithmeticDifference( async function evaluateArithmeticProduct( expression: Pointer.Expression.Arithmetic.Product, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { - const operands = await Promise.all(expression.$product.map( - async expression => await evaluate(expression, options) - )); + const operands = await Promise.all( + expression.$product.map( + async (expression) => await evaluate(expression, options), + ), + ); - const maxLength = operands - .reduce((max, { length }) => length > max ? length : max, 0); + const maxLength = operands.reduce( + (max, { length }) => (length > max ? length : max), + 0, + ); - return Data - .fromUint(operands.reduce((product, data) => product * data.asUint(), 1n)) - .padUntilAtLeast(maxLength); + return Data.fromUint( + operands.reduce((product, data) => product * data.asUint(), 1n), + ).padUntilAtLeast(maxLength); } async function evaluateArithmeticQuotient( expression: Pointer.Expression.Arithmetic.Quotient, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { - const [a, b] = await Promise.all(expression.$quotient.map( - async expression => (await evaluate(expression, options)) - )); + const [a, b] = await Promise.all( + expression.$quotient.map( + async (expression) => await evaluate(expression, options), + ), + ); const maxLength = a.length > b.length ? a.length : b.length; - const data = Data - .fromUint(a.asUint() / b.asUint()) - .padUntilAtLeast(maxLength); + const data = Data.fromUint(a.asUint() / b.asUint()).padUntilAtLeast( + maxLength, + ); return data; } async function evaluateArithmeticRemainder( expression: Pointer.Expression.Arithmetic.Remainder, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { - const [a, b] = await Promise.all(expression.$remainder.map( - async expression => await evaluate(expression, options) - )); + const [a, b] = await Promise.all( + expression.$remainder.map( + async (expression) => await evaluate(expression, options), + ), + ); const maxLength = a.length > b.length ? a.length : b.length; - const data = Data - .fromUint(a.asUint() % b.asUint()) - .padUntilAtLeast(maxLength); + const data = Data.fromUint(a.asUint() % b.asUint()).padUntilAtLeast( + maxLength, + ); return data; } async function evaluateKeccak256( expression: Pointer.Expression.Keccak256, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { - const operands = await Promise.all(expression.$keccak256.map( - async expression => await evaluate(expression, options) - )); + const operands = await Promise.all( + expression.$keccak256.map( + async (expression) => await evaluate(expression, options), + ), + ); const preimage = Data.zero().concat(...operands); const hash = Data.fromBytes(keccak256(preimage)); @@ -225,18 +242,20 @@ async function evaluateKeccak256( async function evaluateConcat( expression: Pointer.Expression.Concat, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { - const operands = await Promise.all(expression.$concat.map( - async expression => await evaluate(expression, options) - )); + const operands = await Promise.all( + expression.$concat.map( + async (expression) => await evaluate(expression, options), + ), + ); return Data.zero().concat(...operands); } async function evaluateResize( expression: Pointer.Expression.Resize, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { const [[operation, subexpression]] = Object.entries(expression); @@ -250,7 +269,7 @@ async function evaluateResize( async function evaluateLookup( operation: O, lookup: Pointer.Expression.Lookup.ForOperation, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { const { regions } = options; @@ -266,7 +285,7 @@ async function evaluateLookup( if (typeof data === "undefined") { throw new Error( - `Region named ${identifier} does not have ${property} needed by lookup` + `Region named ${identifier} does not have ${property} needed by lookup`, ); } @@ -275,7 +294,7 @@ async function evaluateLookup( async function evaluateRead( expression: Pointer.Expression.Read, - options: EvaluateOptions + options: EvaluateOptions, ): Promise { const { state, regions } = options; diff --git a/packages/pointers/src/integration.test.ts b/packages/pointers/src/integration.test.ts index 17b347d01..7fa016ff1 100644 --- a/packages/pointers/src/integration.test.ts +++ b/packages/pointers/src/integration.test.ts @@ -10,11 +10,11 @@ describe("dereference (integration)", () => { describe(`example pointer: ${name}`, () => { it("resolves to values containing the expected sequence", async () => { - const observedValues = - await observeTrace(options as any); + const observedValues = await observeTrace(options as any); - expect(observedValues) - .toEqual(expect.arrayContaining(expectedValues as any)); + expect(observedValues).toEqual( + expect.arrayContaining(expectedValues as any), + ); }); }); } diff --git a/packages/pointers/src/machine.ts b/packages/pointers/src/machine.ts index e603584af..c3eb357a0 100644 --- a/packages/pointers/src/machine.ts +++ b/packages/pointers/src/machine.ts @@ -5,7 +5,6 @@ export interface Machine { } export namespace Machine { - export interface State { get traceIndex(): Promise; get programCounter(): Promise; @@ -30,10 +29,7 @@ export namespace Machine { get length(): Promise; /** read element at position from top of stack */ - peek(options: { - depth: bigint; - slice?: Slice; - }): Promise; + peek(options: { depth: bigint; slice?: Slice }): Promise; } export interface Bytes { diff --git a/packages/pointers/src/read.test.ts b/packages/pointers/src/read.test.ts index d9da0fdbc..51cf1cdbc 100644 --- a/packages/pointers/src/read.test.ts +++ b/packages/pointers/src/read.test.ts @@ -14,51 +14,44 @@ describe("read", () => { const state: Machine.State = { stack: { length: 50n, - peek: vitest.fn( - async ({ depth, slice }) => - Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])) + peek: vitest.fn(async ({ depth, slice }) => + Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), ), }, memory: { - read: vitest.fn( - async ({ slice }) => - Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88])) + read: vitest.fn(async ({ slice }) => + Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88])), ), }, storage: { - read: vitest.fn( - async ({ slot, slice }) => - Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])) + read: vitest.fn(async ({ slot, slice }) => + Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])), ), }, calldata: { - read: vitest.fn( - async ({ slice }) => - Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])) + read: vitest.fn(async ({ slice }) => + Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), ), }, returndata: { - read: vitest.fn( - async ({ slice }) => - Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88])) + read: vitest.fn(async ({ slice }) => + Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88])), ), }, transient: { - read: vitest.fn( - async ({ slot, slice }) => - Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])) + read: vitest.fn(async ({ slot, slice }) => + Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])), ), }, code: { - read: vitest.fn( - async ({ slice }) => - Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])) + read: vitest.fn(async ({ slice }) => + Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), ), }, } as unknown as Machine.State; options = { - state + state, }; }); @@ -72,10 +65,13 @@ describe("read", () => { const result = await read(region, options); - expect(options.state.stack.peek) - .toHaveBeenCalledWith({ depth: 42n, slice: { offset: 1n, length: 2n } }); - expect(result) - .toEqual(Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44]))); + expect(options.state.stack.peek).toHaveBeenCalledWith({ + depth: 42n, + slice: { offset: 1n, length: 2n }, + }); + expect(result).toEqual( + Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), + ); }); it("reads data from memory", async () => { @@ -87,10 +83,12 @@ describe("read", () => { const result = await read(region, options); - expect(options.state.memory.read) - .toHaveBeenCalledWith({ slice: { offset: 0n, length: 4n } }); - expect(result) - .toEqual(Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88]))); + expect(options.state.memory.read).toHaveBeenCalledWith({ + slice: { offset: 0n, length: 4n }, + }); + expect(result).toEqual( + Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88])), + ); }); it("reads data from storage", async () => { @@ -103,14 +101,14 @@ describe("read", () => { const result = await read(region, options); - expect(options.state.storage.read) - .toHaveBeenCalledWith({ - slot: Data.fromNumber(0), - slice: { offset: 2n, length: 2n } - }); + expect(options.state.storage.read).toHaveBeenCalledWith({ + slot: Data.fromNumber(0), + slice: { offset: 2n, length: 2n }, + }); - expect(result) - .toEqual(Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]))); + expect(result).toEqual( + Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])), + ); }); it("reads data from calldata", async () => { @@ -122,10 +120,12 @@ describe("read", () => { const result = await read(region, options); - expect(options.state.calldata.read) - .toHaveBeenCalledWith({ slice: { offset: 0n, length: 4n } }); - expect(result) - .toEqual(Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44]))); + expect(options.state.calldata.read).toHaveBeenCalledWith({ + slice: { offset: 0n, length: 4n }, + }); + expect(result).toEqual( + Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), + ); }); it("reads data from returndata", async () => { @@ -137,10 +137,12 @@ describe("read", () => { const result = await read(region, options); - expect(options.state.returndata.read) - .toHaveBeenCalledWith({ slice: { offset: 0n, length: 4n } }); - expect(result) - .toEqual(Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88]))); + expect(options.state.returndata.read).toHaveBeenCalledWith({ + slice: { offset: 0n, length: 4n }, + }); + expect(result).toEqual( + Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88])), + ); }); it("reads data from transient", async () => { @@ -153,14 +155,14 @@ describe("read", () => { const result = await read(region, options); - expect(options.state.transient.read) - .toHaveBeenCalledWith({ - slot: Data.fromNumber(42), - slice: { offset: 1n, length: 2n } - }); + expect(options.state.transient.read).toHaveBeenCalledWith({ + slot: Data.fromNumber(42), + slice: { offset: 1n, length: 2n }, + }); - expect(result) - .toEqual(Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]))); + expect(result).toEqual( + Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])), + ); }); it("reads data from code", async () => { @@ -172,13 +174,13 @@ describe("read", () => { const result = await read(region, options); - expect(options.state.code.read) - .toHaveBeenCalledWith({ - slice: { offset: 0n, length: 4n } - }); + expect(options.state.code.read).toHaveBeenCalledWith({ + slice: { offset: 0n, length: 4n }, + }); - expect(result) - .toEqual(Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44]))); + expect(result).toEqual( + Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), + ); }); it("uses default offset and length values for stack region", async () => { @@ -189,14 +191,14 @@ describe("read", () => { const result = await read(region, options); - expect(options.state.stack.peek) - .toHaveBeenCalledWith({ - depth: 42n, - slice: { offset: 0n, length: 32n } - }); + expect(options.state.stack.peek).toHaveBeenCalledWith({ + depth: 42n, + slice: { offset: 0n, length: 32n }, + }); - expect(result) - .toEqual(Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44]))); + expect(result).toEqual( + Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), + ); }); it("uses default offset and length values for storage region", async () => { @@ -207,31 +209,31 @@ describe("read", () => { const result = await read(region, options); - expect(options.state.storage.read) - .toHaveBeenCalledWith({ - slot: Data.fromHex("0x1f"), - slice: { offset: 0n, length: 32n } - }); + expect(options.state.storage.read).toHaveBeenCalledWith({ + slot: Data.fromHex("0x1f"), + slice: { offset: 0n, length: 32n }, + }); - expect(result) - .toEqual(Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]))); + expect(result).toEqual( + Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])), + ); }); it("uses default offset and length values for transient region", async () => { const region: Cursor.Region = { location: "transient", - slot: Data.fromNumber(42) + slot: Data.fromNumber(42), }; const result = await read(region, options); - expect(options.state.transient.read) - .toHaveBeenCalledWith({ - slot: Data.fromNumber(42), - slice: { offset: 0n, length: 32n } - }); + expect(options.state.transient.read).toHaveBeenCalledWith({ + slot: Data.fromNumber(42), + slice: { offset: 0n, length: 32n }, + }); - expect(result) - .toEqual(Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]))); + expect(result).toEqual( + Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])), + ); }); }); diff --git a/packages/pointers/src/read.ts b/packages/pointers/src/read.ts index 0a920bdcb..1128aecab 100644 --- a/packages/pointers/src/read.ts +++ b/packages/pointers/src/read.ts @@ -9,7 +9,7 @@ export interface ReadOptions { export async function read( region: Cursor.Region, - options: ReadOptions + options: ReadOptions, ): Promise { const { location } = region; const { state } = options; @@ -19,81 +19,81 @@ export async function read( const { slot, offset = 0n, - length = 32n + length = 32n, } = withPropertiesAsUints(["slot", "offset", "length"], region); return await state.stack.peek({ depth: slot, slice: { offset, - length - } + length, + }, }); } case "memory": { - const { - offset, - length - } = withPropertiesAsUints(["offset", "length"], region); + const { offset, length } = withPropertiesAsUints( + ["offset", "length"], + region, + ); return await state.memory.read({ slice: { offset: offset, - length: length - } + length: length, + }, }); } case "storage": { const { slot } = region; - const { - offset = 0n, - length = 32n - } = withPropertiesAsUints(["offset", "length"], region); + const { offset = 0n, length = 32n } = withPropertiesAsUints( + ["offset", "length"], + region, + ); return await state.storage.read({ slot, slice: { offset, - length - } + length, + }, }); } case "calldata": { - const { - offset, - length - } = withPropertiesAsUints(["offset", "length"], region); + const { offset, length } = withPropertiesAsUints( + ["offset", "length"], + region, + ); return await state.calldata.read({ slice: { offset, length } }); } case "returndata": { - const { - offset, - length - } = withPropertiesAsUints(["offset", "length"], region); + const { offset, length } = withPropertiesAsUints( + ["offset", "length"], + region, + ); return await state.returndata.read({ slice: { offset, length } }); } case "transient": { const { slot } = region; - const { - offset = 0n, - length = 32n - } = withPropertiesAsUints(["offset", "length"], region); + const { offset = 0n, length = 32n } = withPropertiesAsUints( + ["offset", "length"], + region, + ); return await state.transient.read({ slot, slice: { offset, - length - } + length, + }, }); } case "code": { - const { - offset, - length - } = withPropertiesAsUints(["offset", "length"], region); + const { offset, length } = withPropertiesAsUints( + ["offset", "length"], + region, + ); return await state.code.read({ slice: { offset, length } }); } @@ -101,29 +101,21 @@ export async function read( } type DataProperties = { - [K in ( - & keyof Cursor.Region - & ("slot" | "offset" | "length") - )]: Cursor.Region[K]; -} + [K in keyof Cursor.Region & + ("slot" | "offset" | "length")]: Cursor.Region[K]; +}; type PickDataPropertiesAsUints< R extends Pointer.Region, - U extends keyof DataProperties + U extends keyof DataProperties, > = { - [K in U]: - undefined extends Cursor.Region[K] - ? bigint | undefined - : bigint + [K in U]: undefined extends Cursor.Region[K] ? bigint | undefined : bigint; }; function withPropertiesAsUints< R extends Pointer.Region, - U extends keyof DataProperties ->( - uintKeys: U[], - region: Cursor.Region -): PickDataPropertiesAsUints { + U extends keyof DataProperties, +>(uintKeys: U[], region: Cursor.Region): PickDataPropertiesAsUints { const result: Partial> = {}; for (const key of uintKeys) { const data: Data | undefined = region[key] as Data | undefined; diff --git a/packages/pointers/src/test-cases.ts b/packages/pointers/src/test-cases.ts index 3d15d49cd..a75558fd7 100644 --- a/packages/pointers/src/test-cases.ts +++ b/packages/pointers/src/test-cases.ts @@ -1,7 +1,7 @@ import { singleSourceCompilation, findExamplePointer, - type ObserveTraceOptions + type ObserveTraceOptions, } from "../test/index.js"; import { type Cursor, Data } from "./index.js"; @@ -51,7 +51,7 @@ const structStorageTest: ObserveTraceTest<{ uint8 y; bytes4 salt; } - ` + `, }), expectedValues: [ @@ -61,13 +61,9 @@ const structStorageTest: ObserveTraceTest<{ ], async observe({ regions, read }) { - const x = Number( - (await read(regions.lookup["x"])).asUint() - ); + const x = Number((await read(regions.lookup["x"])).asUint()); - const y = Number( - (await read(regions.lookup["y"])).asUint() - ); + const y = Number((await read(regions.lookup["y"])).asUint()); const salt = (await read(regions.lookup["salt"])).toHex(); @@ -76,7 +72,7 @@ const structStorageTest: ObserveTraceTest<{ equals(a, b) { return a.x === b.x && a.y === b.y && a.salt === b.salt; - } + }, }; const stringStorageTest: ObserveTraceTest = { @@ -98,13 +94,13 @@ const stringStorageTest: ObserveTraceTest = { done = true; } } - ` + `, }), expectedValues: [ "", "hello world", - "solidity storage is a fun lesson in endianness" + "solidity storage is a fun lesson in endianness", ], async observe({ regions, read }: Cursor.View): Promise { @@ -112,8 +108,9 @@ const stringStorageTest: ObserveTraceTest = { const strings = regions.named("string"); // read each region and concatenate all the bytes - const stringData: Data = Data.zero() - .concat(...await Promise.all(strings.map(read))); + const stringData: Data = Data.zero().concat( + ...(await Promise.all(strings.map(read))), + ); // decode into JS string return new TextDecoder().decode(stringData); @@ -151,26 +148,21 @@ const uint256ArrayMemoryTest: ObserveTraceTest = { return newArray; } } - ` + `, }), - expectedValues: [ - [], - [1], - [1, 2], - [1, 2, 3] - ], + expectedValues: [[], [1], [1, 2], [1, 2, 3]], async observe({ regions, read }, state): Promise { const items = regions.named("array-item"); - return (await Promise.all( + return await Promise.all( items.map(async (item) => { const data = await read(item); return Number(data.asUint()); - }) - )); + }), + ); }, equals(a, b) { @@ -205,13 +197,13 @@ const uint256ArrayMemoryTest: ObserveTraceTest = { const arrayCount = await state.memory.read({ slice: { offset: arrayOffset.asUint(), - length: 32n - } - }) + length: 32n, + }, + }); // the example code only appends three times return arrayCount.asUint() < 4n; - } + }, }; /** diff --git a/packages/pointers/test/deploy.ts b/packages/pointers/test/deploy.ts index 38c2472df..854a1beba 100644 --- a/packages/pointers/test/deploy.ts +++ b/packages/pointers/test/deploy.ts @@ -4,7 +4,7 @@ import { Data } from "../src/data.js"; export async function deployContract( createBytecode: Data, - provider: EthereumProvider + provider: EthereumProvider, ): Promise<{ transactionHash: Data; contractAddress: Data; @@ -12,27 +12,35 @@ export async function deployContract( // just use the first unlocked account const [account] = await provider.request({ method: "eth_accounts", - params: [] + params: [], }); // issue a transaction that will be mined immediately - const transactionHash = Data.fromHex(await provider.request({ - method: "eth_sendTransaction", - params: [{ - from: account, - gas: "0x989680", - data: createBytecode.toHex() - }] - })); + const transactionHash = Data.fromHex( + await provider.request({ + method: "eth_sendTransaction", + params: [ + { + from: account, + gas: "0x989680", + data: createBytecode.toHex(), + }, + ], + }), + ); // read the receipt and extract the deployed contract address - const contractAddress = Data.fromHex((await provider.request({ - method: "eth_getTransactionReceipt", - params: [transactionHash.toHex()] - })).contractAddress); + const contractAddress = Data.fromHex( + ( + await provider.request({ + method: "eth_getTransactionReceipt", + params: [transactionHash.toHex()], + }) + ).contractAddress, + ); return { transactionHash, - contractAddress + contractAddress, }; } diff --git a/packages/pointers/test/examples.ts b/packages/pointers/test/examples.ts index 7c14cf670..e6b2c398d 100644 --- a/packages/pointers/test/examples.ts +++ b/packages/pointers/test/examples.ts @@ -4,14 +4,11 @@ import type { CompileOptions } from "./solc.js"; export const findExamplePointer = (() => { const { - schema: { - examples: examplePointers - } + schema: { examples: examplePointers }, } = describeSchema({ - schema: { id: "schema:ethdebug/format/pointer" } + schema: { id: "schema:ethdebug/format/pointer" }, }) as { schema: { examples: Pointer[] } }; return (text: string): Pointer => - examplePointers - .find(pointer => JSON.stringify(pointer).includes(text))!; + examplePointers.find((pointer) => JSON.stringify(pointer).includes(text))!; })(); diff --git a/packages/pointers/test/ganache.ts b/packages/pointers/test/ganache.ts index 5cf852519..01065612a 100644 --- a/packages/pointers/test/ganache.ts +++ b/packages/pointers/test/ganache.ts @@ -25,7 +25,7 @@ export async function loadGanache() { export function machineForProvider( provider: EthereumProvider, - transactionHash: Data + transactionHash: Data, ): Machine { return { trace(): AsyncIterable { @@ -33,25 +33,25 @@ export function machineForProvider( async *[Symbol.asyncIterator]() { const structLogs = await requestStructLogs( `0x${transactionHash.asUint().toString(16)}`, - provider + provider, ); for (const [index, structLog] of structLogs.entries()) { yield toMachineState(structLog, index); } - } + }, }; - } + }, }; } async function requestStructLogs( transactionHash: string, - provider: EthereumProvider + provider: EthereumProvider, ) { const { structLogs } = await provider.request({ method: "debug_traceTransaction", - params: [transactionHash] + params: [transactionHash], }); return structLogs; @@ -92,23 +92,17 @@ function makeStack(stack: StructLog["stack"]): Machine.State.Stack { return { length: constantUint(length), - async peek({ - depth, - slice: { - offset = 0n, - length = 32n - } = {} - }) { + async peek({ depth, slice: { offset = 0n, length = 32n } = {} }) { const entry = stack.at(-Number(depth)); const data = Data.fromHex(`0x${entry || ""}`); const sliced = new Uint8Array(data).slice( Number(offset), - Number(offset + length) + Number(offset + length), ); return new Data(sliced); - } + }, }; } @@ -119,33 +113,20 @@ function makeBytes(words: StructLog["memory"]): Machine.State.Bytes { length: constantUint(data.length), async read({ slice: { offset, length } }) { - return new Data(data.slice( - Number(offset), - Number(offset + length) - )); - } - } + return new Data(data.slice(Number(offset), Number(offset + length))); + }, + }; } function makeWords(slots: StructLog["storage"]): Machine.State.Words { return { - async read({ - slot, - slice: { - offset = 0n, - length = 32n - } = {} - }) { - const rawHex = slots[ - slot.resizeTo(32).toHex().slice(2) as keyof typeof slots - ]; + async read({ slot, slice: { offset = 0n, length = 32n } = {} }) { + const rawHex = + slots[slot.resizeTo(32).toHex().slice(2) as keyof typeof slots]; const data = Data.fromHex(`0x${rawHex}`); - return new Data(data.slice( - Number(offset), - Number(offset + length) - )); - } + return new Data(data.slice(Number(offset), Number(offset + length))); + }, }; } diff --git a/packages/pointers/test/index.ts b/packages/pointers/test/index.ts index 961144648..0554d51b7 100644 --- a/packages/pointers/test/index.ts +++ b/packages/pointers/test/index.ts @@ -1,19 +1,13 @@ -export { - loadGanache, - machineForProvider -} from "./ganache.js"; +export { loadGanache, machineForProvider } from "./ganache.js"; export { compileCreateBytecode, singleSourceCompilation, - type CompileOptions + type CompileOptions, } from "./solc.js"; -export { deployContract, } from "./deploy.js"; +export { deployContract } from "./deploy.js"; export { findExamplePointer } from "./examples.js"; -export { - observeTrace, - type ObserveTraceOptions -} from "./observe.js"; +export { observeTrace, type ObserveTraceOptions } from "./observe.js"; diff --git a/packages/pointers/test/observe.ts b/packages/pointers/test/observe.ts index 03b14fa29..bf8549315 100644 --- a/packages/pointers/test/observe.ts +++ b/packages/pointers/test/observe.ts @@ -69,15 +69,15 @@ export async function observeTrace({ compileOptions, observe, equals = (a, b) => a === b, - shouldObserve = () => Promise.resolve(true) + shouldObserve = () => Promise.resolve(true), }: ObserveTraceOptions): Promise { const observedValues: V[] = []; // initialize local development blockchain const provider = (await loadGanache()).provider({ logging: { - quiet: true - } + quiet: true, + }, }); // perform compilation @@ -92,7 +92,7 @@ export async function observeTrace({ let cursor; // delay initialization until first state of trace let lastObservedValue; for await (const state of machine.trace()) { - if (!await shouldObserve(state)) { + if (!(await shouldObserve(state))) { continue; } diff --git a/packages/pointers/test/solc.ts b/packages/pointers/test/solc.ts index bae2c9c1a..00a307841 100644 --- a/packages/pointers/test/solc.ts +++ b/packages/pointers/test/solc.ts @@ -13,8 +13,8 @@ try { export interface CompileOptions { sources: { [path: string]: { - content: string - } + content: string; + }; }; target: { @@ -29,7 +29,7 @@ export interface CompileOptions { */ export async function compileCreateBytecode({ sources, - target + target, }: CompileOptions): Promise { if (!solc) { throw new Error("Unable to load solc"); @@ -42,31 +42,27 @@ export async function compileCreateBytecode({ outputSelection: { "*": { "*": ["ir", "*"], - "": ["*"] - } + "": ["*"], + }, }, viaIR: true, optimizer: { - enabled: true - } - } + enabled: true, + }, + }, }; - const output = JSON.parse( - solc.compile( - JSON.stringify(input), - ) - ); + const output = JSON.parse(solc.compile(JSON.stringify(input))); const { errors = [] } = output; if (errors.length > 0) { - throw new Error(`Compilation error: ${JSON.stringify(errors, undefined, 2)}`); + throw new Error( + `Compilation error: ${JSON.stringify(errors, undefined, 2)}`, + ); } const { - evm: { - bytecode: createBytecode - } + evm: { bytecode: createBytecode }, } = output.contracts[target.path][target.contractName]; return Data.fromHex(`0x${createBytecode.object}`); @@ -90,13 +86,13 @@ export function singleSourceCompilation(options: { return { sources: { [path]: { - content: `${header}\n${contentWithoutHeader}\n` - } + content: `${header}\n${contentWithoutHeader}\n`, + }, }, target: { path, - contractName - } + contractName, + }, }; } diff --git a/packages/pointers/tsconfig.json b/packages/pointers/tsconfig.json index 0650fde99..86950c299 100644 --- a/packages/pointers/tsconfig.json +++ b/packages/pointers/tsconfig.json @@ -2,6 +2,6 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "rootDir": "./", - "outDir": "./dist/", + "outDir": "./dist/" } } diff --git a/packages/pointers/vitest.config.ts b/packages/pointers/vitest.config.ts index 6abfe8d2d..dd9e8a795 100644 --- a/packages/pointers/vitest.config.ts +++ b/packages/pointers/vitest.config.ts @@ -1,6 +1,5 @@ import { defineProject } from "vitest/config"; export default defineProject({ - test: { - } + test: {}, }); diff --git a/packages/web/babel.config.js b/packages/web/babel.config.js index e00595dae..bfd75dbdf 100644 --- a/packages/web/babel.config.js +++ b/packages/web/babel.config.js @@ -1,3 +1,3 @@ module.exports = { - presets: [require.resolve('@docusaurus/core/lib/babel/preset')], + presets: [require.resolve("@docusaurus/core/lib/babel/preset")], }; diff --git a/packages/web/docs/goals.mdx b/packages/web/docs/goals.mdx index 69652f3fd..94c022037 100644 --- a/packages/web/docs/goals.mdx +++ b/packages/web/docs/goals.mdx @@ -35,6 +35,7 @@ A debug format is only as valuable as its adoption. The path to widespread use requires careful attention to the needs of implementers and users alike. To this end, this project prioritizes: + - Clear, comprehensive documentation with practical examples - Reference implementations that demonstrate viability - Designs that respect existing compiler architectures diff --git a/packages/web/docs/implementation-guides/implementation-guides.mdx b/packages/web/docs/implementation-guides/implementation-guides.mdx index 4574f362f..90f42493f 100644 --- a/packages/web/docs/implementation-guides/implementation-guides.mdx +++ b/packages/web/docs/implementation-guides/implementation-guides.mdx @@ -12,7 +12,6 @@ Because of the distinct concerns involved in implementing this format on the compilation side vs. the concerns involved on the debugging side, this page lists and categorizes the available guides into the appropriate heading. - ## For debuggers
@@ -25,12 +24,13 @@ debugger might process **ethdebug/format** pointers. For an introduction to **ethdebug/format** pointers, please see the Pointer specification's [Overview](/spec/pointer/overview) and [Key concepts](/spec/pointer/concepts) pages. +
**Other guides**
-_Guides for other aspects of debugger-side **ethdebug/format** implementation -are planned and still need to be written._ + _Guides for other aspects of debugger-side **ethdebug/format** implementation + are planned and still need to be written._
@@ -38,11 +38,11 @@ are planned and still need to be written._ ## For compilers
-
**No availble guides yet**
-
-_Guides for implementing **ethdebug/format** support inside a compiler are -planned and still need to be written._ -
+
**No availble guides yet**
+
+ _Guides for implementing **ethdebug/format** support inside a compiler are + planned and still need to be written._ +
:::tip[Work in progress] diff --git a/packages/web/docs/implementation-guides/pointers/dereference-logic/dereference-logic.mdx b/packages/web/docs/implementation-guides/pointers/dereference-logic/dereference-logic.mdx index f6e706ba2..1bb90c893 100644 --- a/packages/web/docs/implementation-guides/pointers/dereference-logic/dereference-logic.mdx +++ b/packages/web/docs/implementation-guides/pointers/dereference-logic/dereference-logic.mdx @@ -55,7 +55,8 @@ The full signature of this function is as follows: return tempSourceFile.getFunction("dereference"); } - } /> + +} /> :::tip @@ -76,12 +77,13 @@ compose stack-located regions. sourceFile.getInterface("DereferenceOptions")} - /> + extract={(sourceFile) => sourceFile.getInterface("DereferenceOptions")} +/> ## Control flow architecture The `dereference()` function itself performs two tasks: + 1. Create a "simple cursor": a function that takes a machine state and produces an asynchronous list of `Cursor.Region`s. 2. Adapt this simple cursor to conform to the full `Cursor` interface diff --git a/packages/web/docs/implementation-guides/pointers/dereference-logic/generating-regions.mdx b/packages/web/docs/implementation-guides/pointers/dereference-logic/generating-regions.mdx index fa4b3dc33..428afb4c2 100644 --- a/packages/web/docs/implementation-guides/pointers/dereference-logic/generating-regions.mdx +++ b/packages/web/docs/implementation-guides/pointers/dereference-logic/generating-regions.mdx @@ -23,8 +23,8 @@ with `GenerateRegionsOptions`): sourceFile.getInterface("GenerateRegionsOptions")} - /> + extract={(sourceFile) => sourceFile.getInterface("GenerateRegionsOptions")} +/> + +} /> The `ProcessOptions` interface captures the runtime data at a particular point in the region generation process: @@ -114,8 +115,8 @@ point in the region generation process: sourceFile.getInterface("ProcessOptions")} - /> + extract={(sourceFile) => sourceFile.getInterface("ProcessOptions")} +/> The `Process` type alias provides a short type alias for functions like `processPointer` to use: @@ -123,11 +124,12 @@ The `Process` type alias provides a short type alias for functions like sourceFile.getTypeAlias("Process")} - /> + extract={(sourceFile) => sourceFile.getTypeAlias("Process")} +/> Effectively, by returning a `Process`, the `processPointer()` has two different mechanisms of data return: + - By being a JavaScript `AsyncGenerator`, it produces `Cursor.Region` objects one at a time, emitted as a side effect of execution (via JavaScript `yield`) - Upon completion of exection, the return value is a list of memos to be @@ -158,8 +160,8 @@ consider the implementation of the `processRegion()` function as a base case: sourceFile.getFunction("processRegion")} - /> + extract={(sourceFile) => sourceFile.getFunction("processRegion")} +/> Effectively, this function converts a `Pointer.Region` into a fully-evaluated, concrete `Cursor.Region`, emits this concrete region as the @@ -172,7 +174,6 @@ This pointer evaluation process will be described later. The recursive cases are fairly straightforward following this architecture. - ### Groups The simplest collection, a group of other pointers, yields no regions of its @@ -181,8 +182,8 @@ own, but instead pushes each of its child pointers for evaluation later: sourceFile.getFunction("processGroup")} - /> + extract={(sourceFile) => sourceFile.getFunction("processGroup")} +/> It's essential that each of the child pointers get evaluated in the order they appear in the list, since later pointers may reference regions named @@ -197,8 +198,8 @@ variable identifier for use inside the dynamic composed pointer evaluation. sourceFile.getFunction("processList")} - /> + extract={(sourceFile) => sourceFile.getFunction("processList")} +/> Note how, because each dynamic child pointer is evaluated based on the next incremented index value, the memos for updating this variable and @@ -217,8 +218,8 @@ the `"else"` pointer if it is specified: sourceFile.getFunction("processConditional")} - /> + extract={(sourceFile) => sourceFile.getFunction("processConditional")} +/> ### Scopes @@ -234,5 +235,5 @@ variable values are available immediately. sourceFile.getFunction("processScope")} - /> + extract={(sourceFile) => sourceFile.getFunction("processScope")} +/> diff --git a/packages/web/docs/implementation-guides/pointers/dereference-logic/making-regions-concrete.mdx b/packages/web/docs/implementation-guides/pointers/dereference-logic/making-regions-concrete.mdx index 57698712e..9115f69e2 100644 --- a/packages/web/docs/implementation-guides/pointers/dereference-logic/making-regions-concrete.mdx +++ b/packages/web/docs/implementation-guides/pointers/dereference-logic/making-regions-concrete.mdx @@ -22,8 +22,8 @@ This behavior is encapsulated by the `adjustStackLength` function: sourceFile.getFunction("adjustStackLength")} - /> + extract={(sourceFile) => sourceFile.getFunction("adjustStackLength")} +/> ## Evaluating region property expressions @@ -45,10 +45,7 @@ might take this pointer: { "location": "memory", "offset": { - "$sum": [ - 0x60, - { ".length": "$this" } - ] + "$sum": [0x60, { ".length": "$this" }] }, "length": "$wordsize" } @@ -70,5 +67,5 @@ implementation can infer that there must be a circular reference. sourceFile.getFunction("evaluateRegion")} - /> + extract={(sourceFile) => sourceFile.getFunction("evaluateRegion")} +/> diff --git a/packages/web/docs/implementation-guides/pointers/evaluating-expressions.mdx b/packages/web/docs/implementation-guides/pointers/evaluating-expressions.mdx index 73beaf197..6a6f7ccb2 100644 --- a/packages/web/docs/implementation-guides/pointers/evaluating-expressions.mdx +++ b/packages/web/docs/implementation-guides/pointers/evaluating-expressions.mdx @@ -14,11 +14,10 @@ if variable and region references are pre-evaluated: sourceFile.getExportedDeclarations() - .get("EvaluateOptions") - [0] - } /> + extract={(sourceFile) => + sourceFile.getExportedDeclarations().get("EvaluateOptions")[0] + } +/> The main `evaluate()` function uses type guards to dispatch to the appropriate specific logic based on the kind of expression: @@ -29,11 +28,10 @@ specific logic based on the kind of expression: sourceFile.getExportedDeclarations() - .get("evaluate") - [0] - } /> + extract={(sourceFile) => + sourceFile.getExportedDeclarations().get("evaluate")[0] + } +/> @@ -44,9 +42,8 @@ Evaluating constant expressions is quite straightforward: sourceFile.getFunction("evaluateConstant") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateConstant")} +/> Evaluating literals involves detecting hex string vs. number and converting appropriate to bytes: @@ -54,9 +51,8 @@ appropriate to bytes: sourceFile.getFunction("evaluateLiteral") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateLiteral")} +/> Variable lookups, of course, require consulting the `variables` map passed in `EvaluateOptions`: @@ -64,9 +60,8 @@ in `EvaluateOptions`: sourceFile.getFunction("evaluateVariable") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateVariable")} +/> ## Evaluating arithmetic operations @@ -81,27 +76,26 @@ Evaluating sums: sourceFile.getFunction("evaluateArithmeticSum") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateArithmeticSum")} +/> Evaluating products: sourceFile.getFunction("evaluateArithmeticProduct") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateArithmeticProduct")} +/> Evaluating differences: sourceFile.getFunction("evaluateArithmeticDifference") - } /> + extract={(sourceFile) => + sourceFile.getFunction("evaluateArithmeticDifference") + } +/> **Note** how this function operates on unsigned values only by bounding the result below at 0. @@ -111,9 +105,8 @@ Evaluating quotients: sourceFile.getFunction("evaluateArithmeticQuotient") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateArithmeticQuotient")} +/> (Quotients of course use integer division only.) @@ -122,9 +115,10 @@ Evaluating remainders: sourceFile.getFunction("evaluateArithmeticRemainder") - } /> + extract={(sourceFile) => + sourceFile.getFunction("evaluateArithmeticRemainder") + } +/> ## Evaluating resize expressions @@ -136,9 +130,8 @@ method to perform this operation. sourceFile.getFunction("evaluateResize") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateResize")} +/> ## Evaluating keccak256 hashes @@ -154,9 +147,8 @@ use of hashing to allocate persistent data. sourceFile.getFunction("evaluateKeccak256") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateKeccak256")} +/> ## Evaluating concatenation @@ -166,9 +158,8 @@ join them together, preserving the byte width of each operand. sourceFile.getFunction("evaluateConcat") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateConcat")} +/> ## Evaluating property lookups @@ -189,9 +180,8 @@ implementation needs only a single sourceFile.getFunction("evaluateLookup") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateLookup")} +/> (The use of generic types here serves mostly to appease the type-checker; the minimal type safety it affords is insignificant compared to runtime data @@ -215,9 +205,8 @@ this function presents no surprises: sourceFile.getFunction("evaluateRead") - } /> + extract={(sourceFile) => sourceFile.getFunction("evaluateRead")} +/> ## Note on `"$this"` region lookups diff --git a/packages/web/docs/implementation-guides/pointers/pointers.mdx b/packages/web/docs/implementation-guides/pointers/pointers.mdx index 784deffae..9be30f782 100644 --- a/packages/web/docs/implementation-guides/pointers/pointers.mdx +++ b/packages/web/docs/implementation-guides/pointers/pointers.mdx @@ -27,7 +27,6 @@ This format's [**ethdebug/format/pointer** schema](/spec/pointer/overview) provides such suitable expressiveness, but implementing the logic to read and evaluate data in this schema requires some careful consideration. - :::tip If you're reading this page without first having familiarized yourself with the concepts/terminology defined by the **ethdebug/format/pointer** schema, diff --git a/packages/web/docs/implementation-guides/pointers/reading-from-regions.mdx b/packages/web/docs/implementation-guides/pointers/reading-from-regions.mdx index cd9cd2ff0..d30e7ffd3 100644 --- a/packages/web/docs/implementation-guides/pointers/reading-from-regions.mdx +++ b/packages/web/docs/implementation-guides/pointers/reading-from-regions.mdx @@ -20,7 +20,4 @@ values from raw bytes into unsigned integer `bigint`s. ## Code listing - + diff --git a/packages/web/docs/implementation-guides/pointers/testing/example-pointers.mdx b/packages/web/docs/implementation-guides/pointers/testing/example-pointers.mdx index bd3712b8f..f125b670e 100644 --- a/packages/web/docs/implementation-guides/pointers/testing/example-pointers.mdx +++ b/packages/web/docs/implementation-guides/pointers/testing/example-pointers.mdx @@ -25,9 +25,10 @@ function: sourceFile.getVariableStatement("findExamplePointer") - } /> + extract={(sourceFile) => + sourceFile.getVariableStatement("findExamplePointer") + } +/> (This function is written as an immediately-invoked inline function so as to avoid unnecessary redundant calls to `describeSchema()`.) diff --git a/packages/web/docs/implementation-guides/pointers/testing/test-cases/TestedPointer.tsx b/packages/web/docs/implementation-guides/pointers/testing/test-cases/TestedPointer.tsx index e5450a157..a1ddb9cd6 100644 --- a/packages/web/docs/implementation-guides/pointers/testing/test-cases/TestedPointer.tsx +++ b/packages/web/docs/implementation-guides/pointers/testing/test-cases/TestedPointer.tsx @@ -7,15 +7,16 @@ export interface TestedPointerProps { } export default function TestedPointer({ - pointerQuery + pointerQuery, }: TestedPointerProps): JSX.Element { const { schema } = describeSchema({ - schema: { id: "schema:ethdebug/format/pointer" } + schema: { id: "schema:ethdebug/format/pointer" }, }); - const [exampleIndex] = [...(schema.examples?.entries() || [])] - .find(([_, example]) => JSON.stringify(example).includes(pointerQuery)) - || []; + const [exampleIndex] = + [...(schema.examples?.entries() || [])].find(([_, example]) => + JSON.stringify(example).includes(pointerQuery), + ) || []; if (typeof exampleIndex === "undefined") { throw new Error("Could not find example in pointer schema"); @@ -23,7 +24,7 @@ export default function TestedPointer({ const { yaml: pointerYaml } = describeSchema({ schema: { id: "schema:ethdebug/format/pointer" }, - pointer: `#/examples/${exampleIndex}` + pointer: `#/examples/${exampleIndex}`, }); return {pointerYaml}; diff --git a/packages/web/docs/implementation-guides/pointers/testing/test-cases/string-storage.mdx b/packages/web/docs/implementation-guides/pointers/testing/test-cases/string-storage.mdx index bc52f59a6..0faa61b46 100644 --- a/packages/web/docs/implementation-guides/pointers/testing/test-cases/string-storage.mdx +++ b/packages/web/docs/implementation-guides/pointers/testing/test-cases/string-storage.mdx @@ -19,11 +19,9 @@ value. sourceFile.getVariableStatement("stringStorageTest")} - /> + extract={(sourceFile) => sourceFile.getVariableStatement("stringStorageTest")} +/> ## Tested pointer - + diff --git a/packages/web/docs/implementation-guides/pointers/testing/test-cases/struct-storage.mdx b/packages/web/docs/implementation-guides/pointers/testing/test-cases/struct-storage.mdx index b6269c7fc..26a2b6dcf 100644 --- a/packages/web/docs/implementation-guides/pointers/testing/test-cases/struct-storage.mdx +++ b/packages/web/docs/implementation-guides/pointers/testing/test-cases/struct-storage.mdx @@ -17,11 +17,9 @@ with a few small fields (`struct Record { uint8 x; uint8 y; bytes4 salt; }`). sourceFile.getVariableStatement("structStorageTest")} - /> + extract={(sourceFile) => sourceFile.getVariableStatement("structStorageTest")} +/> ## Tested pointer - + diff --git a/packages/web/docs/implementation-guides/pointers/testing/test-cases/test-cases.mdx b/packages/web/docs/implementation-guides/pointers/testing/test-cases/test-cases.mdx index ad35a48da..9f4ee16dc 100644 --- a/packages/web/docs/implementation-guides/pointers/testing/test-cases/test-cases.mdx +++ b/packages/web/docs/implementation-guides/pointers/testing/test-cases/test-cases.mdx @@ -15,13 +15,16 @@ Test cases are aggregated into the `observeTraceTests` variable: sourceFile.getVariableStatement("observeTraceTests")} + extract={(sourceFile) => sourceFile.getVariableStatement("observeTraceTests")} links={{ - structStorageTest: "/docs/implementation-guides/pointers/testing/test-cases/struct-storage/", - stringStorageTest: "/docs/implementation-guides/pointers/testing/test-cases/string-storage/", - uint256ArrayMemoryTest: "/docs/implementation-guides/pointers/testing/test-cases/uint256-array-memory/", + structStorageTest: + "/docs/implementation-guides/pointers/testing/test-cases/struct-storage/", + stringStorageTest: + "/docs/implementation-guides/pointers/testing/test-cases/string-storage/", + uint256ArrayMemoryTest: + "/docs/implementation-guides/pointers/testing/test-cases/uint256-array-memory/", }} - /> +/> To see a brief introduction and the relevant code listings for each test case, please use the sidebar navigation or the hyperlinks included above. diff --git a/packages/web/docs/implementation-guides/pointers/testing/test-cases/uint256-array-memory.mdx b/packages/web/docs/implementation-guides/pointers/testing/test-cases/uint256-array-memory.mdx index c1ff23d21..fda08009a 100644 --- a/packages/web/docs/implementation-guides/pointers/testing/test-cases/uint256-array-memory.mdx +++ b/packages/web/docs/implementation-guides/pointers/testing/test-cases/uint256-array-memory.mdx @@ -17,11 +17,11 @@ the course of the transaction. sourceFile.getVariableStatement("uint256ArrayMemoryTest")} - /> + extract={(sourceFile) => + sourceFile.getVariableStatement("uint256ArrayMemoryTest") + } +/> ## Tested pointer - + diff --git a/packages/web/docs/implementation-guides/pointers/types/cursors.mdx b/packages/web/docs/implementation-guides/pointers/types/cursors.mdx index f2569291a..f0d24bd66 100644 --- a/packages/web/docs/implementation-guides/pointers/types/cursors.mdx +++ b/packages/web/docs/implementation-guides/pointers/types/cursors.mdx @@ -14,13 +14,16 @@ object. sourceFile.getExportedDeclarations() + extract={(sourceFile) => + sourceFile + .getExportedDeclarations() .get("Cursor") - .find(declaration => - declaration.getKind() === SyntaxKind.InterfaceDeclaration) + .find( + (declaration) => + declaration.getKind() === SyntaxKind.InterfaceDeclaration, + ) } - /> +/> A `Cursor` represents the closure around some pointer, generating concrete information about data locations and bytes _only in consideration of_ @@ -29,11 +32,12 @@ a particular machine state. ## Cursor views and regions Viewing a `Cursor` with a machine state yields two key results: + - A collection of `Cursor.Region` objects representing the pointer in terms of fully-evaluated slots, offsets, conditionals, etc. - A `read(region: Cursor.Region): Promise` method for reading - bytes from the machine + bytes from the machine **Importantly**, a `Cursor.Region` is a fully-evaluated `Pointer.Region`. While the schema allows pointer regions to @@ -47,10 +51,12 @@ The full listing of `namespace Cursor` follows: sourceFile.getExportedDeclarations() + extract={(sourceFile) => + sourceFile + .getExportedDeclarations() .get("Cursor") - .find(declaration => - declaration.getKind() === SyntaxKind.ModuleDeclaration) + .find( + (declaration) => declaration.getKind() === SyntaxKind.ModuleDeclaration, + ) } - /> +/> diff --git a/packages/web/docs/implementation-guides/pointers/types/data-and-machines.mdx b/packages/web/docs/implementation-guides/pointers/types/data-and-machines.mdx index 2c3961cd1..4f0c12bb8 100644 --- a/packages/web/docs/implementation-guides/pointers/types/data-and-machines.mdx +++ b/packages/web/docs/implementation-guides/pointers/types/data-and-machines.mdx @@ -8,14 +8,14 @@ import CodeListing from "@site/src/components/CodeListing"; The **@ethdebug/pointers** package includes two abstractions that it uses for representing low-level concerns: + - `class Data` extends JavaScript's `Uint8Array` to represent sequences of - bytes and allow conversion to/from different formats (like hex strings) + bytes and allow conversion to/from different formats (like hex strings) - `interface Machine` defines an asynchronous API to model a running EVM. - It includes the sole method `trace(): AsyncIterable`, - where the `Machine.State` type represents point-in-time access to a - running EVM at a particular program counter in a particular execution - context, etc. - + It includes the sole method `trace(): AsyncIterable`, + where the `Machine.State` type represents point-in-time access to a + running EVM at a particular program counter in a particular execution + context, etc. ## Data @@ -31,9 +31,7 @@ When implementing this functionality, be careful not to get this wrong.
Code listing for `src/data.ts` - +
@@ -42,8 +40,6 @@ When implementing this functionality, be careful not to get this wrong.
Code listing for `src/machine.ts` - +
diff --git a/packages/web/docs/implementation-guides/pointers/types/pointer-types.mdx b/packages/web/docs/implementation-guides/pointers/types/pointer-types.mdx index bd3652dac..69131bf0a 100644 --- a/packages/web/docs/implementation-guides/pointers/types/pointer-types.mdx +++ b/packages/web/docs/implementation-guides/pointers/types/pointer-types.mdx @@ -46,8 +46,8 @@ See these quick examples to get a sense for this part of the type hierarchy: import { Pointer } from "@ethdebug/format"; const expression: Pointer.Expression = { - $sum: [0, 1] -} + $sum: [0, 1], +}; Pointer.Expression.isKeccak256(expression); // false Pointer.Expression.isArithmetic(expression); // true @@ -59,4 +59,5 @@ Pointer.Expression.Arithmetic.isSum(expression); // true + sourcePath="src/types/pointer/pointer.ts" +/> diff --git a/packages/web/docs/known-challenges.mdx b/packages/web/docs/known-challenges.mdx index cad95dd3c..c051dc4b5 100644 --- a/packages/web/docs/known-challenges.mdx +++ b/packages/web/docs/known-challenges.mdx @@ -2,7 +2,7 @@ sidebar_position: 2 --- -import TOCInline from '@theme/TOCInline'; +import TOCInline from "@theme/TOCInline"; # Known challenges @@ -14,7 +14,7 @@ languages in the future; but also, we want to keep down the complexity of the format itself if possible. In what follows we'll outline some particular thorns of the EVM in general and -Solidity and Vyper in particular that will have to be addressed. This is not +Solidity and Vyper in particular that will have to be addressed. This is not necessarily a complete list. @@ -23,7 +23,7 @@ necessarily a complete list. Any debugging data format will need to handle the fact that in both Solidity and in Vyper the same type can have different representations depending on which -location (the stack, memory, storage, calldata, or code) it is stored in. As +location (the stack, memory, storage, calldata, or code) it is stored in. As such it does not suffice to give a single representation for a single type, but rather, it may be necessary to specify multiple representations, corresponding to the different data locations. @@ -31,21 +31,21 @@ to the different data locations. ## The word-based nature of storage and the stack Of the data locations mentioned above, most are byte-based, but two, the stack -and storage, are word-based. This will likely necessitate slightly different +and storage, are word-based. This will likely necessitate slightly different handling for them. Moreover, the fact that these two locations are word-based means there can be a -need to specify endianness. For instance, in Solidity, arrays may pack multiple -elements into the same storage word, starting from the low byte. However, -segments of strings in storage start at the high byte of their word. So it will -be necessary to have a way to specify this. (In particular, consider the case +need to specify endianness. For instance, in Solidity, arrays may pack multiple +elements into the same storage word, starting from the low byte. However, +segments of strings in storage start at the high byte of their word. So it will +be necessary to have a way to specify this. (In particular, consider the case of a `bytes2[] storage`; each `bytes2` is packed into the word in a little-endian order, but each `bytes2` itself is stored in a big-endian order.) (Of course, there can also be a need to specify endianness in byte-based -locations, e.g. for storage of integers. Currently all EVM languages known to +locations, e.g. for storage of integers. Currently all EVM languages known to me do this in a big-endian fashion, because this is what the EVM makes -convenient. It may be OK to assume that integers are big-endian, but the +convenient. It may be OK to assume that integers are big-endian, but the reverse possibility is at least worth noting.) ## Complex stride patterns @@ -58,9 +58,9 @@ array whose elements are 2 bytes long but which each only begin on 8-byte boundaries. However, this simple notion of stride length is not sufficient for handling -Solidity's storage arrays, whose stride patterns can be more complex. Solidity +Solidity's storage arrays, whose stride patterns can be more complex. Solidity allows for multiple elements in an array to be packed into a word, without -filling the whole word. If we for a moment ignore the word-based nature of +filling the whole word. If we for a moment ignore the word-based nature of storage and instead think of it as byte-based in a little-endian fashion, Solidity allows for patterns like "15 bytes for one element, 15 bytes for the next element, 2 bytes of empty space, repeat", which can't be expressed with a @@ -76,8 +76,8 @@ hash of various things; e.g., in a dynamically-sized array in Solidity, if the length is stored at a slot `p`, the elements are stored beginning at `keccak(p)`. -The format needs some way to be able to specify this. This also raises the -question of whether we should allow for other hash functions. Other hash +The format needs some way to be able to specify this. This also raises the +question of whether we should allow for other hash functions. Other hash functions are unlikely to be used due to the EVM making keccak much more convenient than other hashes, but it may not be the only possibility as there are precompiles for both SHA-256 and RIPEMD-160. @@ -93,23 +93,23 @@ representations, somewhat similar to the notion of union types? ## Mappings Both Solidity and Vyper use mappings, and while these work similarly in both -languages, the two aren't the same. It will be necessary to handle both styles, +languages, the two aren't the same. It will be necessary to handle both styles, and ideally other potential styles as well. In both languages, given a mapping at position `p` and a key `k`, the value corresponding to `k` is stored at a location determined by the Keccak hash of a -combination of `p` and `k`. But the details differ both by the language, and +combination of `p` and `k`. But the details differ both by the language, and whether we are looking at a value type that fits into a word, or whether we are looking at a string or bytestring. Solidity always performs the computation `keccak(k.p)`, where the `.` represents -concatenation. However, for value types the key is padded to a full word, while +concatenation. However, for value types the key is padded to a full word, while for a string or bytestring, no padding is used. -Vyper is similar, but differs in two ways. For value types, the computation is +Vyper is similar, but differs in two ways. For value types, the computation is instead `keccak(p.k)`, with the concatenands in the other order; note that `k` -is still padded. Meanwhile, for strings and bytestrings, the computation is -instead `keccak(p.keccak(k))` (again with no padding on `k`). There will need +is still padded. Meanwhile, for strings and bytestrings, the computation is +instead `keccak(p.keccak(k))` (again with no padding on `k`). There will need to be a way to specify this additional complexity. ## Markings for mapping keys @@ -117,13 +117,13 @@ to be a way to specify this additional complexity. The problem of keeping track of mapping keys is worth discussing separately. Mappings do not keep track of their keys; as such, it is up to the debugger to -keep track of mapping keys touched in a given transaction. This will require +keep track of mapping keys touched in a given transaction. This will require some kind of markings. Truffle Debugger currently handles this by using the AST and determining what value on the stack corresponds to the key specified for a given mapping access. However, this process is complex and requires several workarounds for unusual -cases. While presumably markings could be devised that allow this process to +cases. While presumably markings could be devised that allow this process to work in more generality, it's not clear that it's actually a good solution. An alternate approach, suggested some time ago by Nomic Labs, would be to have @@ -135,16 +135,16 @@ string or bytestring is pre-hashed, prior to the main hashing. ## The use of pointers in or to calldata In Solidity's ABI encoding format (used also by Vyper), which is necessarily -used for variables stored in calldata, pointers are relative. However, they are +used for variables stored in calldata, pointers are relative. However, they are not relative to their own location, but rather relative to the start of the -structure containing them. There will need to be some way to handle this. +structure containing them. There will need to be some way to handle this. Moreover, for types in Solidity with a variable number of elements (including strings and bytestrings), pointers on the stack to that type in calldata do not point to the beginning of the calldata representation (which would start with the length), but rather have both a start word and a length word, with the start word pointing just past where the length is stored (to the beginning of the -actual contents). It will be necessary to handle this as well. +actual contents). It will be necessary to handle this as well. ## Internal function pointers @@ -161,7 +161,7 @@ mapping indices to functions. Thirdly, in the format with `viaIR` turned off, an internal function pointer actually breaks down into one PC value for the deployed code and one PC value for the constructor code (although the latter is not always set and is sometimes -left as zero). So there will need to be a way to specify this complexity. +left as zero). So there will need to be a way to specify this complexity. Moreover, an internal function pointer can point to a designated revert function introduced by the compiler rather than defined by the user; it will be necessary @@ -170,7 +170,7 @@ to handle this case. ## Lack of fixed variable locations on the stack In languages that put variables on the stack, those variables may not have a -fixed location. (For instance, Solidity with optimization turned on.) There +fixed location. (For instance, Solidity with optimization turned on.) There will need to be a way to keep track of variables that move around on the stack. ## The possibility of handling other languages @@ -180,6 +180,6 @@ to be able to handle features that we may expect to see in other languages even if they do not appear in Solidity or Vyper. For instance, the (now-defunct) EVM language Pyramid was (largely) dynamically -typed, making each variable effectively a sum type. Sum types are an example of +typed, making each variable effectively a sum type. Sum types are an example of a feature we may want to be able to handle even if not present in either Solidity or Vyper. diff --git a/packages/web/docs/sketches/layout.mdx b/packages/web/docs/sketches/layout.mdx index e2cefad95..9cf980945 100644 --- a/packages/web/docs/sketches/layout.mdx +++ b/packages/web/docs/sketches/layout.mdx @@ -5,6 +5,7 @@ description: Initial format sketch # @haltman-at's allocation data draft ## Status of this document + This is an initial draft for review and comment. It does not have consensus and should only be cited as work in progress. ## Goal of this document @@ -15,12 +16,12 @@ To present the skeleton of a format for describing layout of complex types or va 2. Simple enough to be usable, and 3. Decently general, avoiding too much building in of Solidity and Vyper behaviors, and instead providing a way to specify those behaviors -Hopefully this approximately does that! (Note that it may make assumptions based on the EVM, rather than Solidity and Vyper; +Hopefully this approximately does that! (Note that it may make assumptions based on the EVM, rather than Solidity and Vyper; e.g., in our discussion of endianness, we'll say that we don't need to support little-endian numbers, because the EVM makes them difficult; but note this is a property of the EVM, not any particular language.) -This is something of a skeleton. One big problem that needs to be solved is to what extent this is applied to types vs to what -extent it's applied to individual variables. For now this will basically assume it's applied to types. Of course, it is also necessary +This is something of a skeleton. One big problem that needs to be solved is to what extent this is applied to types vs to what +extent it's applied to individual variables. For now this will basically assume it's applied to types. Of course, it is also necessary to describe the placement of individual variables, but hopefully with type layout information it's not necessary to individually describe their layout. @@ -28,30 +29,30 @@ So, for each type, we'll discuss what needs to be specified to specify the type in each particular location. Also, we'll discuss how to specify locations of individual variables. -What's written here might not be entirely compatible with what's in [prototype.mdx](./prototype.mdx). That will need to be hammered out. +What's written here might not be entirely compatible with what's in [prototype.mdx](./prototype.mdx). That will need to be hammered out. ### Things this doesn't do There's one big thing that this doesn't attempt, which is arrays that are directly multidimensional; more generally it doesn't cover anything similar, like having arrays of structs where each struct takes up multiple words but they don't all start on word boundaries -but rather are packed in as if it was all just primitive types. That seems to be too much complexity. +but rather are packed in as if it was all just primitive types. That seems to be too much complexity. There's some other weird possibilities I didn't consider, like arrays that go downward in storage instead of upward. ## Specifying variable positions Of course, the overall location itself will need to be specified, which (for now) can be memory, calldata, code, the stack, or storage. -(Coming soon: Transient storage?) For each location, further information is then needed to specify the position within the location. +(Coming soon: Transient storage?) For each location, further information is then needed to specify the position within the location. -**Discussion**: Should position specifications include both start and end? Notionally, end is redundant if layout is specified in the -type information. I'll just discuss start here. ("End" also potentially gets a bit messy when not everything runs the same way in +**Discussion**: Should position specifications include both start and end? Notionally, end is redundant if layout is specified in the +type information. I'll just discuss start here. ("End" also potentially gets a bit messy when not everything runs the same way in storage.) -**Discussion**: This document mentions "bytes" a lot. Should many of these mentions be "bits"? In many cases this would make no sense, -but in some cases, it could conceptually be possible. The problem is that using bits instead of bytes is overall less convenient but -doesn't gain much generality. But, it does gain us one important case (regarding how strings are stored in storage in Solidity), -so we need it at least there. It seems inconsistent to use it only there and not more generally, though. So likely we should more -often be using bits instead of bytes? Something for later. +**Discussion**: This document mentions "bytes" a lot. Should many of these mentions be "bits"? In many cases this would make no sense, +but in some cases, it could conceptually be possible. The problem is that using bits instead of bytes is overall less convenient but +doesn't gain much generality. But, it does gain us one important case (regarding how strings are stored in storage in Solidity), +so we need it at least there. It seems inconsistent to use it only there and not more generally, though. So likely we should more +often be using bits instead of bytes? Something for later. :::note @cameel comments here: @@ -60,7 +61,7 @@ often be using bits instead of bytes? Something for later. > the last bit just as a part of the length field. I.e. the length is specified > as either 2N or 2N+1 and odd numbers indicate one format and even ones the > other. -::: +> ::: ### Positions in memory, calldata, or code @@ -68,9 +69,9 @@ These locations are byte-based, so here, positions can just be described as byte ### Positions on the stack -The stack is word-based. So positions can be described as stack slots (counted from the bottom), plus a byte within the slot -(numbered from the little end?). Now this last part may seem unnecessary, as who would put two different variables in the -same stack slot? Well, see below regarding internal function pointers; I think we may need this. +The stack is word-based. So positions can be described as stack slots (counted from the bottom), plus a byte within the slot +(numbered from the little end?). Now this last part may seem unnecessary, as who would put two different variables in the +same stack slot? Well, see below regarding internal function pointers; I think we may need this. ### Positions in storage @@ -78,21 +79,22 @@ Note: This presumably will apply also to transient storage, although implementat Sometimes multiple variables are packed into the same storage slot, so we need to specify both a storage slot and a byte within that slot (from the little end, probably). -This leaves the question of specifying a storage slot -- is it sufficient to just give the slot address, or do we need to show how it was constructed? For -top-level variables, the slot address should be enough. So if that's all we need, we don't need to say any more. But I'll cover the other case just to be sure. +This leaves the question of specifying a storage slot -- is it sufficient to just give the slot address, or do we need to show how it was constructed? For +top-level variables, the slot address should be enough. So if that's all we need, we don't need to say any more. But I'll cover the other case just to be sure. #### A note on endianness in storage -Above speaks of the "start", but what's the "start" in storage for, e.g., an integer packed into the middle of a word? Is it the big end or the little end? +Above speaks of the "start", but what's the "start" in storage for, e.g., an integer packed into the middle of a word? Is it the big end or the little end? Assuming any particular endianness in storage seems bad (in Solidity e.g. it's different for arrays vs bytestrings), so each type should have a storage endianness -specified -- which does not need to agree with the endianness of its component types! It covers only the outermost layer. +specified -- which does not need to agree with the endianness of its component types! It covers only the outermost layer. For something like an integer this is meaningless per se, but it is necessary to make sense of the "start" of that integer. :::note @cameel asks about this: + > How do you define endianness for arrays? -::: +> ::: #### Specifying complex storage slots (if necessary) @@ -106,11 +108,12 @@ A storage slot can be specified as one of the following objects: :::note @cameel asks: + > Do we need a distinction between relative and absolute locations? I.e. when > describing the nested layout or something like a struct you might want to > interpret locations as relative but then you might still want to have some > things interpreted as absolute (specifically the hashed locations). -::: +> ::: ``` { @@ -121,38 +124,38 @@ key: } ``` -Here, prefix vs postfix means, does the key go before the map slot, or after? "Prehashed" means we hash the key separately and then hash the *result* -together with the map slot (Vyper does this for certain types). The possibility "prefix-prehashed" isn't currently used anywhere but may as well include +Here, prefix vs postfix means, does the key go before the map slot, or after? "Prehashed" means we hash the key separately and then hash the _result_ +together with the map slot (Vyper does this for certain types). The possibility "prefix-prehashed" isn't currently used anywhere but may as well include it form generality. Ideally the key might be represented as some sort of decoded value, but that seems out of scope, so let's just record the raw bytes of it, I figure. Possibly, for types that get padded before hashing, we could restrict the `key` field to be the bytes that actually represent the value, and -correspondingly increase the set of `mapType`s to also include information about how the value is padded. Something to consider. See the section +correspondingly increase the set of `mapType`s to also include information about how the value is padded. Something to consider. See the section on specifying mappings for more discussion of this. -Question: Allow offset on map entry? Don't really see a need for this. +Question: Allow offset on map entry? Don't really see a need for this. ## Specifying basic types -This might not need to be this complex. The suggestions in [prototype.mdx](./prototype.mdx) suggest group all these together as just primitive types -with just `keyword`, `bitwidth`, and `alignment`. Maybe that's better? Although `alignment` should likely distinguish between zero-padding and sign-padding. +This might not need to be this complex. The suggestions in [prototype.mdx](./prototype.mdx) suggest group all these together as just primitive types +with just `keyword`, `bitwidth`, and `alignment`. Maybe that's better? Although `alignment` should likely distinguish between zero-padding and sign-padding. ### Integers -Integers can be signed or unsigned and take up a specified number of bytes. No need for anything exotic here. We assume no integer type takes +Integers can be signed or unsigned and take up a specified number of bytes. No need for anything exotic here. We assume no integer type takes up more than a single word. `{ signed: boolean, bytes: number }` #### Specifying layout -There are two things here that might need to be specified: endianness and padding. Note that since we assume no integer type takes up more than a single word, -endianness is only a question for byte-based locations (memory, calldata, code). It's not a meaningful question for storage or the stack, as these are word-based. (However for storage layout +There are two things here that might need to be specified: endianness and padding. Note that since we assume no integer type takes up more than a single word, +endianness is only a question for byte-based locations (memory, calldata, code). It's not a meaningful question for storage or the stack, as these are word-based. (However for storage layout information there should still be an endianness specified, even though it's technically meaningless, so that sense can be made of which end is the "start".) -The EVM only really makes big-endian easy, so we probably don't need to specify endianness, and can just assume everything is big-endian. If anyone ever does -little-endian for some reason, support for that can be added later. For now though we can ignore the distinction between bytes that are earlier and bytes that +The EVM only really makes big-endian easy, so we probably don't need to specify endianness, and can just assume everything is big-endian. If anyone ever does +little-endian for some reason, support for that can be added later. For now though we can ignore the distinction between bytes that are earlier and bytes that are more significant. That leaves padding. We can specify this as follows: @@ -161,21 +164,22 @@ That leaves padding. We can specify this as follows: :::note @cameel asks about this: + > Does bytes include paddedBytes or not? > > From the note below about "bytewidth of the unpadded type" I assume it does > not, but perhaps that should be said explicitly. -::: +> ::: (Here `"zero"` means left-padded with zeroes, and `"right"` means right-padded with zeroes; `"sign"` means sign-padding.) Likely there should be some simpler way to indicate when no padding is used (`{paddingType: "none"}`?), but this will do. -Note we don't include the bytewidth (or bitwidth) of the unpadded type, as that's in the type information rather than the layout information. But obviously it needs to be specified somewhere. +Note we don't include the bytewidth (or bitwidth) of the unpadded type, as that's in the type information rather than the layout information. But obviously it needs to be specified somewhere. ### Fixed-point numbers -These work like integers, except we also need to specify a denominator. Two possibilities: +These work like integers, except we also need to specify a denominator. Two possibilities: 1. Add a `bigint` `denominator` field 2. Add a `number` `base` field and a `number` `places` field @@ -183,7 +187,7 @@ These work like integers, except we also need to specify a denominator. Two pos Either should work. One could argue that we only need `places`, as only decimal fixed-point is implemented in any popular EVM language (Vyper), but binary fixed-point has -also been discussed in the past, and there's little cost to being general here. If someone wants to do ternary fixed-point for some reason, sure, we can support that, +also been discussed in the past, and there's little cost to being general here. If someone wants to do ternary fixed-point for some reason, sure, we can support that, that isn't costly to include. #### Specifying layout @@ -192,7 +196,7 @@ Same as for integers. ### Short fixed-length bytestrings -"Short" meaning "fits in a word and is treated as a primitive type". Probably this should be folded in with bytestrings more generally rather than treated +"Short" meaning "fits in a word and is treated as a primitive type". Probably this should be folded in with bytestrings more generally rather than treated separately, see below about that, but this is listed here in case we want to treat it separately. Not much to say here, just number of bytes. @@ -211,7 +215,7 @@ Same as above! ### Addresses and other primitive types? -Addresses are often treated as primitive? The idea of not separating out primitive types is starting to sound like a better idea. So maybe that's the thing to do, or maybe we can have the types above +Addresses are often treated as primitive? The idea of not separating out primitive types is starting to sound like a better idea. So maybe that's the thing to do, or maybe we can have the types above and then just have a bucket for other primitives, such as addresses. #### Specifying layout @@ -220,21 +224,22 @@ Same as above! #### A note on function pointers -What about function pointers? Those are treated as a primitive type in Solidity! +What about function pointers? Those are treated as a primitive type in Solidity! -Well, external function pointers decompose into two parts, an address and a selector. So I think they should be treated as a complex type for our purposes here. +Well, external function pointers decompose into two parts, an address and a selector. So I think they should be treated as a complex type for our purposes here. Internal function pointers also decompose into two parts in non-IR Solidity. -But, in IR Solidity, they don't decompose. Also, in non-IR Solidity, what do they decompose into? We might want some way to mark one of these miscellaneous primitive types -as an internal function pointer, so that whatever's reading this format can know to treat them as that. (I don't see that we need this for external function pointers, since -each *part* of those is meaningful without this annotation.) +But, in IR Solidity, they don't decompose. Also, in non-IR Solidity, what do they decompose into? We might want some way to mark one of these miscellaneous primitive types +as an internal function pointer, so that whatever's reading this format can know to treat them as that. (I don't see that we need this for external function pointers, since +each _part_ of those is meaningful without this annotation.) :::note @cameel adds: + > They decompose into two separate jump destinations: one into the creation > code, the other into the deployed code. But this is something that feels like > an implementation detail so not sure it has a place here. -::: +> ::: ## Specifying more complex types @@ -248,58 +253,63 @@ Anyway, obviously, you have to specify the component types and their order. #### Specifying layout -For byte-based locations: Each component needs to have its starting offset specified, but that's not enough. Each one also needs padding specified. +For byte-based locations: Each component needs to have its starting offset specified, but that's not enough. Each one also needs padding specified. You can also specify an overall length for the whole thing, which is useful for in storage specifying that it should take up a whole number of words; for storage this should be allowed in bytes or in words. -Also, each component needs to have specified how it's stored. Based on how things are done in Solidity and Vyper, we can have several possibilities: -1. It's stored inline. (This includes reference types in storage; they're not always "inline" per se -but they're inline for our purposes.) -2. It's stored as a pointer. In this case we'll need to specify the length of the pointer. -3. It's stored as a relative pointer. Now, in Solidity, when relative pointers are used, they're not relative to -the current location, they're relative to the start of the container they're inside. We can allow for both possibilities, -probably (relative pointers aren't so exotic). And of course we need to know the length of the pointer. +Also, each component needs to have specified how it's stored. Based on how things are done in Solidity and Vyper, we can have several possibilities: + +1. It's stored inline. (This includes reference types in storage; they're not always "inline" per se + but they're inline for our purposes.) +2. It's stored as a pointer. In this case we'll need to specify the length of the pointer. +3. It's stored as a relative pointer. Now, in Solidity, when relative pointers are used, they're not relative to + the current location, they're relative to the start of the container they're inside. We can allow for both possibilities, + probably (relative pointers aren't so exotic). And of course we need to know the length of the pointer. :::note @cameel adds: + > In the future in Solidity also pointers to data stored in other locations > will be possible. Things like a storage struct nested inside a memory struct. > The concept of located types in the main spec already allows for that in full > generality. -::: +> ::: -For the stack: Overall this is similar? Structs don't live on the stack, but function pointers do. It'll be necessary here -to use the ability to specify particular bytes within a stack slot. Alternatively, if we don't want to allow that, +For the stack: Overall this is similar? Structs don't live on the stack, but function pointers do. It'll be necessary here +to use the ability to specify particular bytes within a stack slot. Alternatively, if we don't want to allow that, because we don't think splitting up internal function pointers is a good idea, we could allow separately specifying the padding in each stack slot (this is necessary to handle Solidity's external function pointers, assuming we're handling them under this). :::note @cameel adds: + > In the future structs will be allowed to live anywhere. -::: +> ::: + +For storage: We _could_ do something complicated, assuming that structs might get relocated in all sorts of weird ways, +but this is probably not a good idea to start with. Instead we'll just assume that each struct either: -For storage: We *could* do something complicated, assuming that structs might get relocated in all sorts of weird ways, -but this is probably not a good idea to start with. Instead we'll just assume that each struct either: 1. always start on a word boundary and so is always laid out internally in the same way, so we can give the -locations of the components relative to the start of the struct, or + locations of the components relative to the start of the struct, or 2. is no more than a single word in length and never crosses word boundaries, in which case we can give positions -within the single word it's contained within (byte offsets relative to the start; endianness would have to be -marked to make these meaningful). + within the single word it's contained within (byte offsets relative to the start; endianness would have to be + marked to make these meaningful). -It'll probably be necessary to include an explicit tag to distinguish between these two cases. Note the second +It'll probably be necessary to include an explicit tag to distinguish between these two cases. Note the second case is included to cover things that aren't actually structs but decompose into multiple parts. ### Tagged unions -These don't currently exist in Solidity or Vyper, but we should probably handle them? Pyramid had them (in that +These don't currently exist in Solidity or Vyper, but we should probably handle them? Pyramid had them (in that it was dynamically typed so everything was one). :::note @cameel notes: + > They're planned in Solidity and may already exist in Fe. In Solidity they > will most likely be implemented in a form similar to Rust's enums with data. > Algebraic types in general will be possible in the future. -::: +> ::: For the type, we say what it's a union of. @@ -308,7 +318,7 @@ For the type, we say what it's a union of. So, we have to specify where to find the tag, and what to do in each case. For where to find the tag, we can give a start position and a length; note that for the reasons discussed below, -we may want to allow the tag to be have start and length given in individual *bits* rather than bytes. +we may want to allow the tag to be have start and length given in individual _bits_ rather than bytes. For each option, then, we can give a layout specification and a start point. @@ -320,57 +330,58 @@ That is, a type could indicate that in a particular location, it had a tagged un as with tagged unions, it would be specified where to find the tag, and then there'd be an object for each case. But the object would specify a layout, not a type! -This would allow handling Solidity storage strings. The last bit of the word would be the tag. In case 0, -bits 1-31 are the length, and bits 32-255 are the contents. (So, we'd need to be able to specify individual -bits here, not just bytes. Of course that's partly a concern for strings, not unions.) In case 1, bits 1-255 are -the length, and we specify that the contents are at a hashed location. (Note that if we use the ideas below, +This would allow handling Solidity storage strings. The last bit of the word would be the tag. In case 0, +bits 1-31 are the length, and bits 32-255 are the contents. (So, we'd need to be able to specify individual +bits here, not just bytes. Of course that's partly a concern for strings, not unions.) In case 1, bits 1-255 are +the length, and we specify that the contents are at a hashed location. (Note that if we use the ideas below, we wouldn't actually specify the end of the contents, only the start.) -Of course, doing this means that all *ordinary* representations descriptions would need to have an additional -field to specify that they're not a union. Or perhaps this information could go in a field outside the representation +Of course, doing this means that all _ordinary_ representations descriptions would need to have an additional +field to specify that they're not a union. Or perhaps this information could go in a field outside the representation description, to avoid that? ### Enumerations -Maybe these are treated like primitive types? Maybe they're treated like tagged unions whose unioned types are all the unit type? In that case we'd need to be able +Maybe these are treated like primitive types? Maybe they're treated like tagged unions whose unioned types are all the unit type? In that case we'd need to be able to represent the unit type. :::note @cameel adds: -> This *might* need specifying the size in bytes. In older Solidity versions + +> This _might_ need specifying the size in bytes. In older Solidity versions > enums took a variable number of bytes, depending on the number of members. > Now they're limited to 256 members so 1 byte > (https://github.com/ethereum/solidity/pull/10247). Other languages could be > doing it differently. -::: +> ::: ### Strings and bytestrings -Type information: Is it a string or a bytestring? Is there a bound on its length? Is the bound an exact length it must be (as has been proposed for Solidity), or is it a cap (as in Vyper)? +Type information: Is it a string or a bytestring? Is there a bound on its length? Is the bound an exact length it must be (as has been proposed for Solidity), or is it a cap (as in Vyper)? -We probably don't need to bother with questions of string encodings, everything can be assumed to be UTF-8. Possibly we could have a separate type for ASCII-only strings, +We probably don't need to bother with questions of string encodings, everything can be assumed to be UTF-8. Possibly we could have a separate type for ASCII-only strings, since some languages may want that as a separate type (Solidity has separate literals for with or without Unicode, though not separate types). We probably don't need Latin-1 strings or anything like that. #### Specifying layout -For numbers, endianness was potentially a concern for byte-based locations. Here, it's not; instead it's potentially a concern for storage, since it's *not* byte-based. Once again, though, +For numbers, endianness was potentially a concern for byte-based locations. Here, it's not; instead it's potentially a concern for storage, since it's _not_ byte-based. Once again, though, the EVM makes big-endian easy and little-endian hard, so we'll just assume big-endian and not include an endianness specification. (On the other hand, Solidity does little-endian for arrays, so...?) -For ones of fixed (not merely bounded) length, there's not much to specify. We're assuming big-endian, and the start is stored elsewhere. We may want -to allow an offset in case the length is stored redundantly? Also, for storage specifically, we do have to notate whether the -string is stored at the *actual* specified start, or at a hashed location. So, `{ hashSlot: boolean }`. +For ones of fixed (not merely bounded) length, there's not much to specify. We're assuming big-endian, and the start is stored elsewhere. We may want +to allow an offset in case the length is stored redundantly? Also, for storage specifically, we do have to notate whether the +string is stored at the _actual_ specified start, or at a hashed location. So, `{ hashSlot: boolean }`. For ones of variable length, we have more work to do, as we have to specify where to find both the length and the contents. For storage, we can reasonably assume that strings have the two cases that structs do (possibly just the first but seems less clear we should assume that). -(Actually, if we don't assume that, possibly we could fold primitive bytestrings into the fixed-length case here as well. There may be some situations that warrant +(Actually, if we don't assume that, possibly we could fold primitive bytestrings into the fixed-length case here as well. There may be some situations that warrant distinguishing, but that could likely be handled by explicitly tagging the different types as different types, not representing them differently internally aside from the tag.) -So, we can specify where to find the length, the length of the length (or that can be determined by giving the length a type?), and the start of the contents. For byte-based locations +So, we can specify where to find the length, the length of the length (or that can be determined by giving the length a type?), and the start of the contents. For byte-based locations that suffices. However in storage, when we specify the offset, we also have to specify (for both the length and the contents separately!) whether the offset is relative @@ -389,12 +400,12 @@ Mappings are weird and specific enough that it makes sense to build-in a lot of #### Specifying layout -We'll just assume all mappings use something like Solidity or Vyper's system. In this case, what needs to be specified for a given mapping is: +We'll just assume all mappings use something like Solidity or Vyper's system. In this case, what needs to be specified for a given mapping is: 1. Does the key go before the slot, or after? 2. Is the key pre-hashed, like for strings in Vyper? -3. Is the key padded at all, and if so how? I.e., to what width and with which padding type. (Notionally this padding information could go in the key type itself, adding a "key" location for this purpose. I am not assuming that -all locations get the same type of padding because this has not always been true in all versions of Solidity.) +3. Is the key padded at all, and if so how? I.e., to what width and with which padding type. (Notionally this padding information could go in the key type itself, adding a "key" location for this purpose. I am not assuming that + all locations get the same type of padding because this has not always been true in all versions of Solidity.) Probably it is best to combine (1) and (2) into a `mapType` and keep (3) separate as a `paddingType`. @@ -402,15 +413,15 @@ Probably it is best to combine (1) and (2) into a `mapType` and keep (3) separat Note: This will exclude strings and bytestrings, handling them separately above, unlike [prototype.mdx](./prototype.mdx); another difference that will have to be figured out. -We can split these into fixed-length and variable length (whether bounded or unbounded). And then you've got the base type. +We can split these into fixed-length and variable length (whether bounded or unbounded). And then you've got the base type. #### Specifying layout -Oh boy, arrays. This is where it truly gets messy if we want to be general. Probably some generality will have to be +Oh boy, arrays. This is where it truly gets messy if we want to be general. Probably some generality will have to be axed here for the sake of simplicity. If the array is variable length, you need to specify the start of the length and of the contents; -for fixed-length, only the latter (it may not be at the start as the length may be stored redundantly). You also need to specify the +for fixed-length, only the latter (it may not be at the start as the length may be stored redundantly). You also need to specify the length of the length, or perhaps that can be handled by giving the length a type. In the case of storage, as is typical, this requires not only specifying an offset but also whether to hash the slot (this is separate @@ -422,26 +433,26 @@ a relative pointer and of what sort. You can once again also specify an overall length for the whole thing, which is useful for in storage specifying that it should take up a whole number of words; for storage this should be allowed in bytes or in words. -What about padding of the elements? Well, that's the messy part... the stride pattern. +What about padding of the elements? Well, that's the messy part... the stride pattern. -See, we *could* just specify padding for the base type (what it's padded to and with what padding type). But this wouldn't suffice to -handle the case of how Solidity does arrays in storage! Maybe we can make this optional -- you can give a `paddedWith` and `paddingType`, -*or* you can use the more complicated stride pattern system. +See, we _could_ just specify padding for the base type (what it's padded to and with what padding type). But this wouldn't suffice to +handle the case of how Solidity does arrays in storage! Maybe we can make this optional -- you can give a `paddedWith` and `paddingType`, +_or_ you can use the more complicated stride pattern system. Note that for storage you will also need to specify an endianness, since storage is word-based rather than byte-based. -Solidity does arrays little-endian! So we really do need this to be specified here. This could be specified for every +Solidity does arrays little-endian! So we really do need this to be specified here. This could be specified for every location for consistency, but that seems unnecessary. -Anyway, stride patterns. Here's a simple proposal for how a stride pattern might be represented. +Anyway, stride patterns. Here's a simple proposal for how a stride pattern might be represented. A stride pattern will be an array of objects, each of which is one of the following: `{ type: "element" }`, `{ type: "zero", length: number }`, or `{ type: "sign", length: number }`. -A stride pattern is interpreted as follows: `"element"` means an element goes here, of its appropriate length (no padding). The `"zero"` type means this many bytes of zeroes. +A stride pattern is interpreted as follows: `"element"` means an element goes here, of its appropriate length (no padding). The `"zero"` type means this many bytes of zeroes. And (this isn't currently necessary, but) `"sign"` will mean this many bytes of sign-padding, where the thing it's sign-padding is determined from context -(in big-endian contexts, it's the next thing; in little-endian contexts, the previous thing). The stride pattern is implicitly periodic; the number of `"element"` entries is not +(in big-endian contexts, it's the next thing; in little-endian contexts, the previous thing). The stride pattern is implicitly periodic; the number of `"element"` entries is not supposed to match that of the array, rather, when you get to the end of the stride pattern you go back to the start. -In a byte-based location, this means what it sounds like. In storage, you have to read according to the endianness that was specified. Note it's assumed that no element +In a byte-based location, this means what it sounds like. In storage, you have to read according to the endianness that was specified. Note it's assumed that no element that fits in a word will cross a word boundary, and that you won't use `"sign"` in places it doesn't make sense, that you won't have structs that are supposed to start on a word boundary start elsewhere, etc. @@ -449,36 +460,37 @@ In addition to the stride pattern, you can separately specify padding for the ar Solidity examples: -* `uint256[]` -- it takes up the whole word, so the pattern is `[{ type: "element" }]` -* `uint128[]` -- there's two of them, so `[{ type: "element" }, { type: "element" }]` -* `uint96[]` -- there's two of them and then 64 bytes of padding, so `[{ type: "element" }, { type: "element" }, { type: "zero", length: 64 }]` -* `uint96[3][]` -- a `uint96[3]` takes up two full words always, so just `[{ type: "element" }]` suffices; what goes on inside the `uint96[3]` can be handled inside there -* `uint96[3]` -- the stride pattern is `[{ type: "element" }, { type: "element" }, { type: "zero", length: 64 }]` as above, but now we should *also* specify that the array as - a whole has an overall length of two words, so that in a `uint96[3][]`, there's no confusion about the fact that each one should start on a fresh word boundary. - (Not that it would be legal to start it anywhere else, but it should still be explicitly specified, not left as error-recovery behavior.) +- `uint256[]` -- it takes up the whole word, so the pattern is `[{ type: "element" }]` +- `uint128[]` -- there's two of them, so `[{ type: "element" }, { type: "element" }]` +- `uint96[]` -- there's two of them and then 64 bytes of padding, so `[{ type: "element" }, { type: "element" }, { type: "zero", length: 64 }]` +- `uint96[3][]` -- a `uint96[3]` takes up two full words always, so just `[{ type: "element" }]` suffices; what goes on inside the `uint96[3]` can be handled inside there +- `uint96[3]` -- the stride pattern is `[{ type: "element" }, { type: "element" }, { type: "zero", length: 64 }]` as above, but now we should _also_ specify that the array as + a whole has an overall length of two words, so that in a `uint96[3][]`, there's no confusion about the fact that each one should start on a fresh word boundary. + (Not that it would be legal to start it anywhere else, but it should still be explicitly specified, not left as error-recovery behavior.) #### Things probably not to include for now Probably don't attempt to handle arrays that are directly multidimensional (as opposed to -multidimensional arrays just being ordinary arrays of arrays). Allowing this also raises possibility -of a flag for row-major vs column-major order. Probably best to just exclude this for now. +multidimensional arrays just being ordinary arrays of arrays). Allowing this also raises possibility +of a flag for row-major vs column-major order. Probably best to just exclude this for now. :::note @haltman-at notes in a comment (after writing this) + > Oh, geez, I just realized there's something big I left out: How things are -> pointed to on the stack. Actually, one could perhaps speak of cross-location +> pointed to on the stack. Actually, one could perhaps speak of cross-location > pointers in general, but as that doesn't exist mostly at the moment, probably > no sense in including that; it's premature. > > But, I guess something that needs to be added is, for each type, for the > stack location, I talked about from/to but really we also need to say, does -> this thing live directly on the stack or is it pointed to. And if it's +> this thing live directly on the stack or is it pointed to. And if it's > pointed to, we need to specify the pointer format -- do we just point to the -> start, or do we have start/length? And then if it's start/length we need to +> start, or do we have start/length? And then if it's start/length we need to > break down which part is the start and which part is the length... also, for > length, we likely want to be able to specify what the length is measured in > -- for instance it could potentially be `"bytes"` or `"words"` or `"items"`. > > (Yes this should be added to the PR itself but I don't have a lot of time at > the moment) -::: +> ::: diff --git a/packages/web/docs/sketches/prototype.mdx b/packages/web/docs/sketches/prototype.mdx index 2c62039c6..789fb9059 100644 --- a/packages/web/docs/sketches/prototype.mdx +++ b/packages/web/docs/sketches/prototype.mdx @@ -2,7 +2,7 @@ description: Initial format sketch --- -import TOCInline from '@theme/TOCInline'; +import TOCInline from "@theme/TOCInline"; # @jtoman's format prototype @@ -43,7 +43,7 @@ to which source level identifiers. ### Type Information The EVM has one "type": a 256-bit word. Source languages that compile to the EVM have richer type information -which can aid in debugging and fuzzing; for example, the counterexample generation used by the Certora prover +which can aid in debugging and fuzzing; for example, the counterexample generation used by the Certora prover could use type information to pretty print values according to their high-level type. ### Jump Resolution @@ -65,7 +65,7 @@ help explicitly identify the targets of internal function calls and what argumen ### Mapping key identification -EVM languages commonly include non-enumerable mappings. As such, it is useful to be able to dynamically identify any mapping keys that may appear +EVM languages commonly include non-enumerable mappings. As such, it is useful to be able to dynamically identify any mapping keys that may appear while analyzing a transaction trace or debugging. ## The Format @@ -76,9 +76,9 @@ The format will be JSON so that it may be included in the standard input/output The "top-level" artifact of the debug format will be a JSON dictionary with (at least) the following fields: -* `version`: A representation of the major/minor version of the format. The actual representation of this version (a string, an array, etc.) can be decided later. -* `types`: An array describing the layout of user-defined types defined in contracts referenced during compilation (see below). -* `bytecode`: Debug information about the bytecode output by the compiler. +- `version`: A representation of the major/minor version of the format. The actual representation of this version (a string, an array, etc.) can be decided later. +- `types`: An array describing the layout of user-defined types defined in contracts referenced during compilation (see below). +- `bytecode`: Debug information about the bytecode output by the compiler. ### Type Descriptions @@ -86,22 +86,22 @@ When describing user defined types in contracts or describing the types of value will use `type descriptors` to describe the type in question. There is one type descriptor per type in the source language. Each descriptor is a JSON object with at least the following fields: -* `id`: a unique numeric id. This may be referenced by type descriptors for aggregate types (arrays, structs, etc.) -* `sort`: A string representing the sort of the type. Possible values include: - * `"mapping"` for a dynamic mapping from a key type to a value type - * `"primitive"` built in primitive type - * `"array"` for a homogeneous dynamic array of bounded/unbounded size - * `"static_array"` for homogeneous static arrays - * `"struct"` for user defined aggregate struct types - * `"enum"` user defined enumeration types - * `"contract"` a refinement of an address primitive with information about the contract deployed at the address - * `"alias"` a user defined alias for some type - * `"located"` a reference to another type with a data location attached -* `label`: a (not necessarily human-readable) string representation of the type. Expected to be used for debugging +- `id`: a unique numeric id. This may be referenced by type descriptors for aggregate types (arrays, structs, etc.) +- `sort`: A string representing the sort of the type. Possible values include: + - `"mapping"` for a dynamic mapping from a key type to a value type + - `"primitive"` built in primitive type + - `"array"` for a homogeneous dynamic array of bounded/unbounded size + - `"static_array"` for homogeneous static arrays + - `"struct"` for user defined aggregate struct types + - `"enum"` user defined enumeration types + - `"contract"` a refinement of an address primitive with information about the contract deployed at the address + - `"alias"` a user defined alias for some type + - `"located"` a reference to another type with a data location attached +- `label`: a (not necessarily human-readable) string representation of the type. Expected to be used for debugging Depending on the value of `sort` the type descriptor will have additional fields. -**Discussion** The types here do *not* include events or errors. These can be described elsewhere in the format, +**Discussion** The types here do _not_ include events or errors. These can be described elsewhere in the format, and indeed, they will likely reference the types defined here. However, as events and errors are not currently first class in any language targeting the EVM that I'm aware of (i.e., you cannot declare a variable `x` to be of type `error Foo()`) they should be described elsewhere. @@ -111,15 +111,17 @@ type `error Foo()`) they should be described elsewhere. #### Mappings The type descriptor for a mapping type has the following additional fields defined. -* `keyType`: contains the `id` of the type that is the domain of the mapping. -* `valueType`: contains the `id` of the type that is the codomain of the mapping. + +- `keyType`: contains the `id` of the type that is the domain of the mapping. +- `valueType`: contains the `id` of the type that is the codomain of the mapping. #### Primitives The type descriptor for a primitive has the following additional fields: -* `keyword`: the source keyword for the type. Examples include `uint256`, `boolean` etc. -* `bitwidth`: the maximum number of bits a value of this type may occupy -* `alignment`: one of `high` / `low`, indicating if the bits occur in the most significant bits (`high`) or least significant bits (`low`) of 256-bit EVM word. + +- `keyword`: the source keyword for the type. Examples include `uint256`, `boolean` etc. +- `bitwidth`: the maximum number of bits a value of this type may occupy +- `alignment`: one of `high` / `low`, indicating if the bits occur in the most significant bits (`high`) or least significant bits (`low`) of 256-bit EVM word. **Discussion**: The bitwidth field is an initial attempt to come up with some language agnostic way to describe primitive types. It is expected that further fields may be added, or perhaps the Primitive sort @@ -129,14 +131,17 @@ should be split up into more specific units, like `Integral` and `Real` etc. The type descriptor for an array is further subdivided depending on whether the array is a bytes array or any other array. It has at least the following fields: -* `arraySort`: either the string `"bytes"` or `"generic"` (names not final). -* `bound`: a field indicating the statically known upper bound on the size of this array (for Vyper). If null the array is unbounded. + +- `arraySort`: either the string `"bytes"` or `"generic"` (names not final). +- `bound`: a field indicating the statically known upper bound on the size of this array (for Vyper). If null the array is unbounded. If `arraySort` is `"bytes"` then the descriptor has the following field: -* `keyword`: the keyword used to declare this type, to account for `string` vs `bytes` + +- `keyword`: the keyword used to declare this type, to account for `string` vs `bytes` If the `arraySort` is `"generic"` then descriptor has the following field: -* `elementType`: a numeric id that references the type of values held in each element of the array. + +- `elementType`: a numeric id that references the type of values held in each element of the array. **Discussion**: Here, as elsewhere, no attempt is made here in the type descriptors to describe the physical representation of the type. Short of some semi-turing complete DSL, there doesn't seem to be a compact way @@ -145,29 +150,33 @@ to describe declaratively the packed storage representation of strings in storag #### Static Arrays The type descriptor for a static array has the following additional fields: -* `size`: the static, pre-declared size of the fixed size array/list -* `elementType`: a numeric id that references the type of values held in each element of the array. + +- `size`: the static, pre-declared size of the fixed size array/list +- `elementType`: a numeric id that references the type of values held in each element of the array. #### Struct This format assumes that all struct types are user defined types and thus have a declaration site. The type descriptor for a struct has the following addition fields: -* `declaration`: A dictionary describing the definition site of the struct, see below. -* `fields`: An ordered list of dictionaries describing the fields of the struct. -* `name`: The name of the struct without the `struct` keyword and without contract qualifiers. + +- `declaration`: A dictionary describing the definition site of the struct, see below. +- `fields`: An ordered list of dictionaries describing the fields of the struct. +- `name`: The name of the struct without the `struct` keyword and without contract qualifiers. The order of the elements in `fields` is significant, and should match the order that fields are declared in the source file. Each element of the `fields` array is a dictionary with the following fields: -* `name`: the name of the field -* `type`: the numeric id of the type held in this field + +- `name`: the name of the field +- `type`: the numeric id of the type held in this field #### Enums As with structs, this format assumes that all enumeration types are user defined. The descriptor for an enum contains the following fields: -* `declaration`: A dictionary describing the definition site of the enum, see elow. -* `name`: the name of the enum, without the `enum` keyword and without any contract qualifiers. -* `members`: A list of members of the enum, as strings. + +- `declaration`: A dictionary describing the definition site of the enum, see elow. +- `name`: the name of the enum, without the `enum` keyword and without any contract qualifiers. +- `members`: A list of members of the enum, as strings. The order of elements within `members` is significant, and should match the order that members of the enum are declared in the source file. @@ -175,8 +184,9 @@ The order of elements within `members` is significant, and should match the orde The contract type refers to a primitive value that is known/expected to be an address of a contract deployed on the blockchain which implements the given type. It contains the following field: -* `contractDeclaration`: The AST id of the declaration of the contract type. -* `name`: A string holding the (fully qualified) name of the contract type. + +- `contractDeclaration`: The AST id of the declaration of the contract type. +- `name`: A string holding the (fully qualified) name of the contract type. **Discussion** It is unclear to me whether this should actually be separate from primitives. I lean towards no, but it is presented this way to prompt discussion. Note that this format assumes that the declaration of the contract type is "visible" to the compiler @@ -186,9 +196,10 @@ during compilation and thus the declaration site is available for reference. As with enums and structs, this format assumes that all aliases are user defined, but this restriction could be relaxed by making the `definitionScope` field optional. An alias type descriptor has the following additional fields: -* `aliasName`: The user provided name of the alias type, without qualifiers. -* `definitionScope`: A dictionary describing the site of the definition, see below -* `aliasedType`: The numeric id of the type for which this is an alias. + +- `aliasName`: The user provided name of the alias type, without qualifiers. +- `definitionScope`: A dictionary describing the site of the definition, see below +- `aliasedType`: The numeric id of the type for which this is an alias. **Discussion**: This could be extended with information such as "is this alias opaque" a la private types in OCaml. @@ -196,8 +207,9 @@ An alias type descriptor has the following additional fields: A "located" type is simply a type that is additionally qualified with a data location, that is, a refinement on some other type to restrict its location. A located type has the following fields defined: -* `location`: A string describing EVM data locations. Possible values are `"memory"`, `"storage"`, `"calldata"`, `"returndata"`, `"code"`. -* `type`: The numeric ID of the type with this location. + +- `location`: A string describing EVM data locations. Possible values are `"memory"`, `"storage"`, `"calldata"`, `"returndata"`, `"code"`. +- `type`: The numeric ID of the type with this location. It is expected that the type referenced in `type` is not itself a located type, as this would indicate a type like `uint[] calldata memory` which is not valid and is never expected to be. @@ -211,19 +223,21 @@ shape of the struct, and the different data locations of that struct are handled To provide information about where a user defined type was declared, the descriptors for those type include a `definitionScope` field. This field is a dictionary with the following fields: -* `definitionScope`: A dictionary describing where the type is defined. It has at least the following fields - * `sort`: a string, either `"file"` indicating a top-level declaration or `"contract"` indicating a type defined within a contract -* `name`: The string representation of the type name. For struct types this is the name of the struct, and does *not* include the `struct` keyword, and similarly for enums. +- `definitionScope`: A dictionary describing where the type is defined. It has at least the following fields + - `sort`: a string, either `"file"` indicating a top-level declaration or `"contract"` indicating a type defined within a contract +- `name`: The string representation of the type name. For struct types this is the name of the struct, and does _not_ include the `struct` keyword, and similarly for enums. The `definitionScope` dictionary has additional fields depending on the value of `sort`. If it is `"contract"` then it has the following field: -* `definingContract`: A dictionary with the following fields: - * `name`: the source name of the defining contract - * `astId`: the numeric AST id of the declaration which holds this definition + +- `definingContract`: A dictionary with the following fields: + - `name`: the source name of the defining contract + - `astId`: the numeric AST id of the declaration which holds this definition If the field is `"file"`, then it instead has: -* `definingFile`: A dictionary with the following fields: - * `name`: The path to the file (John: Fully resolved path? The path as understood by the compiler?) + +- `definingFile`: A dictionary with the following fields: + - `name`: The path to the file (John: Fully resolved path? The path as understood by the compiler?) It is expected that the combination of `definitionScope` and `name` is unique within the `types` array (otherwise we would have multiple declarations in the same scope). @@ -239,21 +253,22 @@ required that every opcode in the bytecode has a corresponding entry in the debu are encouraged, however, to have as much coverage as possible. Each entry in the debug information dictionary is itself a dictionary that (optionally) includes some of the following: -* The source location(s) that "correspond" to the opcode -* The AST ID(s) that "correspond" to the opcode -* The layout of the stack, including type information and local variable names (if available) -* Jump target information (if available/applicable) -* Identification of mapping key information +- The source location(s) that "correspond" to the opcode +- The AST ID(s) that "correspond" to the opcode +- The layout of the stack, including type information and local variable names (if available) +- Jump target information (if available/applicable) +- Identification of mapping key information In the above "correspond" roughly means "what source code caused the generation of this opcode". Specifically the dictionary may have the following fields: -* `source`: a list of source location specifiers. The format of these source location specifiers should be decided later. Every element should provide the location of the textual source code -that contributed to the generation of this opcode. -* `ast`: A list of AST ids for the "closest" AST node that contributed to the generation of this opcode. -* `stack` A layout of the stack as understood by the compiler, represented as a list. -* `jumps`: If present, provides hints about the location being jumped to by a jumping command (JUMP or JUMPI) -* `mappings`: If present, contains information about how the opcode relates to mapping keys. + +- `source`: a list of source location specifiers. The format of these source location specifiers should be decided later. Every element should provide the location of the textual source code + that contributed to the generation of this opcode. +- `ast`: A list of AST ids for the "closest" AST node that contributed to the generation of this opcode. +- `stack` A layout of the stack as understood by the compiler, represented as a list. +- `jumps`: If present, provides hints about the location being jumped to by a jumping command (JUMP or JUMPI) +- `mappings`: If present, contains information about how the opcode relates to mapping keys. #### Source Locations @@ -270,10 +285,11 @@ The list contained in the `stack` field exposes this view; consumers can combine The list is ordered such that the first element provides information about the top of the stack, the second element is the next element below it, and so on. Each element is a dictionary with the following fields: -* `type`: The type of the value stored in this stack slot. This is *not* a reference to a type descriptor or an embedding of the type descriptor, see below. -* `sourceName`: A nullable string representation of the identifier held in this stack slot. A value of null indicates that the value does not come from any single identifier. -* `sourceId`: A nullable numerical AST id that holds the definition (John: declaration?) of the identifier held in this stack slot. A value of null indicates the value does not come from -any single identifier. + +- `type`: The type of the value stored in this stack slot. This is _not_ a reference to a type descriptor or an embedding of the type descriptor, see below. +- `sourceName`: A nullable string representation of the identifier held in this stack slot. A value of null indicates that the value does not come from any single identifier. +- `sourceId`: A nullable numerical AST id that holds the definition (John: declaration?) of the identifier held in this stack slot. A value of null indicates the value does not come from + any single identifier. Note that due to `dup` commands, multiple stack locations may hold the same variable name. If a compiler knows that a stack slot that holds a variable will be later overwritten with a new value, it should mark the to be overwritten value with the "junk" type (see below). @@ -281,38 +297,42 @@ a variable will be later overwritten with a new value, it should mark the to be The `type` dictionary provides information about the value stored in the stack slot. The types used here are a superset of the types described by type descriptors. The `type` dictionary has the following field: -* `sort`: A string indicating the sort of value stored in the stack slot, drawn from one of the following values: - * `"junk"` indicates a value that is dead or about to be popped. - * `"pc"` A refinement of the numeric type, indicating the slot holds a location which is a jump destination target - * `"program"` The stack slot holds a value with a "program" type, i.e., one that can be expressed using type descriptors. - * `"internal"` Indicates that the stack slot holds a value that is being used by the compiler but does not correspond to a user type. + +- `sort`: A string indicating the sort of value stored in the stack slot, drawn from one of the following values: + - `"junk"` indicates a value that is dead or about to be popped. + - `"pc"` A refinement of the numeric type, indicating the slot holds a location which is a jump destination target + - `"program"` The stack slot holds a value with a "program" type, i.e., one that can be expressed using type descriptors. + - `"internal"` Indicates that the stack slot holds a value that is being used by the compiler but does not correspond to a user type. The dictionaries for `pc` and `junk` sorts do not have any additional information. The `internal` type is to be used for, e.g., "scratch" pointers that are used to marshal calldata buffers or hash storage keys. Compilers may insert their own information into the `internal` dictionary but this format remains intentionally agnostic on these contents. (John: every time a standard has allowed a "vendor specific" extension, it goes badly. Maybe we want to just say, consumers shouldn't look at this field) If the `sort` is `"program"` then the dictionary has the following field: -* `typeId`: The numeric ID of the type held in this slot + +- `typeId`: The numeric ID of the type held in this slot Additionally, the compiler may insert a field to provide additional information about the representation on the stack. This field, if present, has the name `representation` and holds a dictionary. This dictionary has the following optional fields: -* `published`: A boolean field which, if present, indicates that this stack slot holds a pointer to some location in memory/storage. Further, if the field is true, then the object is "fully initialized" (the formal definition of -fully initialized is to be decided on later) -* `componentOf`: If the representation of a single value spans multiple stack slots, this field provides information about how the value is spread across the stack. It is a dictionary with the following fields: - * `id`: an ID unique within each stack list. All stack slots with the same value of `id` are considered to represent the same logical value. It is allowed to re-use the same ID in different entries of the `stack` list. - * `componentName`: The name of the component. The only known use case for this is the decomposition of calldata arrays, so there are two possible values `"ELEM_PTR"` and `"LENGTH"` indicating the stack slots hold the pointer to the calldata location of the array's elements or the logical length of the array respectively. + +- `published`: A boolean field which, if present, indicates that this stack slot holds a pointer to some location in memory/storage. Further, if the field is true, then the object is "fully initialized" (the formal definition of + fully initialized is to be decided on later) +- `componentOf`: If the representation of a single value spans multiple stack slots, this field provides information about how the value is spread across the stack. It is a dictionary with the following fields: + - `id`: an ID unique within each stack list. All stack slots with the same value of `id` are considered to represent the same logical value. It is allowed to re-use the same ID in different entries of the `stack` list. + - `componentName`: The name of the component. The only known use case for this is the decomposition of calldata arrays, so there are two possible values `"ELEM_PTR"` and `"LENGTH"` indicating the stack slots hold the pointer to the calldata location of the array's elements or the logical length of the array respectively. #### Jumps For jumping commands, the `jumps` field provides information about the expected target of the jump, and information about the internal function stack. The value of the `jumps` field is a dictionary with the following (potentially optional) fields: -* `targets`: if present, a list of known PCs to which this command may jump. For JUMPI, this does **not** include the fallthrough case, as this is readily computable. This list may be non-singleton due to, -e.g., function pointers, but the compiler is able to restrict the potential callees. -* `sort`: A string indicating the type of jump being performed. One of the following values: - * `"return"`: Used for a jump out of an internal function - * `"call"`: Used for a jump into an internal function - * `"normal"`: Used for all other jumps + +- `targets`: if present, a list of known PCs to which this command may jump. For JUMPI, this does **not** include the fallthrough case, as this is readily computable. This list may be non-singleton due to, + e.g., function pointers, but the compiler is able to restrict the potential callees. +- `sort`: A string indicating the type of jump being performed. One of the following values: + - `"return"`: Used for a jump out of an internal function + - `"call"`: Used for a jump into an internal function + - `"normal"`: Used for all other jumps **Discussion**: It may be useful to ask compilers to provide richer information about some jumps. For example, tagging a loop exit as a "break" or a backjump as a "continue". This may be redundant given sufficiently reliable source information however. @@ -320,22 +340,25 @@ reliable source information however. As elsewhere, the dictionary may contain additional fields depending on the value in `sort`. If the value is `"call"`, then the dictionary contains the following fields: -* `arguments`: A list describing the calling convention. As in the `stack` layout, the first element of this list describes the value on the top of the stack (**after** popping the jump destination). Each element is a - dictionary described below. + +- `arguments`: A list describing the calling convention. As in the `stack` layout, the first element of this list describes the value on the top of the stack (**after** popping the jump destination). Each element is a + dictionary described below. If the callee of the call is known, then the dictionary with sort `"call"` has the following field: -* `callee`: a dictionary with the following fields: - * `target`: a human readable string name for the function being called - * `astId`: the AST id of the declaration site of the callee + +- `callee`: a dictionary with the following fields: + - `target`: a human readable string name for the function being called + - `astId`: the AST id of the declaration site of the callee Note that if the function being called is `virtual` then the declaration site may not have any corresponding body. Each element of the `arguments` array is a dictionary with the following fields: -* `sort`: `"program"` or `"return_address"`. `"program"` has the same interpretation as in the `type` dictionary above. `"return_address"` is a refinement of the `pc` type indicating this stack slot holds -the return address of the call being performed. -* `position`: The logical position of the **parameter** represented by this stack value. The ordering of parameters is defined by their program declaration order, where the first formal parameter to a function has position `0`, -the next `1`, etc. As with the stack, a single logical argument can be spread across multiple stack slots. If multiple entries share the same `position` value, then those arguments -should have a `representation` field that has a `componentOf` entry. + +- `sort`: `"program"` or `"return_address"`. `"program"` has the same interpretation as in the `type` dictionary above. `"return_address"` is a refinement of the `pc` type indicating this stack slot holds + the return address of the call being performed. +- `position`: The logical position of the **parameter** represented by this stack value. The ordering of parameters is defined by their program declaration order, where the first formal parameter to a function has position `0`, + the next `1`, etc. As with the stack, a single logical argument can be spread across multiple stack slots. If multiple entries share the same `position` value, then those arguments + should have a `representation` field that has a `componentOf` entry. **Note** Due to named arguments, the order given in the debug information may not match the order of parameters as they appear at a call-site. For example, given a declaration: @@ -353,13 +376,15 @@ myFunction(b = 3, a = 4) the stack location which contains the `4` argument value will be tagged with position `0`, as that is the position of parameter `a` in the declaration. If the value of `sort` is `"return"`, then the dictionary has the following field: -* `returns`: A list of dictionaries with the same format as the `arguments` array of `call`, but without any `return_address` entries. + +- `returns`: A list of dictionaries with the same format as the `arguments` array of `call`, but without any `return_address` entries. **Discussion**: The above proposal doesn't really handle the case of "tail-calls" identified at the beginning of this document, where multiple return addresses can be pushed onto the stack. Is that something the debug format must explicitly model? #### Mapping key identification The value of this field (when present) is a dictionary with (some of) the following fields: -* `isMappingHash`: A boolean that identifies whether the opcode is computing a hash for a mapping. -* `isMappingPreHash`: For mappings that use two hashes, this boolean can identify whether the opcode is computing the first of the two hashes. Possibly this field should be combined with a previous one into some sort of enum? -* `mappingHashFormat`: An enumeration; specifies the format of what gets hashed for the mapping. Formats could include "prefix" (for Solidity), "postfix" (for Vyper value types), and "postfix-prehashed" (for Vyper strings and bytestrings). Possibly "prefix" could be split further into "prefix-padded" (for Solidity value types) and "prefix-unpadded" (for Solidity strings and bytestrings). This could be expanded in the future if necessary. (Also, potentially `"prefix-padded"`, if split out, could be broken down even further, by padding type -- zero padding (left) vs sign-padding vs zero-padding (right)...) + +- `isMappingHash`: A boolean that identifies whether the opcode is computing a hash for a mapping. +- `isMappingPreHash`: For mappings that use two hashes, this boolean can identify whether the opcode is computing the first of the two hashes. Possibly this field should be combined with a previous one into some sort of enum? +- `mappingHashFormat`: An enumeration; specifies the format of what gets hashed for the mapping. Formats could include "prefix" (for Solidity), "postfix" (for Vyper value types), and "postfix-prehashed" (for Vyper strings and bytestrings). Possibly "prefix" could be split further into "prefix-padded" (for Solidity value types) and "prefix-unpadded" (for Solidity strings and bytestrings). This could be expanded in the future if necessary. (Also, potentially `"prefix-padded"`, if split out, could be broken down even further, by padding type -- zero padding (left) vs sign-padding vs zero-padding (right)...) diff --git a/packages/web/docusaurus.config.ts b/packages/web/docusaurus.config.ts index 89f88a223..30cc36ebf 100644 --- a/packages/web/docusaurus.config.ts +++ b/packages/web/docusaurus.config.ts @@ -1,18 +1,18 @@ -import {themes as prismThemes} from 'prism-react-renderer'; +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 { Config } from "@docusaurus/types"; +import type * as Preset from "@docusaurus/preset-classic"; import type { Configuration } from "webpack"; const baseUrl = process.env["BASE_URL"] || "/"; const config: Config = { - title: 'ethdebug format', - tagline: 'Debugging data format for smart contracts', - favicon: 'img/favicon.ico', + title: "ethdebug format", + tagline: "Debugging data format for smart contracts", + favicon: "img/favicon.ico", // Set the production url of your site here - url: 'https://ethdebug.github.io', + url: "https://ethdebug.github.io", // Set the // pathname under which your site is served // For GitHub pages deployment, it is often '//' @@ -20,23 +20,23 @@ const config: Config = { // GitHub pages deployment config. // If you aren't using GitHub pages, you don't need these. - organizationName: 'ethdebug', // Usually your GitHub org/user name. - projectName: 'format', // Usually your repo name. + organizationName: "ethdebug", // Usually your GitHub org/user name. + projectName: "format", // Usually your repo name. - onBrokenLinks: 'throw', - onBrokenMarkdownLinks: 'warn', + onBrokenLinks: "throw", + onBrokenMarkdownLinks: "warn", // Even if you don't use internationalization, you can use this field to set // useful metadata like html lang. For example, if your site is Chinese, you // may want to replace "en" with "zh-Hans". i18n: { - defaultLocale: 'en', - locales: ['en'], + defaultLocale: "en", + locales: ["en"], }, themes: [ ["docusaurus-json-schema-plugin", {}], - "@saucelabs/theme-github-codeblock" + "@saucelabs/theme-github-codeblock", ], plugins: [ @@ -47,16 +47,16 @@ const config: Config = { return { resolve: { alias: { - react: path.resolve('../../node_modules/react'), + react: path.resolve("../../node_modules/react"), }, fallback: { buffer: false, - util: false - } - } + util: false, + }, + }, }; - } - } + }, + }; }, [ @@ -64,27 +64,30 @@ const config: Config = { { packages: { "@ethdebug/format": { - tsConfigFilePath: - path.resolve(__dirname, "../format/tsconfig.json") + tsConfigFilePath: path.resolve( + __dirname, + "../format/tsconfig.json", + ), }, "@ethdebug/pointers": { - tsConfigFilePath: - path.resolve(__dirname, "../pointers/tsconfig.json") - } - } - } + tsConfigFilePath: path.resolve( + __dirname, + "../pointers/tsconfig.json", + ), + }, + }, + }, ], // Used to maintain separate spec/ directory, outside the core docs/ [ - '@docusaurus/plugin-content-docs', + "@docusaurus/plugin-content-docs", { - id: 'spec', - path: 'spec', - routeBasePath: 'spec', - sidebarPath: './sidebars.ts', - editUrl: - 'https://github.com/ethdebug/format/tree/main/packages/web' + id: "spec", + path: "spec", + routeBasePath: "spec", + sidebarPath: "./sidebars.ts", + editUrl: "https://github.com/ethdebug/format/tree/main/packages/web", // ... other options }, ], @@ -92,15 +95,14 @@ const config: Config = { presets: [ [ - 'classic', + "classic", { docs: { - sidebarPath: './sidebars.ts', - editUrl: - 'https://github.com/ethdebug/format/tree/main/packages/web', + sidebarPath: "./sidebars.ts", + editUrl: "https://github.com/ethdebug/format/tree/main/packages/web", }, theme: { - customCss: './src/css/custom.css', + customCss: "./src/css/custom.css", }, } satisfies Preset.Options, ], @@ -108,76 +110,76 @@ const config: Config = { themeConfig: { navbar: { - title: 'ethdebug format', + title: "ethdebug format", logo: { - alt: 'ethdebug logo', - src: 'img/logo.svg', + alt: "ethdebug logo", + src: "img/logo.svg", }, items: [ { - type: 'docSidebar', - sidebarId: 'docsSidebar', - position: 'left', - label: 'Documentation', + type: "docSidebar", + sidebarId: "docsSidebar", + position: "left", + label: "Documentation", }, { - to: '/spec/overview', - label: 'Specification', - position: 'left', + to: "/spec/overview", + label: "Specification", + position: "left", activeBaseRegex: `/spec/`, }, { - to: '/status', + to: "/status", label: "Status: Draft", className: "status-indicator", - position: "right" + position: "right", }, { - href: 'https://github.com/ethdebug/format', - label: 'GitHub', - position: 'right', + href: "https://github.com/ethdebug/format", + label: "GitHub", + position: "right", }, ], }, footer: { - style: 'dark', + style: "dark", links: [ { - title: 'Docs', + title: "Docs", items: [ { label: "Project overview", - to: "/docs/overview" + to: "/docs/overview", }, { - label: 'Known challenges', - to: '/docs/known-challenges', + label: "Known challenges", + to: "/docs/known-challenges", }, ], }, { - title: 'Spec', + title: "Spec", items: [ { label: "Specification overview", - to: "/spec/overview" + to: "/spec/overview", }, ], }, { - title: 'Community', + title: "Community", items: [ { - label: 'Matrix.chat', - href: 'https://matrix.to/#/#ethdebug:matrix.org', + label: "Matrix.chat", + href: "https://matrix.to/#/#ethdebug:matrix.org", }, { - label: 'Twitter', - href: 'https://twitter.com/ethdebug', + label: "Twitter", + href: "https://twitter.com/ethdebug", }, { - label: 'GitHub', - href: 'https://github.com/ethdebug/format', + label: "GitHub", + href: "https://github.com/ethdebug/format", }, ], }, @@ -187,9 +189,7 @@ const config: Config = { prism: { theme: prismThemes.github, darkTheme: prismThemes.dracula, - additionalLanguages: [ - "json" - ], + additionalLanguages: ["json"], }, } satisfies Preset.ThemeConfig, }; diff --git a/packages/web/plugins/project-code-plugin.ts b/packages/web/plugins/project-code-plugin.ts index 8bfbbc6a6..5a68e96ba 100644 --- a/packages/web/plugins/project-code-plugin.ts +++ b/packages/web/plugins/project-code-plugin.ts @@ -6,8 +6,8 @@ export interface PluginOptions { packages: { [packageName: string]: { tsConfigFilePath: string; - } - } + }; + }; } export type LoadedContent = { @@ -15,15 +15,15 @@ export type LoadedContent = { [packageName: string]: { sourceFiles: { filePath: string; - text: string + text: string; }[]; - } - } + }; + }; }; export default function projectCodePlugin( context: LoadContext, - options: PluginOptions + options: PluginOptions, ): Plugin { const { packages } = options; @@ -32,29 +32,27 @@ export default function projectCodePlugin( async loadContent() { const content: LoadedContent = { - packages: {} + packages: {}, }; for (const [packageName, packageConfig] of Object.entries(packages)) { const { tsConfigFilePath } = packageConfig; const project = new Project({ - tsConfigFilePath + tsConfigFilePath, }); - const sourceFiles = project.getSourceFiles() - .map(sourceFile => ({ - filePath: - path.relative( - path.dirname(tsConfigFilePath), - sourceFile.getFilePath() - ), + const sourceFiles = project.getSourceFiles().map((sourceFile) => ({ + filePath: path.relative( + path.dirname(tsConfigFilePath), + sourceFile.getFilePath(), + ), - text: sourceFile.getText() - })); + text: sourceFile.getText(), + })); content.packages[packageName] = { - sourceFiles + sourceFiles, }; } @@ -65,6 +63,6 @@ export default function projectCodePlugin( const { setGlobalData } = actions; setGlobalData(content); - } + }, }; } diff --git a/packages/web/sidebars.ts b/packages/web/sidebars.ts index b20b04372..dc8323038 100644 --- a/packages/web/sidebars.ts +++ b/packages/web/sidebars.ts @@ -1,4 +1,4 @@ -import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; +import type { SidebarsConfig } from "@docusaurus/plugin-content-docs"; /** * Creating a sidebar enables you to: @@ -12,7 +12,7 @@ import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; */ const sidebars: SidebarsConfig = { // By default, Docusaurus generates a sidebar from the docs folder structure - docsSidebar: [{type: 'autogenerated', dirName: '.'}], + docsSidebar: [{ type: "autogenerated", dirName: "." }], // But you can create a sidebar manually /* diff --git a/packages/web/spec/data/hex.mdx b/packages/web/spec/data/hex.mdx index daaeb94ae..c9a46c527 100644 --- a/packages/web/spec/data/hex.mdx +++ b/packages/web/spec/data/hex.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Hexadecimal strings - + diff --git a/packages/web/spec/data/unsigned.mdx b/packages/web/spec/data/unsigned.mdx index f531c79e0..cd3d488c0 100644 --- a/packages/web/spec/data/unsigned.mdx +++ b/packages/web/spec/data/unsigned.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Unsigned integers - + diff --git a/packages/web/spec/data/value.mdx b/packages/web/spec/data/value.mdx index b520f47c8..c2b3605f5 100644 --- a/packages/web/spec/data/value.mdx +++ b/packages/web/spec/data/value.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Non-negative numeric values - + diff --git a/packages/web/spec/info/info.mdx b/packages/web/spec/info/info.mdx index decf23edc..1d6f15ced 100644 --- a/packages/web/spec/info/info.mdx +++ b/packages/web/spec/info/info.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Schema - + diff --git a/packages/web/spec/info/overview.mdx b/packages/web/spec/info/overview.mdx index 33fadc09b..21eb287bd 100644 --- a/packages/web/spec/info/overview.mdx +++ b/packages/web/spec/info/overview.mdx @@ -13,6 +13,7 @@ import StatusBanner from "@site/src/components/StatusBanner"; for representing the debugging data pertaining to a particular compilation. These two schemas serve to address two distinct purposes: + 1. **ethdebug/format/info** provides a means for representing a complete, standalone, and language-agnostic representation of all necessary debugging data. Objects in this schema contain all information specified by diff --git a/packages/web/spec/info/resources.mdx b/packages/web/spec/info/resources.mdx index 37b4752a4..5335efbe3 100644 --- a/packages/web/spec/info/resources.mdx +++ b/packages/web/spec/info/resources.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Resources lookup schema - + diff --git a/packages/web/spec/materials/compilation.mdx b/packages/web/spec/materials/compilation.mdx index a597d03a0..6e6cb0e26 100644 --- a/packages/web/spec/materials/compilation.mdx +++ b/packages/web/spec/materials/compilation.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Compilation schema - + diff --git a/packages/web/spec/materials/id.mdx b/packages/web/spec/materials/id.mdx index 9a7afd5bb..873ac3dee 100644 --- a/packages/web/spec/materials/id.mdx +++ b/packages/web/spec/materials/id.mdx @@ -10,14 +10,10 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; This format defines a very loosely specified schema for external IDs. - + ## Reference schema This format defines a schema for referencing external resources by ID. - + diff --git a/packages/web/spec/materials/source-range.mdx b/packages/web/spec/materials/source-range.mdx index e7128d2b6..f7ebcc7d6 100644 --- a/packages/web/spec/materials/source-range.mdx +++ b/packages/web/spec/materials/source-range.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/materials/source.mdx b/packages/web/spec/materials/source.mdx index fcea7942e..c99971205 100644 --- a/packages/web/spec/materials/source.mdx +++ b/packages/web/spec/materials/source.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Source schema - + diff --git a/packages/web/spec/overview.mdx b/packages/web/spec/overview.mdx index fefbde891..e66b3e729 100644 --- a/packages/web/spec/overview.mdx +++ b/packages/web/spec/overview.mdx @@ -7,7 +7,6 @@ sidebar_position: 1 The **ethdebug format** is currently in the design phase and specification is only just beginning. - ## Contents This specification currently contains the following primary schemas: @@ -16,25 +15,24 @@ This specification currently contains the following primary schemas:
[**ethdebug/format/type**](/spec/type/overview)
-A schema for representing high-level data types such as arrays of integers, -payable addresses, etc. + A schema for representing high-level data types such as arrays of integers, + payable addresses, etc.
[**ethdebug/format/pointer**](/spec/pointer/overview)
-A schema for representing dynamic data address ranges in the EVM, particularly -to indicate where high-level variables are allocated in the machine state. + A schema for representing dynamic data address ranges in the EVM, particularly + to indicate where high-level variables are allocated in the machine state.
[**ethdebug/format/program**](/spec/program/overview)
-A schema for representing high-level semantics from the perspective of an -annotated compiled bytecode. + A schema for representing high-level semantics from the perspective of an + annotated compiled bytecode.
- In addition, this format defines namespaces containing schemas for common concerns: @@ -42,15 +40,15 @@ concerns:
[**ethdebug/format/data**](/spec/data/overview)
-A namespace of schemas containing definitions of commonly used data -representations, such as how to represent raw byte strings and unsigned -integers. + A namespace of schemas containing definitions of commonly used data + representations, such as how to represent raw byte strings and unsigned + integers.
[**ethdebug/format/materials**](/spec/materials/overview)
-A namespace of schemas for representing "external" resources, such as -compiler source inputs. + A namespace of schemas for representing "external" resources, such as compiler + source inputs.
diff --git a/packages/web/spec/pointer/collection/collection.mdx b/packages/web/spec/pointer/collection/collection.mdx index 87641040e..ebf6f3c8e 100644 --- a/packages/web/spec/pointer/collection/collection.mdx +++ b/packages/web/spec/pointer/collection/collection.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Collection schema - + diff --git a/packages/web/spec/pointer/collection/conditional.mdx b/packages/web/spec/pointer/collection/conditional.mdx index 279400ef6..28b29e355 100644 --- a/packages/web/spec/pointer/collection/conditional.mdx +++ b/packages/web/spec/pointer/collection/conditional.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/pointer/collection/group.mdx b/packages/web/spec/pointer/collection/group.mdx index 2fc8f3bd8..87c9c4311 100644 --- a/packages/web/spec/pointer/collection/group.mdx +++ b/packages/web/spec/pointer/collection/group.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/pointer/collection/list.mdx b/packages/web/spec/pointer/collection/list.mdx index 4757b6060..2179baaaa 100644 --- a/packages/web/spec/pointer/collection/list.mdx +++ b/packages/web/spec/pointer/collection/list.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/pointer/collection/reference.mdx b/packages/web/spec/pointer/collection/reference.mdx index d9bb24fd8..1a8f88cc2 100644 --- a/packages/web/spec/pointer/collection/reference.mdx +++ b/packages/web/spec/pointer/collection/reference.mdx @@ -11,4 +11,4 @@ the regions it produces via the `yields` property. +/> diff --git a/packages/web/spec/pointer/collection/scope.mdx b/packages/web/spec/pointer/collection/scope.mdx index 2a8c92c85..bb4a6fe0e 100644 --- a/packages/web/spec/pointer/collection/scope.mdx +++ b/packages/web/spec/pointer/collection/scope.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/pointer/collection/templates.mdx b/packages/web/spec/pointer/collection/templates.mdx index d77e6359c..7ad3731d5 100644 --- a/packages/web/spec/pointer/collection/templates.mdx +++ b/packages/web/spec/pointer/collection/templates.mdx @@ -14,4 +14,4 @@ instead of variables. +/> diff --git a/packages/web/spec/pointer/concepts.mdx b/packages/web/spec/pointer/concepts.mdx index 7f85e3de5..8e48f22fb 100644 --- a/packages/web/spec/pointer/concepts.mdx +++ b/packages/web/spec/pointer/concepts.mdx @@ -63,6 +63,7 @@ representation can describe the aggregation of other composed pointers. Consider the `struct` definition: + ```solidity struct Record { uint256 x; @@ -76,15 +77,18 @@ members. ```json { - "group": [{ - "location": "memory", - "offset": "0x40", - "length": 32 - }, { - "location": "memory", - "offset": "0x60", - "length": 32 - }] + "group": [ + { + "location": "memory", + "offset": "0x40", + "length": 32 + }, + { + "location": "memory", + "offset": "0x60", + "length": 32 + } + ] } ``` @@ -96,7 +100,6 @@ This schema includes several sub-schemas for different kinds of collections allocation of array types, etc.). The **ethdebug/format/pointer/collection** schema aggregates these. - ## Pointers allow describing a value as a complex **expression** The examples above all use literal values for `"offset"` and `"length"`, but @@ -141,17 +144,20 @@ known at some point in execution to be the value at the top of the stack. ```json { - "group": [{ - "name": "pointer-to-storage-slot", - "location": "stack", - "slot": 0 - }, { - "name": "storage-slot", - "location": "storage", - "slot": { - "$read": "pointer-to-storage-slot" + "group": [ + { + "name": "pointer-to-storage-slot", + "location": "stack", + "slot": 0 + }, + { + "name": "storage-slot", + "location": "storage", + "slot": { + "$read": "pointer-to-storage-slot" + } } - }] + ] } ``` @@ -170,25 +176,29 @@ and length. ```json { - "group": [{ - "name": "record-pointer", - "location": "stack", - "slot": 0 - }, { - "name": "record-x", - "location": "memory", - "offset": { - "$read": "record-pointer" + "group": [ + { + "name": "record-pointer", + "location": "stack", + "slot": 0 }, - "length": 32 - }, { - "name": "record-y", - "location": "memory", - "offset": { - "$sum": [{ ".offset": "record-x" }, { ".length": "record-x" }] + { + "name": "record-x", + "location": "memory", + "offset": { + "$read": "record-pointer" + }, + "length": 32 }, - "length": 32 - }] + { + "name": "record-y", + "location": "memory", + "offset": { + "$sum": [{ ".offset": "record-x" }, { ".length": "record-x" }] + }, + "length": 32 + } + ] } ``` diff --git a/packages/web/spec/pointer/expression.mdx b/packages/web/spec/pointer/expression.mdx index 29a010b8e..86f5d2d6e 100644 --- a/packages/web/spec/pointer/expression.mdx +++ b/packages/web/spec/pointer/expression.mdx @@ -9,9 +9,7 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; Pointer expressions operate on the domain of bytes representing unsigned integers. - + ## Literal values @@ -31,7 +29,7 @@ assumed to be left-padded to the bytes width appropriate for the context. +/> ## Variables @@ -44,7 +42,7 @@ For an example where scalar variables may appear, see the +/> ## Arithmetic operations @@ -54,7 +52,7 @@ denotes an arithmetic operation. +/> ## Lookup region definition @@ -65,7 +63,7 @@ same value as the expression specified for that corresponding property. +/> ## Reading from the EVM @@ -79,7 +77,7 @@ region. +/> ## Keccak256 hashes @@ -90,7 +88,7 @@ hash of the concatenation of bytes specified by the list. +/> ## Bytes concatenation @@ -105,7 +103,7 @@ constructing storage slot keys or preparing data for hashing. +/> ## Resize operations @@ -117,7 +115,7 @@ particular sub-expression. +/> ## Region references @@ -135,4 +133,4 @@ other. (Don't make this harder than it has to be.) +/> diff --git a/packages/web/spec/pointer/overview.mdx b/packages/web/spec/pointer/overview.mdx index 8b18e7825..1ea37fd93 100644 --- a/packages/web/spec/pointer/overview.mdx +++ b/packages/web/spec/pointer/overview.mdx @@ -27,7 +27,6 @@ expressiveness required for describing these allocation techniques at compile-time. To readers continuing on, a [warning](https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule) may apply. - ::: This format defines a schema for locating semantically-cohesive bytes ranges @@ -46,7 +45,7 @@ regions. ## Reading this schema The **ethdebug/format/pointer** schema is a root schema that composes other -related schemas in the ethdebug/format/pointer/* namespace. +related schemas in the ethdebug/format/pointer/\* namespace. These schemas (like all schemas in this format) are specified as [JSON Schema](https://json-schema.org), draft 2020-12. diff --git a/packages/web/spec/pointer/pointer.mdx b/packages/web/spec/pointer/pointer.mdx index d1adff1d2..2d51669a0 100644 --- a/packages/web/spec/pointer/pointer.mdx +++ b/packages/web/spec/pointer/pointer.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Schema - + diff --git a/packages/web/spec/pointer/region/base.mdx b/packages/web/spec/pointer/region/base.mdx index dc7d31e7d..ea3898e39 100644 --- a/packages/web/spec/pointer/region/base.mdx +++ b/packages/web/spec/pointer/region/base.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Base region schema - + diff --git a/packages/web/spec/pointer/region/location/calldata.mdx b/packages/web/spec/pointer/region/location/calldata.mdx index d764d1d03..834613d81 100644 --- a/packages/web/spec/pointer/region/location/calldata.mdx +++ b/packages/web/spec/pointer/region/location/calldata.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/pointer/region/location/code.mdx b/packages/web/spec/pointer/region/location/code.mdx index 2c4be0588..161af1e23 100644 --- a/packages/web/spec/pointer/region/location/code.mdx +++ b/packages/web/spec/pointer/region/location/code.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `code` - + diff --git a/packages/web/spec/pointer/region/location/memory.mdx b/packages/web/spec/pointer/region/location/memory.mdx index feb2778d7..b33f78551 100644 --- a/packages/web/spec/pointer/region/location/memory.mdx +++ b/packages/web/spec/pointer/region/location/memory.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `memory` - + diff --git a/packages/web/spec/pointer/region/location/returndata.mdx b/packages/web/spec/pointer/region/location/returndata.mdx index e76586bf6..c3272b254 100644 --- a/packages/web/spec/pointer/region/location/returndata.mdx +++ b/packages/web/spec/pointer/region/location/returndata.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/pointer/region/location/stack.mdx b/packages/web/spec/pointer/region/location/stack.mdx index 7164d0fb2..6945bed5b 100644 --- a/packages/web/spec/pointer/region/location/stack.mdx +++ b/packages/web/spec/pointer/region/location/stack.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `stack` - + diff --git a/packages/web/spec/pointer/region/location/storage.mdx b/packages/web/spec/pointer/region/location/storage.mdx index 63e9e22ac..830432564 100644 --- a/packages/web/spec/pointer/region/location/storage.mdx +++ b/packages/web/spec/pointer/region/location/storage.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/pointer/region/location/transient.mdx b/packages/web/spec/pointer/region/location/transient.mdx index a93109d3f..56054b469 100644 --- a/packages/web/spec/pointer/region/location/transient.mdx +++ b/packages/web/spec/pointer/region/location/transient.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/pointer/region/region.mdx b/packages/web/spec/pointer/region/region.mdx index 916dcb9f7..c7c9d52a9 100644 --- a/packages/web/spec/pointer/region/region.mdx +++ b/packages/web/spec/pointer/region/region.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Region schema - + diff --git a/packages/web/spec/pointer/region/scheme/segment.mdx b/packages/web/spec/pointer/region/scheme/segment.mdx index 8452429ee..dae6e6c08 100644 --- a/packages/web/spec/pointer/region/scheme/segment.mdx +++ b/packages/web/spec/pointer/region/scheme/segment.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/pointer/region/scheme/slice.mdx b/packages/web/spec/pointer/region/scheme/slice.mdx index 5d9e05c2a..5bc957d9b 100644 --- a/packages/web/spec/pointer/region/scheme/slice.mdx +++ b/packages/web/spec/pointer/region/scheme/slice.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `slice` - + diff --git a/packages/web/spec/pointer/template.mdx b/packages/web/spec/pointer/template.mdx index 6f7109e9b..368642a55 100644 --- a/packages/web/spec/pointer/template.mdx +++ b/packages/web/spec/pointer/template.mdx @@ -13,6 +13,6 @@ variables. +/> diff --git a/packages/web/spec/program/concepts.mdx b/packages/web/spec/program/concepts.mdx index 928f02f51..892d88bf4 100644 --- a/packages/web/spec/program/concepts.mdx +++ b/packages/web/spec/program/concepts.mdx @@ -39,9 +39,9 @@ Instructions represent these details using the - Source code ranges associated with the instruction (i.e., "source mappings") - Variables known to be in scope following the instruction and where to - find those variable's values in the machine state + find those variable's values in the machine state - Control flow information such as an instruction being associated with the - process of calling from one function to another + process of calling from one function to another This information serves as a compile-time guarantee about the high-level state of the world that exists following each instruction. diff --git a/packages/web/spec/program/context/code.mdx b/packages/web/spec/program/context/code.mdx index 8231b5a46..afd07907f 100644 --- a/packages/web/spec/program/context/code.mdx +++ b/packages/web/spec/program/context/code.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Code contexts - + diff --git a/packages/web/spec/program/context/context.mdx b/packages/web/spec/program/context/context.mdx index 05ee98d75..6d960c3e6 100644 --- a/packages/web/spec/program/context/context.mdx +++ b/packages/web/spec/program/context/context.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Schema - + diff --git a/packages/web/spec/program/context/frame.mdx b/packages/web/spec/program/context/frame.mdx index 18bef1e67..572daa3b7 100644 --- a/packages/web/spec/program/context/frame.mdx +++ b/packages/web/spec/program/context/frame.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Frame contexts - + diff --git a/packages/web/spec/program/context/gather.mdx b/packages/web/spec/program/context/gather.mdx index fcb4f9aac..eb9cc3613 100644 --- a/packages/web/spec/program/context/gather.mdx +++ b/packages/web/spec/program/context/gather.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/program/context/pick.mdx b/packages/web/spec/program/context/pick.mdx index 0383684ba..18c0fbb8f 100644 --- a/packages/web/spec/program/context/pick.mdx +++ b/packages/web/spec/program/context/pick.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Pick one of several contexts - + diff --git a/packages/web/spec/program/context/remark.mdx b/packages/web/spec/program/context/remark.mdx index 7658c363e..932fadb49 100644 --- a/packages/web/spec/program/context/remark.mdx +++ b/packages/web/spec/program/context/remark.mdx @@ -12,4 +12,4 @@ for compilers to use. +/> diff --git a/packages/web/spec/program/context/variables.mdx b/packages/web/spec/program/context/variables.mdx index 88e2b5524..a4b7825bb 100644 --- a/packages/web/spec/program/context/variables.mdx +++ b/packages/web/spec/program/context/variables.mdx @@ -8,4 +8,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/program/example.mdx b/packages/web/spec/program/example.mdx index b3c17892f..021a17257 100644 --- a/packages/web/spec/program/example.mdx +++ b/packages/web/spec/program/example.mdx @@ -2,7 +2,13 @@ sidebar_position: 3 --- -import { ProgramExampleContextProvider, useProgramExampleContext, SourceContents, Opcodes, Viewer } from "@theme/ProgramExample"; +import { + ProgramExampleContextProvider, + useProgramExampleContext, + SourceContents, + Opcodes, + Viewer, +} from "@theme/ProgramExample"; # Example program @@ -16,109 +22,109 @@ import { ProgramExampleContextProvider, useProgramExampleContext, SourceContents // define storage layout to include variable // at slot 0 storage { - [0] storedValue: uint256; +[0] storedValue: uint256; } // runtime logic code { - // require fee for incrementing - if (msg.callvalue < 3 finney) { - return; - } +// require fee for incrementing +if (msg.callvalue < 3 finney) { +return; +} - let localValue = storedValue + 1; - storedValue = localValue; - return; +let localValue = storedValue + 1; +storedValue = localValue; +return; } `}]} - instructions={[ - { - operation: { - mnemonic: "PUSH6", - arguments: ["0x02ba7def3000"], - }, - context: ({ findSourceRange }) => ({ - code: findSourceRange("3 finney"), - variables: [{ - identifier: "storedValue", - type: { - kind: "uint", - bits: 256 - }, - pointer: { - location: "storage", - slot: 0 - }, - declaration: findSourceRange("[0] storedValue: uint256") - }], - remark: "hexadecimal for 3 finney" - }) - }, - { - operation: { - mnemonic: "CALLVALUE" - }, - context: ({ findSourceRange }) => ({ - code: findSourceRange("msg.callvalue"), - variables: [{ - identifier: "storedValue", - type: { - kind: "uint", - bits: 256 - }, - pointer: { - location: "storage", - slot: 0 - }, - declaration: findSourceRange("[0] storedValue: uint256") - }], - }) - }, - { - operation: { - mnemonic: "LT" - }, - context: ({ findSourceRange }) => ({ - code: findSourceRange("msg.callvalue < 3 finney"), - variables: [{ - identifier: "storedValue", - type: { - kind: "uint", - bits: 256 - }, - pointer: { - location: "storage", - slot: 0 - }, - declaration: findSourceRange("[0] storedValue: uint256") - }], - }) - }, - { - operation: { - mnemonic: "PUSH1", - arguments: ["0x13"] - }, - context: ({ findSourceRange }) => ({ - code: findSourceRange("if (msg.callvalue < 3 finney) {\n return;\n }"), - variables: [{ - identifier: "storedValue", - type: { - kind: "uint", - bits: 256 - }, - pointer: { - location: "storage", - slot: 0 - }, - declaration: findSourceRange("[0] storedValue: uint256") - }], - }) - }, - { - operation: { - mnemonic: "JUMPI" - }, +instructions={[ +{ +operation: { +mnemonic: "PUSH6", +arguments: ["0x02ba7def3000"], +}, +context: ({ findSourceRange }) => ({ +code: findSourceRange("3 finney"), +variables: [{ +identifier: "storedValue", +type: { +kind: "uint", +bits: 256 +}, +pointer: { +location: "storage", +slot: 0 +}, +declaration: findSourceRange("[0] storedValue: uint256") +}], +remark: "hexadecimal for 3 finney" +}) +}, +{ +operation: { +mnemonic: "CALLVALUE" +}, +context: ({ findSourceRange }) => ({ +code: findSourceRange("msg.callvalue"), +variables: [{ +identifier: "storedValue", +type: { +kind: "uint", +bits: 256 +}, +pointer: { +location: "storage", +slot: 0 +}, +declaration: findSourceRange("[0] storedValue: uint256") +}], +}) +}, +{ +operation: { +mnemonic: "LT" +}, +context: ({ findSourceRange }) => ({ +code: findSourceRange("msg.callvalue < 3 finney"), +variables: [{ +identifier: "storedValue", +type: { +kind: "uint", +bits: 256 +}, +pointer: { +location: "storage", +slot: 0 +}, +declaration: findSourceRange("[0] storedValue: uint256") +}], +}) +}, +{ +operation: { +mnemonic: "PUSH1", +arguments: ["0x13"] +}, +context: ({ findSourceRange }) => ({ +code: findSourceRange("if (msg.callvalue < 3 finney) {\n return;\n }"), +variables: [{ +identifier: "storedValue", +type: { +kind: "uint", +bits: 256 +}, +pointer: { +location: "storage", +slot: 0 +}, +declaration: findSourceRange("[0] storedValue: uint256") +}], +}) +}, +{ +operation: { +mnemonic: "JUMPI" +}, context: ({ findSourceRange }) => ({ code: findSourceRange("if (msg.callvalue < 3 finney) {\n return;\n }"), @@ -292,9 +298,10 @@ code { ] }) } - ]} -> +]} + +> This page helps illustrate the program schema's [key concepts](/spec/program/concepts) by offering a fictional diff --git a/packages/web/spec/program/instruction.mdx b/packages/web/spec/program/instruction.mdx index ac9a6b9d2..49fe195db 100644 --- a/packages/web/spec/program/instruction.mdx +++ b/packages/web/spec/program/instruction.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Instruction schema - + diff --git a/packages/web/spec/program/overview.mdx b/packages/web/spec/program/overview.mdx index d6365a7ad..0ce2501ff 100644 --- a/packages/web/spec/program/overview.mdx +++ b/packages/web/spec/program/overview.mdx @@ -25,13 +25,14 @@ back to high-level language concepts at any point during execution. Key information that programs contain for a particular instruction might include: + - the source range or source ranges that are "associated" with the - instruction + instruction - the collection of known high-level variables at that point in time, - including their types and where to find the bytes with those variables' - values + including their types and where to find the bytes with those variables' + values - signals to indicate that the instruction is part of some control flow - operation, such as calling some function from another. + operation, such as calling some function from another. These program records provide debuggers with a powerful reference resource to be consulted while observing a running EVM. At each step of EVM machine @@ -42,7 +43,7 @@ high-level world, step-by-step. ::: This format defines the primary **ethdebug/format/program** schema as well as -various sub-schemas in the ethdebug/format/program/* namespace. +various sub-schemas in the ethdebug/format/program/\* namespace. JSON values adhering to this schema contain comprehensive information about a particular EVM bytecode object. This includes contract metadata (e.g., reference to the source range where the contract is defined) and, importantly, an @@ -60,7 +61,7 @@ program state at any point during execution. ## Reading this schema The **ethdebug/format/program** schema is a root schema that composes other -related schemas in the ethdebug/format/program/* namespace. +related schemas in the ethdebug/format/program/\* namespace. These schemas (like all schemas in this format) are specified as [JSON Schema](https://json-schema.org), draft 2020-12. diff --git a/packages/web/spec/program/program.mdx b/packages/web/spec/program/program.mdx index 9be2c82d0..f5a6b514e 100644 --- a/packages/web/spec/program/program.mdx +++ b/packages/web/spec/program/program.mdx @@ -6,6 +6,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # Schema - + diff --git a/packages/web/spec/type/base.mdx b/packages/web/spec/type/base.mdx index 77a248401..0283a8376 100644 --- a/packages/web/spec/type/base.mdx +++ b/packages/web/spec/type/base.mdx @@ -3,7 +3,7 @@ sidebar_position: 6 --- import SchemaViewer from "@site/src/components/SchemaViewer"; -import TOCInline from '@theme/TOCInline'; +import TOCInline from "@theme/TOCInline"; import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import yaml from "yaml-template"; @@ -93,13 +93,11 @@ schema. +/> ## Full base schema - + ## Example schema extensions for particular types diff --git a/packages/web/spec/type/complex/alias.mdx b/packages/web/spec/type/complex/alias.mdx index b29fe6b6e..a944e7b95 100644 --- a/packages/web/spec/type/complex/alias.mdx +++ b/packages/web/spec/type/complex/alias.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `alias` - + diff --git a/packages/web/spec/type/complex/array.mdx b/packages/web/spec/type/complex/array.mdx index a99fe26b5..1839168b7 100644 --- a/packages/web/spec/type/complex/array.mdx +++ b/packages/web/spec/type/complex/array.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `array` - + diff --git a/packages/web/spec/type/complex/function.mdx b/packages/web/spec/type/complex/function.mdx index 366cbe5d2..4451f6842 100644 --- a/packages/web/spec/type/complex/function.mdx +++ b/packages/web/spec/type/complex/function.mdx @@ -7,14 +7,11 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `function` - - + ## Parameters schema +/> diff --git a/packages/web/spec/type/complex/mapping.mdx b/packages/web/spec/type/complex/mapping.mdx index 828cc3e9f..b65fe35b4 100644 --- a/packages/web/spec/type/complex/mapping.mdx +++ b/packages/web/spec/type/complex/mapping.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `mapping` - + diff --git a/packages/web/spec/type/complex/struct.mdx b/packages/web/spec/type/complex/struct.mdx index 54d437fb6..4f46cd30a 100644 --- a/packages/web/spec/type/complex/struct.mdx +++ b/packages/web/spec/type/complex/struct.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `struct` - + diff --git a/packages/web/spec/type/complex/tuple.mdx b/packages/web/spec/type/complex/tuple.mdx index 091f78c9c..11c3fdba2 100644 --- a/packages/web/spec/type/complex/tuple.mdx +++ b/packages/web/spec/type/complex/tuple.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `tuple` - + diff --git a/packages/web/spec/type/concepts.mdx b/packages/web/spec/type/concepts.mdx index 870cd6c3d..e87a516f4 100644 --- a/packages/web/spec/type/concepts.mdx +++ b/packages/web/spec/type/concepts.mdx @@ -14,11 +14,13 @@ 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 @@ -72,6 +74,7 @@ two ways (the optional `"class"` field, and the absence or existence of a 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 @@ -151,6 +154,7 @@ possibly includes other fields alongside `"type"`. } ``` + @@ -178,6 +182,7 @@ type representation or a reference to another type by ID. } } ``` +
@@ -193,25 +198,20 @@ type representation or a reference to another type by 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. - + ## Sometimes types are defined in code @@ -242,6 +242,4 @@ to a type expression. ### Type definition schema - + diff --git a/packages/web/spec/type/elementary/address.mdx b/packages/web/spec/type/elementary/address.mdx index c17010605..cceca35c9 100644 --- a/packages/web/spec/type/elementary/address.mdx +++ b/packages/web/spec/type/elementary/address.mdx @@ -9,4 +9,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/type/elementary/bool.mdx b/packages/web/spec/type/elementary/bool.mdx index dffc65f46..70d419dcb 100644 --- a/packages/web/spec/type/elementary/bool.mdx +++ b/packages/web/spec/type/elementary/bool.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `bool` - + diff --git a/packages/web/spec/type/elementary/bytes.mdx b/packages/web/spec/type/elementary/bytes.mdx index cd8768012..ef9f20aa0 100644 --- a/packages/web/spec/type/elementary/bytes.mdx +++ b/packages/web/spec/type/elementary/bytes.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `bytes` - + diff --git a/packages/web/spec/type/elementary/contract.mdx b/packages/web/spec/type/elementary/contract.mdx index 3db7926a1..7a8d0bafc 100644 --- a/packages/web/spec/type/elementary/contract.mdx +++ b/packages/web/spec/type/elementary/contract.mdx @@ -9,4 +9,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/type/elementary/enum.mdx b/packages/web/spec/type/elementary/enum.mdx index 6ee77496d..715e5d898 100644 --- a/packages/web/spec/type/elementary/enum.mdx +++ b/packages/web/spec/type/elementary/enum.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `enum` - + diff --git a/packages/web/spec/type/elementary/fixed.mdx b/packages/web/spec/type/elementary/fixed.mdx index 846329b7f..df82cfcc9 100644 --- a/packages/web/spec/type/elementary/fixed.mdx +++ b/packages/web/spec/type/elementary/fixed.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `fixed` - + diff --git a/packages/web/spec/type/elementary/int.mdx b/packages/web/spec/type/elementary/int.mdx index 4b64f6650..a70712cc9 100644 --- a/packages/web/spec/type/elementary/int.mdx +++ b/packages/web/spec/type/elementary/int.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `int` - + diff --git a/packages/web/spec/type/elementary/string.mdx b/packages/web/spec/type/elementary/string.mdx index c1eb679b4..a16a2b89a 100644 --- a/packages/web/spec/type/elementary/string.mdx +++ b/packages/web/spec/type/elementary/string.mdx @@ -9,4 +9,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/type/elementary/ufixed.mdx b/packages/web/spec/type/elementary/ufixed.mdx index 85845244e..3a033f528 100644 --- a/packages/web/spec/type/elementary/ufixed.mdx +++ b/packages/web/spec/type/elementary/ufixed.mdx @@ -9,4 +9,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; +/> diff --git a/packages/web/spec/type/elementary/uint.mdx b/packages/web/spec/type/elementary/uint.mdx index 4db8af597..b324b7d60 100644 --- a/packages/web/spec/type/elementary/uint.mdx +++ b/packages/web/spec/type/elementary/uint.mdx @@ -7,6 +7,4 @@ import SchemaViewer from "@site/src/components/SchemaViewer"; # `uint` - + diff --git a/packages/web/spec/type/overview.mdx b/packages/web/spec/type/overview.mdx index f737ea3b8..fba7f4a3c 100644 --- a/packages/web/spec/type/overview.mdx +++ b/packages/web/spec/type/overview.mdx @@ -46,7 +46,6 @@ See [additional examples](#example-valid-representations) below for a sample of valid type representations according to this schema. ::: - This format defines schemas for representing the data types allowable in a supporting high-level language. @@ -62,7 +61,7 @@ type, and so on. ## Reading this schema 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. +to one or more other related schemas in the ethdebug/format/type/\* namespace. These schemas (like all schemas in this format) are specified as [JSON Schema](https://json-schema.org), draft 2020-12. @@ -82,29 +81,23 @@ Please refer to one or more of the following resources in this section: - The [Base schema](/spec/type/base) defines the mimimum overall structure of **ethdebug/format/type** objects for purposes of schema extension. - ## Example valid representations Here are some example **ethdebug/format/type** type representations. -{ - [ + + {[ "ethdebug/format/type/elementary/address", "ethdebug/format/type/complex/mapping", - "ethdebug/format/type/complex/struct" + "ethdebug/format/type/complex/struct", ].map((id, index) => { const { schema } = describeSchema({ schema: `schema:${id}` }); - return - { - JSON.stringify(schema.examples[0], undefined, 2) - } - - }) -} + return ( + + + {JSON.stringify(schema.examples[0], undefined, 2)} + + + ); + })} + diff --git a/packages/web/spec/type/type.mdx b/packages/web/spec/type/type.mdx index 3f005accd..a7c71d28b 100644 --- a/packages/web/spec/type/type.mdx +++ b/packages/web/spec/type/type.mdx @@ -9,18 +9,12 @@ import { Collapsible, CreateTypes } from "@theme/JSONSchemaViewer/components"; ## Root schema - + ## Elementary type schema - + ## Complex type schema - + diff --git a/packages/web/src/components/CodeListing.tsx b/packages/web/src/components/CodeListing.tsx index 16ce7bf4a..d78baadca 100644 --- a/packages/web/src/components/CodeListing.tsx +++ b/packages/web/src/components/CodeListing.tsx @@ -4,17 +4,18 @@ import { Project, type SourceFile, type ts } from "ts-morph"; import useProjectCode from "@site/src/hooks/useProjectCode"; import LinkedCodeBlock from "./LinkedCodeBlock"; -export interface CodeListingProps - extends Omit -{ +export interface CodeListingProps extends Omit< + CodeBlockProps, + "language" | "children" +> { packageName: string; sourcePath: string; includePackageNameInTitle?: boolean; extract?: ( sourceFile: SourceFile, - project: Project + project: Project, ) => Pick; - links?: { [key: string]: string; }; + links?: { [key: string]: string }; } export default function CodeListing({ @@ -29,18 +30,20 @@ export default function CodeListing({ const sourceFile = project.getSourceFileOrThrow(sourcePath); - const node = !extract - ? sourceFile - : extract(sourceFile, project); + const node = !extract ? sourceFile : extract(sourceFile, project); const code = node.getFullText().trim(); // bit of a HACK const listingFullSource = !extract; - const title = includePackageNameInTitle - ? <>{packageName} {sourcePath} - : sourcePath; + const title = includePackageNameInTitle ? ( + <> + {packageName} {sourcePath} + + ) : ( + sourcePath + ); if (Object.keys(links).length > 0) { return ( @@ -58,15 +61,13 @@ export default function CodeListing({ { - node.getFullText().trim() - } + > + {node.getFullText().trim()} + ); } diff --git a/packages/web/src/components/LinkedCodeBlock.tsx b/packages/web/src/components/LinkedCodeBlock.tsx index 203e15357..41f7f5558 100644 --- a/packages/web/src/components/LinkedCodeBlock.tsx +++ b/packages/web/src/components/LinkedCodeBlock.tsx @@ -50,12 +50,12 @@ export default function LinkedCodeBlock({ const codeElement = codeRef.current.querySelector("pre > code"); if (codeElement) { const processedNodes = Array.from(codeElement.childNodes).flatMap( - (node) => processNode(node, links) + (node) => processNode(node, links), ); setProcessedCode(
               {processedNodes}
-            
+ , ); } } @@ -83,9 +83,7 @@ export default function LinkedCodeBlock({ return processedCode; } -type ProcessedNode = - | JSX.Element - | (JSX.Element | string)[]; +type ProcessedNode = JSX.Element | (JSX.Element | string)[]; // Recursively process a DOM node and its children function processNode(node: Node, links: Links): ProcessedNode { @@ -119,7 +117,7 @@ function processTextNode(node: Text, links: Links): ProcessedNode { className="linked-code-block-link" > {linkText} - + , ); lastIndex = index + linkText.length; index = text.indexOf(linkText, lastIndex); @@ -137,8 +135,20 @@ function processTextNode(node: Text, links: Links): ProcessedNode { let nodeKey: number = 0; // elements that do not allow closing tags const voidElements = new Set([ - "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", - "param", "source", "track", "wbr" + "area", + "base", + "br", + "col", + "embed", + "hr", + "img", + "input", + "link", + "meta", + "param", + "source", + "track", + "wbr", ]); function processElementNode(node: HTMLElement, links: Links): ProcessedNode { @@ -158,8 +168,9 @@ function processElementNode(node: HTMLElement, links: Links): ProcessedNode { return React.createElement(tagName, props); } - const children = Array.from(node.childNodes) - .flatMap((child) => processNode(child, links)); + const children = Array.from(node.childNodes).flatMap((child) => + processNode(child, links), + ); return React.createElement(tagName, props, children); } @@ -170,10 +181,9 @@ function convertStyleToObject(style: string): React.CSSProperties { if (declaration) { const [property, value] = declaration.split(":"); if (property && value) { - const camelCaseProperty = property.trim().replace( - /-./g, - (x) => x[1].toUpperCase() - ); + const camelCaseProperty = property + .trim() + .replace(/-./g, (x) => x[1].toUpperCase()); // HACK coerce object instead of key to avoid a giant keyof union (styleObject as any)[camelCaseProperty] = value.trim(); } diff --git a/packages/web/src/components/Playground.tsx b/packages/web/src/components/Playground.tsx index 1ac4bef48..a8af982af 100644 --- a/packages/web/src/components/Playground.tsx +++ b/packages/web/src/components/Playground.tsx @@ -108,7 +108,7 @@ export default function Playground(props: PlaygroundProps): JSX.Element { */ function showValidationErrors( errors: ValidationError[], - sourceMap: SourceMap + sourceMap: SourceMap, ) { const model = editorRef.current?.getModel(); if (!model || !monaco) return showError("Unable to validate schema"); diff --git a/packages/web/src/components/SchemaListing.tsx b/packages/web/src/components/SchemaListing.tsx index 6fa0aa63a..fb555cb28 100644 --- a/packages/web/src/components/SchemaListing.tsx +++ b/packages/web/src/components/SchemaListing.tsx @@ -1,34 +1,20 @@ -import { - type DescribeSchemaOptions, - describeSchema -} from "@ethdebug/format"; +import { type DescribeSchemaOptions, describeSchema } from "@ethdebug/format"; import CodeBlock from "@theme/CodeBlock"; import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; -export interface SchemaListingProps extends DescribeSchemaOptions { -} +export interface SchemaListingProps extends DescribeSchemaOptions {} export default function SchemaListing(props: SchemaListingProps): JSX.Element { - const { - id: qualifiedId, - pointer, - schema, - yaml - } = describeSchema(props); + const { id: qualifiedId, pointer, schema, yaml } = describeSchema(props); - const id = - qualifiedId - ? qualifiedId.startsWith("schema:") - ? qualifiedId.slice(7) - : qualifiedId - : undefined; + const id = qualifiedId + ? qualifiedId.startsWith("schema:") + ? qualifiedId.slice(7) + : qualifiedId + : undefined; - const reference = id && pointer - ? `${id}${pointer}` - : id - ? id - : undefined; + const reference = id && pointer ? `${id}${pointer}` : id ? id : undefined; return ( @@ -37,28 +23,20 @@ export default function SchemaListing(props: SchemaListingProps): JSX.Element { className="schema-listing" language="yaml" showLineNumbers - title={ - reference - ? reference - : "schema.yaml" - } - >{ - yaml - } + title={reference ? reference : "schema.yaml"} + > + {yaml} + { - JSON.stringify(schema, undefined, 2) - } + title={reference ? `${reference}` : "schema.json"} + > + {JSON.stringify(schema, undefined, 2)} + ); diff --git a/packages/web/src/components/SchemaViewer.tsx b/packages/web/src/components/SchemaViewer.tsx index 44f280422..dda624e8f 100644 --- a/packages/web/src/components/SchemaViewer.tsx +++ b/packages/web/src/components/SchemaViewer.tsx @@ -5,15 +5,10 @@ import JSONSchemaViewer from "@theme/JSONSchemaViewer"; import CodeBlock from "@theme/CodeBlock"; import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; +import { type DescribeSchemaOptions, describeSchema } from "@ethdebug/format"; +import { schemaIndex } from "@site/src/schemas"; import { - type DescribeSchemaOptions, - describeSchema, -} from "@ethdebug/format"; -import { - schemaIndex, -} from "@site/src/schemas"; -import { - SchemaContext , + SchemaContext, type PointerSchemaIds, internalIdKey, } from "@site/src/contexts/SchemaContext"; @@ -21,27 +16,23 @@ import ReactMarkdown from "react-markdown"; import SchemaListing from "./SchemaListing"; import Playground from "./Playground"; -export interface SchemaViewerProps extends DescribeSchemaOptions { -} +export interface SchemaViewerProps extends DescribeSchemaOptions {} export default function SchemaViewer(props: SchemaViewerProps): JSX.Element { const rootSchemaInfo = describeSchema(props); - const { - id, - rootSchema, - yaml, - pointer - } = rootSchemaInfo; + const { id, rootSchema, yaml, pointer } = rootSchemaInfo; const transformedSchema = transformSchema(rootSchema, id || ""); return ( - + { const id = uri.toString(); const { schema } = describeSchema({ - schema: { id } + schema: { id }, }); return transformSchema(schema, id); - } - } - } + }, + }, + }, }} viewerOptions={{ showExamples: true, ValueComponent: ({ value }: { value: unknown }) => { // deal with simple types first - if ([ - "string", - "number", - "bigint", - "boolean" - ].includes(typeof value)) { - return { - (value as string | number | bigint | boolean).toString() - }; + 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) - }`}; + return ( + {`${JSON.stringify( + value, + undefined, + 2, + )}`} + ); }, - DescriptionComponent: ({description}: { description: string }) => - - }} /> - + DescriptionComponent: ({ + description, + }: { + description: string; + }) => , + }} + /> + @@ -94,22 +94,23 @@ export default function SchemaViewer(props: SchemaViewerProps): JSX.Element { } function transformSchema(schema: JSONSchema, id: string): JSONSchema { - return insertIds(ensureRefsLackSiblings(schema), `${id}#`) + return insertIds(ensureRefsLackSiblings(schema), `${id}#`); } function insertIds(obj: T, rootId: string): T { if (Array.isArray(obj)) { return obj.map((item, index) => insertIds(item, `${rootId}/${index}`)) as T; - } else if (obj !== null && typeof obj === 'object') { - return Object.entries(obj).reduce((newObj, [key, value]) => { - // @ts-ignore - newObj[key] = insertIds(value, `${rootId}/${key}`); - return newObj; - }, { - [internalIdKey]: rootId.endsWith("#") - ? rootId.slice(0, -1) - : rootId - } as T); + } else if (obj !== null && typeof obj === "object") { + return Object.entries(obj).reduce( + (newObj, [key, value]) => { + // @ts-ignore + newObj[key] = insertIds(value, `${rootId}/${key}`); + return newObj; + }, + { + [internalIdKey]: rootId.endsWith("#") ? rootId.slice(0, -1) : rootId, + } as T, + ); } return obj; } @@ -147,29 +148,26 @@ function ensureRefsLackSiblings(obj: T): T { return obj; } - const { - $ref, - ...rest - } = obj as T & object & { $ref?: string }; + const { $ref, ...rest } = obj as T & object & { $ref?: string }; - const result = Object.entries(rest) - .reduce((newObj, [key, value]) => { - // @ts-ignore - newObj[key] = ensureRefsLackSiblings(value); - return newObj; - }, {} as T); + const result = Object.entries(rest).reduce((newObj, [key, value]) => { + // @ts-ignore + newObj[key] = ensureRefsLackSiblings(value); + return newObj; + }, {} as T); if (!$ref) { return result; } // find an unused schema composition keyword and move the $ref there - const propertyName = ["allOf", "oneOf", "anyOf"] - .find((candidate) => !(candidate in obj)); + const propertyName = ["allOf", "oneOf", "anyOf"].find( + (candidate) => !(candidate in obj), + ); if (!propertyName) { throw new Error( - `Could not find available composition keyword in ${JSON.stringify(obj)}` + `Could not find available composition keyword in ${JSON.stringify(obj)}`, ); } diff --git a/packages/web/src/components/StatusBadge.tsx b/packages/web/src/components/StatusBadge.tsx index 648319672..c2c248bd1 100644 --- a/packages/web/src/components/StatusBadge.tsx +++ b/packages/web/src/components/StatusBadge.tsx @@ -1,9 +1,6 @@ import React from "react"; import Link from "@docusaurus/Link"; -import { - statusLevels, - type StatusLevel, -} from "@site/src/status/status-config"; +import { statusLevels, type StatusLevel } from "@site/src/status/status-config"; import styles from "./StatusBadge.module.css"; export interface StatusBadgeProps { diff --git a/packages/web/src/components/StatusBanner.tsx b/packages/web/src/components/StatusBanner.tsx index b747938fe..01a04b0f6 100644 --- a/packages/web/src/components/StatusBanner.tsx +++ b/packages/web/src/components/StatusBanner.tsx @@ -1,9 +1,6 @@ import React from "react"; import Link from "@docusaurus/Link"; -import { - schemaStatus, - statusLevels, -} from "@site/src/status/status-config"; +import { schemaStatus, statusLevels } from "@site/src/status/status-config"; import StatusBadge from "./StatusBadge"; import styles from "./StatusBanner.module.css"; diff --git a/packages/web/src/components/StatusLevelExplainer.tsx b/packages/web/src/components/StatusLevelExplainer.tsx index 787de38e2..f38d9eba5 100644 --- a/packages/web/src/components/StatusLevelExplainer.tsx +++ b/packages/web/src/components/StatusLevelExplainer.tsx @@ -1,8 +1,5 @@ import React from "react"; -import { - statusLevels, - type StatusLevel, -} from "@site/src/status/status-config"; +import { statusLevels, type StatusLevel } from "@site/src/status/status-config"; import StatusBadge from "./StatusBadge"; import styles from "./StatusLevelExplainer.module.css"; diff --git a/packages/web/src/contexts/SchemaContext.tsx b/packages/web/src/contexts/SchemaContext.tsx index cb73369b9..f7bf935ff 100644 --- a/packages/web/src/contexts/SchemaContext.tsx +++ b/packages/web/src/contexts/SchemaContext.tsx @@ -6,12 +6,9 @@ import type { SchemaIndex } from "@site/src/schemas"; export type JSONSchemaWithInternalIdKeys = | boolean - | ( - & Exclude - & { - [internalIdKey]: string; - } - ); + | (Exclude & { + [internalIdKey]: string; + }); export interface SchemaContextValue { rootSchemaInfo?: SchemaInfo; @@ -19,7 +16,7 @@ export interface SchemaContextValue { } export type PointerSchemaIds = { - [jsonPointer: string]: string + [jsonPointer: string]: string; }; export const SchemaContext = createContext({ diff --git a/packages/web/src/hooks/useProjectCode.ts b/packages/web/src/hooks/useProjectCode.ts index 6a6147131..e8f4297d6 100644 --- a/packages/web/src/hooks/useProjectCode.ts +++ b/packages/web/src/hooks/useProjectCode.ts @@ -10,7 +10,7 @@ export default function useProjectCode(packageName: string): Project { const { sourceFiles } = packages[packageName]; const project = new Project({ - useInMemoryFileSystem: true + useInMemoryFileSystem: true, }); for (const { filePath, text } of sourceFiles) { project.createSourceFile(filePath, text, { overwrite: true }); diff --git a/packages/web/src/pages/home/index.tsx b/packages/web/src/pages/home/index.tsx index a3a96a7d1..6430b645d 100644 --- a/packages/web/src/pages/home/index.tsx +++ b/packages/web/src/pages/home/index.tsx @@ -1,19 +1,17 @@ -import clsx from 'clsx'; -import Link from '@docusaurus/Link'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import Layout from '@theme/Layout'; -import Heading from '@theme/Heading'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; // Import the FontAwesomeIcon component. +import clsx from "clsx"; +import Link from "@docusaurus/Link"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import Layout from "@theme/Layout"; +import Heading from "@theme/Heading"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; // Import the FontAwesomeIcon component. import IconExternalLink from "@theme/Icon/ExternalLink"; -import styles from './index.module.css'; +import styles from "./index.module.css"; export default function Home(): JSX.Element { - const {siteConfig} = useDocusaurusContext(); + const { siteConfig } = useDocusaurusContext(); return ( - +
@@ -23,9 +21,9 @@ export default function Home(): JSX.Element { } function HomepageHeader() { - const {siteConfig} = useDocusaurusContext(); + const { siteConfig } = useDocusaurusContext(); return ( -
+
{siteConfig.title} @@ -43,15 +41,16 @@ type FeatureItem = { const FeatureList: FeatureItem[] = [ { - title: 'Building a debugging standard', + title: "Building a debugging standard", description: ( <>

- The ethdebug format group seeks to design a - debugging data format - suitable for smart contract languages. + The ethdebug format group seeks to design a{" "} + + debugging data format + + {" "} + suitable for smart contract languages.

@@ -62,50 +61,56 @@ const FeatureList: FeatureItem[] = [ ), }, { - title: 'Current status', + title: "Current status", description: ( <>

The ethdebug format project is currently in design phase and seeking to onboard contributors with interest in this area. - Our most immediate goals are to establish a v1 formal schema and - to increase awareness of our efforts. + Our most immediate goals are to establish a v1 formal schema and to + increase awareness of our efforts.

- The Ethereum Foundation and the Solidity team are graciously - funding this effort with a keen interest in building a format that is + The Ethereum Foundation and the Solidity team are graciously funding + this effort with a keen interest in building a format that is compatible with current and future EVM languages.

), }, { - title: 'Get involved', + title: "Get involved", description: ( <>

- Join the - Matrix.chat - or watch the - GitHub repo - to follow along with our ongoing development. + Join the{" "} + + Matrix.chat + + {" "} + or watch the{" "} + + GitHub repo + + {" "} + to follow along with our ongoing development.

- Our group (including individuals and members of teams including Solidity - and Tenderly) meets every two weeks on Thursdays at 17:00 Berlin time. - Meetings are announced in our Matrix.chat, but please reach out if - you'd like a calendar invite. + Our group (including individuals and members of teams including + Solidity and Tenderly) meets every two weeks on Thursdays at 17:00 + Berlin time. Meetings are announced in our Matrix.chat, but please + reach out if you'd like a calendar invite.

), }, ]; -function Feature({title, description}: FeatureItem) { +function Feature({ title, description }: FeatureItem) { return ( -
+
{title} <>{description} diff --git a/packages/web/src/schemas.ts b/packages/web/src/schemas.ts index eedb1b33f..194cdf034 100644 --- a/packages/web/src/schemas.ts +++ b/packages/web/src/schemas.ts @@ -1,14 +1,14 @@ export type SchemaIndex = { [schemaId: `schema:${string}`]: { - href: string /* relative or external URL */; - title?: string; + href: string /* relative or external URL */; + title?: string; }; }; const typeSchemaIndex: SchemaIndex = { "schema:ethdebug/format/type/base": { title: "ethdebug/format/type/base schema", - href: "/spec/type/base" + href: "/spec/type/base", }, "schema:ethdebug/format/type/base#/$defs/TypeWrapper": { title: "Base type wrapper schema", @@ -20,219 +20,225 @@ const typeSchemaIndex: SchemaIndex = { }, "schema:ethdebug/format/type/reference": { title: "Type reference schema", - href: "/spec/type/concepts#type-reference-schema" + href: "/spec/type/concepts#type-reference-schema", }, "schema:ethdebug/format/type/definition": { title: "Type definition schema", - href: "/spec/type/concepts#type-definition-schema" + href: "/spec/type/concepts#type-definition-schema", }, "schema:ethdebug/format/type": { - href: "/spec/type" + href: "/spec/type", }, "schema:ethdebug/format/type/elementary": { - href: "/spec/type#elementary-type-schema" + 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 => ({ + 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}` - } + href: `/spec/type/elementary/${kind}`, + }, })) - .reduce((a, b) => ({ ...a, ...b }), {}) - ), - ...( - [ - "alias", "tuple", "array", "mapping", "struct", "function" - ].map(kind => ({ + .reduce((a, b) => ({ ...a, ...b }), {}), + ...["alias", "tuple", "array", "mapping", "struct", "function"] + .map((kind) => ({ [`schema:ethdebug/format/type/complex/${kind}`]: { - href: `/spec/type/complex/${kind}` - } + href: `/spec/type/complex/${kind}`, + }, })) - .reduce((a, b) => ({ ...a, ...b }), {}) - ), + .reduce((a, b) => ({ ...a, ...b }), {}), "schema:ethdebug/format/type/complex/function#/$defs/Parameters": { title: "Parameters schema", - href: "/spec/type/complex/function#parameters-schema" + href: "/spec/type/complex/function#parameters-schema", }, }; const pointerSchemaIndex: SchemaIndex = { "schema:ethdebug/format/pointer": { - href: "/spec/pointer" + href: "/spec/pointer", }, "schema:ethdebug/format/pointer/region": { - href: "/spec/pointer/region" + href: "/spec/pointer/region", }, "schema:ethdebug/format/pointer/region/base": { - href: "/spec/pointer/region/base" - }, - - ...( - [ - "stack", "memory", "storage", "calldata", "returndata", "transient", - "code" - ].map(location => ({ + href: "/spec/pointer/region/base", + }, + + ...[ + "stack", + "memory", + "storage", + "calldata", + "returndata", + "transient", + "code", + ] + .map((location) => ({ [`schema:ethdebug/format/pointer/region/${location}`]: { - href: `/spec/pointer/region/location/${location}` - } + href: `/spec/pointer/region/location/${location}`, + }, })) - .reduce((a, b) => ({ ...a, ...b }), {}) - ), + .reduce((a, b) => ({ ...a, ...b }), {}), - ...( - [ - "slice", "segment" - ].map(scheme => ({ + ...["slice", "segment"] + .map((scheme) => ({ [`schema:ethdebug/format/pointer/scheme/${scheme}`]: { - href: `/spec/pointer/region/scheme/${scheme}` - } + href: `/spec/pointer/region/scheme/${scheme}`, + }, })) - .reduce((a, b) => ({ ...a, ...b }), {}) - ), + .reduce((a, b) => ({ ...a, ...b }), {}), "schema:ethdebug/format/pointer/collection": { - href: "/spec/pointer/collection" + href: "/spec/pointer/collection", }, - ...( - [ - "group", "list", "conditional", "scope", "reference", "templates" - ].map(collection => ({ + ...["group", "list", "conditional", "scope", "reference", "templates"] + .map((collection) => ({ [`schema:ethdebug/format/pointer/collection/${collection}`]: { - href: `/spec/pointer/collection/${collection}` - } + href: `/spec/pointer/collection/${collection}`, + }, })) - .reduce((a, b) => ({ ...a, ...b }), {}) - ), + .reduce((a, b) => ({ ...a, ...b }), {}), "schema:ethdebug/format/pointer/expression": { - href: "/spec/pointer/expression" + href: "/spec/pointer/expression", }, "schema:ethdebug/format/pointer/template": { - href: "/spec/pointer/template" + href: "/spec/pointer/template", }, ...Object.entries({ Literal: { title: "Literal values schema", - anchor: "#literal-values" + anchor: "#literal-values", }, Variable: { title: "Variable expression schema", - anchor: "#variables" + anchor: "#variables", }, Arithmetic: { title: "Arithmetic operation expression schema", - anchor: "#arithmetic-operations" + anchor: "#arithmetic-operations", }, Lookup: { title: "Lookup expression schema", - anchor: "#lookup-region-definition" + anchor: "#lookup-region-definition", }, Read: { title: "Read expression schema", - anchor: "#reading-from-the-evm" + anchor: "#reading-from-the-evm", }, Keccak256: { title: "Keccak256 hash expression schema", - anchor: "#keccak256-hashes" + anchor: "#keccak256-hashes", }, Concat: { title: "Bytes concatenation schema", - anchor: "#bytes-concatenation" + anchor: "#bytes-concatenation", }, Resize: { title: "Resize operation schema", - anchor: "#resize-operations" + anchor: "#resize-operations", }, Reference: { title: "Region reference", - anchor: "#region-references" + anchor: "#region-references", }, - }).map(([def, { title, anchor }]) => ({ - [`schema:ethdebug/format/pointer/expression#/$defs/${def}`]: { - title, - href: `/spec/pointer/expression${anchor}` - } - })).reduce((a, b) => ({ ...a, ...b }), {}), + }) + .map(([def, { title, anchor }]) => ({ + [`schema:ethdebug/format/pointer/expression#/$defs/${def}`]: { + title, + href: `/spec/pointer/expression${anchor}`, + }, + })) + .reduce((a, b) => ({ ...a, ...b }), {}), }; -const dataSchemaIndex: SchemaIndex = ["value", "hex", "unsigned"].map(name => ({ - [`schema:ethdebug/format/data/${name}`]: { - href: `/spec/data/${name}` - } -})).reduce((a, b) => ({ ...a, ...b }), {}); +const dataSchemaIndex: SchemaIndex = ["value", "hex", "unsigned"] + .map((name) => ({ + [`schema:ethdebug/format/data/${name}`]: { + href: `/spec/data/${name}`, + }, + })) + .reduce((a, b) => ({ ...a, ...b }), {}); const materialsSchemaIndex: SchemaIndex = { "schema:ethdebug/format/materials/id": { title: "Identifier schema", - href: "/spec/materials/id#identifier-schema" + href: "/spec/materials/id#identifier-schema", }, "schema:ethdebug/format/materials/reference": { title: "Reference schema", - href: "/spec/materials/id#reference-schema" + href: "/spec/materials/id#reference-schema", }, "schema:ethdebug/format/materials/compilation": { title: "Compilation schema", - href: "/spec/materials/compilation" + href: "/spec/materials/compilation", }, "schema:ethdebug/format/materials/source": { title: "Source schema", - href: "/spec/materials/source" + href: "/spec/materials/source", }, "schema:ethdebug/format/materials/source-range": { title: "Source range schema", - href: "/spec/materials/source-range" + href: "/spec/materials/source-range", }, "schema:ethdebug/format/info": { title: "ethdebug/format/info", - href: "/spec/info" + href: "/spec/info", }, }; const programSchemaIndex: SchemaIndex = { "schema:ethdebug/format/program": { - href: "/spec/program" + href: "/spec/program", }, "schema:ethdebug/format/program/instruction": { - href: "/spec/program/instruction" + href: "/spec/program/instruction", }, "schema:ethdebug/format/program/context": { - href: "/spec/program/context" + href: "/spec/program/context", }, - ...( - ["code", "variables", "remark", "pick", "gather", "frame"].map(name => ({ + ...["code", "variables", "remark", "pick", "gather", "frame"] + .map((name) => ({ [`schema:ethdebug/format/program/context/${name}`]: { - href: `/spec/program/context/${name}` - } - })).reduce((a, b) => ({ ...a, ...b }), {}) - ), + href: `/spec/program/context/${name}`, + }, + })) + .reduce((a, b) => ({ ...a, ...b }), {}), }; const infoSchemaIndex: SchemaIndex = { "schema:ethdebug/format/info": { - href: "/spec/info" + href: "/spec/info", }, "schema:ethdebug/format/info/resources": { - href: "/spec/info/resources" + href: "/spec/info/resources", }, }; diff --git a/packages/web/src/status/status-config.ts b/packages/web/src/status/status-config.ts index 18156eeef..bbd98eec4 100644 --- a/packages/web/src/status/status-config.ts +++ b/packages/web/src/status/status-config.ts @@ -5,10 +5,7 @@ * status details across the ethdebug/format specification. */ -export type StatusLevel = - | "in-design" - | "implementable" - | "reference-available"; +export type StatusLevel = "in-design" | "implementable" | "reference-available"; export interface StatusLevelInfo { label: string; @@ -28,7 +25,7 @@ export const statusLevels: Record = { "Early feedback welcome, but implementations should expect breaking " + "changes.", }, - "implementable": { + implementable: { label: "Implementable", color: "#d97706", // Amber description: @@ -63,19 +60,14 @@ export const schemaStatus: Record = { summary: "Comprehensive schema for describing data locations in EVM state. " + "Debugger-side reference implementation available in @ethdebug/pointers.", - caveats: [ - "No compiler-side reference implementation yet.", - ], + caveats: ["No compiler-side reference implementation yet."], detailsPath: "/spec/pointer/overview#status", referenceUrl: "/docs/implementation-guides/pointers", }, type: { level: "implementable", - summary: - "Complete coverage of Solidity types (elementary and complex).", - caveats: [ - "No support for generic types (e.g., parameterized types).", - ], + summary: "Complete coverage of Solidity types (elementary and complex).", + caveats: ["No support for generic types (e.g., parameterized types)."], detailsPath: "/spec/type/overview#status", }, program: { @@ -86,7 +78,7 @@ export const schemaStatus: Record = { "actively evolving.", caveats: [ "Context types for function calls, returns, and reverts are still " + - "being designed.", + "being designed.", "Broader structural changes may occur to accommodate new concerns.", ], detailsPath: "/spec/program/overview#status", @@ -123,7 +115,7 @@ export const schemaStatus: Record = { export function getOverallStatus(): StatusLevel { const primarySchemas = ["pointer", "type", "program"]; const levels: StatusLevel[] = primarySchemas.map( - (key) => schemaStatus[key].level + (key) => schemaStatus[key].level, ); // Return the least mature level diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx index ae7a171bd..3bc382cab 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx @@ -1,33 +1,30 @@ -import React from "react" +import React from "react"; -import Translate from "@docusaurus/Translate" +import Translate from "@docusaurus/Translate"; import { IfElseThen, DependentRequired, DependentSchemas, Dependencies, -} from "@theme-original/JSONSchemaViewer/JSONSchemaElements/SchemaConditional" +} from "@theme-original/JSONSchemaViewer/JSONSchemaElements/SchemaConditional"; import { Collapsible } from "@theme-original/JSONSchemaViewer/components"; - type Props = { schema: any; -} +}; // To handle Schema Conditional (if-then-else , dependentRequired , dependentSchemas , dependencies ) export default function SchemaConditional(props: Props): JSX.Element { - const { schema } = props + const { schema } = props; // Checks - const isIfThenElse = schema.if !== undefined + const isIfThenElse = schema.if !== undefined; - const isDependentRequired = - schema.dependentRequired !== undefined - const isDependentSchemas = - schema.dependentSchemas !== undefined - const isDependencies = schema.dependencies !== undefined + const isDependentRequired = schema.dependentRequired !== undefined; + const isDependentSchemas = schema.dependentSchemas !== undefined; + const isDependencies = schema.dependencies !== undefined; return ( <> @@ -40,5 +37,5 @@ export default function SchemaConditional(props: Props): JSX.Element { {/* Handles dependencies (deprecated) */} {isDependencies && } - ) + ); } diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx index cc8b12774..8d8c04d15 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx @@ -1,14 +1,14 @@ -import React from 'react'; -import type { JSONSchema } from "json-schema-typed/draft-2020-12" +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 { SchemaHierarchyContextProvider, useSchemaHierarchyContext, -} from "@theme-original/JSONSchemaViewer/contexts" +} from "@theme-original/JSONSchemaViewer/contexts"; -import { CreateNodes } from "@theme-original/JSONSchemaViewer/components" +import { CreateNodes } from "@theme-original/JSONSchemaViewer/components"; export interface Discriminator { propertyName: string; @@ -16,83 +16,79 @@ export interface Discriminator { [value: string]: { schema: JSONSchema; index: number; - } - } + }; + }; } -export interface DiscriminatorSchemaProps extends Discriminator { -} +export interface DiscriminatorSchemaProps extends Discriminator {} export default function DiscriminatorSchema({ propertyName, - schemasByConst + schemasByConst, }: DiscriminatorSchemaProps): JSX.Element { const { jsonPointer: currentJsonPointer, level: currentLevel } = - useSchemaHierarchyContext() + useSchemaHierarchyContext(); return (

polymorphic discriminator  - The value of the {propertyName} field - determines which sub-schema applies: - - { - Object.entries(schemasByConst) - .map(([value, { schema, index }]) => ( - - - - - - )) - } + The value of the {propertyName} field determines which + sub-schema applies: + + {Object.entries(schemasByConst).map(([value, { schema, index }]) => ( + + + + + + ))} +
); } export function detectDiscriminator(schema: { - allOf: JSONSchema[] + allOf: JSONSchema[]; }): Discriminator | undefined { const { allOf } = schema; const allIfThen = allOf.every( - (clause: JSONSchema): clause is { "if": JSONSchema; then: JSONSchema } => { + (clause: JSONSchema): clause is { if: JSONSchema; then: JSONSchema } => { if (typeof clause === "boolean") { return false; } - const { title, description, "if": if_, then, ...others } = clause; + const { title, description, if: if_, then, ...others } = clause; return !!if_ && !!then && Object.keys(others).length === 0; - } - ) + }, + ); if (!allIfThen) { return; } const allIfsHaveSinglePropertyWithConst = allOf.every( - (ifThen: { "if": JSONSchema; then: JSONSchema }): ifThen is { - "if": { + (ifThen: { + if: JSONSchema; + then: JSONSchema; + }): ifThen is { + if: { properties: { [propertyName: string]: { - "const": string - } - } + const: string; + }; + }; }; then: JSONSchema; } => { - const { "if": if_ } = ifThen; + const { if: if_ } = ifThen; if ( typeof if_ === "boolean" || @@ -116,8 +112,8 @@ export function detectDiscriminator(schema: { "const" in propertySchema && typeof propertySchema.const === "string" && !!propertySchema.const - ) ; - } + ); + }, ); if (!allIfsHaveSinglePropertyWithConst) { @@ -127,19 +123,18 @@ export function detectDiscriminator(schema: { const propertyName = Object.keys(allOf[0]["if"].properties)[0]; const schemasByConst = allOf - .map(({ "if": if_, then }, index) => { + .map(({ if: if_, then }, index) => { const value = if_.properties[propertyName]["const"]; return { [value]: { schema: then, - index - } + index, + }, }; }) .reduce((a, b) => ({ ...a, ...b }), {}); - const isUniquelyDiscriminating = Object.keys(schemasByConst).length === allOf.length; @@ -149,6 +144,6 @@ export function detectDiscriminator(schema: { return { propertyName, - schemasByConst + schemasByConst, }; } diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx index 0f1e4979e..5ec676191 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx @@ -1,13 +1,13 @@ -import React from 'react'; -import type { JSONSchema } from "json-schema-typed/draft-2020-12" +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 { CreateNodes } from "@theme-original/JSONSchemaViewer/components"; import { SchemaHierarchyContextProvider, useSchemaHierarchyContext, -} from "@theme-original/JSONSchemaViewer/contexts" +} from "@theme-original/JSONSchemaViewer/contexts"; export interface Exclusions { propertyNames: string[]; @@ -15,61 +15,66 @@ export interface Exclusions { [propertyName: string]: { schema: JSONSchema & { type: "object" }; index: number; - } - } + }; + }; } -export interface ExclusiveRequiredPropertiesSchemaProps extends Exclusions { -} +export interface ExclusiveRequiredPropertiesSchemaProps extends Exclusions {} export default function ExcusiveRequiredPropertiesSchema({ propertyNames, - schemasByPropertyName + schemasByPropertyName, }: ExclusiveRequiredPropertiesSchemaProps): JSX.Element { const { jsonPointer: currentJsonPointer, level: currentLevel } = - useSchemaHierarchyContext() + useSchemaHierarchyContext(); return (

- mutually-exclusive required properties  - This object must specify exactly one of the following: + + mutually-exclusive required properties + +   This object must specify exactly one of the following:
    - {propertyNames.map((propertyName, index) => -
  • {propertyName}
  • - )} + {propertyNames.map((propertyName, index) => ( +
  • + {propertyName} +
  • + ))}
- Depending on which required property is used, one of the following sub-schemas applies: - - { - Object.entries(schemasByPropertyName) - .map(([propertyName, { schema, index }]) => ( + + {Object.entries(schemasByPropertyName).map( + ([propertyName, { schema, index }]) => ( - )) - } - + ), + )} +
); } - export function detectExclusiveRequiredProperties(schema: { - allOf: JSONSchema[] + allOf: JSONSchema[]; }): Exclusions | undefined { const { allOf } = schema; @@ -86,12 +91,11 @@ export function detectExclusiveRequiredProperties(schema: { if ( !oneOf || !oneOf.every( - (clause: JSONSchema): clause is { required: [string] } => ( + (clause: JSONSchema): clause is { required: [string] } => typeof clause === "object" && "required" in clause && clause.required instanceof Array && - clause.required.length === 1 - ) + clause.required.length === 1, ) ) { return; @@ -99,8 +103,7 @@ export function detectExclusiveRequiredProperties(schema: { const propertyNames = ( oneOf as (JSONSchema & { required: [propertyName: string] })[] - ) - .map(({ required: [propertyName] }) => propertyName); + ).map(({ required: [propertyName] }) => propertyName); // check that there is one conditional for each `oneOf` required // property and that the conditional is the right kind of if/then @@ -110,29 +113,32 @@ export function detectExclusiveRequiredProperties(schema: { } const allIfThen = conditionals.every( - (clause: JSONSchema): clause is { "if": JSONSchema; then: JSONSchema } => { + (clause: JSONSchema): clause is { if: JSONSchema; then: JSONSchema } => { if (typeof clause === "boolean") { return false; } - const { title, description, "if": if_, then, ...others } = clause; + const { title, description, if: if_, then, ...others } = clause; return !!if_ && !!then && Object.keys(others).length === 0; - } - ) + }, + ); if (!allIfThen) { return; } const allIfsIndicateASingleRequiredProperty = conditionals.every( - (ifThen: { "if": JSONSchema; then: JSONSchema }): ifThen is { - "if": { + (ifThen: { + if: JSONSchema; + then: JSONSchema; + }): ifThen is { + if: { required: [string]; }; then: any; } => { - const { "if": if_ } = ifThen; + const { if: if_ } = ifThen; if (typeof if_ === "boolean" || !("required" in if_)) { return false; @@ -147,7 +153,7 @@ export function detectExclusiveRequiredProperties(schema: { const [propertyName] = required; return typeof propertyName === "string" && !!propertyName; - } + }, ); if (!allIfsIndicateASingleRequiredProperty) { @@ -158,22 +164,23 @@ export function detectExclusiveRequiredProperties(schema: { .map( ( { - "if": { required: [propertyName] }, - then + if: { + required: [propertyName], + }, + then, }, - index + index, ) => ({ [propertyName]: { schema: then, - index - } - }) + index, + }, + }), ) .reduce((a, b) => ({ ...a, ...b }), {}); return { propertyNames, - schemasByPropertyName + schemasByPropertyName, }; } - diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/InclusiveRequiredPropertiesSchema.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/InclusiveRequiredPropertiesSchema.tsx index 18e037f83..df6791f12 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/InclusiveRequiredPropertiesSchema.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/InclusiveRequiredPropertiesSchema.tsx @@ -1,13 +1,13 @@ -import React from 'react'; -import type { JSONSchema } from "json-schema-typed/draft-2020-12" +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 { CreateNodes } from "@theme-original/JSONSchemaViewer/components"; import { SchemaHierarchyContextProvider, useSchemaHierarchyContext, -} from "@theme-original/JSONSchemaViewer/contexts" +} from "@theme-original/JSONSchemaViewer/contexts"; export interface Inclusions { propertyNames: string[]; @@ -15,77 +15,82 @@ export interface Inclusions { [propertyName: string]: { schema: Exclude; index: number; - } - } + }; + }; } -export interface InclusiveRequiredPropertiesSchemaProps extends Inclusions { -} +export interface InclusiveRequiredPropertiesSchemaProps extends Inclusions {} export default function InclusiveRequiredPropertiesSchema({ propertyNames, - schemasByPropertyName + schemasByPropertyName, }: InclusiveRequiredPropertiesSchemaProps): JSX.Element { const { jsonPointer: currentJsonPointer, level: currentLevel } = - useSchemaHierarchyContext() + useSchemaHierarchyContext(); return (

- independently-inclusive required properties  - This object may specify any of the following: + + independently-inclusive required properties + +   This object may specify any of the following:
    - {propertyNames.map((propertyName, index) => -
  • {propertyName}
  • - )} + {propertyNames.map((propertyName, index) => ( +
  • + {propertyName} +
  • + ))}
- Depending on which required properties are used, the following corresponding sub-schemas may apply: - - { - Object.entries(schemasByPropertyName) - .map(([propertyName, { schema, index }]) => ( + + {Object.entries(schemasByPropertyName).map( + ([propertyName, { schema, index }]) => ( - )) - } - + ), + )} +
); } const isIfThen = ( - schema: JSONSchema + schema: JSONSchema, ): schema is JSONSchema & { if: JSONSchema; then: JSONSchema; -} => - typeof schema !== "boolean" && - "if" in schema && "then" in schema; +} => typeof schema !== "boolean" && "if" in schema && "then" in schema; const isSingleRequiredProperty = ( - schema: JSONSchema + schema: JSONSchema, ): schema is JSONSchema & { - required: [string] + required: [string]; } => typeof schema !== "boolean" && - "required" in schema && schema.required?.length === 1; + "required" in schema && + schema.required?.length === 1; export function detectInclusiveRequiredProperties(schema: { - allOf: JSONSchema[] + allOf: JSONSchema[]; }): Inclusions | undefined { const { allOf } = schema; @@ -102,9 +107,9 @@ export function detectInclusiveRequiredProperties(schema: { return; } - const propertyNames = [...new Set( - ifs.map(({ required: [propertyName] }) => propertyName) - )]; + const propertyNames = [ + ...new Set(ifs.map(({ required: [propertyName] }) => propertyName)), + ]; // check that property names are unique if (propertyNames.length !== ifs.length) { @@ -112,29 +117,32 @@ export function detectInclusiveRequiredProperties(schema: { return; } - const schemasByPropertyName = ( - allOf as (JSONSchema & { if: { required: [string] }; then: Exclude; })[] + allOf as (JSONSchema & { + if: { required: [string] }; + then: Exclude; + })[] ) .map( ( { - if: { required: [propertyName] }, - then + if: { + required: [propertyName], + }, + then, }, - index + index, ) => ({ [propertyName]: { schema: then, - index - } - }) + index, + }, + }), ) .reduce((a, b) => ({ ...a, ...b }), {}); return { propertyNames, - schemasByPropertyName + schemasByPropertyName, }; } - diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/allOfSchema.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/allOfSchema.tsx index 22b7174f8..a7065d87f 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/allOfSchema.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/allOfSchema.tsx @@ -1,37 +1,37 @@ -import React from 'react'; -import type { JSONSchema } from "json-schema-typed/draft-2020-12" -import AllOfSchema from '@theme-original/JSONSchemaViewer/JSONSchemaElements/schemaComposition/allOfSchema'; +import React from "react"; +import type { JSONSchema } from "json-schema-typed/draft-2020-12"; +import AllOfSchema from "@theme-original/JSONSchemaViewer/JSONSchemaElements/schemaComposition/allOfSchema"; import DiscriminatorSchema, { - detectDiscriminator + detectDiscriminator, } from "./DiscriminatorSchema"; import ExclusiveRequiredPropertiesSchema, { - detectExclusiveRequiredProperties + detectExclusiveRequiredProperties, } from "./ExclusiveRequiredPropertiesSchema"; import InclusiveRequiredPropertiesSchema, { - detectInclusiveRequiredProperties + detectInclusiveRequiredProperties, } from "./InclusiveRequiredPropertiesSchema"; export default function allOfSchemaWrapper(props: { - schema: Exclude & { allOf: JSONSchema[]; } + schema: Exclude & { allOf: JSONSchema[] }; }) { const { schema } = props; const discriminator = detectDiscriminator(schema); if (discriminator) { - return + return ; } const exclusions = detectExclusiveRequiredProperties(schema); if (exclusions) { - return + return ; } const inclusions = detectInclusiveRequiredProperties(schema); if (inclusions) { - return + return ; } return ( @@ -40,4 +40,3 @@ export default function allOfSchemaWrapper(props: { ); } - diff --git a/packages/web/src/theme/JSONSchemaViewer/components/CreateNodes.tsx b/packages/web/src/theme/JSONSchemaViewer/components/CreateNodes.tsx index 75663b445..48a84dad1 100644 --- a/packages/web/src/theme/JSONSchemaViewer/components/CreateNodes.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/components/CreateNodes.tsx @@ -1,28 +1,25 @@ -import React from 'react'; +import React from "react"; import CreateTypes from "@theme-original/JSONSchemaViewer/components/CreateTypes"; -import CreateNodes from '@theme-original/JSONSchemaViewer/components/CreateNodes'; +import CreateNodes from "@theme-original/JSONSchemaViewer/components/CreateNodes"; import { useSchemaHierarchyContext } from "@theme-original/JSONSchemaViewer/contexts"; import { useSchemaContext, internalIdKey, - type JSONSchemaWithInternalIdKeys as JSONSchema + type JSONSchemaWithInternalIdKeys as JSONSchema, } from "@site/src/contexts/SchemaContext"; import Link from "@docusaurus/Link"; import UnnecessaryCompositionSchema, { - detectUnnecessaryComposition + detectUnnecessaryComposition, } from "./UnnecessaryComposition"; export default function CreateNodesWrapper(props: { - schema: Exclude + schema: Exclude; }) { const { level } = useSchemaHierarchyContext(); const { schemaIndex } = useSchemaContext(); - const { - schema, - ...otherProps - } = props; + const { schema, ...otherProps } = props; const { [internalIdKey]: id } = schema; @@ -30,15 +27,15 @@ export default function CreateNodesWrapper(props: { const { href, title = `${ - id.startsWith("schema:") - ? id.slice("schema:".length) - : id - } schema` + id.startsWith("schema:") ? id.slice("schema:".length) : id + } schema`, } = schemaIndex[id as keyof typeof schemaIndex]; return ( <> -

See {title} documentation.

+

+ See {title} documentation. +

); } diff --git a/packages/web/src/theme/JSONSchemaViewer/components/UnnecessaryComposition.tsx b/packages/web/src/theme/JSONSchemaViewer/components/UnnecessaryComposition.tsx index 45a0e4866..0d9b2599b 100644 --- a/packages/web/src/theme/JSONSchemaViewer/components/UnnecessaryComposition.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/components/UnnecessaryComposition.tsx @@ -2,33 +2,42 @@ import React from "react"; 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 { SchemaHierarchyComponent } from "@theme-original/JSONSchemaViewer/contexts"; import { Collapsible } from "@theme/JSONSchemaViewer/components"; -import { GenerateFriendlyName, QualifierMessages } from "@theme/JSONSchemaViewer/utils"; +import { + GenerateFriendlyName, + QualifierMessages, +} from "@theme/JSONSchemaViewer/utils"; import { useSchemaContext, internalIdKey, - type JSONSchemaWithInternalIdKeys + 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" +import { useJSVOptionsContext } from "@theme/JSONSchemaViewer/contexts"; export interface UnnecessaryComposition { - schemaWithoutUnnecessaryComposition: Exclude; + schemaWithoutUnnecessaryComposition: Exclude< + JSONSchemaWithInternalIdKeys, + boolean + >; unnecessaryCompositionKeyword: "allOf" | "oneOf" | "anyOf"; unnecessarilyComposedSchema: JSONSchemaWithInternalIdKeys; } export function detectUnnecessaryComposition( - schema: JSONSchemaWithInternalIdKeys + schema: JSONSchemaWithInternalIdKeys, ): UnnecessaryComposition | undefined { if (typeof schema === "boolean") { return; } - const unnecessaryCompositionKeywords = (["allOf", "oneOf", "anyOf"] as const) - .filter(keyword => keyword in schema && (schema[keyword] || []).length === 1); + const unnecessaryCompositionKeywords = ( + ["allOf", "oneOf", "anyOf"] as const + ).filter( + (keyword) => keyword in schema && (schema[keyword] || []).length === 1, + ); if (unnecessaryCompositionKeywords.length !== 1) { return; @@ -41,23 +50,23 @@ export function detectUnnecessaryComposition( ...schemaWithoutUnnecessaryComposition } = schema; - const [unnecessarilyComposedSchema] = - composition as [JSONSchemaWithInternalIdKeys] /* (we know this from filter above) */; + const [unnecessarilyComposedSchema] = composition as [ + JSONSchemaWithInternalIdKeys, + ]; /* (we know this from filter above) */ return { unnecessarilyComposedSchema, unnecessaryCompositionKeyword, - schemaWithoutUnnecessaryComposition + schemaWithoutUnnecessaryComposition, }; } -export interface UnnecessaryCompositionSchemaProps extends UnnecessaryComposition { -} +export interface UnnecessaryCompositionSchemaProps extends UnnecessaryComposition {} export default function UnnecessaryCompositionSchema({ schemaWithoutUnnecessaryComposition, unnecessaryCompositionKeyword, - unnecessarilyComposedSchema + unnecessarilyComposedSchema, }: UnnecessaryCompositionSchemaProps): JSX.Element { const jsvOptions = useJSVOptionsContext(); const { schemaIndex } = useSchemaContext(); @@ -66,62 +75,60 @@ export default function UnnecessaryCompositionSchema({ // schema, where the unnecessarily composed schema is the base const baseSchema = unnecessarilyComposedSchema; const extensionSchema = schemaWithoutUnnecessaryComposition; - const { - documentation, - semantics - } = separateDocumentationFromSemantics(extensionSchema); + const { documentation, semantics } = + separateDocumentationFromSemantics(extensionSchema); // 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_) - ) - )) - ); + 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 onlyChangesTitle = Object.keys(documentation).length === 1 && - "title" in documentation; + const onlyChangesTitle = + Object.keys(documentation).length === 1 && "title" in documentation; if (onlyChangesTitle) { - return <> - - - - ; + return ( + <> + + + + + ); } const { description } = documentation; - return <> - - {description && } -
+ return ( + <> + + {description && } +
- - - - ; + + + + + ); } const { [internalIdKey]: id } = baseSchema; @@ -130,18 +137,16 @@ export default function UnnecessaryCompositionSchema({ const { href, title = `${ - id.startsWith("schema:") - ? id.slice("schema:".length) - : id - } schema` + id.startsWith("schema:") ? id.slice("schema:".length) : id + } schema`, } = schemaIndex[id as keyof typeof schemaIndex]; return ( <> - extensions  - This schema extends the {title}. + extensions  This schema + extends the {title}.

- +

); @@ -149,21 +154,23 @@ export default function UnnecessaryCompositionSchema({ return ( <> - extensions  - These extensions apply to the base schema below: + extensions  These + extensions apply to the base schema below:

- +

- -   + + + +   base schema } detailsProps={{ - open: true + open: true, }} > - ); } function separateDocumentationFromSemantics(schema: JSONSchema): { - documentation: Exclude, - semantics: JSONSchema + documentation: Exclude; + semantics: JSONSchema; } { if (typeof schema === "boolean") { return { documentation: {}, - semantics: schema + semantics: schema, }; } @@ -202,15 +208,20 @@ function separateDocumentationFromSemantics(schema: JSONSchema): { title, description, examples, - default: default_ - }).filter(( - pair: [string, string | object | undefined] - ): pair is [string, string | object] => pair[1] !== undefined).map( - ([key, value]) => ({ [key]: value }) - ).reduce((a, b) => ({ ...a, ...b }), {}) as Partial>; + default: default_, + }) + .filter( + ( + pair: [string, string | object | undefined], + ): pair is [string, string | object] => pair[1] !== undefined, + ) + .map(([key, value]) => ({ [key]: value })) + .reduce((a, b) => ({ ...a, ...b }), {}) as Partial< + Pick + >; return { documentation, - semantics + semantics, }; } diff --git a/packages/web/src/theme/MDXComponents.tsx b/packages/web/src/theme/MDXComponents.tsx index a69570c00..357e154cc 100644 --- a/packages/web/src/theme/MDXComponents.tsx +++ b/packages/web/src/theme/MDXComponents.tsx @@ -1,12 +1,12 @@ -import React from 'react'; -import isInternalUrl from '@docusaurus/isInternalUrl'; -import MDXComponents from '@theme-original/MDXComponents'; -import MDXA from "@theme-original/MDXComponents/A"; +import React from "react"; +import isInternalUrl from "@docusaurus/isInternalUrl"; +import MDXComponents from "@theme-original/MDXComponents"; +import MDXA from "@theme-original/MDXComponents/A"; import type { Props as LinkProps } from "@docusaurus/Link"; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { library } from '@fortawesome/fontawesome-svg-core'; -import { fab } from '@fortawesome/free-brands-svg-icons'; -import { fas } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { library } from "@fortawesome/fontawesome-svg-core"; +import { fab } from "@fortawesome/free-brands-svg-icons"; +import { fas } from "@fortawesome/free-solid-svg-icons"; import IconExternalLink from "@theme-original/Icon/ExternalLink"; import StatusBadge from "@site/src/components/StatusBadge"; import StatusBanner from "@site/src/components/StatusBanner"; @@ -15,11 +15,17 @@ library.add(fab, fas); // Add all icons to the library so you can use them witho // custom link component that appends external link svg inside Markdown files function A({ children, href, ...props }: LinkProps): JSX.Element { - return { - children - }{href && !isInternalUrl(href) && ( - <> - ) }; + return ( + + {children} + {href && !isInternalUrl(href) && ( + <> +  + + + )} + + ); } export default { diff --git a/packages/web/src/theme/ProgramExample/Details.tsx b/packages/web/src/theme/ProgramExample/Details.tsx index 46ba0f335..6ee2f0106 100644 --- a/packages/web/src/theme/ProgramExample/Details.tsx +++ b/packages/web/src/theme/ProgramExample/Details.tsx @@ -8,60 +8,72 @@ import { Variables } from "./Variables"; // imported for style legend import "./SourceContents.css"; -export interface Props { -} +export interface Props {} export function Details(props: Props): JSX.Element { const { highlightedInstruction, highlightMode } = useProgramExampleContext(); if (highlightMode === "simple" || !highlightedInstruction) { - return <> -

Details

- - ; + return ( + <> +

Details

+ + + ); } - - return <> -

Details

- -
- See full ethdebug/format/program/instruction object - -
- ; + return ( + <> +

Details

+ +
+ + See full ethdebug/format/program/instruction object + + +
+ + ); } interface InstructionAdmonitionProps { instruction: Program.Instruction; } function InstructionAdmonition({ - instruction + instruction, }: InstructionAdmonitionProps): JSX.Element { - return -

- The selected instruction provides the following - ethdebug/format Program contexts - : -

-
    -
  • - Code context is highlighted in this - style above. -
  • -
  • - Variables context is indicated by variable declarations - highlighted in this - style above. -
  • -
-
; + return ( + +

+ The selected instruction provides the following{" "} + + ethdebug/format Program contexts + + : +

+
    +
  • + Code context is highlighted{" "} + in this style above. +
  • +
  • + Variables context is indicated by variable + declarations highlighted{" "} + + in this style + {" "} + above. +
  • +
+
+ ); } function BasicAdmonition(props: {}): JSX.Element { - return - Select an instruction offset to see associated - ethdebug/format - debugging information. - ; + return ( + + Select an instruction offset to see associated{" "} + ethdebug/format debugging information. + + ); } diff --git a/packages/web/src/theme/ProgramExample/HighlightedInstruction.tsx b/packages/web/src/theme/ProgramExample/HighlightedInstruction.tsx index 467b876c2..290fc86f5 100644 --- a/packages/web/src/theme/ProgramExample/HighlightedInstruction.tsx +++ b/packages/web/src/theme/ProgramExample/HighlightedInstruction.tsx @@ -8,12 +8,12 @@ import { ShikiCodeBlock } from "@theme/ShikiCodeBlock"; export function HighlightedInstruction(): JSX.Element { const { highlightedInstruction } = useProgramExampleContext(); - return <> - - ; + return ( + <> + + + ); } diff --git a/packages/web/src/theme/ProgramExample/Opcodes.css b/packages/web/src/theme/ProgramExample/Opcodes.css index 1ea4eb5b7..ea4101889 100644 --- a/packages/web/src/theme/ProgramExample/Opcodes.css +++ b/packages/web/src/theme/ProgramExample/Opcodes.css @@ -1,5 +1,3 @@ - - dl.opcodes { display: grid; grid-template-columns: max-content max-content; @@ -18,7 +16,8 @@ dl.opcodes dt { cursor: pointer; } -dl.opcodes dt, dl.opcodes dt + dd{ +dl.opcodes dt, +dl.opcodes dt + dd { margin-top: 5px; border-bottom: 1px solid var(--ifm-color-primary-light); } diff --git a/packages/web/src/theme/ProgramExample/Opcodes.tsx b/packages/web/src/theme/ProgramExample/Opcodes.tsx index 28cc554a1..3beedcf7f 100644 --- a/packages/web/src/theme/ProgramExample/Opcodes.tsx +++ b/packages/web/src/theme/ProgramExample/Opcodes.tsx @@ -12,7 +12,7 @@ export function Opcodes(): JSX.Element { highlightInstruction, highlightMode, showDetails, - hideDetails + hideDetails, } = useProgramExampleContext(); const [activeOffset, setActiveOffset] = useState(); @@ -44,12 +44,12 @@ export function Opcodes(): JSX.Element { } highlightInstruction(undefined); - }, [activeOffset, hoverOffset, highlightedInstruction, highlightMode]); - const handleClick = (offset: Data.Value) => offset === activeOffset - ? setActiveOffset(undefined) - : setActiveOffset(offset); + const handleClick = (offset: Data.Value) => + offset === activeOffset + ? setActiveOffset(undefined) + : setActiveOffset(offset); const handleMouseEnter = (offset: Data.Value) => setHoverOffset(offset); // skipping the current hover offset check here and assuming that the mouse @@ -58,22 +58,23 @@ export function Opcodes(): JSX.Element { const paddingLength = instructions.at(-1)!.offset.toString(16).length; - return
{ - instructions.map((instruction) => - handleClick(instruction.offset)} - onMouseEnter={() => handleMouseEnter(instruction.offset)} - onMouseLeave={() => handleMouseLeave(instruction.offset)} - /> - ) - }
+ return ( +
+ {instructions.map((instruction) => ( + handleClick(instruction.offset)} + onMouseEnter={() => handleMouseEnter(instruction.offset)} + onMouseLeave={() => handleMouseLeave(instruction.offset)} + /> + ))} +
+ ); } - function Opcode(props: { instruction: Program.Instruction; active: boolean; @@ -88,39 +89,41 @@ function Opcode(props: { paddingLength, onClick, onMouseEnter, - onMouseLeave + onMouseLeave, } = props; const { offset, operation, context } = instruction; - const offsetLabel = <> - 0x{offset.toString(16).padStart(paddingLength, "0")} - ; - - const commentLabel = context && "remark" in context - ? <> ({context.remark}) - : <> - - const operationLabel = <> - {operation && { - [operation.mnemonic, ...operation.arguments || []].join(" ") - }} - {commentLabel} - ; - - return <> -
{ - offsetLabel - }
-
{ - operationLabel - }
- ; + const offsetLabel = <>0x{offset.toString(16).padStart(paddingLength, "0")}; + + const commentLabel = + context && "remark" in context ? <> ({context.remark}) : <>; + + const operationLabel = ( + <> + {operation && ( + + {[operation.mnemonic, ...(operation.arguments || [])].join(" ")} + + )} + {commentLabel} + + ); + + return ( + <> +
+ {offsetLabel} +
+
+ {operationLabel} +
+ + ); } - diff --git a/packages/web/src/theme/ProgramExample/ProgramExampleContext.tsx b/packages/web/src/theme/ProgramExample/ProgramExampleContext.tsx index 7674f31e2..d514cdea8 100644 --- a/packages/web/src/theme/ProgramExample/ProgramExampleContext.tsx +++ b/packages/web/src/theme/ProgramExample/ProgramExampleContext.tsx @@ -4,7 +4,6 @@ import { Data, Materials, Program } from "@ethdebug/format"; import { computeOffsets } from "./offsets"; import { type DynamicInstruction, resolveDynamicInstruction } from "./dynamic"; - export interface ProgramExampleState { // props sources: Materials.Source[]; @@ -18,13 +17,16 @@ export interface ProgramExampleState { hideDetails(): void; } -const ProgramExampleContext = - createContext(undefined); +const ProgramExampleContext = createContext( + undefined, +); export function useProgramExampleContext() { const context = useContext(ProgramExampleContext); if (context === undefined) { - throw new Error("useProgramExampleContext must be used within a ProgramExampleContextProvider"); + throw new Error( + "useProgramExampleContext must be used within a ProgramExampleContextProvider", + ); } return context; @@ -41,32 +43,23 @@ export function ProgramExampleContextProvider({ }: ProgramExampleProps & { children: React.ReactNode; }): JSX.Element { - const { - sources, - instructions: dynamicInstructionsWithoutOffsets - } = props; + const { sources, instructions: dynamicInstructionsWithoutOffsets } = props; - const dynamicInstructions = computeOffsets( - dynamicInstructionsWithoutOffsets - ); + const dynamicInstructions = computeOffsets(dynamicInstructionsWithoutOffsets); - const instructions = dynamicInstructions.map( - (dynamicInstruction) => - resolveDynamicInstruction(dynamicInstruction, { sources }) + const instructions = dynamicInstructions.map((dynamicInstruction) => + resolveDynamicInstruction(dynamicInstruction, { sources }), ); - const [ - highlightedOffset, - highlightInstruction - ] = useState(); - const [ - highlightedInstruction, - setHighlightedInstruction - ] = useState(); - const [ - highlightMode, - setHighlightMode - ] = useState<"simple" | "detailed">("simple"); + const [highlightedOffset, highlightInstruction] = useState< + Data.Value | undefined + >(); + const [highlightedInstruction, setHighlightedInstruction] = useState< + Program.Instruction | undefined + >(); + const [highlightMode, setHighlightMode] = useState<"simple" | "detailed">( + "simple", + ); const showDetails = () => setHighlightMode("detailed"); const hideDetails = () => setHighlightMode("simple"); @@ -77,25 +70,32 @@ export function ProgramExampleContextProvider({ return; } - const instruction = instructions - .find(({ offset }) => offset === highlightedOffset); + const instruction = instructions.find( + ({ offset }) => offset === highlightedOffset, + ); if (!instruction) { - throw new Error(`Unexpected could not find instruction with offset ${highlightedOffset}`); + throw new Error( + `Unexpected could not find instruction with offset ${highlightedOffset}`, + ); } setHighlightedInstruction(instruction); }, [highlightedOffset, setHighlightedInstruction]); - return - {children} - + return ( + + {children} + + ); } diff --git a/packages/web/src/theme/ProgramExample/SourceContents.css b/packages/web/src/theme/ProgramExample/SourceContents.css index c07d3689a..6544878fe 100644 --- a/packages/web/src/theme/ProgramExample/SourceContents.css +++ b/packages/web/src/theme/ProgramExample/SourceContents.css @@ -1,4 +1,3 @@ - .highlighted-code { font-weight: bold; background-color: var(--ifm-color-primary-lightest); diff --git a/packages/web/src/theme/ProgramExample/SourceContents.tsx b/packages/web/src/theme/ProgramExample/SourceContents.tsx index 40b0dc434..2d3094055 100644 --- a/packages/web/src/theme/ProgramExample/SourceContents.tsx +++ b/packages/web/src/theme/ProgramExample/SourceContents.tsx @@ -2,7 +2,7 @@ import React, { useEffect } from "react"; import { ShikiCodeBlock, - type Props as ShikiCodeBlockProps + type Props as ShikiCodeBlockProps, } from "@theme/ShikiCodeBlock"; import "./SourceContents.css"; @@ -13,13 +13,10 @@ import { useProgramExampleContext } from "./ProgramExampleContext"; import { Materials, Program } from "@ethdebug/format"; export function SourceContents( - props: Omit + props: Omit, ): JSX.Element { - const { - sources, - highlightedInstruction, - highlightMode - } = useProgramExampleContext(); + const { sources, highlightedInstruction, highlightMode } = + useProgramExampleContext(); if (sources.length !== 1) { throw new Error("Multiple sources per example not currently supported"); @@ -39,27 +36,27 @@ export function SourceContents( ...simpleDecorations, ...(Program.Context.isVariables(context) ? decorateVariablesContext(context, source) - : [] - ) + : []), ]; - const decorations = highlightMode === "detailed" - ? detailedDecorations - : simpleDecorations; - - return ; + const decorations = + highlightMode === "detailed" ? detailedDecorations : simpleDecorations; + + return ( + + ); } function decorateCodeContext( { code }: Program.Context.Code, source: Materials.Source, - className: string = "highlighted-code" + className: string = "highlighted-code", ): Shiki.DecorationItem[] { const { offset, length } = normalizeRange(code.range, source); @@ -68,49 +65,49 @@ function decorateCodeContext( start: offset, end: offset + length, properties: { - class: className - } - } + class: className, + }, + }, ]; } function decoratePickContext( { pick }: Program.Context.Pick, - source: Materials.Source + source: Materials.Source, ): Shiki.DecorationItem[] { // HACK this only supports picking from a choice of several different code // contexts if (!pick.every(Program.Context.isCode)) { - console.warn("decoratePickContext encountered non-code contexts in pick array. These will be ignored."); + console.warn( + "decoratePickContext encountered non-code contexts in pick array. These will be ignored.", + ); return []; } - return pick.flatMap( - (choice) => decorateCodeContext(choice, source, "highlighted-ambiguous-code") + return pick.flatMap((choice) => + decorateCodeContext(choice, source, "highlighted-ambiguous-code"), ); } - function decorateVariablesContext( { variables }: Program.Context.Variables, - source: Materials.Source + source: Materials.Source, ): Shiki.DecorationItem[] { - return variables.map(({ declaration }) => { const { offset, length } = normalizeRange(declaration?.range, source); return { start: offset, end: offset + length, properties: { - class: "highlighted-variable-declaration" - } + class: "highlighted-variable-declaration", + }, }; }); } function normalizeRange( range: Materials.SourceRange["range"], - source: Materials.Source + source: Materials.Source, ): Materials.SourceRange["range"] & { offset: number; length: number } { const { offset, length } = range ? { offset: Number(range.offset), length: Number(range.length) } diff --git a/packages/web/src/theme/ProgramExample/Variables.tsx b/packages/web/src/theme/ProgramExample/Variables.tsx index fbdf8c873..445e94459 100644 --- a/packages/web/src/theme/ProgramExample/Variables.tsx +++ b/packages/web/src/theme/ProgramExample/Variables.tsx @@ -9,46 +9,52 @@ import { ShikiCodeBlock } from "@theme/ShikiCodeBlock"; export function Variables(): JSX.Element { const { highlightedInstruction } = useProgramExampleContext(); - const link = - ethdebug/format/program Variables context schema - ; + const link = ( + + ethdebug/format/program Variables context schema + + ); if (highlightedInstruction === undefined) { - return - Hover or click on an offset above to see the {link} object - for that instruction. - ; + return ( + + Hover or click on an offset above to see the {link} object for that + instruction. + + ); } const { context } = highlightedInstruction; if (!(context && "variables" in context)) { - return - The highlighted instruction does not specify any variables in context - information. See other tab for full instruction object. - ; + return ( + + The highlighted instruction does not specify any variables in context + information. See other tab for full instruction object. + + ); } const { variables } = context; - if (!variables.every(variable => "identifier" in variable)) { + if (!variables.every((variable) => "identifier" in variable)) { throw new Error( - "Unnamed variables are currently unsupported by this documentation system" + "Unnamed variables are currently unsupported by this documentation system", ); } - return <> - - The following is the {link} object for the selected instruction. - + return ( + <> + + The following is the {link} object for the selected instruction. + -
{ - variables.map((variable) => - - ) - }
- ; +
+ {variables.map((variable) => ( + + ))} +
+ + ); } interface VariableProps { @@ -59,25 +65,25 @@ function Variable(props: VariableProps): JSX.Element { const { variable } = props; const details = (["type", "pointer"] as const) - .filter(detail => detail in variable) - .map((detail) =>
-

{`${detail.slice(0,1).toUpperCase()}${detail.slice(1)}`}

+ .filter((detail) => detail in variable) + .map((detail) => ( +
+

{`${detail.slice(0, 1).toUpperCase()}${detail.slice(1)}`}

- -
) - return <> -
- {variable.identifier} -
-
-
- {details} -
-
- ; + +
+ )); + return ( + <> +
+ {variable.identifier} +
+
+
{details}
+
+ + ); } diff --git a/packages/web/src/theme/ProgramExample/Viewer.css b/packages/web/src/theme/ProgramExample/Viewer.css index db4d60832..826afa5ea 100644 --- a/packages/web/src/theme/ProgramExample/Viewer.css +++ b/packages/web/src/theme/ProgramExample/Viewer.css @@ -1,4 +1,3 @@ - .viewer-row { display: flex; @@ -7,9 +6,8 @@ width: 100%; gap: 5px; - } .viewer-row > * { - flex-grow:1; + flex-grow: 1; } diff --git a/packages/web/src/theme/ProgramExample/Viewer.tsx b/packages/web/src/theme/ProgramExample/Viewer.tsx index 017acb6c7..8e4661004 100644 --- a/packages/web/src/theme/ProgramExample/Viewer.tsx +++ b/packages/web/src/theme/ProgramExample/Viewer.tsx @@ -7,22 +7,23 @@ import { Variables } from "./Variables"; import "./Viewer.css"; -export interface Props { -} +export interface Props {} export function Viewer(props: Props): JSX.Element { - return <> -

Interactive example

-
-
-

Source contents

- -
-
-

Compiled opcodes

- + return ( + <> +

Interactive example

+
+
+

Source contents

+ +
+
+

Compiled opcodes

+ +
-
-
- ; +
+ + ); } diff --git a/packages/web/src/theme/ProgramExample/dynamic.ts b/packages/web/src/theme/ProgramExample/dynamic.ts index b8bc6a20b..e80dada73 100644 --- a/packages/web/src/theme/ProgramExample/dynamic.ts +++ b/packages/web/src/theme/ProgramExample/dynamic.ts @@ -1,18 +1,16 @@ import { Program, Materials } from "@ethdebug/format"; -export type DynamicInstruction = - & Omit - & { operation: Program.Instruction.Operation; } - & { context: DynamicContext; }; +export type DynamicInstruction = Omit< + Program.Instruction, + "context" | "operation" +> & { operation: Program.Instruction.Operation } & { context: DynamicContext }; -export type DynamicContext = - | Program.Context - | ContextThunk; +export type DynamicContext = Program.Context | ContextThunk; export type ContextThunk = (props: { findSourceRange( query: string, - options?: FindSourceRangeOptions + options?: FindSourceRangeOptions, ): Materials.SourceRange | undefined; }) => Program.Context; @@ -27,16 +25,13 @@ export interface ResolverOptions { export function resolveDynamicInstruction( dynamicInstruction: DynamicInstruction, - options: ResolverOptions + options: ResolverOptions, ): Program.Instruction { - const context = resolveDynamicContext( - dynamicInstruction.context, - options - ); + const context = resolveDynamicContext(dynamicInstruction.context, options); const instruction = { ...dynamicInstruction, - context + context, }; return instruction; @@ -44,7 +39,7 @@ export function resolveDynamicInstruction( function resolveDynamicContext( context: DynamicContext, - { sources }: ResolverOptions + { sources }: ResolverOptions, ): Program.Context { if (typeof context !== "function") { return context; @@ -52,11 +47,12 @@ function resolveDynamicContext( const findSourceRange = ( query: string, - options: FindSourceRangeOptions = {} + options: FindSourceRangeOptions = {}, ) => { - const source = "source" in options && options.source - ? sources.find(source => source.id === options.source?.id) - : sources[0]; + const source = + "source" in options && options.source + ? sources.find((source) => source.id === options.source?.id) + : sources[0]; if (!source) { return; @@ -67,11 +63,10 @@ function resolveDynamicContext( const afterQueryOffset = source.contents.indexOf(afterQuery); if (afterQueryOffset === -1) { throw new Error( - `Unexpected could not find string ${options.after} as prior occurrence to ${query}` + `Unexpected could not find string ${options.after} as prior occurrence to ${query}`, ); } - const startOffset = afterQueryOffset + afterQuery.length; const offset = source.contents.indexOf(query, startOffset); @@ -85,8 +80,8 @@ function resolveDynamicContext( source: { id: source.id }, range: { offset, - length - } + length, + }, }; }; diff --git a/packages/web/src/theme/ProgramExample/index.ts b/packages/web/src/theme/ProgramExample/index.ts index a7901da1a..02f07f310 100644 --- a/packages/web/src/theme/ProgramExample/index.ts +++ b/packages/web/src/theme/ProgramExample/index.ts @@ -4,4 +4,3 @@ export * from "./Opcodes"; export * from "./HighlightedInstruction"; export * from "./Viewer"; - diff --git a/packages/web/src/theme/ProgramExample/offsets.ts b/packages/web/src/theme/ProgramExample/offsets.ts index bb112d61d..9e60320f4 100644 --- a/packages/web/src/theme/ProgramExample/offsets.ts +++ b/packages/web/src/theme/ProgramExample/offsets.ts @@ -6,53 +6,44 @@ interface OffsetComputableInstruction { operation: Program.Instruction.Operation; } -type OffsetComputedInstruction = - & I - & { offset: Data.Value; }; +type OffsetComputedInstruction = I & { + offset: Data.Value; +}; export function computeOffsets( - instructions: I[] + instructions: I[], ): OffsetComputedInstruction[] { const initialResults: { nextOffset: number; results: OffsetComputedInstruction[]; } = { nextOffset: 0, - results: [] + results: [], }; - const { - results - } = instructions.reduce( + const { results } = instructions.reduce( ({ nextOffset, results }, instruction) => { const result = { offset: nextOffset, - ...instruction + ...instruction, }; - const operationSize = ( + const operationSize = 1 /* for opcode */ + Math.ceil( (instruction.operation.arguments || []) - .map( - value => typeof value === "number" - ? value.toString(16) - : value.slice(2) + .map((value) => + typeof value === "number" ? value.toString(16) : value.slice(2), ) - .join("") - .length / 2 - ) - ); + .join("").length / 2, + ); return { nextOffset: nextOffset + operationSize, - results: [ - ...results, - result - ] + results: [...results, result], }; }, - initialResults + initialResults, ); return results; diff --git a/packages/web/src/theme/ShikiCodeBlock/ShikiCodeBlock.tsx b/packages/web/src/theme/ShikiCodeBlock/ShikiCodeBlock.tsx index ef68a2cb6..645b7cd3a 100644 --- a/packages/web/src/theme/ShikiCodeBlock/ShikiCodeBlock.tsx +++ b/packages/web/src/theme/ShikiCodeBlock/ShikiCodeBlock.tsx @@ -2,7 +2,7 @@ import React from "react"; import { type Highlighter, type HighlightOptions, - useHighlighter + useHighlighter, } from "./useHighlighter"; export interface Props extends HighlightOptions { diff --git a/packages/web/src/theme/ShikiCodeBlock/useHighlighter.ts b/packages/web/src/theme/ShikiCodeBlock/useHighlighter.ts index c81735a70..96f091e61 100644 --- a/packages/web/src/theme/ShikiCodeBlock/useHighlighter.ts +++ b/packages/web/src/theme/ShikiCodeBlock/useHighlighter.ts @@ -15,8 +15,8 @@ export interface HighlightOptions { export function useHighlighter() { const [highlighter, setHighlighter] = useState(); - useEffect(() => { - createHighlighter().then(setHighlighter) + useEffect(() => { + createHighlighter().then(setHighlighter); }, [setHighlighter]); return highlighter; @@ -24,14 +24,12 @@ export function useHighlighter() { async function createHighlighter(): Promise { const shiki = await Shiki.createHighlighterCore({ - themes: [ - import("@shikijs/themes/github-light"), - ], + themes: [import("@shikijs/themes/github-light")], langs: [ import("@shikijs/langs/solidity"), import("@shikijs/langs/javascript"), ], - engine: createOnigurumaEngine(import("shiki/wasm")) + engine: createOnigurumaEngine(import("shiki/wasm")), }); const themeName = "github-light"; @@ -41,8 +39,8 @@ async function createHighlighter(): Promise { return shiki.codeToHtml(text, { lang: language || "text", theme: themeName, - decorations - }) - } + decorations, + }); + }, }; } diff --git a/packages/web/tsconfig.json b/packages/web/tsconfig.json index f1b07b8fb..1740afae9 100644 --- a/packages/web/tsconfig.json +++ b/packages/web/tsconfig.json @@ -7,7 +7,11 @@ "resolveJsonModule": true, "target": "es2015", // Extending "@tsconfig/docusaurus/tsconfig.json".types with "docusaurus-json-schema-plugin" - "types": ["node", "@docusaurus/module-type-aliases", "@docusaurus/theme-classic", "docusaurus-json-schema-plugin"] - + "types": [ + "node", + "@docusaurus/module-type-aliases", + "@docusaurus/theme-classic", + "docusaurus-json-schema-plugin" + ] } } diff --git a/schemas/info.schema.yaml b/schemas/info.schema.yaml index 624c2bca9..13eaede97 100644 --- a/schemas/info.schema.yaml +++ b/schemas/info.schema.yaml @@ -14,13 +14,11 @@ properties: type: array items: $ref: "schema:ethdebug/format/program" - additionalItems: - false + additionalItems: false compilation: $ref: "schema:ethdebug/format/materials/compilation" - required: - compilation - programs @@ -181,4 +179,3 @@ examples: range: offset: 891 length: 20 - diff --git a/schemas/info/resources.schema.yaml b/schemas/info/resources.schema.yaml index 83f96ed65..1c323b675 100644 --- a/schemas/info/resources.schema.yaml +++ b/schemas/info/resources.schema.yaml @@ -27,7 +27,6 @@ properties: compilation: $ref: "schema:ethdebug/format/materials/compilation" - required: - types - pointers diff --git a/schemas/pointer.schema.yaml b/schemas/pointer.schema.yaml index d6c276956..cf0ec1683 100644 --- a/schemas/pointer.schema.yaml +++ b/schemas/pointer.schema.yaml @@ -145,8 +145,8 @@ examples: - .offset: "array-count" - .length: "array-count" - $product: - - "item-index" - - .length: "struct-pointer" + - "item-index" + - .length: "struct-pointer" length: $wordsize # following that pointer leads to the region corresponding to @@ -214,8 +214,8 @@ examples: "string-length": $quotient: - $difference: - - $read: "long-string-length-data" - - 1 + - $read: "long-string-length-data" + - 1 - 2 "start-slot": diff --git a/schemas/pointer/collection.schema.yaml b/schemas/pointer/collection.schema.yaml index 47f4ec1b4..c01705112 100644 --- a/schemas/pointer/collection.schema.yaml +++ b/schemas/pointer/collection.schema.yaml @@ -5,7 +5,6 @@ title: ethdebug/format/pointer/collection description: | A representation of a collection of pointers to data in the EVM type: object - allOf: - oneOf: - required: [group] diff --git a/schemas/pointer/collection/list.schema.yaml b/schemas/pointer/collection/list.schema.yaml index 32af2a335..9c2abbdf9 100644 --- a/schemas/pointer/collection/list.schema.yaml +++ b/schemas/pointer/collection/list.schema.yaml @@ -5,7 +5,6 @@ title: ethdebug/format/pointer/collection/list description: | An ordered list of pointers, indexed starting at zero. type: object - properties: list: type: object diff --git a/schemas/pointer/expression.schema.yaml b/schemas/pointer/expression.schema.yaml index 882962494..21a1ff161 100644 --- a/schemas/pointer/expression.schema.yaml +++ b/schemas/pointer/expression.schema.yaml @@ -96,10 +96,10 @@ $defs: - "$quotient": [5, 3] - "$remainder": - "$product": - - 2 - - 2 - - 2 - - 2 + - 2 + - 2 + - 2 + - 2 - 3 Operands: @@ -131,7 +131,6 @@ $defs: - .length: "array-item" - .offset: $this - Read: title: Read region bytes description: | @@ -161,7 +160,6 @@ $defs: the matching name, then secondly resolving to the parent if it matches, then to parent's earlier siblings, and so on. type: string - oneOf: - $ref: "schema:ethdebug/format/pointer/identifier" - const: "$this" diff --git a/schemas/pointer/region.schema.yaml b/schemas/pointer/region.schema.yaml index 13a40acbb..0ab06a053 100644 --- a/schemas/pointer/region.schema.yaml +++ b/schemas/pointer/region.schema.yaml @@ -5,12 +5,10 @@ title: ethdebug/format/pointer/region description: | A representation of a region of data in the EVM type: object - properties: location: $ref: "#/$defs/Location" - allOf: - if: properties: @@ -80,4 +78,3 @@ unevaluatedProperties: false examples: - location: storage slot: "0x0000000000000000000000000000000000000000000000000000000000000000" - diff --git a/schemas/pointer/region/calldata.schema.yaml b/schemas/pointer/region/calldata.schema.yaml index 32d6bfa77..ba1e50598 100644 --- a/schemas/pointer/region/calldata.schema.yaml +++ b/schemas/pointer/region/calldata.schema.yaml @@ -8,7 +8,6 @@ description: | This schema is constructed by extending the base region schema and the schema for the slice addressing scheme. type: object - allOf: - title: '{ "location": "calldata" }' # note: whitespace chars are \255 (nbsp) properties: diff --git a/schemas/pointer/region/code.schema.yaml b/schemas/pointer/region/code.schema.yaml index 8c9723df7..b78eaf894 100644 --- a/schemas/pointer/region/code.schema.yaml +++ b/schemas/pointer/region/code.schema.yaml @@ -8,7 +8,6 @@ description: | This schema is constructed by extending the base region schema and the schema for the slice addressing scheme. type: object - allOf: - title: '{ "location": "code" }' # note: whitespace chars are \255 (nbsp) properties: diff --git a/schemas/pointer/region/memory.schema.yaml b/schemas/pointer/region/memory.schema.yaml index c44745245..a62b4ae44 100644 --- a/schemas/pointer/region/memory.schema.yaml +++ b/schemas/pointer/region/memory.schema.yaml @@ -9,7 +9,6 @@ description: | This schema is constructed by extending the base region schema and the schema for the slice addressing scheme. type: object - allOf: - title: '{ "location": "memory" }' # note: whitespace chars are \255 (nbsp) properties: diff --git a/schemas/pointer/region/returndata.schema.yaml b/schemas/pointer/region/returndata.schema.yaml index 864c2ec7f..cfb2ebc16 100644 --- a/schemas/pointer/region/returndata.schema.yaml +++ b/schemas/pointer/region/returndata.schema.yaml @@ -8,7 +8,6 @@ description: | This schema is constructed by extending the base region schema and the schema for the slice addressing scheme. type: object - allOf: - title: '{ "location": "returndata" }' # note: whitespace chars are \255 (nbsp) properties: diff --git a/schemas/pointer/region/stack.schema.yaml b/schemas/pointer/region/stack.schema.yaml index fd057a6cd..64a3303d0 100644 --- a/schemas/pointer/region/stack.schema.yaml +++ b/schemas/pointer/region/stack.schema.yaml @@ -12,7 +12,6 @@ description: | This schema is constructed by extending the base region schema and the schema for the segment addressing scheme. type: object - allOf: - title: '{ "location": "stack" }' # note: whitespace chars are \255 (nbsp) properties: diff --git a/schemas/pointer/region/storage.schema.yaml b/schemas/pointer/region/storage.schema.yaml index ca912b560..6b1138fb9 100644 --- a/schemas/pointer/region/storage.schema.yaml +++ b/schemas/pointer/region/storage.schema.yaml @@ -8,7 +8,6 @@ description: | This schema is constructed by extending the base region schema and the schema for the segment addressing scheme. type: object - allOf: - title: '{ "location": "storage" }' # note: whitespace chars are \255 (nbsp) properties: diff --git a/schemas/pointer/region/transient.schema.yaml b/schemas/pointer/region/transient.schema.yaml index 287a854c4..0a74376c5 100644 --- a/schemas/pointer/region/transient.schema.yaml +++ b/schemas/pointer/region/transient.schema.yaml @@ -8,7 +8,6 @@ description: | This schema is constructed by extending the base region schema and the schema for the segment addressing scheme. type: object - allOf: - title: '{ "location": "transient" }' # note: whitespace chars are \255 (nbsp) properties: diff --git a/schemas/program/context/gather.schema.yaml b/schemas/program/context/gather.schema.yaml index 59c5768b2..23137660d 100644 --- a/schemas/program/context/gather.schema.yaml +++ b/schemas/program/context/gather.schema.yaml @@ -35,24 +35,24 @@ examples: offset: 113 length: 19 - gather: - - variables: - - identifier: x - declaration: - source: - id: 5 - range: - offset: 10 - length: 56 - type: - kind: string - - variables: - - identifier: x - declaration: - source: - id: 5 - range: - offset: 10 - length: 56 - pointer: - location: storage - slot: 0 + - variables: + - identifier: x + declaration: + source: + id: 5 + range: + offset: 10 + length: 56 + type: + kind: string + - variables: + - identifier: x + declaration: + source: + id: 5 + range: + offset: 10 + length: 56 + pointer: + location: storage + slot: 0 diff --git a/schemas/program/context/pick.schema.yaml b/schemas/program/context/pick.schema.yaml index 18cf04dd9..c36c8a9be 100644 --- a/schemas/program/context/pick.schema.yaml +++ b/schemas/program/context/pick.schema.yaml @@ -21,15 +21,15 @@ required: examples: - pick: - - code: - source: - id: 5 - range: - offset: 68 - length: 16 - - code: - source: - id: 5 - range: - offset: 132 - length: 16 + - code: + source: + id: 5 + range: + offset: 68 + length: 16 + - code: + source: + id: 5 + range: + offset: 132 + length: 16 diff --git a/schemas/type.schema.yaml b/schemas/type.schema.yaml index 6e58b06ef..51a9fd5a9 100644 --- a/schemas/type.schema.yaml +++ b/schemas/type.schema.yaml @@ -2,15 +2,13 @@ $schema: "https://json-schema.org/draft/2020-12/schema" $id: "schema:ethdebug/format/type" title: ethdebug/format/type -description: - Canonical representation for all types. +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 + description: If `kind` adheres to the set of known kinds defined by this format properties: kind: anyOf: @@ -20,8 +18,7 @@ if: then: type: object title: KnownType - description: - Then the object must adhere to exactly one known kind of type + description: Then the object must adhere to exactly one known kind of type allOf: - if: properties: @@ -49,14 +46,12 @@ else: - title: Specialized complex type `contains` field type: object if: - description: - If this object is a complex type + description: If this object is a complex type properties: class: const: complex then: - description: - Then the `contains` field must adhere to + description: Then the `contains` field must adhere to **ethdebug/format/type/wrapper** schemas, not the **ethdebug/format/type/base** equivalent. diff --git a/schemas/type/base.schema.yaml b/schemas/type/base.schema.yaml index 47b79582d..b39e8c28d 100644 --- a/schemas/type/base.schema.yaml +++ b/schemas/type/base.schema.yaml @@ -2,8 +2,7 @@ $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. +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 @@ -14,8 +13,7 @@ oneOf: $defs: ElementaryType: title: Base elementary type - description: - Represents an elementary type (one that does not compose other types) + description: Represents an elementary type (one that does not compose other types) type: object properties: class: @@ -25,8 +23,7 @@ $defs: type: string contains: not: - description: - "Elementary types **must not** specify a `contains` field + description: "Elementary types **must not** specify a `contains` field (to make it easier to discriminate elementary vs. complex)" required: - kind @@ -113,8 +110,7 @@ $defs: TypeWrapperObject: title: '{ "key": { "type": ... }, ... }' - description: - A key-value mapping of wrapped types, where the wrapper may add fields + description: A key-value mapping of wrapped types, where the wrapper may add fields type: object additionalProperties: $ref: "#/$defs/TypeWrapper" diff --git a/schemas/type/complex.schema.yaml b/schemas/type/complex.schema.yaml index d6194b0e4..c69933ff1 100644 --- a/schemas/type/complex.schema.yaml +++ b/schemas/type/complex.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Canonical representation of a complex type type: object properties: diff --git a/schemas/type/complex/alias.schema.yaml b/schemas/type/complex/alias.schema.yaml index 3c0b4730f..6e68e5eae 100644 --- a/schemas/type/complex/alias.schema.yaml +++ b/schemas/type/complex/alias.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema representing a type alias to another type type: object properties: diff --git a/schemas/type/complex/mapping.schema.yaml b/schemas/type/complex/mapping.schema.yaml index e070bc31a..8f1b0c23e 100644 --- a/schemas/type/complex/mapping.schema.yaml +++ b/schemas/type/complex/mapping.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema for representing mapping types type: object properties: diff --git a/schemas/type/complex/struct.schema.yaml b/schemas/type/complex/struct.schema.yaml index 98b7c5fb8..9affcbc29 100644 --- a/schemas/type/complex/struct.schema.yaml +++ b/schemas/type/complex/struct.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema for representing struct types type: object properties: diff --git a/schemas/type/complex/tuple.schema.yaml b/schemas/type/complex/tuple.schema.yaml index 4a282f802..70c4ed84c 100644 --- a/schemas/type/complex/tuple.schema.yaml +++ b/schemas/type/complex/tuple.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema for representing tuple types type: object properties: @@ -42,8 +41,7 @@ $defs: Element: type: object title: Element - description: - An optionally named element type within a tuple. This is an + description: An optionally named element type within a tuple. This is an **ethdebug/format/type/wrapper** with additional fields. allOf: - $ref: "schema:ethdebug/format/type/wrapper" diff --git a/schemas/type/elementary.schema.yaml b/schemas/type/elementary.schema.yaml index e2ba13012..91642bf96 100644 --- a/schemas/type/elementary.schema.yaml +++ b/schemas/type/elementary.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Canonical representation of an elementary type type: object properties: diff --git a/schemas/type/elementary/address.schema.yaml b/schemas/type/elementary/address.schema.yaml index 0a09a5f74..d38694042 100644 --- a/schemas/type/elementary/address.schema.yaml +++ b/schemas/type/elementary/address.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema describing the representation of an address type type: object properties: @@ -13,8 +12,7 @@ properties: const: address payable: type: boolean - description: - If this field is omitted, this type represents an address whose + description: If this field is omitted, this type represents an address whose payability is not known. required: - kind diff --git a/schemas/type/elementary/bool.schema.yaml b/schemas/type/elementary/bool.schema.yaml index f19a3d823..044dea73e 100644 --- a/schemas/type/elementary/bool.schema.yaml +++ b/schemas/type/elementary/bool.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema describing the representation of the boolean type type: object properties: diff --git a/schemas/type/elementary/bytes.schema.yaml b/schemas/type/elementary/bytes.schema.yaml index dcccb46e7..5fb217ad4 100644 --- a/schemas/type/elementary/bytes.schema.yaml +++ b/schemas/type/elementary/bytes.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema describing the representation of a type of bytes string (either dynamic or static) type: object diff --git a/schemas/type/elementary/contract.schema.yaml b/schemas/type/elementary/contract.schema.yaml index 16f41353b..df9090775 100644 --- a/schemas/type/elementary/contract.schema.yaml +++ b/schemas/type/elementary/contract.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema describing the representation of a contract type type: object properties: @@ -13,8 +12,7 @@ properties: const: contract payable: type: boolean - description: - If this field is omitted, this type represents an address whose + description: If this field is omitted, this type represents an address whose payability is not known. definition: $ref: "schema:ethdebug/format/type/definition" @@ -31,8 +29,7 @@ oneOf: properties: library: const: true - description: - Indicates that this is a type representing a library + description: Indicates that this is a type representing a library required: - library @@ -40,8 +37,7 @@ oneOf: properties: interface: const: true - description: - Indicates that this is a type representing an interface + description: Indicates that this is a type representing an interface required: - interface diff --git a/schemas/type/elementary/enum.schema.yaml b/schemas/type/elementary/enum.schema.yaml index 799062b33..f20a4488d 100644 --- a/schemas/type/elementary/enum.schema.yaml +++ b/schemas/type/elementary/enum.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema describing the representation of an enumerated type type: object properties: diff --git a/schemas/type/elementary/fixed.schema.yaml b/schemas/type/elementary/fixed.schema.yaml index 4740db50a..61bf0206c 100644 --- a/schemas/type/elementary/fixed.schema.yaml +++ b/schemas/type/elementary/fixed.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema describing the representation of a signed fixed decimal type type: object properties: diff --git a/schemas/type/elementary/int.schema.yaml b/schemas/type/elementary/int.schema.yaml index b912be839..fac0c378a 100644 --- a/schemas/type/elementary/int.schema.yaml +++ b/schemas/type/elementary/int.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema describing the representation of a signed integer type type: object properties: diff --git a/schemas/type/elementary/string.schema.yaml b/schemas/type/elementary/string.schema.yaml index 5b9383f08..381bfcd6e 100644 --- a/schemas/type/elementary/string.schema.yaml +++ b/schemas/type/elementary/string.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema describing the representation of a string type type: object properties: diff --git a/schemas/type/elementary/ufixed.schema.yaml b/schemas/type/elementary/ufixed.schema.yaml index 3985b6fcd..f548c20f2 100644 --- a/schemas/type/elementary/ufixed.schema.yaml +++ b/schemas/type/elementary/ufixed.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema describing the representation of an unsigned fixed decimal type type: object properties: @@ -31,4 +30,3 @@ examples: - kind: ufixed bits: 256 places: 10 - diff --git a/schemas/type/elementary/uint.schema.yaml b/schemas/type/elementary/uint.schema.yaml index 9d7f51d07..6a913e478 100644 --- a/schemas/type/elementary/uint.schema.yaml +++ b/schemas/type/elementary/uint.schema.yaml @@ -2,8 +2,7 @@ $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 +description: Schema describing the representation of an unsigned integer type type: object properties: diff --git a/schemas/type/wrapper.schema.yaml b/schemas/type/wrapper.schema.yaml index f7513f5ab..eefca6a56 100644 --- a/schemas/type/wrapper.schema.yaml +++ b/schemas/type/wrapper.schema.yaml @@ -39,8 +39,7 @@ $defs: Object: title: '{ "key": { "type": ... }, ... }' - description: - A key-value mapping of wrapped types, where the wrapper may add fields + 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/tsconfig.base.json b/tsconfig.base.json index a7e598d7a..b9f77881f 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -11,7 +11,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2020" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ @@ -25,9 +25,9 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "nodenext", /* Specify what module code is generated. */ + "module": "nodenext" /* Specify what module code is generated. */, // "rootDir": "./", /* Specify the root folder within your source files. */ - "moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "nodenext" /* Specify how TypeScript looks up a file from a given module specifier. */, // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ @@ -49,8 +49,8 @@ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ /* Emit */ - "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - "declarationMap": true, /* Create sourcemaps for d.ts files. */ + "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, + "declarationMap": true /* Create sourcemaps for d.ts files. */, // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ @@ -77,12 +77,12 @@ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ @@ -104,6 +104,6 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ } } diff --git a/vitest.config.ts b/vitest.config.ts index 3d8f15111..80379cc38 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -2,6 +2,6 @@ import { defineConfig } from "vitest/config"; export default defineConfig({ test: { - workspace: ["packages/*"] - } + workspace: ["packages/*"], + }, }); From 8629026da385083ddcd392301d9901e83bfbda2a Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 00:24:03 -0500 Subject: [PATCH 03/11] Add .git-blame-ignore-revs for formatting commits --- .git-blame-ignore-revs | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..0458e839d --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,3 @@ +# Prettier formatting +# Apply Prettier formatting +d42ac838468820243ce5bfaed89bfd686f296bee From 3774ea923b613a29f42458ca86e6b16c64a6366f Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 00:42:19 -0500 Subject: [PATCH 04/11] Add ESLint configuration --- .eslintignore | 13 ++ .eslintrc.json | 18 +++ package.json | 7 +- yarn.lock | 432 +++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 456 insertions(+), 14 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.json diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..a57f5c729 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,13 @@ +node_modules/ +dist/ +coverage/ +*.d.ts +*.config.js +*.config.ts + +# Auto-generated files +packages/format/src/schemas/yamls.ts + +# Docusaurus +packages/web/.docusaurus/ +packages/web/build/ diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..1eca16fda --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], + "rules": { + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-unused-vars": [ + "error", + { "varsIgnorePattern": "^_", "argsIgnorePattern": "^_" } + ], + "@typescript-eslint/no-namespace": "off", + "no-console": "warn" + }, + "env": { + "node": true, + "es2022": true + } +} diff --git a/package.json b/package.json index bc99f8361..6cbcf4de6 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,16 @@ "lerna": "lerna", "postinstall": "lerna run prepare", "format": "prettier --write .", - "format:check": "prettier --check ." + "format:check": "prettier --check .", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "eslint . --ext .ts,.tsx --fix" }, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^8.21.0", + "@typescript-eslint/parser": "^8.21.0", "@vitest/ui": "^3.0.5", "concurrently": "^8.2.2", + "eslint": "^8.57.1", "lerna": "^8.0.2", "prettier": "^3.4.2", "tsx": "^4.16.2", diff --git a/yarn.lock b/yarn.lock index 47c570808..d1e48489f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2731,6 +2731,38 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz#34aa0b52d0fbb1a654b596acfa595f0c7b77a77b" integrity sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg== +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595" + integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.12.2", "@eslint-community/regexpp@^4.6.1": + version "4.12.2" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + "@fortawesome/fontawesome-common-types@6.5.1": version "6.5.1" resolved "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz" @@ -2776,6 +2808,25 @@ dependencies: "@hapi/hoek" "^9.0.0" +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + "@hutson/parse-repository-url@^3.0.0": version "3.0.2" resolved "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz" @@ -3104,9 +3155,9 @@ resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" - resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: "@nodelib/fs.scandir" "2.1.5" @@ -4312,11 +4363,112 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@^8.21.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz#afb966c66a2fdc6158cf81118204a971a36d0fc5" + integrity sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg== + dependencies: + "@eslint-community/regexpp" "^4.12.2" + "@typescript-eslint/scope-manager" "8.53.0" + "@typescript-eslint/type-utils" "8.53.0" + "@typescript-eslint/utils" "8.53.0" + "@typescript-eslint/visitor-keys" "8.53.0" + ignore "^7.0.5" + natural-compare "^1.4.0" + ts-api-utils "^2.4.0" + +"@typescript-eslint/parser@^8.21.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.53.0.tgz#d8bed6f12dc74e03751e5f947510ff2b165990c6" + integrity sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg== + dependencies: + "@typescript-eslint/scope-manager" "8.53.0" + "@typescript-eslint/types" "8.53.0" + "@typescript-eslint/typescript-estree" "8.53.0" + "@typescript-eslint/visitor-keys" "8.53.0" + debug "^4.4.3" + +"@typescript-eslint/project-service@8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.53.0.tgz#327c67c61c16a1c8b12a440b0779b41eb77cc7df" + integrity sha512-Bl6Gdr7NqkqIP5yP9z1JU///Nmes4Eose6L1HwpuVHwScgDPPuEWbUVhvlZmb8hy0vX9syLk5EGNL700WcBlbg== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.53.0" + "@typescript-eslint/types" "^8.53.0" + debug "^4.4.3" + +"@typescript-eslint/scope-manager@8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.53.0.tgz#f922fcbf0d42e72f065297af31779ccf19de9a97" + integrity sha512-kWNj3l01eOGSdVBnfAF2K1BTh06WS0Yet6JUgb9Cmkqaz3Jlu0fdVUjj9UI8gPidBWSMqDIglmEXifSgDT/D0g== + dependencies: + "@typescript-eslint/types" "8.53.0" + "@typescript-eslint/visitor-keys" "8.53.0" + +"@typescript-eslint/tsconfig-utils@8.53.0", "@typescript-eslint/tsconfig-utils@^8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.0.tgz#105279d7969a7abdc8345cc9c57cff83cf910f8f" + integrity sha512-K6Sc0R5GIG6dNoPdOooQ+KtvT5KCKAvTcY8h2rIuul19vxH5OTQk7ArKkd4yTzkw66WnNY0kPPzzcmWA+XRmiA== + +"@typescript-eslint/type-utils@8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.53.0.tgz#81a0de5c01fc68f6df0591d03cd8226bda01c91f" + integrity sha512-BBAUhlx7g4SmcLhn8cnbxoxtmS7hcq39xKCgiutL3oNx1TaIp+cny51s8ewnKMpVUKQUGb41RAUWZ9kxYdovuw== + dependencies: + "@typescript-eslint/types" "8.53.0" + "@typescript-eslint/typescript-estree" "8.53.0" + "@typescript-eslint/utils" "8.53.0" + debug "^4.4.3" + ts-api-utils "^2.4.0" + +"@typescript-eslint/types@8.53.0", "@typescript-eslint/types@^8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.53.0.tgz#1adcad3fa32bc2c4cbf3785ba07a5e3151819efb" + integrity sha512-Bmh9KX31Vlxa13+PqPvt4RzKRN1XORYSLlAE+sO1i28NkisGbTtSLFVB3l7PWdHtR3E0mVMuC7JilWJ99m2HxQ== + +"@typescript-eslint/typescript-estree@8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.0.tgz#7805b46b7a8ce97e91b7bb56fc8b1ba26ca8ef52" + integrity sha512-pw0c0Gdo7Z4xOG987u3nJ8akL9093yEEKv8QTJ+Bhkghj1xyj8cgPaavlr9rq8h7+s6plUJ4QJYw2gCZodqmGw== + dependencies: + "@typescript-eslint/project-service" "8.53.0" + "@typescript-eslint/tsconfig-utils" "8.53.0" + "@typescript-eslint/types" "8.53.0" + "@typescript-eslint/visitor-keys" "8.53.0" + debug "^4.4.3" + minimatch "^9.0.5" + semver "^7.7.3" + tinyglobby "^0.2.15" + ts-api-utils "^2.4.0" + +"@typescript-eslint/utils@8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.53.0.tgz#bf0a4e2edaf1afc9abce209fc02f8cab0b74af13" + integrity sha512-XDY4mXTez3Z1iRDI5mbRhH4DFSt46oaIFsLg+Zn97+sYrXACziXSQcSelMybnVZ5pa1P6xYkPr5cMJyunM1ZDA== + dependencies: + "@eslint-community/eslint-utils" "^4.9.1" + "@typescript-eslint/scope-manager" "8.53.0" + "@typescript-eslint/types" "8.53.0" + "@typescript-eslint/typescript-estree" "8.53.0" + +"@typescript-eslint/visitor-keys@8.53.0": + version "8.53.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.0.tgz#9a785664ddae7e3f7e570ad8166e48dbc9c6cf02" + integrity sha512-LZ2NqIHFhvFwxG0qZeLL9DvdNAHPGCY5dIRwBhyYeU+LfLhcStE1ImjsuTG/WaVh3XysGaeLW8Rqq7cGkPCFvw== + dependencies: + "@typescript-eslint/types" "8.53.0" + eslint-visitor-keys "^4.2.1" + "@ungap/structured-clone@^1.0.0": version "1.2.0" resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== +"@ungap/structured-clone@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + "@vitest/expect@3.0.5": version "3.0.5" resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.0.5.tgz#aa0acd0976cf56842806e5dcaebd446543966b14" @@ -4596,9 +4748,9 @@ acorn-import-assertions@^1.9.0: resolved "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz" integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== -acorn-jsx@^5.0.0: +acorn-jsx@^5.0.0, acorn-jsx@^5.3.2: version "5.3.2" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^8.0.0: @@ -4623,6 +4775,11 @@ acorn@^8.11.0, acorn@^8.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.0.tgz#1627bfa2e058148036133b8d9b51a700663c294c" integrity sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw== +acorn@^8.9.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + add-stream@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz" @@ -4681,9 +4838,9 @@ ajv-keywords@^5.1.0: dependencies: fast-deep-equal "^3.1.3" -ajv@^6.12.2, ajv@^6.12.5: +ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" @@ -5976,6 +6133,15 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +cross-spawn@^7.0.2: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + crypto-random-string@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz" @@ -6172,6 +6338,13 @@ debug@4, debug@^4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug dependencies: ms "2.1.2" +debug@^4.3.2, debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + debug@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" @@ -6221,6 +6394,11 @@ deep-extend@^0.6.0: resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + deepmerge@^4.2.2, deepmerge@^4.3.1: version "4.3.1" resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" @@ -6379,6 +6557,13 @@ dns-packet@^5.2.2: dependencies: "@leichtgewicht/ip-codec" "^2.0.1" +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + docusaurus-json-schema-plugin@^1.12.1: version "1.12.1" resolved "https://registry.yarnpkg.com/docusaurus-json-schema-plugin/-/docusaurus-json-schema-plugin-1.12.1.tgz#7ba31b5ff4c8b4f1e78abaffec70b0ff3419d64b" @@ -6742,11 +6927,89 @@ eslint-scope@5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + +eslint@^8.57.1: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esquery@^1.4.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== + dependencies: + estraverse "^5.1.0" + esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" @@ -6759,7 +7022,7 @@ estraverse@^4.1.1: resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.2.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -6980,6 +7243,11 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + fast-memoize@^2.5.2: version "2.5.2" resolved "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz" @@ -7018,6 +7286,11 @@ fdir@^6.4.2: resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.3.tgz#011cdacf837eca9b811c89dbb902df714273db72" integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw== +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + feed@^4.2.2: version "4.2.2" resolved "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz" @@ -7037,6 +7310,13 @@ figures@3.2.0, figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + file-loader@^6.2.0: version "6.2.0" resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz" @@ -7123,11 +7403,25 @@ find-up@^6.3.0: locate-path "^7.1.0" path-exists "^5.0.0" +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + flat@^5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + flatted@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" @@ -7413,9 +7707,9 @@ glob-parent@5.1.2, glob-parent@^5.1.2, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob-parent@^6.0.1: +glob-parent@^6.0.1, glob-parent@^6.0.2: version "6.0.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== dependencies: is-glob "^4.0.3" @@ -7509,6 +7803,13 @@ globals@^11.1.0: resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + globby@11.1.0, globby@^11.0.1, globby@^11.0.4, globby@^11.1.0: version "11.1.0" resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" @@ -7566,6 +7867,11 @@ graceful-fs@4.2.11, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2 resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + gray-matter@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz" @@ -8108,6 +8414,11 @@ ignore@^5.0.4, ignore@^5.2.0, ignore@^5.2.4: resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz" integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== +ignore@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== + image-size@^1.0.2: version "1.1.1" resolved "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz" @@ -8128,6 +8439,14 @@ import-fresh@^3.1.0, import-fresh@^3.3.0: parent-module "^1.0.0" resolve-from "^4.0.0" +import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-lazy@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz" @@ -8324,9 +8643,9 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" @@ -8379,9 +8698,9 @@ is-path-cwd@^2.2.0: resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz" integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== -is-path-inside@^3.0.2: +is-path-inside@^3.0.2, is-path-inside@^3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: @@ -8655,6 +8974,11 @@ json-schema@^0.4.0: resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz" integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + json-stringify-deterministic@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/json-stringify-deterministic/-/json-stringify-deterministic-1.0.12.tgz#aaa3f907466ed01e3afd77b898d0a2b3b132820a" @@ -8864,6 +9188,14 @@ leven@^3.1.0: resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + libnpmaccess@7.0.2: version "7.0.2" resolved "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-7.0.2.tgz" @@ -8992,6 +9324,11 @@ lodash.memoize@^4.1.2: resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" @@ -9953,6 +10290,13 @@ minimatch@^9.0.0, minimatch@^9.0.1, minimatch@^9.0.3: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz" @@ -10156,6 +10500,11 @@ napi-macros@~2.0.0: resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + negotiator@0.6.3, negotiator@^0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" @@ -10601,6 +10950,18 @@ opener@^1.5.2: resolved "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + ora@^5.4.1: version "5.4.1" resolved "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz" @@ -11022,6 +11383,11 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== +picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + pify@5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz" @@ -11378,6 +11744,11 @@ postcss@^8.5.1: picocolors "^1.1.1" source-map-js "^1.2.1" +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prettier@^3.4.2: version "3.7.4" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.7.4.tgz#d2f8335d4b1cec47e1c8098645411b0c9dff9c0f" @@ -12354,6 +12725,11 @@ semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semve dependencies: lru-cache "^6.0.0" +semver@^7.7.3: + version "7.7.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== + send@0.18.0: version "0.18.0" resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" @@ -13161,6 +13537,14 @@ tinyglobby@^0.2.10: fdir "^6.4.2" picomatch "^4.0.2" +tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.3" + tinypool@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.0.2.tgz#706193cc532f4c100f66aa00b01c42173d9051b2" @@ -13244,6 +13628,11 @@ trough@^2.0.0: resolved "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz" integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== +ts-api-utils@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.4.0.tgz#2690579f96d2790253bdcf1ca35d569ad78f9ad8" + integrity sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA== + ts-morph@^22.0.0: version "22.0.0" resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-22.0.0.tgz#5532c592fb6dddae08846f12c9ab0fc590b1d42e" @@ -13313,11 +13702,23 @@ tuf-js@^2.1.0: debug "^4.3.4" make-fetch-happen "^13.0.0" +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-fest@^0.18.0: version "0.18.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz" integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.21.3: version "0.21.3" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" @@ -13961,6 +14362,11 @@ wildcard@^2.0.0: resolved "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" From 1080960d9e200e302315e8a6006312cd44fdeaa4 Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 00:57:35 -0500 Subject: [PATCH 05/11] Apply ESLint fixes and adjust configuration --- .eslintrc.json | 4 +++- bin/bundle-schema.ts | 1 - packages/format/src/describe.ts | 2 +- packages/format/src/schemas/validity.test.ts | 2 +- .../format/src/types/program/instruction.test.ts | 2 +- packages/format/src/types/program/program.test.ts | 2 +- packages/format/test/extensions.ts | 1 - packages/format/test/hyperjump.ts | 3 +-- packages/format/vitest.setup.ts | 2 +- packages/pointers/bin/run-example.ts | 2 +- packages/pointers/src/data.ts | 8 +++++--- packages/pointers/src/dereference/process.ts | 4 ++-- packages/pointers/src/evaluate.test.ts | 2 +- packages/pointers/src/evaluate.ts | 3 +-- packages/pointers/src/integration.test.ts | 2 +- packages/pointers/src/read.test.ts | 14 +++++++------- packages/pointers/src/test-cases.ts | 2 +- packages/pointers/test/examples.ts | 2 -- packages/pointers/test/solc.ts | 4 +++- .../pointers/testing/test-cases/TestedPointer.tsx | 1 - packages/web/src/components/CodeListing.tsx | 2 +- packages/web/src/components/LinkedCodeBlock.tsx | 2 +- packages/web/src/components/Playground.tsx | 14 ++++++++------ packages/web/src/components/SchemaViewer.tsx | 9 ++++----- packages/web/src/pages/home/index.tsx | 3 +-- .../SchemaConditional/schemaConditional.tsx | 3 --- .../schemaComposition/DiscriminatorSchema.tsx | 2 +- .../ExclusiveRequiredPropertiesSchema.tsx | 2 +- .../JSONSchemaViewer/components/CreateNodes.tsx | 1 - .../components/UnnecessaryComposition.tsx | 4 +--- packages/web/src/theme/ProgramExample/Details.tsx | 7 +++---- .../ProgramExample/HighlightedInstruction.tsx | 4 +--- packages/web/src/theme/ProgramExample/Opcodes.tsx | 2 +- .../src/theme/ProgramExample/SourceContents.tsx | 2 +- .../web/src/theme/ProgramExample/Variables.tsx | 2 +- packages/web/src/theme/ProgramExample/Viewer.tsx | 5 +---- .../src/theme/ShikiCodeBlock/ShikiCodeBlock.tsx | 6 +----- 37 files changed, 58 insertions(+), 75 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 1eca16fda..585cb984f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,7 +9,9 @@ { "varsIgnorePattern": "^_", "argsIgnorePattern": "^_" } ], "@typescript-eslint/no-namespace": "off", - "no-console": "warn" + "@typescript-eslint/no-empty-object-type": "off", + "no-console": "warn", + "require-yield": "off" }, "env": { "node": true, diff --git a/bin/bundle-schema.ts b/bin/bundle-schema.ts index f9aea366f..a85f11361 100644 --- a/bin/bundle-schema.ts +++ b/bin/bundle-schema.ts @@ -1,7 +1,6 @@ import { addSchema } from "@hyperjump/json-schema/draft-2020-12"; import { bundle as bundleSchema } from "@hyperjump/json-schema/bundle"; import { schemas, describeSchema } from "@ethdebug/format"; -import type { JSONSchema } from "json-schema-typed/draft-2020-12"; async function main() { const schema = { id: process.argv[2] }; // a bit brittle diff --git a/packages/format/src/describe.ts b/packages/format/src/describe.ts index 1f7e6ed17..225e94c9d 100644 --- a/packages/format/src/describe.ts +++ b/packages/format/src/describe.ts @@ -170,7 +170,7 @@ function pointToYaml(yaml: string, pointer?: SchemaPointer): string { // slice(2) because we want to remove leading #/ for (const step of pointer.slice(2).split("/")) { - // @ts-ignore + // @ts-expect-error doc.get exists at runtime doc = doc.get(step, true); if (!doc) { diff --git a/packages/format/src/schemas/validity.test.ts b/packages/format/src/schemas/validity.test.ts index 89ba2d514..ca604bb82 100644 --- a/packages/format/src/schemas/validity.test.ts +++ b/packages/format/src/schemas/validity.test.ts @@ -24,7 +24,7 @@ const printErrors = (output: OutputUnit): string => .join("\n"); describe("Valid schemas", () => { - for (const [id, schema] of Object.entries(schemas)) { + for (const [id, _schema] of Object.entries(schemas)) { it(`should include ${id}`, async () => { try { await validate(id); diff --git a/packages/format/src/types/program/instruction.test.ts b/packages/format/src/types/program/instruction.test.ts index ee4139af5..d3c7287aa 100644 --- a/packages/format/src/types/program/instruction.test.ts +++ b/packages/format/src/types/program/instruction.test.ts @@ -1,5 +1,5 @@ import { testSchemaGuards } from "../../../test/guards"; -import { Instruction, isInstruction } from "./instruction"; +import { isInstruction } from "./instruction"; testSchemaGuards("ethdebug/format/program/instruction", [ { diff --git a/packages/format/src/types/program/program.test.ts b/packages/format/src/types/program/program.test.ts index 7fdff788c..7e82206b1 100644 --- a/packages/format/src/types/program/program.test.ts +++ b/packages/format/src/types/program/program.test.ts @@ -1,5 +1,5 @@ import { testSchemaGuards } from "../../../test/guards"; -import { Program, isProgram } from "./program"; +import { isProgram } from "./program"; testSchemaGuards("ethdebug/format/program", [ { diff --git a/packages/format/test/extensions.ts b/packages/format/test/extensions.ts index 0e55322a4..7d47969fc 100644 --- a/packages/format/test/extensions.ts +++ b/packages/format/test/extensions.ts @@ -1,4 +1,3 @@ -import { schemas } from "../src"; export const schemaExtensions: { [schemaId: string]: { diff --git a/packages/format/test/hyperjump.ts b/packages/format/test/hyperjump.ts index 1c6aee7ac..de5c3e7e0 100644 --- a/packages/format/test/hyperjump.ts +++ b/packages/format/test/hyperjump.ts @@ -4,9 +4,8 @@ import { validate, setMetaSchemaOutputFormat, } from "@hyperjump/json-schema/draft-2020-12"; -// @ts-ignore +// @ts-expect-error no types for experimental export import { BASIC } from "@hyperjump/json-schema/experimental"; -import { bundle } from "@hyperjump/json-schema/bundle"; import * as YAML from "yaml"; import indentString from "indent-string"; import { highlight } from "cli-highlight"; diff --git a/packages/format/vitest.setup.ts b/packages/format/vitest.setup.ts index 3b099a359..be78f7e01 100644 --- a/packages/format/vitest.setup.ts +++ b/packages/format/vitest.setup.ts @@ -37,7 +37,7 @@ expect.extend({ .map( (result) => ` ${result.pass ? chalk.green("✓") : chalk.red("✗")} ${ - // @ts-ignore + // @ts-expect-error this.utils exists in vitest matcher context this.utils.printReceived(result.value) }`, ) diff --git a/packages/pointers/bin/run-example.ts b/packages/pointers/bin/run-example.ts index 7a2dccb47..f3e6a3468 100644 --- a/packages/pointers/bin/run-example.ts +++ b/packages/pointers/bin/run-example.ts @@ -2,7 +2,7 @@ import chalk from "chalk"; import { highlight } from "cli-highlight"; import { describeSchema } from "@ethdebug/format"; -import { type Cursor, Data } from "../src/index.js"; +import "../src/index.js"; import { observeTrace } from "../test/index.js"; diff --git a/packages/pointers/src/data.ts b/packages/pointers/src/data.ts index 470e83d12..093c4c4d0 100644 --- a/packages/pointers/src/data.ts +++ b/packages/pointers/src/data.ts @@ -5,7 +5,9 @@ import type * as Util from "util"; let util: typeof Util | undefined; try { util = await import("util"); -} catch {} +} catch { + // util is not available in browser environments +} export class Data extends Uint8Array { static zero(): Data { @@ -102,9 +104,9 @@ export class Data extends Uint8Array { } inspect( - depth: number, + _depth: number, options: Util.InspectOptionsStylized, - inspect: typeof Util.inspect, + _inspect: typeof Util.inspect, ): string { return `Data[${options.stylize(this.toHex(), "number")}]`; } diff --git a/packages/pointers/src/dereference/process.ts b/packages/pointers/src/dereference/process.ts index 963992622..8d4756e88 100644 --- a/packages/pointers/src/dereference/process.ts +++ b/packages/pointers/src/dereference/process.ts @@ -88,7 +88,7 @@ async function* processRegion( async function* processGroup( collection: Pointer.Collection.Group, - options: ProcessOptions, + _options: ProcessOptions, ): Process { const { group } = collection; return group.map(Memo.dereferencePointer); @@ -202,7 +202,7 @@ async function* processReference( async function* processTemplates( collection: Pointer.Collection.Templates, - options: ProcessOptions, + _options: ProcessOptions, ): Process { const { templates, in: in_ } = collection; diff --git a/packages/pointers/src/evaluate.test.ts b/packages/pointers/src/evaluate.test.ts index 82be6529b..9cf3023db 100644 --- a/packages/pointers/src/evaluate.test.ts +++ b/packages/pointers/src/evaluate.test.ts @@ -29,7 +29,7 @@ const state: Machine.State = { describe("evaluate", () => { let regions: { [identifier: string]: Cursor.Region }; let variables: { [identifier: string]: Data }; - let cursor: Cursor; + let _cursor: Cursor; let options: EvaluateOptions; beforeEach(() => { diff --git a/packages/pointers/src/evaluate.ts b/packages/pointers/src/evaluate.ts index e819d48e4..586ca729c 100644 --- a/packages/pointers/src/evaluate.ts +++ b/packages/pointers/src/evaluate.ts @@ -4,7 +4,6 @@ import { Data } from "./data.js"; import type { Cursor } from "./cursor.js"; import { read } from "./read.js"; import { keccak256 } from "ethereum-cryptography/keccak"; -import { toHex } from "ethereum-cryptography/utils"; export interface EvaluateOptions { state: Machine.State; @@ -296,7 +295,7 @@ async function evaluateRead( expression: Pointer.Expression.Read, options: EvaluateOptions, ): Promise { - const { state, regions } = options; + const { state: _state, regions } = options; const identifier = expression.$read; const region = regions[identifier]; diff --git a/packages/pointers/src/integration.test.ts b/packages/pointers/src/integration.test.ts index 7fa016ff1..4db2f8d21 100644 --- a/packages/pointers/src/integration.test.ts +++ b/packages/pointers/src/integration.test.ts @@ -1,4 +1,4 @@ -import { expect, describe, it, beforeEach } from "vitest"; +import { expect, describe, it } from "vitest"; import { observeTrace } from "../test/index.js"; import { observeTraceTests } from "./test-cases.js"; diff --git a/packages/pointers/src/read.test.ts b/packages/pointers/src/read.test.ts index 51cf1cdbc..7a037efe8 100644 --- a/packages/pointers/src/read.test.ts +++ b/packages/pointers/src/read.test.ts @@ -14,37 +14,37 @@ describe("read", () => { const state: Machine.State = { stack: { length: 50n, - peek: vitest.fn(async ({ depth, slice }) => + peek: vitest.fn(async ({ depth: _depth, slice: _slice }) => Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), ), }, memory: { - read: vitest.fn(async ({ slice }) => + read: vitest.fn(async ({ slice: _slice }) => Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88])), ), }, storage: { - read: vitest.fn(async ({ slot, slice }) => + read: vitest.fn(async ({ slot: _slot, slice: _slice }) => Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])), ), }, calldata: { - read: vitest.fn(async ({ slice }) => + read: vitest.fn(async ({ slice: _slice }) => Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), ), }, returndata: { - read: vitest.fn(async ({ slice }) => + read: vitest.fn(async ({ slice: _slice }) => Data.fromBytes(new Uint8Array([0x55, 0x66, 0x77, 0x88])), ), }, transient: { - read: vitest.fn(async ({ slot, slice }) => + read: vitest.fn(async ({ slot: _slot, slice: _slice }) => Data.fromBytes(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd])), ), }, code: { - read: vitest.fn(async ({ slice }) => + read: vitest.fn(async ({ slice: _slice }) => Data.fromBytes(new Uint8Array([0x11, 0x22, 0x33, 0x44])), ), }, diff --git a/packages/pointers/src/test-cases.ts b/packages/pointers/src/test-cases.ts index a75558fd7..ad726d4ec 100644 --- a/packages/pointers/src/test-cases.ts +++ b/packages/pointers/src/test-cases.ts @@ -153,7 +153,7 @@ const uint256ArrayMemoryTest: ObserveTraceTest = { expectedValues: [[], [1], [1, 2], [1, 2, 3]], - async observe({ regions, read }, state): Promise { + async observe({ regions, read }, _state): Promise { const items = regions.named("array-item"); return await Promise.all( diff --git a/packages/pointers/test/examples.ts b/packages/pointers/test/examples.ts index e6b2c398d..be1cb8fe8 100644 --- a/packages/pointers/test/examples.ts +++ b/packages/pointers/test/examples.ts @@ -1,7 +1,5 @@ import { type Pointer, describeSchema } from "@ethdebug/format"; -import type { CompileOptions } from "./solc.js"; - export const findExamplePointer = (() => { const { schema: { examples: examplePointers }, diff --git a/packages/pointers/test/solc.ts b/packages/pointers/test/solc.ts index 00a307841..824a8c2ee 100644 --- a/packages/pointers/test/solc.ts +++ b/packages/pointers/test/solc.ts @@ -4,7 +4,9 @@ import type * as Solc from "solc"; let solc: typeof Solc | undefined; try { solc = (await import("solc")).default; -} catch {} +} catch { + // solc not available +} /** * Organizes the sources being compiled by their path identifier, as well diff --git a/packages/web/docs/implementation-guides/pointers/testing/test-cases/TestedPointer.tsx b/packages/web/docs/implementation-guides/pointers/testing/test-cases/TestedPointer.tsx index a1ddb9cd6..f3b88a4a8 100644 --- a/packages/web/docs/implementation-guides/pointers/testing/test-cases/TestedPointer.tsx +++ b/packages/web/docs/implementation-guides/pointers/testing/test-cases/TestedPointer.tsx @@ -1,4 +1,3 @@ -import { Collapsible } from "@theme/JSONSchemaViewer/components"; import CodeBlock from "@theme/CodeBlock"; import { describeSchema } from "@ethdebug/format"; diff --git a/packages/web/src/components/CodeListing.tsx b/packages/web/src/components/CodeListing.tsx index d78baadca..81a44b5e2 100644 --- a/packages/web/src/components/CodeListing.tsx +++ b/packages/web/src/components/CodeListing.tsx @@ -57,7 +57,7 @@ export default function CodeListing({ } return ( - // @ts-ignore element seems to work even though title says it wants string + // @ts-expect-error element seems to work even though title says it wants string { - ready && validateSchema(); + if (ready) { + validateSchema(); + } }, [editorInput]); /** @@ -92,7 +94,7 @@ export default function Playground(props: PlaygroundProps): JSX.Element { const sourceMap = getParsedEditorInput(); validate(sourceMap.data); const betterErrors = betterAjvErrors({ - //@ts-ignore + // @ts-expect-error dynamic schema lookup schema: schemas[props.schema.id], data: sourceMap.data, errors: validate.errors, @@ -112,11 +114,11 @@ export default function Playground(props: PlaygroundProps): JSX.Element { ) { const model = editorRef.current?.getModel(); if (!model || !monaco) return showError("Unable to validate schema"); - let markers = []; + const markers = []; if (errors) { for (const [_, error] of Object.entries(errors)) { - let instancePath = error.path.replace("{base}", "").replace(/\./g, "/"); - let node = sourceMap.pointers[instancePath]; + const instancePath = error.path.replace("{base}", "").replace(/\./g, "/"); + const node = sourceMap.pointers[instancePath]; let message = error.message.replace("{base}", "").replace(/\./g, "/"); if (error.context.errorType == "const") { message = `Expecting a constant value of "${error.context.allowedValue}"`; diff --git a/packages/web/src/components/SchemaViewer.tsx b/packages/web/src/components/SchemaViewer.tsx index dda624e8f..3c848cd0e 100644 --- a/packages/web/src/components/SchemaViewer.tsx +++ b/packages/web/src/components/SchemaViewer.tsx @@ -9,7 +9,6 @@ import { type DescribeSchemaOptions, describeSchema } from "@ethdebug/format"; import { schemaIndex } from "@site/src/schemas"; import { SchemaContext, - type PointerSchemaIds, internalIdKey, } from "@site/src/contexts/SchemaContext"; import ReactMarkdown from "react-markdown"; @@ -20,7 +19,7 @@ export interface SchemaViewerProps extends DescribeSchemaOptions {} export default function SchemaViewer(props: SchemaViewerProps): JSX.Element { const rootSchemaInfo = describeSchema(props); - const { id, rootSchema, yaml, pointer } = rootSchemaInfo; + const { id, rootSchema, yaml: _yaml, pointer } = rootSchemaInfo; const transformedSchema = transformSchema(rootSchema, id || ""); @@ -103,7 +102,7 @@ function insertIds(obj: T, rootId: string): T { } else if (obj !== null && typeof obj === "object") { return Object.entries(obj).reduce( (newObj, [key, value]) => { - // @ts-ignore + // @ts-expect-error dynamic key assignment newObj[key] = insertIds(value, `${rootId}/${key}`); return newObj; }, @@ -151,7 +150,7 @@ function ensureRefsLackSiblings(obj: T): T { const { $ref, ...rest } = obj as T & object & { $ref?: string }; const result = Object.entries(rest).reduce((newObj, [key, value]) => { - // @ts-ignore + // @ts-expect-error dynamic key assignment newObj[key] = ensureRefsLackSiblings(value); return newObj; }, {} as T); @@ -171,7 +170,7 @@ function ensureRefsLackSiblings(obj: T): T { ); } - // @ts-ignore + // @ts-expect-error dynamic property assignment result[propertyName] = [{ $ref: $ref }]; return result; diff --git a/packages/web/src/pages/home/index.tsx b/packages/web/src/pages/home/index.tsx index 6430b645d..58290fbe4 100644 --- a/packages/web/src/pages/home/index.tsx +++ b/packages/web/src/pages/home/index.tsx @@ -3,13 +3,12 @@ import Link from "@docusaurus/Link"; import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Layout from "@theme/Layout"; import Heading from "@theme/Heading"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; // Import the FontAwesomeIcon component. import IconExternalLink from "@theme/Icon/ExternalLink"; import styles from "./index.module.css"; export default function Home(): JSX.Element { - const { siteConfig } = useDocusaurusContext(); + const { siteConfig: _siteConfig } = useDocusaurusContext(); return ( diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx index 3bc382cab..79b3571b2 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx @@ -1,6 +1,5 @@ import React from "react"; -import Translate from "@docusaurus/Translate"; import { IfElseThen, @@ -9,8 +8,6 @@ import { Dependencies, } from "@theme-original/JSONSchemaViewer/JSONSchemaElements/SchemaConditional"; -import { Collapsible } from "@theme-original/JSONSchemaViewer/components"; - type Props = { schema: any; }; diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx index 8d8c04d15..cad9822de 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx @@ -64,7 +64,7 @@ export function detectDiscriminator(schema: { return false; } - const { title, description, if: if_, then, ...others } = clause; + const { title: _title, description: _description, if: if_, then, ...others } = clause; return !!if_ && !!then && Object.keys(others).length === 0; }, diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx index 5ec676191..07bb0b081 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx @@ -118,7 +118,7 @@ export function detectExclusiveRequiredProperties(schema: { return false; } - const { title, description, if: if_, then, ...others } = clause; + const { title: _title, description: _description, if: if_, then, ...others } = clause; return !!if_ && !!then && Object.keys(others).length === 0; }, diff --git a/packages/web/src/theme/JSONSchemaViewer/components/CreateNodes.tsx b/packages/web/src/theme/JSONSchemaViewer/components/CreateNodes.tsx index 48a84dad1..b1bd4498d 100644 --- a/packages/web/src/theme/JSONSchemaViewer/components/CreateNodes.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/components/CreateNodes.tsx @@ -1,5 +1,4 @@ import React from "react"; -import CreateTypes from "@theme-original/JSONSchemaViewer/components/CreateTypes"; import CreateNodes from "@theme-original/JSONSchemaViewer/components/CreateNodes"; import { useSchemaHierarchyContext } from "@theme-original/JSONSchemaViewer/contexts"; import { diff --git a/packages/web/src/theme/JSONSchemaViewer/components/UnnecessaryComposition.tsx b/packages/web/src/theme/JSONSchemaViewer/components/UnnecessaryComposition.tsx index 0d9b2599b..8640d9a47 100644 --- a/packages/web/src/theme/JSONSchemaViewer/components/UnnecessaryComposition.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/components/UnnecessaryComposition.tsx @@ -1,9 +1,7 @@ import React from "react"; 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, @@ -199,7 +197,7 @@ function separateDocumentationFromSemantics(schema: JSONSchema): { description, examples, default: default_, - // @ts-ignore + // @ts-expect-error internal key for tracking [internalIdKey]: _id, ...semantics } = schema; diff --git a/packages/web/src/theme/ProgramExample/Details.tsx b/packages/web/src/theme/ProgramExample/Details.tsx index 6ee2f0106..68bb9cee6 100644 --- a/packages/web/src/theme/ProgramExample/Details.tsx +++ b/packages/web/src/theme/ProgramExample/Details.tsx @@ -3,14 +3,13 @@ import Link from "@docusaurus/Link"; import { Program } from "@ethdebug/format"; import { useProgramExampleContext } from "./ProgramExampleContext"; import { HighlightedInstruction } from "./HighlightedInstruction"; -import { Variables } from "./Variables"; // imported for style legend import "./SourceContents.css"; export interface Props {} -export function Details(props: Props): JSX.Element { +export function Details(_props: Props): JSX.Element { const { highlightedInstruction, highlightMode } = useProgramExampleContext(); if (highlightMode === "simple" || !highlightedInstruction) { @@ -40,7 +39,7 @@ interface InstructionAdmonitionProps { instruction: Program.Instruction; } function InstructionAdmonition({ - instruction, + instruction: _instruction, }: InstructionAdmonitionProps): JSX.Element { return ( @@ -69,7 +68,7 @@ function InstructionAdmonition({ ); } -function BasicAdmonition(props: {}): JSX.Element { +function BasicAdmonition(_props: {}): JSX.Element { return ( Select an instruction offset to see associated{" "} diff --git a/packages/web/src/theme/ProgramExample/HighlightedInstruction.tsx b/packages/web/src/theme/ProgramExample/HighlightedInstruction.tsx index 290fc86f5..8dcb4b476 100644 --- a/packages/web/src/theme/ProgramExample/HighlightedInstruction.tsx +++ b/packages/web/src/theme/ProgramExample/HighlightedInstruction.tsx @@ -1,6 +1,4 @@ -import React, { useEffect, useState } from "react"; -import Admonition from "@theme/Admonition"; -import Link from "@docusaurus/Link"; +import React from "react"; import { useProgramExampleContext } from "./ProgramExampleContext"; import { ShikiCodeBlock } from "@theme/ShikiCodeBlock"; diff --git a/packages/web/src/theme/ProgramExample/Opcodes.tsx b/packages/web/src/theme/ProgramExample/Opcodes.tsx index 3beedcf7f..7e6debc37 100644 --- a/packages/web/src/theme/ProgramExample/Opcodes.tsx +++ b/packages/web/src/theme/ProgramExample/Opcodes.tsx @@ -54,7 +54,7 @@ export function Opcodes(): JSX.Element { const handleMouseEnter = (offset: Data.Value) => setHoverOffset(offset); // skipping the current hover offset check here and assuming that the mouse // must leave the boundary of one offset before entering another - const handleMouseLeave = (offset: Data.Value) => setHoverOffset(undefined); + const handleMouseLeave = (_offset: Data.Value) => setHoverOffset(undefined); const paddingLength = instructions.at(-1)!.offset.toString(16).length; diff --git a/packages/web/src/theme/ProgramExample/SourceContents.tsx b/packages/web/src/theme/ProgramExample/SourceContents.tsx index 2d3094055..82429a604 100644 --- a/packages/web/src/theme/ProgramExample/SourceContents.tsx +++ b/packages/web/src/theme/ProgramExample/SourceContents.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React from "react"; import { ShikiCodeBlock, diff --git a/packages/web/src/theme/ProgramExample/Variables.tsx b/packages/web/src/theme/ProgramExample/Variables.tsx index 445e94459..da7099881 100644 --- a/packages/web/src/theme/ProgramExample/Variables.tsx +++ b/packages/web/src/theme/ProgramExample/Variables.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React from "react"; import Admonition from "@theme/Admonition"; import Link from "@docusaurus/Link"; import { useProgramExampleContext } from "./ProgramExampleContext"; diff --git a/packages/web/src/theme/ProgramExample/Viewer.tsx b/packages/web/src/theme/ProgramExample/Viewer.tsx index 8e4661004..94adc29f3 100644 --- a/packages/web/src/theme/ProgramExample/Viewer.tsx +++ b/packages/web/src/theme/ProgramExample/Viewer.tsx @@ -1,15 +1,12 @@ -import Admonition from "@theme/Admonition"; -import Link from "@docusaurus/Link"; import { SourceContents } from "./SourceContents"; import { Opcodes } from "./Opcodes"; import { Details } from "./Details"; -import { Variables } from "./Variables"; import "./Viewer.css"; export interface Props {} -export function Viewer(props: Props): JSX.Element { +export function Viewer(_props: Props): JSX.Element { return ( <>

Interactive example

diff --git a/packages/web/src/theme/ShikiCodeBlock/ShikiCodeBlock.tsx b/packages/web/src/theme/ShikiCodeBlock/ShikiCodeBlock.tsx index 645b7cd3a..d1319152f 100644 --- a/packages/web/src/theme/ShikiCodeBlock/ShikiCodeBlock.tsx +++ b/packages/web/src/theme/ShikiCodeBlock/ShikiCodeBlock.tsx @@ -1,9 +1,5 @@ import React from "react"; -import { - type Highlighter, - type HighlightOptions, - useHighlighter, -} from "./useHighlighter"; +import { type HighlightOptions, useHighlighter } from "./useHighlighter"; export interface Props extends HighlightOptions { code: string; From 7fc9c1ff676633e05c68d1e9f8b0196dccef61cc Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 01:03:48 -0500 Subject: [PATCH 06/11] Add ESLint fixes commit to blame ignore revs --- .git-blame-ignore-revs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 0458e839d..57ea71c32 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,3 +1,7 @@ # Prettier formatting # Apply Prettier formatting d42ac838468820243ce5bfaed89bfd686f296bee + +# ESLint fixes +# Apply ESLint fixes and adjust configuration +1080960d9e200e302315e8a6006312cd44fdeaa4 From 735a8701d3b8ca749d8986a0175b40a42d8915f6 Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 01:06:16 -0500 Subject: [PATCH 07/11] Add Husky and lint-staged pre-commit hooks --- .husky/pre-commit | 1 + package.json | 12 ++ yarn.lock | 286 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 296 insertions(+), 3 deletions(-) create mode 100644 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 000000000..2312dc587 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged diff --git a/package.json b/package.json index 6cbcf4de6..78d6fb480 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "start": "./bin/start", "lerna": "lerna", "postinstall": "lerna run prepare", + "prepare": "husky", "format": "prettier --write .", "format:check": "prettier --check .", "lint": "eslint . --ext .ts,.tsx", @@ -21,9 +22,20 @@ "@vitest/ui": "^3.0.5", "concurrently": "^8.2.2", "eslint": "^8.57.1", + "husky": "^9.1.7", "lerna": "^8.0.2", + "lint-staged": "^15.4.1", "prettier": "^3.4.2", "tsx": "^4.16.2", "vitest": "^3.0.5" + }, + "lint-staged": { + "*.{ts,tsx}": [ + "prettier --write", + "eslint --fix" + ], + "*.{json,md,yaml,yml}": [ + "prettier --write" + ] } } diff --git a/yarn.lock b/yarn.lock index d1e48489f..8753a319e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4904,6 +4904,13 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" +ansi-escapes@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.2.0.tgz#31b25afa3edd3efc09d98c2fee831d460ff06b49" + integrity sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw== + dependencies: + environment "^1.0.0" + ansi-html-community@^0.0.8: version "0.0.8" resolved "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz" @@ -4938,6 +4945,11 @@ ansi-styles@^5.0.0: resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.0.0, ansi-styles@^6.2.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" + integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== + ansi-styles@^6.1.0: version "6.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" @@ -5286,6 +5298,13 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -5549,6 +5568,11 @@ chalk@^5.0.1, chalk@^5.2.0, chalk@^5.3.0: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== +chalk@^5.4.1: + version "5.6.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.2.tgz#b1238b6e23ea337af71c7f8a295db5af0c158aea" + integrity sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" @@ -5663,6 +5687,13 @@ cli-cursor@3.1.0, cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" +cli-cursor@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38" + integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw== + dependencies: + restore-cursor "^5.0.0" + cli-highlight@^2.1.11: version "2.1.11" resolved "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz" @@ -5694,6 +5725,14 @@ cli-table3@^0.6.3: optionalDependencies: "@colors/colors" "1.5.0" +cli-truncate@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-4.0.0.tgz#6cc28a2924fee9e25ce91e973db56c7066e6172a" + integrity sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA== + dependencies: + slice-ansi "^5.0.0" + string-width "^7.0.0" + cli-width@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz" @@ -5790,9 +5829,9 @@ colord@^2.9.3: resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== -colorette@^2.0.10: +colorette@^2.0.10, colorette@^2.0.20: version "2.0.20" - resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== columnify@1.6.0: @@ -5830,6 +5869,11 @@ commander@^10.0.0: resolved "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz" integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== +commander@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46" + integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw== + commander@^2.20.0: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" @@ -6723,6 +6767,11 @@ emoji-regex-xs@^1.0.0: resolved "https://registry.yarnpkg.com/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz#e8af22e5d9dbd7f7f22d280af3d19d2aab5b0724" integrity sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg== +emoji-regex@^10.3.0: + version "10.6.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.6.0.tgz#bf3d6e8f7f8fd22a65d9703475bc0147357a6b0d" + integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" @@ -6802,6 +6851,11 @@ envinfo@7.8.1: resolved "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== + err-code@^2.0.2: version "2.0.3" resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz" @@ -7119,6 +7173,11 @@ eventemitter3@^4.0.0, eventemitter3@^4.0.4: resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + events@^3.2.0: version "3.3.0" resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" @@ -7154,6 +7213,21 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +execa@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + expect-type@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.1.0.tgz#a146e414250d13dfc49eafcfd1344a4060fa4c75" @@ -7344,6 +7418,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + finalhandler@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" @@ -7601,6 +7682,11 @@ get-caller-file@^2.0.5: resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-east-asian-width@^1.0.0, get-east-asian-width@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz#9bc4caa131702b4b61729cb7e42735bc550c9ee6" + integrity sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q== + get-intrinsic@^1.0.2, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz" @@ -7641,6 +7727,11 @@ get-stream@^6.0.0, get-stream@^6.0.1: resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + get-tsconfig@^4.7.5: version "4.7.5" resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.5.tgz#5e012498579e9a6947511ed0cd403272c7acbbaf" @@ -8359,6 +8450,11 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz" @@ -8366,6 +8462,11 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" +husky@^9.1.7: + version "9.1.7" + resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.7.tgz#d46a38035d101b46a70456a850ff4201344c0b2d" + integrity sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA== + iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" @@ -8643,6 +8744,18 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + +is-fullwidth-code-point@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz#046b2a6d4f6b156b2233d3207d4b5a9783999b98" + integrity sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ== + dependencies: + get-east-asian-width "^1.3.1" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -8764,6 +8877,11 @@ is-stream@^2.0.0: resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + is-text-path@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz" @@ -9223,6 +9341,11 @@ lilconfig@^3.1.1: resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb" integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow== +lilconfig@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4" + integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" @@ -9233,6 +9356,34 @@ lines-and-columns@~2.0.3: resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz" integrity sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A== +lint-staged@^15.4.1: + version "15.5.2" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-15.5.2.tgz#beff028fd0681f7db26ffbb67050a21ed4d059a3" + integrity sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w== + dependencies: + chalk "^5.4.1" + commander "^13.1.0" + debug "^4.4.0" + execa "^8.0.1" + lilconfig "^3.1.3" + listr2 "^8.2.5" + micromatch "^4.0.8" + pidtree "^0.6.0" + string-argv "^0.3.2" + yaml "^2.7.0" + +listr2@^8.2.5: + version "8.3.3" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-8.3.3.tgz#815fc8f738260ff220981bf9e866b3e11e8121bf" + integrity sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ== + dependencies: + cli-truncate "^4.0.0" + colorette "^2.0.20" + eventemitter3 "^5.0.1" + log-update "^6.1.0" + rfdc "^1.4.1" + wrap-ansi "^9.0.0" + load-json-file@6.2.0: version "6.2.0" resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz" @@ -9347,6 +9498,17 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" +log-update@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.1.0.tgz#1a04ff38166f94647ae1af562f4bd6a15b1b7cd4" + integrity sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w== + dependencies: + ansi-escapes "^7.0.0" + cli-cursor "^5.0.0" + slice-ansi "^7.1.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" + longest-streak@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz" @@ -10189,6 +10351,14 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" @@ -10223,6 +10393,16 @@ mimic-fn@^2.1.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== + mimic-response@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" @@ -10798,6 +10978,13 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +npm-run-path@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== + dependencies: + path-key "^4.0.0" + npmlog@^6.0.2: version "6.0.2" resolved "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz" @@ -10927,6 +11114,20 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +onetime@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60" + integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ== + dependencies: + mimic-function "^5.0.0" + oniguruma-to-es@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/oniguruma-to-es/-/oniguruma-to-es-2.3.0.tgz#35ea9104649b7c05f3963c6b3b474d964625028b" @@ -11297,6 +11498,11 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" @@ -11388,6 +11594,11 @@ picomatch@^4.0.3: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== +pidtree@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + pify@5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz" @@ -12513,6 +12724,14 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +restore-cursor@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7" + integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA== + dependencies: + onetime "^7.0.0" + signal-exit "^4.1.0" + retry@^0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" @@ -12528,6 +12747,11 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rfdc@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== + rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" @@ -12889,7 +13113,7 @@ signal-exit@3.0.7, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signal-exit@^4.0.1: +signal-exit@^4.0.1, signal-exit@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== @@ -12972,6 +13196,22 @@ slash@^4.0.0: resolved "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz" integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + +slice-ansi@^7.1.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-7.1.2.tgz#adf7be70aa6d72162d907cd0e6d5c11f507b5403" + integrity sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w== + dependencies: + ansi-styles "^6.2.1" + is-fullwidth-code-point "^5.0.0" + smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" @@ -13205,6 +13445,11 @@ std-env@^3.8.0: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.0.tgz#b56ffc1baf1a29dcc80a3bdf11d7fca7c315e7d5" integrity sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w== +string-argv@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -13232,6 +13477,15 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" +string-width@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-7.2.0.tgz#b5bb8e2165ce275d4d43476dd2700ad9091db6dc" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== + dependencies: + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" @@ -13284,6 +13538,13 @@ strip-ansi@^7.0.1: dependencies: ansi-regex "^6.0.1" +strip-ansi@^7.1.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba" + integrity sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA== + dependencies: + ansi-regex "^6.0.1" + strip-bom-string@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz" @@ -13304,6 +13565,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + strip-indent@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" @@ -14408,6 +14674,15 @@ wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: string-width "^5.0.1" strip-ansi "^7.0.1" +wrap-ansi@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz#956832dea9494306e6d209eb871643bb873d7c98" + integrity sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww== + dependencies: + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" + wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" @@ -14525,6 +14800,11 @@ yaml@^2.3.4: resolved "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz" integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== +yaml@^2.7.0: + version "2.8.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.2.tgz#5694f25eca0ce9c3e7a9d9e00ce0ddabbd9e35c5" + integrity sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A== + yargs-parser@21.1.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" From 82a4d5407e92d96a6b59eeb44d05110554f881ac Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 01:07:52 -0500 Subject: [PATCH 08/11] Add lint and format check to CI --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f34e63fb..1232ed2c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,26 @@ on: - pull_request jobs: + lint-and-format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-node@v3 + with: + node-version: 20 + cache: yarn + cache-dependency-path: yarn.lock + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Check formatting + run: yarn format:check + + - name: Lint + run: yarn lint + run-tests: runs-on: ubuntu-latest steps: From b3b53a99b599e56c0277999d9e1c0e246f669e00 Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 01:10:25 -0500 Subject: [PATCH 09/11] Apply remaining Prettier formatting fixes --- packages/format/test/extensions.ts | 1 - packages/web/src/components/Playground.tsx | 4 +++- packages/web/src/components/SchemaViewer.tsx | 5 +---- .../SchemaConditional/schemaConditional.tsx | 1 - .../schemaComposition/DiscriminatorSchema.tsx | 8 +++++++- .../ExclusiveRequiredPropertiesSchema.tsx | 8 +++++++- 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/format/test/extensions.ts b/packages/format/test/extensions.ts index 7d47969fc..20e07ec7d 100644 --- a/packages/format/test/extensions.ts +++ b/packages/format/test/extensions.ts @@ -1,4 +1,3 @@ - export const schemaExtensions: { [schemaId: string]: { extends: Set; diff --git a/packages/web/src/components/Playground.tsx b/packages/web/src/components/Playground.tsx index 80566cfc2..9a810fa80 100644 --- a/packages/web/src/components/Playground.tsx +++ b/packages/web/src/components/Playground.tsx @@ -117,7 +117,9 @@ export default function Playground(props: PlaygroundProps): JSX.Element { const markers = []; if (errors) { for (const [_, error] of Object.entries(errors)) { - const instancePath = error.path.replace("{base}", "").replace(/\./g, "/"); + const instancePath = error.path + .replace("{base}", "") + .replace(/\./g, "/"); const node = sourceMap.pointers[instancePath]; let message = error.message.replace("{base}", "").replace(/\./g, "/"); if (error.context.errorType == "const") { diff --git a/packages/web/src/components/SchemaViewer.tsx b/packages/web/src/components/SchemaViewer.tsx index 3c848cd0e..db803ddef 100644 --- a/packages/web/src/components/SchemaViewer.tsx +++ b/packages/web/src/components/SchemaViewer.tsx @@ -7,10 +7,7 @@ import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import { type DescribeSchemaOptions, describeSchema } from "@ethdebug/format"; import { schemaIndex } from "@site/src/schemas"; -import { - SchemaContext, - internalIdKey, -} from "@site/src/contexts/SchemaContext"; +import { SchemaContext, internalIdKey } from "@site/src/contexts/SchemaContext"; import ReactMarkdown from "react-markdown"; import SchemaListing from "./SchemaListing"; import Playground from "./Playground"; diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx index 79b3571b2..cc6b36bfa 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/SchemaConditional/schemaConditional.tsx @@ -1,6 +1,5 @@ import React from "react"; - import { IfElseThen, DependentRequired, diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx index cad9822de..7fac7cbdc 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/DiscriminatorSchema.tsx @@ -64,7 +64,13 @@ export function detectDiscriminator(schema: { return false; } - const { title: _title, description: _description, if: if_, then, ...others } = clause; + const { + title: _title, + description: _description, + if: if_, + then, + ...others + } = clause; return !!if_ && !!then && Object.keys(others).length === 0; }, diff --git a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx index 07bb0b081..c5a38d2ad 100644 --- a/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx +++ b/packages/web/src/theme/JSONSchemaViewer/JSONSchemaElements/schemaComposition/ExclusiveRequiredPropertiesSchema.tsx @@ -118,7 +118,13 @@ export function detectExclusiveRequiredProperties(schema: { return false; } - const { title: _title, description: _description, if: if_, then, ...others } = clause; + const { + title: _title, + description: _description, + if: if_, + then, + ...others + } = clause; return !!if_ && !!then && Object.keys(others).length === 0; }, From d3374a98234847314e03e3d595288efcfe090184 Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 01:10:50 -0500 Subject: [PATCH 10/11] Add formatting fix commit to blame ignore revs --- .git-blame-ignore-revs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 57ea71c32..6fdb9e400 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -5,3 +5,7 @@ d42ac838468820243ce5bfaed89bfd686f296bee # ESLint fixes # Apply ESLint fixes and adjust configuration 1080960d9e200e302315e8a6006312cd44fdeaa4 + +# Additional Prettier formatting +# Apply remaining Prettier formatting fixes +b3b53a99b599e56c0277999d9e1c0e246f669e00 From 18ccd99ca59609ff58310de6c87abf9e04391c08 Mon Sep 17 00:00:00 2001 From: "g. nicholas d'andrea" Date: Tue, 13 Jan 2026 01:47:09 -0500 Subject: [PATCH 11/11] Ignore example.mdx in Prettier (contains embedded source code) --- .prettierignore | 3 + packages/web/spec/program/example.mdx | 205 +++++++++++++------------- 2 files changed, 102 insertions(+), 106 deletions(-) diff --git a/.prettierignore b/.prettierignore index 0909188c0..ad23bcd4d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -12,3 +12,6 @@ packages/format/src/schemas/yamls.ts # Docusaurus build output packages/web/.docusaurus/ packages/web/build/ + +# Contains embedded source code with specific formatting for findSourceRange +packages/web/spec/program/example.mdx diff --git a/packages/web/spec/program/example.mdx b/packages/web/spec/program/example.mdx index 021a17257..b3c17892f 100644 --- a/packages/web/spec/program/example.mdx +++ b/packages/web/spec/program/example.mdx @@ -2,13 +2,7 @@ sidebar_position: 3 --- -import { - ProgramExampleContextProvider, - useProgramExampleContext, - SourceContents, - Opcodes, - Viewer, -} from "@theme/ProgramExample"; +import { ProgramExampleContextProvider, useProgramExampleContext, SourceContents, Opcodes, Viewer } from "@theme/ProgramExample"; # Example program @@ -22,109 +16,109 @@ import { // define storage layout to include variable // at slot 0 storage { -[0] storedValue: uint256; + [0] storedValue: uint256; } // runtime logic code { -// require fee for incrementing -if (msg.callvalue < 3 finney) { -return; -} + // require fee for incrementing + if (msg.callvalue < 3 finney) { + return; + } -let localValue = storedValue + 1; -storedValue = localValue; -return; + let localValue = storedValue + 1; + storedValue = localValue; + return; } `}]} -instructions={[ -{ -operation: { -mnemonic: "PUSH6", -arguments: ["0x02ba7def3000"], -}, -context: ({ findSourceRange }) => ({ -code: findSourceRange("3 finney"), -variables: [{ -identifier: "storedValue", -type: { -kind: "uint", -bits: 256 -}, -pointer: { -location: "storage", -slot: 0 -}, -declaration: findSourceRange("[0] storedValue: uint256") -}], -remark: "hexadecimal for 3 finney" -}) -}, -{ -operation: { -mnemonic: "CALLVALUE" -}, -context: ({ findSourceRange }) => ({ -code: findSourceRange("msg.callvalue"), -variables: [{ -identifier: "storedValue", -type: { -kind: "uint", -bits: 256 -}, -pointer: { -location: "storage", -slot: 0 -}, -declaration: findSourceRange("[0] storedValue: uint256") -}], -}) -}, -{ -operation: { -mnemonic: "LT" -}, -context: ({ findSourceRange }) => ({ -code: findSourceRange("msg.callvalue < 3 finney"), -variables: [{ -identifier: "storedValue", -type: { -kind: "uint", -bits: 256 -}, -pointer: { -location: "storage", -slot: 0 -}, -declaration: findSourceRange("[0] storedValue: uint256") -}], -}) -}, -{ -operation: { -mnemonic: "PUSH1", -arguments: ["0x13"] -}, -context: ({ findSourceRange }) => ({ -code: findSourceRange("if (msg.callvalue < 3 finney) {\n return;\n }"), -variables: [{ -identifier: "storedValue", -type: { -kind: "uint", -bits: 256 -}, -pointer: { -location: "storage", -slot: 0 -}, -declaration: findSourceRange("[0] storedValue: uint256") -}], -}) -}, -{ -operation: { -mnemonic: "JUMPI" -}, + instructions={[ + { + operation: { + mnemonic: "PUSH6", + arguments: ["0x02ba7def3000"], + }, + context: ({ findSourceRange }) => ({ + code: findSourceRange("3 finney"), + variables: [{ + identifier: "storedValue", + type: { + kind: "uint", + bits: 256 + }, + pointer: { + location: "storage", + slot: 0 + }, + declaration: findSourceRange("[0] storedValue: uint256") + }], + remark: "hexadecimal for 3 finney" + }) + }, + { + operation: { + mnemonic: "CALLVALUE" + }, + context: ({ findSourceRange }) => ({ + code: findSourceRange("msg.callvalue"), + variables: [{ + identifier: "storedValue", + type: { + kind: "uint", + bits: 256 + }, + pointer: { + location: "storage", + slot: 0 + }, + declaration: findSourceRange("[0] storedValue: uint256") + }], + }) + }, + { + operation: { + mnemonic: "LT" + }, + context: ({ findSourceRange }) => ({ + code: findSourceRange("msg.callvalue < 3 finney"), + variables: [{ + identifier: "storedValue", + type: { + kind: "uint", + bits: 256 + }, + pointer: { + location: "storage", + slot: 0 + }, + declaration: findSourceRange("[0] storedValue: uint256") + }], + }) + }, + { + operation: { + mnemonic: "PUSH1", + arguments: ["0x13"] + }, + context: ({ findSourceRange }) => ({ + code: findSourceRange("if (msg.callvalue < 3 finney) {\n return;\n }"), + variables: [{ + identifier: "storedValue", + type: { + kind: "uint", + bits: 256 + }, + pointer: { + location: "storage", + slot: 0 + }, + declaration: findSourceRange("[0] storedValue: uint256") + }], + }) + }, + { + operation: { + mnemonic: "JUMPI" + }, context: ({ findSourceRange }) => ({ code: findSourceRange("if (msg.callvalue < 3 finney) {\n return;\n }"), @@ -298,11 +292,10 @@ mnemonic: "JUMPI" ] }) } - -]} - + ]} > + This page helps illustrate the program schema's [key concepts](/spec/program/concepts) by offering a fictional pseudo-code example and its hypothetical compiled program.