From 71578d6aa5b5f2000e2eff2d5f358264de0332c2 Mon Sep 17 00:00:00 2001 From: Denis Badurina Date: Fri, 13 Jan 2023 16:27:20 +0100 Subject: [PATCH] style: use the guild's shared config for eslint and prettier (#1031) * add eslint and use the guild shared config * prettier * eslint * node protocol for imports not ready yet --- .eslintignore | 9 + .eslintrc.cjs | 17 + .github/ISSUE_TEMPLATE/config.yml | 4 +- .github/workflows/ci.yml | 8 +- .prettierrc.cjs | 1 + .prettierrc.json | 7 - CONTRIBUTING.md | 15 +- NEWS.md | 43 +- README.md | 55 +- examples/basic-event-handlers/README.md | 3 +- .../migrations/1_initial_migration.js | 6 +- .../migrations/2_deploy_contract.js | 6 +- .../migrations/3_create_gravatars.js | 14 +- .../migrations/4_update_gravatars.js | 12 +- examples/basic-event-handlers/package.json | 16 +- examples/basic-event-handlers/src/mapping.ts | 24 +- .../basic-event-handlers/test/handlers.js | 62 +- examples/basic-event-handlers/truffle.js | 14 +- examples/example-subgraph/package.json | 4 +- examples/example-subgraph/src/mapping.ts | 470 ++-- package.json | 35 +- packages/cli/CHANGELOG.md | 8 +- packages/cli/babel.config.js | 2 +- packages/cli/jest.config.js | 2 +- packages/cli/package.json | 18 +- packages/cli/src/bin.ts | 5 +- packages/cli/src/cli.ts | 24 +- packages/cli/src/codegen/schema.test.ts | 94 +- packages/cli/src/codegen/schema.ts | 177 +- packages/cli/src/codegen/template.ts | 32 +- packages/cli/src/codegen/types/conversions.ts | 50 +- packages/cli/src/codegen/types/index.test.ts | 922 ++++---- packages/cli/src/codegen/types/index.ts | 74 +- packages/cli/src/codegen/typescript.ts | 150 +- packages/cli/src/codegen/util.test.ts | 26 +- packages/cli/src/codegen/util.ts | 43 +- packages/cli/src/command-helpers/abi.ts | 82 +- packages/cli/src/command-helpers/auth.ts | 57 +- packages/cli/src/command-helpers/compiler.ts | 48 +- .../cli/src/command-helpers/data-sources.ts | 26 +- packages/cli/src/command-helpers/fs.ts | 6 +- packages/cli/src/command-helpers/gluegun.ts | 22 +- .../src/command-helpers/ipfs-http-client.d.ts | 2 +- packages/cli/src/command-helpers/ipfs.ts | 4 +- packages/cli/src/command-helpers/jsonrpc.ts | 24 +- .../cli/src/command-helpers/network.test.ts | 86 +- packages/cli/src/command-helpers/network.ts | 110 +- packages/cli/src/command-helpers/node.ts | 42 +- packages/cli/src/command-helpers/scaffold.ts | 156 +- packages/cli/src/command-helpers/spinner.ts | 50 +- .../cli/src/command-helpers/studio.test.ts | 30 +- packages/cli/src/command-helpers/studio.ts | 18 +- packages/cli/src/command-helpers/subgraph.ts | 19 +- .../cli/src/command-helpers/version.test.ts | 122 +- packages/cli/src/command-helpers/version.ts | 61 +- packages/cli/src/commands/add.ts | 226 +- packages/cli/src/commands/auth.ts | 104 +- .../cli/src/commands/binary-install-raw.d.ts | 2 +- packages/cli/src/commands/build.ts | 117 +- packages/cli/src/commands/codegen.ts | 124 +- packages/cli/src/commands/create.ts | 97 +- packages/cli/src/commands/deploy.ts | 284 ++- packages/cli/src/commands/init.ts | 689 +++--- packages/cli/src/commands/local.ts | 394 ++-- packages/cli/src/commands/remove.ts | 97 +- packages/cli/src/commands/test.ts | 288 ++- packages/cli/src/compiler/asc.ts | 52 +- packages/cli/src/compiler/index.ts | 546 ++--- packages/cli/src/debug.ts | 14 +- packages/cli/src/migrations.ts | 31 +- .../migrations/mapping_api_version_0_0_1.ts | 36 +- .../migrations/mapping_api_version_0_0_2.ts | 36 +- .../migrations/mapping_api_version_0_0_3.ts | 36 +- .../migrations/mapping_api_version_0_0_4.ts | 36 +- .../migrations/mapping_api_version_0_0_5.ts | 36 +- .../cli/src/migrations/spec_version_0_0_2.ts | 30 +- .../cli/src/migrations/spec_version_0_0_3.ts | 14 +- .../cli/src/migrations/util/load-manifest.ts | 11 +- packages/cli/src/migrations/util/versions.ts | 25 +- .../protocols/arweave/scaffold/manifest.ts | 4 +- .../src/protocols/arweave/scaffold/mapping.ts | 2 +- .../cli/src/protocols/arweave/subgraph.ts | 20 +- packages/cli/src/protocols/contract.ts | 6 +- .../src/protocols/cosmos/scaffold/manifest.ts | 4 +- .../src/protocols/cosmos/scaffold/mapping.ts | 2 +- packages/cli/src/protocols/cosmos/subgraph.ts | 20 +- packages/cli/src/protocols/ethereum/abi.ts | 111 +- .../protocols/ethereum/codegen/abi.test.ts | 192 +- .../cli/src/protocols/ethereum/codegen/abi.ts | 418 ++-- .../protocols/ethereum/codegen/template.ts | 16 +- .../cli/src/protocols/ethereum/contract.ts | 15 +- .../protocols/ethereum/scaffold/manifest.ts | 18 +- .../protocols/ethereum/scaffold/mapping.ts | 12 +- .../cli/src/protocols/ethereum/subgraph.ts | 108 +- .../src/protocols/ethereum/type-generator.ts | 132 +- packages/cli/src/protocols/index.ts | 181 +- .../protocols/ipfs/codegen/file_template.ts | 18 +- packages/cli/src/protocols/near/contract.ts | 27 +- .../src/protocols/near/scaffold/manifest.ts | 6 +- .../src/protocols/near/scaffold/mapping.ts | 2 +- packages/cli/src/protocols/near/subgraph.ts | 20 +- packages/cli/src/protocols/subgraph.ts | 12 +- .../protocols/substreams/scaffold/manifest.ts | 4 +- .../cli/src/protocols/substreams/subgraph.ts | 20 +- packages/cli/src/scaffold/cosmos.test.ts | 24 +- packages/cli/src/scaffold/ethereum.test.ts | 249 +- packages/cli/src/scaffold/index.ts | 109 +- packages/cli/src/scaffold/mapping.ts | 22 +- packages/cli/src/scaffold/near.test.ts | 24 +- packages/cli/src/scaffold/schema.ts | 49 +- packages/cli/src/scaffold/tests.ts | 122 +- packages/cli/src/schema.ts | 22 +- packages/cli/src/subgraph.ts | 193 +- packages/cli/src/type-generator.ts | 256 +-- packages/cli/src/validation/contract.ts | 52 +- packages/cli/src/validation/index.ts | 8 +- packages/cli/src/validation/manifest.ts | 131 +- packages/cli/src/validation/schema.test.ts | 44 +- packages/cli/src/validation/schema.ts | 475 ++-- packages/cli/src/watcher.ts | 90 +- packages/cli/tests/cli/globalSetup.ts | 10 +- packages/cli/tests/cli/globalTeardown.ts | 10 +- packages/cli/tests/cli/init.test.ts | 40 +- packages/cli/tests/cli/spawn-command.d.ts | 9 +- packages/cli/tests/cli/util.ts | 94 +- packages/cli/tests/cli/validation.test.ts | 78 +- pnpm-lock.yaml | 2004 ++++++++++++++++- 127 files changed, 6789 insertions(+), 5438 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.cjs create mode 100644 .prettierrc.cjs delete mode 100644 .prettierrc.json diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..5d41b78e --- /dev/null +++ b/.eslintignore @@ -0,0 +1,9 @@ +node_modules +dist +build +generated +packages/cli/tests/cli/init +packages/cli/tests/cli/validation + +# TODO: cleanup examples and lint +examples diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 00000000..9304cd1a --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,17 @@ +module.exports = { + extends: ['@theguild'], + rules: { + // not necessary here, we dont build with bob + 'import/extensions': 'off', + // pushing to array multiple times is not a big deal + 'unicorn/no-array-push-push': 'off', + // TODO: warning for now, clean up + '@typescript-eslint/no-this-alias': 'warn', + // TODO: remove default exports, breaking change? + 'import/no-default-export': 'off', + // TODO: remove once we get rid of all anys + '@typescript-eslint/no-explicit-any': 'off', + // TODO: not ready yet + 'unicorn/prefer-node-protocol': 'off', + }, +}; diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d5feb964..a057f384 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,4 +2,6 @@ blank_issues_enabled: false contact_links: - name: Have a question? url: https://discord.gg/vtvv7FP - about: Not sure about something? need help from the community? have a question to our team? please ask and answer questions here. + about: + Not sure about something? need help from the community? have a question to our team? please + ask and answer questions here. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4034d23..f9bc6cb7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,9 @@ jobs: uses: actions/cache@v3 with: path: ${{ steps.pnpm-store.outputs.PATH }} - key: ${{ runner.os }}-pnpm-store-graphql-v${{ matrix.graphql-version }}-${{ hashFiles('**/pnpm-lock.yaml') }} + key: + ${{ runner.os }}-pnpm-store-graphql-v${{ matrix.graphql-version }}-${{ + hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm-store-graphql-v${{ matrix.graphql-version }}- @@ -88,7 +90,9 @@ jobs: uses: actions/cache@v3 with: path: ${{ steps.pnpm-store.outputs.PATH }} - key: ${{ runner.os }}-pnpm-store-graphql-v${{ matrix.graphql-version }}-${{ hashFiles('**/pnpm-lock.yaml') }} + key: + ${{ runner.os }}-pnpm-store-graphql-v${{ matrix.graphql-version }}-${{ + hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm-store-graphql-v${{ matrix.graphql-version }}- diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 00000000..fc5ea06f --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1 @@ +module.exports = require('@theguild/prettier-config'); diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index dce2fc20..00000000 --- a/.prettierrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "semi": false, - "trailingComma": "all", - "printWidth": 90, - "singleQuote": true, - "arrowParens": "avoid" -} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f4e81796..1f8a818b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,15 +2,20 @@ Welcome to the Graph Protocol! Thanks a ton for your interest in contributing. -If you run into any problems feel free to create an issue. PRs are much appreciated for simple things. If it's something more complex we'd appreciate having a quick chat in GitHub Issues or Discord. +If you run into any problems feel free to create an issue. PRs are much appreciated for simple +things. If it's something more complex we'd appreciate having a quick chat in GitHub Issues or +Discord. Join the conversation on our [Discord](https://discord.gg/9a5VCua). -Please follow the [Code of Conduct](https://github.com/graphprotocol/graph-node/blob/master/CODE_OF_CONDUCT.md) for all the communications and at events. Thank you! +Please follow the +[Code of Conduct](https://github.com/graphprotocol/graph-node/blob/master/CODE_OF_CONDUCT.md) for +all the communications and at events. Thank you! ## Commit messages -We use the following format for commit messages: -`{component-name}: {Brief description of changes}`, for example: `cli: Print stacktrace of codegen errors`. +We use the following format for commit messages: `{component-name}: {Brief description of changes}`, +for example: `cli: Print stacktrace of codegen errors`. -If multiple components are being changed list them all like this: `src/cli, src/runtime: Fix accessing EthereumEvent params` +If multiple components are being changed list them all like this: +`src/cli, src/runtime: Fix accessing EthereumEvent params` diff --git a/NEWS.md b/NEWS.md index 641f0a71..3039fa4a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,9 +1,8 @@ # NEWS -Note: This file only includes short summaries of the changes introduced in -each release. More detailed release notes can be found in the -[graph-node](https://github.com/graphprotocol/graph-node/tree/master/NEWS.md) -repo. +Note: This file only includes short summaries of the changes introduced in each release. More +detailed release notes can be found in the +[graph-node](https://github.com/graphprotocol/graph-node/tree/master/NEWS.md) repo. ## Unreleased @@ -17,8 +16,7 @@ repo. - Allow specifying a graft base in the manifest. - Fix `Value is not a XYZ` errors for null values. - Fix path lookups in compiler script (thanks @fubhy!). -- Add support for yarn workspaces and otherwise hoisted node modules (thanks - @fubhy!). +- Add support for yarn workspaces and otherwise hoisted node modules (thanks @fubhy!). - Fix validating call handlers for functions with tuple parameters (#500). - Properly unfold tuple event/call parameters in signatures. - Pass `--debug` to AssemblyScript compiler. @@ -28,13 +26,13 @@ repo. ### Feature: `graph test` (#414, #420, #421) -This release introduces a new `graph test` command that can be used to run -test commands against a (customizable) test environment (by default: Graph -Node, Postgres, IPFS and Ganache in Docker Compose). +This release introduces a new `graph test` command that can be used to run test commands against a +(customizable) test environment (by default: Graph Node, Postgres, IPFS and Ganache in Docker +Compose). -This essentially provides a framework for writing integration tests, where a -subgraph is indexed against a fresh Graph node, tests can wait for it to -synced, run queries at specific blocks and so on. +This essentially provides a framework for writing integration tests, where a subgraph is indexed +against a fresh Graph node, tests can wait for it to synced, run queries at specific blocks and so +on. ``` graph test [options] @@ -52,29 +50,24 @@ Options: --node-logs Print the Graph Node logs (optional) ``` -The `` can be anything: it can be a shell script that builds -and deploys a subgraph, it can be a JS test suite run with Jest or it can be -a Truffle test suite, run with `truffle test`. +The `` can be anything: it can be a shell script that builds and deploys a subgraph, +it can be a JS test suite run with Jest or it can be a Truffle test suite, run with `truffle test`. -Overriding the `--node-image` allows to use a custom build of Graph Node, -which is useful for running integration tests for specific versions of Graph -Node. +Overriding the `--node-image` allows to use a custom build of Graph Node, which is useful for +running integration tests for specific versions of Graph Node. -Overriding the `--compose-file` allows to e.g. use a different Ethereum -provider than the default Ganache, making it possible to test subgraphs -against mainnet for instance. +Overriding the `--compose-file` allows to e.g. use a different Ethereum provider than the default +Ganache, making it possible to test subgraphs against mainnet for instance. ### Misc - Fix codegen for tuple arrays (#455 via #456). Thanks @JamesLefrere! - Add `createWithContext()` code generation for data source templates (#446). -- Fix building in situations where `subgraph.yaml` is not in the working - directory (#443). +- Fix building in situations where `subgraph.yaml` is not in the working directory (#443). - Add validation for new `@fulltext` directive (#433). - Fix `URL` not being defined in older Node.js versions (#422). - Add auto-migration from `apiVersion` 0.0.3 to 0.0.4 (#418). - Fix Entity field getters for nullable fields (#417). - Add support for overloaded Ethereum contract functions (#415). - Update code generation to dedicated `ethereum` module in graph-ts (#409). -- Dependency updates: docker-compose, handlebars, jest, tern, keytar, - request. +- Dependency updates: docker-compose, handlebars, jest, tern, keytar, request. diff --git a/README.md b/README.md index 3f1168e5..c5e10a85 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,16 @@ As of today, the command line interface supports the following commands: - `graph remove` — Unregisters a subgraph name with a Graph Node. - `graph codegen` — Generates AssemblyScript types for smart contract ABIs and the subgraph schema. - `graph build` — Compiles a subgraph to WebAssembly. -- `graph deploy` — Deploys a subgraph to a [Graph Node](https://github.com/graphprotocol/graph-node). -- `graph auth` — Stores a [Graph Node](https://github.com/graphprotocol/graph-node) access token in the system's keychain. -- `graph local` — Runs tests against a [Graph Node](https://github.com/graphprotocol/graph-node) test environment (using Ganache by default). -- `graph test` — Downloads and runs the [Matchstick](https://github.com/LimeChain/matchstick) rust binary in order to test a subgraph. -- `graph add` - Adds a new datasource to the yaml file and writes the necessary changes to other files - schema.graphql, abi and mapping. +- `graph deploy` — Deploys a subgraph to a + [Graph Node](https://github.com/graphprotocol/graph-node). +- `graph auth` — Stores a [Graph Node](https://github.com/graphprotocol/graph-node) access token in + the system's keychain. +- `graph local` — Runs tests against a [Graph Node](https://github.com/graphprotocol/graph-node) + test environment (using Ganache by default). +- `graph test` — Downloads and runs the [Matchstick](https://github.com/LimeChain/matchstick) rust + binary in order to test a subgraph. +- `graph add` - Adds a new datasource to the yaml file and writes the necessary changes to other + files - schema.graphql, abi and mapping. ## How It Works @@ -26,7 +31,9 @@ The Graph CLI takes a subgraph manifest (defaults to `subgraph.yaml`) with refer - Smart contract ABIs, and - Mappings written in AssemblyScript. -It compiles the mappings to WebAssembly, builds a ready-to-use version of the subgraph saved to IPFS or a local directory for debugging, and deploys the subgraph to a [Graph Node](https://github.com/graphprotocol/graph-node). +It compiles the mappings to WebAssembly, builds a ready-to-use version of the subgraph saved to IPFS +or a local directory for debugging, and deploys the subgraph to a +[Graph Node](https://github.com/graphprotocol/graph-node). ## Installation @@ -42,7 +49,8 @@ yarn global add @graphprotocol/graph-cli ### On Linux -`libsecret` is used for storing access tokens, so you may need to install it before getting started. Use one of the following commands depending on your distribution: +`libsecret` is used for storing access tokens, so you may need to install it before getting started. +Use one of the following commands depending on your distribution: - Debian/Ubuntu: `sudo apt-get install libsecret-1-dev` - Red Hat: `sudo yum install libsecret-devel` @@ -50,16 +58,25 @@ yarn global add @graphprotocol/graph-cli ## Getting Started -The Graph CLI can be used with a local or self-hosted [Graph Node](https://github.com/graphprotocol/graph-node) or with the [Hosted Service](https://thegraph.com/explorer/). To help you get going, there are [quick start guides](https://thegraph.com/docs/en/developer/quick-start/) available for both. +The Graph CLI can be used with a local or self-hosted +[Graph Node](https://github.com/graphprotocol/graph-node) or with the +[Hosted Service](https://thegraph.com/explorer/). To help you get going, there are +[quick start guides](https://thegraph.com/docs/en/developer/quick-start/) available for both. -If you are ready to dive into the details of building a subgraph from scratch, there is a [detailed walkthrough](https://thegraph.com/docs/en/developer/create-subgraph-hosted/) for that as well, along with API documentation for the [AssemblyScript API](https://thegraph.com/docs/en/developer/assemblyscript-api/). +If you are ready to dive into the details of building a subgraph from scratch, there is a +[detailed walkthrough](https://thegraph.com/docs/en/developer/create-subgraph-hosted/) for that as +well, along with API documentation for the +[AssemblyScript API](https://thegraph.com/docs/en/developer/assemblyscript-api/). ## Release process -We use `changeset` to manage releases. Every PR should include a changeset file. The release process is as follows: +We use `changeset` to manage releases. Every PR should include a changeset file. The release process +is as follows: -1. Author creates the PR with changes and runs `pnpm changeset` to create a changeset file to summarize the changes. -2. When the PR is merged to `main`, a Github Action will run and create a PR with the version bump and changelog. +1. Author creates the PR with changes and runs `pnpm changeset` to create a changeset file to + summarize the changes. +2. When the PR is merged to `main`, a Github Action will run and create a PR with the version bump + and changelog. 3. We will merge the bot generated PR to `main`. 4. A Github Action will run and publish the new version to npm. @@ -71,7 +88,8 @@ Helpful links: ### Stable release example -When PRs are merged and to `main` we can choose to merge the bot generated changeset PR to `main` and it will publish a new version to npm. +When PRs are merged and to `main` we can choose to merge the bot generated changeset PR to `main` +and it will publish a new version to npm. Example of a `graph-client` release: https://github.com/graphprotocol/graph-client/pull/295 @@ -79,12 +97,17 @@ Example of a `graph-client` release: https://github.com/graphprotocol/graph-clie Every PR to `main` that includes a changeset file will create a new alpha version. -Example of `graph-client` snapshot release: https://github.com/graphprotocol/graph-client/pull/178#issuecomment-1214822036 +Example of `graph-client` snapshot release: +https://github.com/graphprotocol/graph-client/pull/178#issuecomment-1214822036 ## License Copyright © 2018-2019 Graph Protocol, Inc. and contributors. -The Graph CLI is dual-licensed under the [MIT license](LICENSE-MIT) and the [Apache License, Version 2.0](LICENSE-APACHE). +The Graph CLI is dual-licensed under the [MIT license](LICENSE-MIT) and the +[Apache License, Version 2.0](LICENSE-APACHE). -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied. See the License for the specific language governing permissions and limitations under the License. +Unless required by applicable law or agreed to in writing, software distributed under the License is +distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or +implied. See the License for the specific language governing permissions and limitations under the +License. diff --git a/examples/basic-event-handlers/README.md b/examples/basic-event-handlers/README.md index a5032164..3d1882f4 100644 --- a/examples/basic-event-handlers/README.md +++ b/examples/basic-event-handlers/README.md @@ -1,3 +1,4 @@ # Example Subgraph -An example to help you get started with The Graph. For more information see the docs on https://thegraph.com/docs/. +An example to help you get started with The Graph. For more information see the docs on +https://thegraph.com/docs/. diff --git a/examples/basic-event-handlers/migrations/1_initial_migration.js b/examples/basic-event-handlers/migrations/1_initial_migration.js index 42968952..a4725fe7 100644 --- a/examples/basic-event-handlers/migrations/1_initial_migration.js +++ b/examples/basic-event-handlers/migrations/1_initial_migration.js @@ -1,5 +1,5 @@ -var Migrations = artifacts.require('./Migrations.sol') +var Migrations = artifacts.require('./Migrations.sol'); module.exports = function (deployer) { - deployer.deploy(Migrations) -} + deployer.deploy(Migrations); +}; diff --git a/examples/basic-event-handlers/migrations/2_deploy_contract.js b/examples/basic-event-handlers/migrations/2_deploy_contract.js index 15c8458e..f4f50e52 100644 --- a/examples/basic-event-handlers/migrations/2_deploy_contract.js +++ b/examples/basic-event-handlers/migrations/2_deploy_contract.js @@ -1,5 +1,5 @@ -const GravatarRegistry = artifacts.require('./GravatarRegistry.sol') +const GravatarRegistry = artifacts.require('./GravatarRegistry.sol'); module.exports = async function (deployer) { - await deployer.deploy(GravatarRegistry) -} + await deployer.deploy(GravatarRegistry); +}; diff --git a/examples/basic-event-handlers/migrations/3_create_gravatars.js b/examples/basic-event-handlers/migrations/3_create_gravatars.js index 12ce1fd1..81428e8d 100644 --- a/examples/basic-event-handlers/migrations/3_create_gravatars.js +++ b/examples/basic-event-handlers/migrations/3_create_gravatars.js @@ -1,14 +1,14 @@ -const GravatarRegistry = artifacts.require('./GravatarRegistry.sol') +const GravatarRegistry = artifacts.require('./GravatarRegistry.sol'); module.exports = async function (deployer) { - let accounts = await web3.eth.getAccounts() + const accounts = await web3.eth.getAccounts(); - const registry = await GravatarRegistry.deployed() - await registry.setMythicalGravatar({ from: accounts[0] }) + const registry = await GravatarRegistry.deployed(); + await registry.setMythicalGravatar({ from: accounts[0] }); await registry.createGravatar('Carl', 'https://thegraph.com/img/team/team_04.png', { from: accounts[0], - }) + }); await registry.createGravatar('Lucas', 'https://thegraph.com/img/team/bw_Lucas.jpg', { from: accounts[1], - }) -} + }); +}; diff --git a/examples/basic-event-handlers/migrations/4_update_gravatars.js b/examples/basic-event-handlers/migrations/4_update_gravatars.js index 5471cbad..7c5f12ac 100644 --- a/examples/basic-event-handlers/migrations/4_update_gravatars.js +++ b/examples/basic-event-handlers/migrations/4_update_gravatars.js @@ -1,9 +1,9 @@ -const GravatarRegistry = artifacts.require('./GravatarRegistry.sol') +const GravatarRegistry = artifacts.require('./GravatarRegistry.sol'); module.exports = async function (deployer) { - let accounts = await web3.eth.getAccounts() + const accounts = await web3.eth.getAccounts(); - const registry = await GravatarRegistry.deployed() - await registry.updateGravatarName('Nena', { from: accounts[0] }) - await registry.updateGravatarName('Jorge', { from: accounts[1] }) -} + const registry = await GravatarRegistry.deployed(); + await registry.updateGravatarName('Nena', { from: accounts[0] }); + await registry.updateGravatarName('Jorge', { from: accounts[1] }); +}; diff --git a/examples/basic-event-handlers/package.json b/examples/basic-event-handlers/package.json index a5080c5a..5a70b67e 100644 --- a/examples/basic-event-handlers/package.json +++ b/examples/basic-event-handlers/package.json @@ -1,17 +1,13 @@ { "name": "basic-event-handlers", - "private": true, "version": "0.1.0", + "private": true, "scripts": { - "codegen": "../../packages/cli/dist/bin.js codegen", "build": "../../packages/cli/dist/bin.js build", - "test": "docker compose up -d && sleep 30 && truffle test --network test && docker compose down", + "codegen": "../../packages/cli/dist/bin.js codegen", "create-test": "../../packages/cli/dist/bin.js create test/basic-event-handlers --node http://127.0.0.1:18020", - "deploy-test": "../../packages/cli/dist/bin.js deploy test/basic-event-handlers --version-label v0.0.1 --ipfs http://localhost:15001 --node http://127.0.0.1:18020" - }, - "devDependencies": { - "@graphprotocol/graph-ts": "0.29.1", - "apollo-fetch": "^0.7.0" + "deploy-test": "../../packages/cli/dist/bin.js deploy test/basic-event-handlers --version-label v0.0.1 --ipfs http://localhost:15001 --node http://127.0.0.1:18020", + "test": "docker compose up -d && sleep 30 && truffle test --network test && docker compose down" }, "dependencies": { "babel-polyfill": "6.26.0", @@ -19,6 +15,10 @@ "truffle": "5.0.12", "truffle-hdwallet-provider": "1.0.6" }, + "devDependencies": { + "@graphprotocol/graph-ts": "0.29.1", + "apollo-fetch": "^0.7.0" + }, "resolutions": { "assemblyscript": "0.19.10" } diff --git a/examples/basic-event-handlers/src/mapping.ts b/examples/basic-event-handlers/src/mapping.ts index ae6f1fc3..62f6c525 100644 --- a/examples/basic-event-handlers/src/mapping.ts +++ b/examples/basic-event-handlers/src/mapping.ts @@ -1,21 +1,21 @@ import { NewGravatar as NewGravatarEvent, UpdatedGravatar as UpdatedGravatarEvent, -} from '../generated/Gravity/Gravity' -import { NewGravatar, UpdatedGravatar } from '../generated/schema' +} from '../generated/Gravity/Gravity'; +import { NewGravatar, UpdatedGravatar } from '../generated/schema'; export function handleNewGravatar(event: NewGravatarEvent): void { - let newGravatar = new NewGravatar(event.params.id.toHex()) - newGravatar.owner = event.params.owner - newGravatar.displayName = event.params.displayName - newGravatar.imageUrl = event.params.imageUrl - newGravatar.save() + const newGravatar = new NewGravatar(event.params.id.toHex()); + newGravatar.owner = event.params.owner; + newGravatar.displayName = event.params.displayName; + newGravatar.imageUrl = event.params.imageUrl; + newGravatar.save(); } export function handleUpdatedGravatar(event: UpdatedGravatarEvent): void { - let updatedGravatar = new UpdatedGravatar(event.params.id.toHex()) - updatedGravatar.owner = event.params.owner - updatedGravatar.displayName = event.params.displayName - updatedGravatar.imageUrl = event.params.imageUrl - updatedGravatar.save() + const updatedGravatar = new UpdatedGravatar(event.params.id.toHex()); + updatedGravatar.owner = event.params.owner; + updatedGravatar.displayName = event.params.displayName; + updatedGravatar.imageUrl = event.params.imageUrl; + updatedGravatar.save(); } diff --git a/examples/basic-event-handlers/test/handlers.js b/examples/basic-event-handlers/test/handlers.js index 462bbc0a..ec02c06d 100644 --- a/examples/basic-event-handlers/test/handlers.js +++ b/examples/basic-event-handlers/test/handlers.js @@ -1,28 +1,28 @@ -const path = require('path') -const { system, patching } = require('gluegun') -const { createApolloFetch } = require('apollo-fetch') +const path = require('node:path'); +const { system, patching } = require('gluegun'); +const { createApolloFetch } = require('apollo-fetch'); -const GravatarRegistry = artifacts.require('./GravatarRegistry.sol') +const GravatarRegistry = artifacts.require('./GravatarRegistry.sol'); -const srcDir = path.join(__dirname, '..') +const srcDir = path.join(__dirname, '..'); -const fetchSubgraphs = createApolloFetch({ uri: 'http://localhost:18030/graphql' }) +const fetchSubgraphs = createApolloFetch({ uri: 'http://localhost:18030/graphql' }); const fetchSubgraph = createApolloFetch({ uri: 'http://localhost:18000/subgraphs/name/test/basic-event-handlers', -}) +}); const waitForSubgraphToBeSynced = async () => new Promise((resolve, reject) => { // Wait for 10s - let deadline = Date.now() + 10 * 1000 + const deadline = Date.now() + 10 * 1000; const checkSubgraphSynced = async () => { if (Date.now() > deadline) { - reject('Timeout while waiting for the subgraph to be synced') + reject('Timeout while waiting for the subgraph to be synced'); } // Query the subgraph meta data for the indexing status - let result = await fetchSubgraphs({ + const result = await fetchSubgraphs({ query: ` { statuses: indexingStatusesForSubgraphName( @@ -32,54 +32,52 @@ const waitForSubgraphToBeSynced = async () => } } `, - }) + }); - if ( - JSON.stringify(result.data) === JSON.stringify({ statuses: [{ synced: true }] }) - ) { - setTimeout(resolve, 1000) + if (JSON.stringify(result.data) === JSON.stringify({ statuses: [{ synced: true }] })) { + setTimeout(resolve, 1000); } else { - setTimeout(checkSubgraphSynced, 500) + setTimeout(checkSubgraphSynced, 500); } - } + }; - setTimeout(checkSubgraphSynced, 0) - }) + setTimeout(checkSubgraphSynced, 0); + }); contract('Basic event handlers', accounts => { // Deploy the subgraph once before all tests before(async () => { // Deploy the contract - const registry = await GravatarRegistry.deployed() + const registry = await GravatarRegistry.deployed(); // Insert its address into subgraph manifest await patching.replace( path.join(srcDir, 'subgraph.yaml'), '0x2E645469f354BB4F5c8a05B3b30A929361cf77eC', registry.address, - ) + ); // Create and deploy the subgraph - await system.run(`yarn codegen`, { cwd: srcDir }) - await system.run(`yarn create-test`, { cwd: srcDir }) - await system.run(`yarn deploy-test`, { cwd: srcDir }) + await system.run(`yarn codegen`, { cwd: srcDir }); + await system.run(`yarn create-test`, { cwd: srcDir }); + await system.run(`yarn deploy-test`, { cwd: srcDir }); // Wait for the subgraph to be indexed - await waitForSubgraphToBeSynced() - }) + await waitForSubgraphToBeSynced(); + }); it('all events are indexed', async () => { // Query the subgraph for entities - let result = await fetchSubgraph({ + const result = await fetchSubgraph({ query: ` { newGravatars(orderBy: id) { id displayName imageUrl } updatedGravatars(orderBy: id) { id displayName imageUrl } } `, - }) + }); - expect(result.errors).to.be.undefined + expect(result.errors).to.be.undefined; expect(result.data).to.deep.equal({ newGravatars: [ { @@ -105,6 +103,6 @@ contract('Basic event handlers', accounts => { imageUrl: 'https://thegraph.com/img/team/bw_Lucas.jpg', }, ], - }) - }) -}) + }); + }); +}); diff --git a/examples/basic-event-handlers/truffle.js b/examples/basic-event-handlers/truffle.js index 433e66f0..9e49d32c 100644 --- a/examples/basic-event-handlers/truffle.js +++ b/examples/basic-event-handlers/truffle.js @@ -1,6 +1,6 @@ -require('babel-register') -require('babel-polyfill') -const HDWalletProvider = require('truffle-hdwallet-provider') +require('babel-register'); +require('babel-polyfill'); +const HDWalletProvider = require('truffle-hdwallet-provider'); module.exports = { networks: { @@ -10,17 +10,17 @@ module.exports = { network_id: '*', }, ropsten: { - provider: function () { + provider() { return new HDWalletProvider( process.env.MNEMONIC, `https://ropsten.infura.io/v3/${process.env.ROPSTEN_INFURA_API_KEY}`, - ) + ); }, network_id: '3', }, test: { host: 'localhost', - port: 18545, + port: 18_545, network_id: '*', gas: '100000000000', gasPrice: '1', @@ -31,4 +31,4 @@ module.exports = { version: '0.4.25', // Fetch exact version from solc-bin (default: truffle's version) }, }, -} +}; diff --git a/examples/example-subgraph/package.json b/examples/example-subgraph/package.json index 46e92404..7e06d644 100644 --- a/examples/example-subgraph/package.json +++ b/examples/example-subgraph/package.json @@ -2,10 +2,10 @@ "name": "example-event-handler", "private": true, "scripts": { - "codegen": "../../packages/cli/dist/bin.js codegen --output-dir src/types/ subgraph.yaml", "build": "../../packages/cli/dist/bin.js build subgraph.yaml", "build-ipfs": "../../packages/cli/dist/bin.js build --ipfs /ip4/127.0.0.1/tcp/5001 subgraph.yaml", - "build-wast": "../../packages/cli/dist/bin.js build -t wast subgraph.yaml" + "build-wast": "../../packages/cli/dist/bin.js build -t wast subgraph.yaml", + "codegen": "../../packages/cli/dist/bin.js codegen --output-dir src/types/ subgraph.yaml" }, "devDependencies": { "@graphprotocol/graph-ts": "0.29.1" diff --git a/examples/example-subgraph/src/mapping.ts b/examples/example-subgraph/src/mapping.ts index a56f0e61..fc923b4b 100644 --- a/examples/example-subgraph/src/mapping.ts +++ b/examples/example-subgraph/src/mapping.ts @@ -1,286 +1,270 @@ -import { - Address, - BigInt, - Bytes, - crypto, - Entity, - log, - store, -} from '@graphprotocol/graph-ts' -import { - ExampleContract, - ExampleEvent, -} from './../generated/ExampleSubgraph/ExampleContract' -import { ExampleEntity } from './../generated/schema' +import { Address, BigInt, Bytes, crypto, Entity, log, store } from '@graphprotocol/graph-ts'; +import { ExampleContract, ExampleEvent } from './../generated/ExampleSubgraph/ExampleContract'; +import { ExampleEntity } from './../generated/schema'; export function handleExampleEvent(event: ExampleEvent): void { - let entity = new ExampleEntity('example id') + const entity = new ExampleEntity('example id'); // Entity field access - entity.optionalBoolean = true - entity.optionalBoolean = false - entity.optionalBooleanList = [true, false] - entity.optionalBooleanList = null + entity.optionalBoolean = true; + entity.optionalBoolean = false; + entity.optionalBooleanList = [true, false]; + entity.optionalBooleanList = null; - let optionalBoolean: boolean = entity.optionalBoolean - let optionalBooleanList: Array | null = entity.optionalBooleanList + const optionalBoolean: boolean = entity.optionalBoolean; + const optionalBooleanList: Array | null = entity.optionalBooleanList; - entity.requiredBoolean = true - entity.requiredBoolean = false - entity.requiredBooleanList = [true, false] + entity.requiredBoolean = true; + entity.requiredBoolean = false; + entity.requiredBooleanList = [true, false]; - let requiredBoolean: boolean = entity.requiredBoolean - let requiredBooleanList: Array = entity.requiredBooleanList + const requiredBoolean: boolean = entity.requiredBoolean; + const requiredBooleanList: Array = entity.requiredBooleanList; - entity.optionalString = 'hello' - entity.optionalString = null - entity.optionalStringList = ['hello', 'world'] - entity.optionalStringList = null + entity.optionalString = 'hello'; + entity.optionalString = null; + entity.optionalStringList = ['hello', 'world']; + entity.optionalStringList = null; - let optionalString: string | null = entity.optionalString - let optionalStringList: Array | null = entity.optionalStringList + const optionalString: string | null = entity.optionalString; + const optionalStringList: Array | null = entity.optionalStringList; - entity.requiredString = 'hello' - entity.requiredStringList = ['hello', 'world'] + entity.requiredString = 'hello'; + entity.requiredStringList = ['hello', 'world']; - let requiredString: string = entity.requiredString - let requiredStringList: Array = entity.requiredStringList + const requiredString: string = entity.requiredString; + const requiredStringList: Array = entity.requiredStringList; - entity.optionalInt = 128 - entity.optionalInt = -500 - entity.optionalInt = null - entity.optionalIntList = [128, -500] - entity.optionalIntList = null + entity.optionalInt = 128; + entity.optionalInt = -500; + entity.optionalInt = null; + entity.optionalIntList = [128, -500]; + entity.optionalIntList = null; - let optionalInt: i32 = entity.optionalInt - let optionalIntList: Array | null = entity.optionalIntList + const optionalInt: i32 = entity.optionalInt; + const optionalIntList: Array | null = entity.optionalIntList; - entity.requiredInt = 128 - entity.requiredInt = -500 - entity.requiredIntList = [128, -500] + entity.requiredInt = 128; + entity.requiredInt = -500; + entity.requiredIntList = [128, -500]; - let requiredInt: i32 = entity.requiredInt - let requiredIntList: Array = entity.requiredIntList + const requiredInt: i32 = entity.requiredInt; + const requiredIntList: Array = entity.requiredIntList; - entity.optionalBigInt = new BigInt(0) - entity.optionalBigInt = null - entity.optionalBigIntList = [new BigInt(0), new BigInt(0)] - entity.optionalBigIntList = null + entity.optionalBigInt = new BigInt(0); + entity.optionalBigInt = null; + entity.optionalBigIntList = [new BigInt(0), new BigInt(0)]; + entity.optionalBigIntList = null; - let optionalBigInt: BigInt | null = entity.optionalBigInt - let optionalBigIntList: Array | null = entity.optionalBigIntList + const optionalBigInt: bigint | null = entity.optionalBigInt; + const optionalBigIntList: Array | null = entity.optionalBigIntList; - entity.requiredBigInt = new BigInt(0) - entity.requiredBigIntList = [new BigInt(0), new BigInt(0)] + entity.requiredBigInt = new BigInt(0); + entity.requiredBigIntList = [new BigInt(0), new BigInt(0)]; - let requiredBigInt: BigInt = entity.requiredBigInt - let requiredBigIntList: Array = entity.requiredBigIntList + const requiredBigInt: bigint = entity.requiredBigInt; + const requiredBigIntList: Array = entity.requiredBigIntList; - entity.optionalBytes = new Bytes(0) - entity.optionalBytes = null - entity.optionalBytesList = [new Bytes(0), new Bytes(0)] - entity.optionalBytesList = null + entity.optionalBytes = new Bytes(0); + entity.optionalBytes = null; + entity.optionalBytesList = [new Bytes(0), new Bytes(0)]; + entity.optionalBytesList = null; - let optionalBytes: Bytes | null = entity.optionalBytes - let optionalBytesList: Array | null = entity.optionalBytesList + const optionalBytes: Bytes | null = entity.optionalBytes; + const optionalBytesList: Array | null = entity.optionalBytesList; - entity.requiredBytes = new Bytes(0) - entity.requiredBytesList = [new Bytes(0), new Bytes(0)] + entity.requiredBytes = new Bytes(0); + entity.requiredBytesList = [new Bytes(0), new Bytes(0)]; - let requiredBytes: Bytes = entity.requiredBytes - let requiredBytesList: Array = entity.requiredBytesList + const requiredBytes: Bytes = entity.requiredBytes; + const requiredBytesList: Array = entity.requiredBytesList; - entity.optionalReference = 'some-id' - entity.optionalReference = null - entity.optionalReferenceList = ['some-id', 'other-id'] - entity.optionalReferenceList = null + entity.optionalReference = 'some-id'; + entity.optionalReference = null; + entity.optionalReferenceList = ['some-id', 'other-id']; + entity.optionalReferenceList = null; - let optionalReference: string | null = entity.optionalReference - let optionalReferenceList: Array | null = entity.optionalReferenceList + const optionalReference: string | null = entity.optionalReference; + const optionalReferenceList: Array | null = entity.optionalReferenceList; - entity.requiredReference = 'some-id' - entity.requiredReferenceList = ['some-id', 'other-id'] + entity.requiredReference = 'some-id'; + entity.requiredReferenceList = ['some-id', 'other-id']; - let requiredReference: string = entity.requiredReference - let requiredReferenceList: Array = entity.requiredReferenceList + const requiredReference: string = entity.requiredReference; + const requiredReferenceList: Array = entity.requiredReferenceList; // Smart contract calls - let contract = ExampleContract.bind(event.address) - entity.requiredBytes = contract.getAndReturnAddress(entity.requiredBytes as Address) - entity.requiredString = contract.getAndReturnString(entity.requiredString) - entity.requiredBoolean = contract.getAndReturnBool(entity.requiredBoolean) - entity.requiredBytes = contract.getAndReturnByte(entity.requiredBytes) - entity.requiredBytes = contract.getAndReturnBytes1(entity.requiredBytes) - entity.requiredBytes = contract.getAndReturnBytes32(entity.requiredBytes) - entity.requiredInt = contract.getAndReturnInt8(entity.requiredInt) - entity.requiredInt = contract.getAndReturnInt16(entity.requiredInt) - entity.requiredInt = contract.getAndReturnInt24(entity.requiredInt) - entity.requiredInt = contract.getAndReturnInt32(entity.requiredInt) - entity.requiredBigInt = contract.getAndReturnInt40(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt56(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt64(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt72(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt80(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt88(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt96(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt104(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt112(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt120(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt128(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt136(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt144(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt152(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt160(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt168(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt176(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt184(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt192(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt200(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt200(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt208(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt216(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt224(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt232(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt240(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt248(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnInt256(entity.requiredBigInt) - entity.requiredInt = contract.getAndReturnUint8(entity.requiredInt) - entity.requiredInt = contract.getAndReturnUint16(entity.requiredInt) - entity.requiredInt = contract.getAndReturnUint24(entity.requiredInt) - entity.requiredBigInt = contract.getAndReturnUint32(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint40(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint56(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint64(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint72(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint80(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint88(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint96(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint104(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint112(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint120(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint128(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint136(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint144(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint152(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint160(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint168(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint176(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint184(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint192(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint200(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint200(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint208(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint216(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint224(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint232(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint240(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint248(entity.requiredBigInt) - entity.requiredBigInt = contract.getAndReturnUint256(entity.requiredBigInt) - - let addrArray: Array
= contract.getAndReturnAddressArray([ + const contract = ExampleContract.bind(event.address); + entity.requiredBytes = contract.getAndReturnAddress(entity.requiredBytes as Address); + entity.requiredString = contract.getAndReturnString(entity.requiredString); + entity.requiredBoolean = contract.getAndReturnBool(entity.requiredBoolean); + entity.requiredBytes = contract.getAndReturnByte(entity.requiredBytes); + entity.requiredBytes = contract.getAndReturnBytes1(entity.requiredBytes); + entity.requiredBytes = contract.getAndReturnBytes32(entity.requiredBytes); + entity.requiredInt = contract.getAndReturnInt8(entity.requiredInt); + entity.requiredInt = contract.getAndReturnInt16(entity.requiredInt); + entity.requiredInt = contract.getAndReturnInt24(entity.requiredInt); + entity.requiredInt = contract.getAndReturnInt32(entity.requiredInt); + entity.requiredBigInt = contract.getAndReturnInt40(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt56(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt64(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt72(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt80(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt88(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt96(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt104(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt112(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt120(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt128(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt136(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt144(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt152(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt160(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt168(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt176(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt184(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt192(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt200(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt200(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt208(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt216(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt224(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt232(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt240(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt248(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnInt256(entity.requiredBigInt); + entity.requiredInt = contract.getAndReturnUint8(entity.requiredInt); + entity.requiredInt = contract.getAndReturnUint16(entity.requiredInt); + entity.requiredInt = contract.getAndReturnUint24(entity.requiredInt); + entity.requiredBigInt = contract.getAndReturnUint32(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint40(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint56(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint64(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint72(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint80(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint88(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint96(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint104(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint112(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint120(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint128(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint136(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint144(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint152(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint160(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint168(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint176(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint184(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint192(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint200(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint200(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint208(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint216(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint224(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint232(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint240(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint248(entity.requiredBigInt); + entity.requiredBigInt = contract.getAndReturnUint256(entity.requiredBigInt); + + const addrArray: Array
= contract.getAndReturnAddressArray([ new Address(0), new Address(0), - ]) - entity.requiredStringList = contract.getAndReturnStringArray(entity.requiredStringList) - entity.requiredBooleanList = contract.getAndReturnBoolArray(entity.requiredBooleanList) - entity.requiredBytesList = contract.getAndReturnByteArray(entity.requiredBytesList) - entity.requiredBytesList = contract.getAndReturnBytes1Array(entity.requiredBytesList) - entity.requiredBytesList = contract.getAndReturnBytes32Array(entity.requiredBytesList) - entity.requiredIntList = contract.getAndReturnInt8Array(entity.requiredIntList) - entity.requiredIntList = contract.getAndReturnInt16Array(entity.requiredIntList) - entity.requiredIntList = contract.getAndReturnInt24Array(entity.requiredIntList) - contract.getAndReturnInt32Array(entity.requiredIntList) - entity.requiredBigIntList = contract.getAndReturnInt40Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt56Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt64Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt72Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt80Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt88Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt96Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt104Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt112Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt120Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt128Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt136Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt144Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt152Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt160Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt168Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt176Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt184Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt192Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt200Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt200Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt208Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt216Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt224Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt232Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt240Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt248Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnInt256Array(entity.requiredBigIntList) - let u8Array: Array = contract.getAndReturnUint8Array([1 as i32, 100 as i32]) - let u16Array: Array = contract.getAndReturnUint16Array([1 as i32, 100 as i32]) - let u24Array: Array = contract.getAndReturnUint24Array([1 as i32, 100 as i32]) - let u32Array: Array = contract.getAndReturnUint32Array([ - new BigInt(0), - new BigInt(0), - ]) - entity.requiredBigIntList = contract.getAndReturnUint40Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint56Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint64Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint72Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint80Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint88Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint96Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint104Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint112Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint120Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint128Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint136Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint144Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint152Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint160Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint168Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint176Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint184Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint192Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint200Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint200Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint208Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint216Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint224Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint232Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint240Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint248Array(entity.requiredBigIntList) - entity.requiredBigIntList = contract.getAndReturnUint256Array(entity.requiredBigIntList) + ]); + entity.requiredStringList = contract.getAndReturnStringArray(entity.requiredStringList); + entity.requiredBooleanList = contract.getAndReturnBoolArray(entity.requiredBooleanList); + entity.requiredBytesList = contract.getAndReturnByteArray(entity.requiredBytesList); + entity.requiredBytesList = contract.getAndReturnBytes1Array(entity.requiredBytesList); + entity.requiredBytesList = contract.getAndReturnBytes32Array(entity.requiredBytesList); + entity.requiredIntList = contract.getAndReturnInt8Array(entity.requiredIntList); + entity.requiredIntList = contract.getAndReturnInt16Array(entity.requiredIntList); + entity.requiredIntList = contract.getAndReturnInt24Array(entity.requiredIntList); + contract.getAndReturnInt32Array(entity.requiredIntList); + entity.requiredBigIntList = contract.getAndReturnInt40Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt56Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt64Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt72Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt80Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt88Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt96Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt104Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt112Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt120Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt128Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt136Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt144Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt152Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt160Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt168Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt176Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt184Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt192Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt200Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt200Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt208Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt216Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt224Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt232Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt240Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt248Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnInt256Array(entity.requiredBigIntList); + const u8Array: Array = contract.getAndReturnUint8Array([1 as i32, 100 as i32]); + const u16Array: Array = contract.getAndReturnUint16Array([1 as i32, 100 as i32]); + const u24Array: Array = contract.getAndReturnUint24Array([1 as i32, 100 as i32]); + const u32Array: Array = contract.getAndReturnUint32Array([new BigInt(0), new BigInt(0)]); + entity.requiredBigIntList = contract.getAndReturnUint40Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint56Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint64Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint72Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint80Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint88Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint96Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint104Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint112Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint120Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint128Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint136Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint144Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint152Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint160Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint168Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint176Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint184Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint192Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint200Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint200Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint208Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint216Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint224Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint232Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint240Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint248Array(entity.requiredBigIntList); + entity.requiredBigIntList = contract.getAndReturnUint256Array(entity.requiredBigIntList); // Store access - store.set('ExampleEntity', 'example id', entity) - store.get('ExampleEntity', 'example id') - store.remove('ExampleEntity', 'example id') + store.set('ExampleEntity', 'example id', entity); + store.get('ExampleEntity', 'example id'); + store.remove('ExampleEntity', 'example id'); // Entity load and save (using the store behind the scenes) - entity.save() - let other = ExampleEntity.load('other example id') - if (other == null) { - other = new ExampleEntity('other example id') - } - other.save() + entity.save(); + let other = ExampleEntity.load('other example id'); + other ??= new ExampleEntity('other example id'); + other.save(); // BigInt math - let bigIntPlus = entity.requiredBigInt + entity.requiredBigInt - let bigIntMinus = entity.requiredBigInt - entity.requiredBigInt - let bigIntTimes = entity.requiredBigInt * entity.requiredBigInt - let bigIntDividedBy = entity.requiredBigInt / entity.requiredBigInt - let bigIntMod = entity.requiredBigInt % entity.requiredBigInt + const bigIntPlus = entity.requiredBigInt + entity.requiredBigInt; + const bigIntMinus = entity.requiredBigInt - entity.requiredBigInt; + const bigIntTimes = entity.requiredBigInt * entity.requiredBigInt; + const bigIntDividedBy = entity.requiredBigInt / entity.requiredBigInt; + const bigIntMod = entity.requiredBigInt % entity.requiredBigInt; // Logging - log.debug('Hello {}', ['World']) - log.info('Hello {}', ['World']) - log.warning('Hello {}', ['World']) - log.error('Hello {}', ['World']) - log.critical('Hello {}', ['World']) + log.debug('Hello {}', ['World']); + log.info('Hello {}', ['World']); + log.warning('Hello {}', ['World']); + log.error('Hello {}', ['World']); + log.critical('Hello {}', ['World']); } diff --git a/package.json b/package.json index 650d7210..a9f64a03 100644 --- a/package.json +++ b/package.json @@ -1,33 +1,38 @@ { "name": "graphprotocol-tools-monorepo", - "private": true, - "devDependencies": { - "@babel/core": "^7.20.5", - "@babel/preset-env": "^7.20.2", - "@babel/preset-typescript": "^7.18.6", - "@changesets/changelog-github": "^0.4.7", - "@changesets/cli": "^2.25.2", - "babel-jest": "^29.3.1", - "jest": "26.0.0", - "prettier": "^2.8.2" - }, "repository": { "type": "git", "url": "git+https://github.com/graphprotocol/graph-cli" }, - "license": "(Apache-2.0 OR MIT)", "homepage": "https://github.com/graphprotocol/graph-cli#readme", "bugs": { "url": "https://github.com/graphprotocol/graph-cli/issues" }, + "license": "(Apache-2.0 OR MIT)", + "private": true, "engines": { "pnpm": ">=7.14.2" }, "scripts": { - "lint": "prettier -c .", - "type-check": "pnpm --filter=@graphprotocol/graph-cli type-check", "build": "pnpm --filter=@graphprotocol/graph-cli build", + "lint": "pnpm lint:prettier && pnpm lint:eslint", + "lint:eslint": "eslint .", + "lint:prettier": "prettier -c .", "release": "changeset publish", - "test:cli": "pnpm --filter @graphprotocol/graph-cli test" + "test:cli": "pnpm --filter @graphprotocol/graph-cli test", + "type-check": "pnpm --filter=@graphprotocol/graph-cli type-check" + }, + "devDependencies": { + "@babel/core": "^7.20.5", + "@babel/preset-env": "^7.20.2", + "@babel/preset-typescript": "^7.18.6", + "@changesets/changelog-github": "^0.4.7", + "@changesets/cli": "^2.25.2", + "@theguild/eslint-config": "^0.6.0", + "@theguild/prettier-config": "^1.0.0", + "babel-jest": "^29.3.1", + "eslint": "^8.31.0", + "jest": "26.0.0", + "prettier": "^2.8.2" } } diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 0f101843..15b3cee7 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -4,10 +4,14 @@ ### Patch Changes -- [#1023](https://github.com/graphprotocol/graph-cli/pull/1023) [`bf5ab6d`](https://github.com/graphprotocol/graph-cli/commit/bf5ab6dc0f19fcb5b8e599b7d9b1c2b6efcbe005) Thanks [@evaporei](https://github.com/evaporei)! - update graph-ts to 0.29.1 +- [#1023](https://github.com/graphprotocol/graph-cli/pull/1023) + [`bf5ab6d`](https://github.com/graphprotocol/graph-cli/commit/bf5ab6dc0f19fcb5b8e599b7d9b1c2b6efcbe005) + Thanks [@evaporei](https://github.com/evaporei)! - update graph-ts to 0.29.1 ## 0.37.1 ### Patch Changes -- [#1015](https://github.com/graphprotocol/graph-cli/pull/1015) [`5df304c`](https://github.com/graphprotocol/graph-cli/commit/5df304c75ecc339f681eeae858325a7859183dda) Thanks [@saihaj](https://github.com/saihaj)! - fix fantom network init URLs +- [#1015](https://github.com/graphprotocol/graph-cli/pull/1015) + [`5df304c`](https://github.com/graphprotocol/graph-cli/commit/5df304c75ecc339f681eeae858325a7859183dda) + Thanks [@saihaj](https://github.com/saihaj)! - fix fantom network init URLs diff --git a/packages/cli/babel.config.js b/packages/cli/babel.config.js index e6dcb492..5595a6a0 100644 --- a/packages/cli/babel.config.js +++ b/packages/cli/babel.config.js @@ -1,3 +1,3 @@ module.exports = { presets: [['@babel/env', { targets: { node: 'current' } }], '@babel/typescript'], -} +}; diff --git a/packages/cli/jest.config.js b/packages/cli/jest.config.js index 0da989a1..39e53527 100644 --- a/packages/cli/jest.config.js +++ b/packages/cli/jest.config.js @@ -172,4 +172,4 @@ module.exports = { // Whether to use watchman for file crawling // watchman: true, -} +}; diff --git a/packages/cli/package.json b/packages/cli/package.json index 3b636f91..9079df55 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,12 +1,19 @@ { "name": "@graphprotocol/graph-cli", "version": "0.37.2", - "license": "(Apache-2.0 OR MIT)", "description": "CLI for building for and deploying to The Graph", - "main": "dist/cli.js", + "license": "(Apache-2.0 OR MIT)", "bin": { "graph": "dist/bin.js" }, + "main": "dist/cli.js", + "scripts": { + "build": "tsc -b tsconfig.build.json && copyfiles -u 1 src/**/*.graphql dist/ && chmod +x ./dist/bin.js", + "test": "jest --verbose", + "test:init": "jest tests/cli/init.test.ts --verbose", + "test:validation": "jest tests/cli/validation.test.ts --verbose", + "type-check": "tsc --noEmit" + }, "dependencies": { "@float-capital/float-subgraph-uncrashable": "^0.0.0-alpha.4", "assemblyscript": "0.19.23", @@ -50,13 +57,6 @@ "tern": "0.24.3", "typescript": "^4.9.4" }, - "scripts": { - "test": "jest --verbose", - "test:init": "jest tests/cli/init.test.ts --verbose", - "test:validation": "jest tests/cli/validation.test.ts --verbose", - "type-check": "tsc --noEmit", - "build": "tsc -b tsconfig.build.json && copyfiles -u 1 src/**/*.graphql dist/ && chmod +x ./dist/bin.js" - }, "publishConfig": { "access": "public" } diff --git a/packages/cli/src/bin.ts b/packages/cli/src/bin.ts index 6fa48296..48646d81 100644 --- a/packages/cli/src/bin.ts +++ b/packages/cli/src/bin.ts @@ -1,5 +1,6 @@ #!/usr/bin/env node // run the CLI with the current process arguments -import { run } from './cli' -run(process.argv) +import { run } from './cli'; + +run(process.argv); diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index 93d9d963..dd52aec6 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -1,30 +1,30 @@ -import path from 'path' -import { build, system } from 'gluegun' +import path from 'path'; +import { build, system } from 'gluegun'; const run = async (argv: string[]) => { - let builder = build().brand('graph').src(__dirname) + let builder = build().brand('graph').src(__dirname); - const pluginDirs: string[] = [] + const pluginDirs: string[] = []; await Promise.all( ['npm root -g', 'npm root', 'yarn global dir'].map(async cmd => { try { - const dir = await system.run(cmd, { trim: true }) - pluginDirs.push(dir) + const dir = await system.run(cmd, { trim: true }); + pluginDirs.push(dir); } catch (_) { // noop } }), - ) + ); // Inject potential plugin directories builder = pluginDirs.reduce( (cli, dir) => cli.plugin(path.join(dir, '@graphprotocol', 'indexer-cli', 'dist')), builder, - ) + ); - const cli = builder.help().version().defaultCommand().create() + const cli = builder.help().version().defaultCommand().create(); - return await cli.run(argv) -} + return await cli.run(argv); +}; -export { run } +export { run }; diff --git a/packages/cli/src/codegen/schema.test.ts b/packages/cli/src/codegen/schema.test.ts index cb52c177..3335db31 100644 --- a/packages/cli/src/codegen/schema.test.ts +++ b/packages/cli/src/codegen/schema.test.ts @@ -1,49 +1,48 @@ -import prettier from 'prettier' -import * as graphql from 'graphql/language' -import immutable from 'immutable' -import Schema from '../schema' -import SchemaCodeGenerator from './schema' +import * as graphql from 'graphql/language'; +import immutable from 'immutable'; +import prettier from 'prettier'; +import Schema from '../schema'; +import SchemaCodeGenerator from './schema'; import { + ArrayType, Class, Method, - StaticMethod, - Param, NamedType, NullableType, - ArrayType, -} from './typescript' + Param, + StaticMethod, +} from './typescript'; -const formatTS = (code: string) => - prettier.format(code, { parser: 'typescript', semi: false }) +const formatTS = (code: string) => prettier.format(code, { parser: 'typescript', semi: false }); const createSchemaCodeGen = (schema: string) => - new SchemaCodeGenerator(new Schema('', schema, immutable.fromJS(graphql.parse(schema)))) + new SchemaCodeGenerator(new Schema('', schema, immutable.fromJS(graphql.parse(schema)))); const testEntity = (generatedTypes: any[], expectedEntity: any) => { - const entity = generatedTypes.find(type => type.name === expectedEntity.name) + const entity = generatedTypes.find(type => type.name === expectedEntity.name); - expect(entity instanceof Class).toBe(true) - expect(entity.extends).toBe('Entity') - expect(entity.export).toBe(true) + expect(entity instanceof Class).toBe(true); + expect(entity.extends).toBe('Entity'); + expect(entity.export).toBe(true); - const { members, methods } = entity + const { members, methods } = entity; - expect(members).toStrictEqual(expectedEntity.members) + expect(members).toStrictEqual(expectedEntity.members); for (const expectedMethod of expectedEntity.methods) { - const method = methods.find((method: any) => method.name === expectedMethod.name) + const method = methods.find((method: any) => method.name === expectedMethod.name); expectedMethod.static ? expect(method instanceof StaticMethod).toBe(true) - : expect(method instanceof Method).toBe(true) + : expect(method instanceof Method).toBe(true); - expect(method.params).toStrictEqual(expectedMethod.params) - expect(method.returnType).toStrictEqual(expectedMethod.returnType) - expect(formatTS(method.body)).toBe(formatTS(expectedMethod.body)) + expect(method.params).toStrictEqual(expectedMethod.params); + expect(method.returnType).toStrictEqual(expectedMethod.returnType); + expect(formatTS(method.body)).toBe(formatTS(expectedMethod.body)); } - expect(methods.length).toBe(expectedEntity.methods.length) -} + expect(methods.length).toBe(expectedEntity.methods.length); +}; describe('Schema code generator', () => { test('Should generate nothing for non entity types', () => { @@ -55,10 +54,10 @@ describe('Schema code generator', () => { type Bar { barfoo: Int } - `) + `); - expect(codegen.generateTypes().size).toBe(0) - }) + expect(codegen.generateTypes().size).toBe(0); + }); describe('Should generate correct classes for each entity', () => { const codegen = createSchemaCodeGen(` @@ -87,16 +86,16 @@ describe('Schema code generator', () => { amount: BigInt! account: Account! } - `) + `); - const generatedTypes = codegen.generateTypes() + const generatedTypes = codegen.generateTypes(); test('Foo is NOT an entity', () => { - const foo = generatedTypes.find((type: any) => type.name === 'Foo') - expect(foo).toBe(undefined) + const foo = generatedTypes.find((type: any) => type.name === 'Foo'); + expect(foo).toBe(undefined); // Account and Wallet - expect(generatedTypes.size).toBe(2) - }) + expect(generatedTypes.size).toBe(2); + }); test('Account is an entity with the correct methods', () => { testEntity(generatedTypes, { @@ -244,12 +243,7 @@ describe('Schema code generator', () => { }, { name: 'set wallets', - params: [ - new Param( - 'value', - new NullableType(new ArrayType(new NamedType('string'))), - ), - ], + params: [new Param('value', new NullableType(new ArrayType(new NamedType('string'))))], returnType: undefined, body: ` if (!value) { @@ -260,8 +254,8 @@ describe('Schema code generator', () => { `, }, ], - }) - }) + }); + }); test('Wallet is an entity with the correct methods', () => { testEntity(generatedTypes, { @@ -353,9 +347,9 @@ describe('Schema code generator', () => { `, }, ], - }) - }) - }) + }); + }); + }); test('Should handle references with Bytes id types', () => { const codegen = createSchemaCodeGen(` @@ -374,9 +368,9 @@ describe('Schema code generator', () => { employee: Employee! worker: Worker! } -`) +`); - const generatedTypes = codegen.generateTypes() + const generatedTypes = codegen.generateTypes(); testEntity(generatedTypes, { name: 'Task', members: [], @@ -461,6 +455,6 @@ describe('Schema code generator', () => { body: "\n this.set('worker', Value.fromBytes(value))\n ", }, ], - }) - }) -}) + }); + }); +}); diff --git a/packages/cli/src/codegen/schema.ts b/packages/cli/src/codegen/schema.ts index 62da2e6d..3625dd5e 100644 --- a/packages/cli/src/codegen/schema.ts +++ b/packages/cli/src/codegen/schema.ts @@ -1,60 +1,60 @@ -import immutable from 'immutable' -import * as tsCodegen from './typescript' -import * as typesCodegen from './types' -import Schema from '../schema' +import immutable from 'immutable'; +import Schema from '../schema'; +import * as typesCodegen from './types'; +import * as tsCodegen from './typescript'; class IdField { - static BYTES = Symbol('Bytes') - static STRING = Symbol('String') + static BYTES = Symbol('Bytes'); + static STRING = Symbol('String'); - private kind: typeof IdField.BYTES | typeof IdField.STRING + private kind: typeof IdField.BYTES | typeof IdField.STRING; constructor(idField: immutable.Map) { - const typeName = idField.getIn(['type', 'type', 'name', 'value']) - this.kind = typeName === 'Bytes' ? IdField.BYTES : IdField.STRING + const typeName = idField.getIn(['type', 'type', 'name', 'value']); + this.kind = typeName === 'Bytes' ? IdField.BYTES : IdField.STRING; } typeName() { - return this.kind === IdField.BYTES ? 'Bytes' : 'string' + return this.kind === IdField.BYTES ? 'Bytes' : 'string'; } gqlTypeName() { - return this.kind === IdField.BYTES ? 'Bytes' : 'String' + return this.kind === IdField.BYTES ? 'Bytes' : 'String'; } tsNamedType() { - return tsCodegen.namedType(this.typeName()) + return tsCodegen.namedType(this.typeName()); } tsValueFrom() { - return this.kind === IdField.BYTES ? 'Value.fromBytes(id)' : 'Value.fromString(id)' + return this.kind === IdField.BYTES ? 'Value.fromBytes(id)' : 'Value.fromString(id)'; } tsValueKind() { - return this.kind === IdField.BYTES ? 'ValueKind.BYTES' : 'ValueKind.STRING' + return this.kind === IdField.BYTES ? 'ValueKind.BYTES' : 'ValueKind.STRING'; } tsValueToString() { - return this.kind == IdField.BYTES ? 'id.toBytes().toHexString()' : 'id.toString()' + return this.kind == IdField.BYTES ? 'id.toBytes().toHexString()' : 'id.toString()'; } tsToString() { - return this.kind == IdField.BYTES ? 'id.toHexString()' : 'id' + return this.kind == IdField.BYTES ? 'id.toHexString()' : 'id'; } static fromFields(fields: immutable.List) { - const idField = fields.find(field => field.getIn(['name', 'value']) === 'id') - return new IdField(idField) + const idField = fields.find(field => field.getIn(['name', 'value']) === 'id'); + return new IdField(idField); } static fromTypeDef(def: immutable.Map) { - return IdField.fromFields(def.get('fields')) + return IdField.fromFields(def.get('fields')); } } export default class SchemaCodeGenerator { constructor(private schema: Schema) { - this.schema = schema + this.schema = schema; } generateModuleImports() { @@ -77,14 +77,14 @@ export default class SchemaCodeGenerator { ], '@graphprotocol/graph-ts', ), - ] + ]; } generateTypes() { return this.schema.ast .get('definitions') .filter((def: any) => this._isEntityTypeDefinition(def)) - .map((def: any) => this._generateEntityType(def)) + .map((def: any) => this._generateEntityType(def)); } _isEntityTypeDefinition(def: immutable.Map) { @@ -92,42 +92,40 @@ export default class SchemaCodeGenerator { def.get('kind') === 'ObjectTypeDefinition' && def .get('directives') - .find((directive: any) => directive.getIn(['name', 'value']) === 'entity') !== - undefined - ) + .find((directive: any) => directive.getIn(['name', 'value']) === 'entity') !== undefined + ); } _isInterfaceDefinition(def: immutable.Map) { - return def.get('kind') === 'InterfaceTypeDefinition' + return def.get('kind') === 'InterfaceTypeDefinition'; } _generateEntityType(def: immutable.Map) { - let name = def.getIn(['name', 'value']) as string - let klass = tsCodegen.klass(name, { export: true, extends: 'Entity' }) - const fields = def.get('fields') - const idField = IdField.fromFields(fields) + const name = def.getIn(['name', 'value']) as string; + const klass = tsCodegen.klass(name, { export: true, extends: 'Entity' }); + const fields = def.get('fields'); + const idField = IdField.fromFields(fields); // Generate and add a constructor - klass.addMethod(this._generateConstructor(name, fields)) + klass.addMethod(this._generateConstructor(name, fields)); // Generate and add save() and getById() methods - this._generateStoreMethods(name, idField).forEach(method => klass.addMethod(method)) + this._generateStoreMethods(name, idField).forEach(method => klass.addMethod(method)); // Generate and add entity field getters and setters def .get('fields') .reduce( - (methods: any, field: any) => - methods.concat(this._generateEntityFieldMethods(def, field)), + (methods: any, field: any) => methods.concat(this._generateEntityFieldMethods(def, field)), immutable.List(), ) - .forEach((method: any) => klass.addMethod(method)) + .forEach((method: any) => klass.addMethod(method)); - return klass + return klass; } _generateConstructor(_entityName: string, fields: immutable.List) { - const idField = IdField.fromFields(fields) + const idField = IdField.fromFields(fields); return tsCodegen.method( 'constructor', [tsCodegen.param('id', idField.tsNamedType())], @@ -136,7 +134,7 @@ export default class SchemaCodeGenerator { super() this.set('id', ${idField.tsValueFrom()}) `, - ) + ); } _generateStoreMethods(entityName: any, idField: any) { @@ -164,29 +162,29 @@ export default class SchemaCodeGenerator { return changetype<${entityName} | null>(store.get('${entityName}', ${idField.tsToString()})) `, ), - ) + ); } _generateEntityFieldMethods(entityDef: any, fieldDef: immutable.Map) { return immutable.List([ this._generateEntityFieldGetter(entityDef, fieldDef), this._generateEntityFieldSetter(entityDef, fieldDef), - ]) + ]); } _generateEntityFieldGetter(_entityDef: any, fieldDef: immutable.Map) { - let name = fieldDef.getIn(['name', 'value']) - let gqlType = fieldDef.get('type') - let fieldValueType = this._valueTypeFromGraphQl(gqlType) - let returnType = this._typeFromGraphQl(gqlType) - let isNullable = returnType instanceof tsCodegen.NullableType - - let getNonNullable = `return ${typesCodegen.valueToAsc('value!', fieldValueType)}` - let getNullable = `if (!value || value.kind == ValueKind.NULL) { + const name = fieldDef.getIn(['name', 'value']); + const gqlType = fieldDef.get('type'); + const fieldValueType = this._valueTypeFromGraphQl(gqlType); + const returnType = this._typeFromGraphQl(gqlType); + const isNullable = returnType instanceof tsCodegen.NullableType; + + const getNonNullable = `return ${typesCodegen.valueToAsc('value!', fieldValueType)}`; + const getNullable = `if (!value || value.kind == ValueKind.NULL) { return null } else { return ${typesCodegen.valueToAsc('value', fieldValueType)} - }` + }`; return tsCodegen.method( `get ${name}`, @@ -196,31 +194,31 @@ export default class SchemaCodeGenerator { let value = this.get('${name}') ${isNullable ? getNullable : getNonNullable} `, - ) + ); } _generateEntityFieldSetter(_entityDef: any, fieldDef: immutable.Map) { - let name = fieldDef.getIn(['name', 'value']) - let gqlType = fieldDef.get('type') - let fieldValueType = this._valueTypeFromGraphQl(gqlType) - let paramType = this._typeFromGraphQl(gqlType) - let isNullable = paramType instanceof tsCodegen.NullableType - let paramTypeString = isNullable ? paramType.inner.toString() : paramType.toString() - let isArray = paramType instanceof tsCodegen.ArrayType + const name = fieldDef.getIn(['name', 'value']); + const gqlType = fieldDef.get('type'); + const fieldValueType = this._valueTypeFromGraphQl(gqlType); + const paramType = this._typeFromGraphQl(gqlType); + const isNullable = paramType instanceof tsCodegen.NullableType; + const paramTypeString = isNullable ? paramType.inner.toString() : paramType.toString(); + const isArray = paramType instanceof tsCodegen.ArrayType; if (isArray && paramType.inner instanceof tsCodegen.NullableType) { - let baseType = this._baseType(gqlType) + const baseType = this._baseType(gqlType); throw new Error(` GraphQL schema can't have List's with Nullable members. Error in '${name}' field of type '[${baseType}]'. -Suggestion: add an '!' to the member type of the List, change from '[${baseType}]' to '[${baseType}!]'`) +Suggestion: add an '!' to the member type of the List, change from '[${baseType}]' to '[${baseType}!]'`); } - let setNonNullable = ` + const setNonNullable = ` this.set('${name}', ${typesCodegen.valueFromAsc(`value`, fieldValueType)}) - ` - let setNullable = ` + `; + const setNullable = ` if (!value) { this.unset('${name}') } else { @@ -229,18 +227,18 @@ Suggestion: add an '!' to the member type of the List, change from '[${baseType} fieldValueType, )}) } - ` + `; return tsCodegen.method( `set ${name}`, [tsCodegen.param('value', paramType)], undefined, isNullable ? setNullable : setNonNullable, - ) + ); } _resolveFieldType(gqlType: immutable.Map) { - let typeName = gqlType.getIn(['name', 'value']) + const typeName = gqlType.getIn(['name', 'value']); // If this is a reference to another type, the field has the type of // the referred type's id field @@ -250,12 +248,11 @@ Suggestion: add an '!' to the member type of the List, change from '[${baseType} (def: any) => (this._isEntityTypeDefinition(def) || this._isInterfaceDefinition(def)) && def.getIn(['name', 'value']) === typeName, - ) + ); if (typeDef) { - return IdField.fromTypeDef(typeDef).typeName() - } else { - return typeName as string + return IdField.fromTypeDef(typeDef).typeName(); } + return typeName as string; } /** Return the type that values for this field must have. For scalar @@ -264,39 +261,39 @@ Suggestion: add an '!' to the member type of the List, change from '[${baseType} * referred type, i.e., `string` or `Bytes`*/ _valueTypeFromGraphQl(gqlType: immutable.Map): any { if (gqlType.get('kind') === 'NonNullType') { - return this._valueTypeFromGraphQl(gqlType.get('type')) - } else if (gqlType.get('kind') === 'ListType') { - return '[' + this._valueTypeFromGraphQl(gqlType.get('type')) + ']' - } else { - return this._resolveFieldType(gqlType) + return this._valueTypeFromGraphQl(gqlType.get('type')); + } + if (gqlType.get('kind') === 'ListType') { + return '[' + this._valueTypeFromGraphQl(gqlType.get('type')) + ']'; } + return this._resolveFieldType(gqlType); } /** Determine the base type of `gqlType` by removing any non-null * constraints and using the type of elements of lists */ _baseType(gqlType: immutable.Map): any { if (gqlType.get('kind') === 'NonNullType') { - return this._baseType(gqlType.get('type')) - } else if (gqlType.get('kind') === 'ListType') { - return this._baseType(gqlType.get('type')) - } else { - return gqlType.getIn(['name', 'value']) + return this._baseType(gqlType.get('type')); + } + if (gqlType.get('kind') === 'ListType') { + return this._baseType(gqlType.get('type')); } + return gqlType.getIn(['name', 'value']); } _typeFromGraphQl(gqlType: immutable.Map, nullable = true): any { if (gqlType.get('kind') === 'NonNullType') { - return this._typeFromGraphQl(gqlType.get('type'), false) - } else if (gqlType.get('kind') === 'ListType') { - let type = tsCodegen.arrayType(this._typeFromGraphQl(gqlType.get('type'))) - return nullable ? tsCodegen.nullableType(type) : type - } else { - // NamedType - let type = tsCodegen.namedType( - typesCodegen.ascTypeForValue(this._resolveFieldType(gqlType)) as any, - ) - // In AssemblyScript, primitives cannot be nullable. - return nullable && !type.isPrimitive() ? tsCodegen.nullableType(type) : type + return this._typeFromGraphQl(gqlType.get('type'), false); + } + if (gqlType.get('kind') === 'ListType') { + const type = tsCodegen.arrayType(this._typeFromGraphQl(gqlType.get('type'))); + return nullable ? tsCodegen.nullableType(type) : type; } + // NamedType + const type = tsCodegen.namedType( + typesCodegen.ascTypeForValue(this._resolveFieldType(gqlType)) as any, + ); + // In AssemblyScript, primitives cannot be nullable. + return nullable && !type.isPrimitive() ? tsCodegen.nullableType(type) : type; } } diff --git a/packages/cli/src/codegen/template.ts b/packages/cli/src/codegen/template.ts index 97e0ced1..85314eae 100644 --- a/packages/cli/src/codegen/template.ts +++ b/packages/cli/src/codegen/template.ts @@ -1,19 +1,19 @@ -import immutable from 'immutable' -import Protocol from '../protocols' -import IpfsFileTemplateCodeGen from '../protocols/ipfs/codegen/file_template' -import * as tsCodegen from './typescript' +import immutable from 'immutable'; +import Protocol from '../protocols'; +import IpfsFileTemplateCodeGen from '../protocols/ipfs/codegen/file_template'; +import * as tsCodegen from './typescript'; export default class DataSourceTemplateCodeGenerator { - protocolTemplateCodeGen: any + protocolTemplateCodeGen: any; constructor(public template: immutable.Map, protocol: Protocol) { - this.template = template - let kind = template.get('kind') + this.template = template; + const kind = template.get('kind'); if (kind.split('/')[0] == protocol.name) { - this.protocolTemplateCodeGen = protocol.getTemplateCodeGen(template) + this.protocolTemplateCodeGen = protocol.getTemplateCodeGen(template); } else if (kind == 'file/ipfs') { - this.protocolTemplateCodeGen = new IpfsFileTemplateCodeGen(template) + this.protocolTemplateCodeGen = new IpfsFileTemplateCodeGen(template); } } @@ -27,19 +27,19 @@ export default class DataSourceTemplateCodeGenerator { ], '@graphprotocol/graph-ts', ), - ] + ]; } generateTypes() { - return immutable.List([this._generateTemplateType()]) + return immutable.List([this._generateTemplateType()]); } _generateTemplateType() { - let name = this.template.get('name') + const name = this.template.get('name'); - let klass = tsCodegen.klass(name, { export: true, extends: 'DataSourceTemplate' }) - klass.addMethod(this.protocolTemplateCodeGen.generateCreateMethod()) - klass.addMethod(this.protocolTemplateCodeGen.generateCreateWithContextMethod()) - return klass + const klass = tsCodegen.klass(name, { export: true, extends: 'DataSourceTemplate' }); + klass.addMethod(this.protocolTemplateCodeGen.generateCreateMethod()); + klass.addMethod(this.protocolTemplateCodeGen.generateCreateWithContextMethod()); + return klass; } } diff --git a/packages/cli/src/codegen/types/conversions.ts b/packages/cli/src/codegen/types/conversions.ts index a2eab4ab..030b856a 100644 --- a/packages/cli/src/codegen/types/conversions.ts +++ b/packages/cli/src/codegen/types/conversions.ts @@ -1,4 +1,4 @@ -import immutable from 'immutable' +import immutable from 'immutable'; /** * ethereum.Value -> AssemblyScript conversions @@ -105,7 +105,7 @@ const ETHEREUM_VALUE_TO_ASSEMBLYSCRIPT = [ 'Array>', (code: any, type: any) => `${code}.toTupleMatrix<${type}>()`, ], -] +]; /** * AssemblyScript -> ethereum.Value conversions @@ -161,11 +161,7 @@ const ASSEMBLYSCRIPT_TO_ETHEREUM_VALUE = [ /^byte\[([0-9]+)?\]$/, (code: any) => `ethereum.Value.fromFixedBytesArray(${code})`, ], - [ - 'Array', - /bytes\[([0-9]+)?\]$/, - (code: any) => `ethereum.Value.fromBytesArray(${code})`, - ], + ['Array', /bytes\[([0-9]+)?\]$/, (code: any) => `ethereum.Value.fromBytesArray(${code})`], [ 'Array', /^bytes(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32)\[([0-9]+)?\]$/, @@ -263,7 +259,7 @@ const ASSEMBLYSCRIPT_TO_ETHEREUM_VALUE = [ /^tuple\[([0-9]+)?\]\[([0-9]+)?\]$/, (code: any) => `ethereum.Value.fromTupleMatrix(${code})`, ], -] +]; /** * Value -> AssemblyScript conversions @@ -290,7 +286,7 @@ const VALUE_TO_ASSEMBLYSCRIPT = [ ['String', 'string', (code: any) => `${code}.toString()`], ['BigDecimal', 'BigDecimal', (code: any) => `${code}.toBigDecimal()`], [/.*/, 'string', (code: any) => `${code}.toString()`], -] +]; /** * AssemblyScript -> Value conversions @@ -304,33 +300,17 @@ const ASSEMBLYSCRIPT_TO_VALUE = [ ['Array>', '[[Bytes]]', (code: any) => `Value.fromBytesMatrix(${code})`], ['Array>', '[[Bytes]]', (code: any) => `Value.fromBytesMatrix(${code})`], - [ - 'Array>', - '[[Boolean]]', - (code: any) => `Value.fromBooleanMatrix(${code})`, - ], + ['Array>', '[[Boolean]]', (code: any) => `Value.fromBooleanMatrix(${code})`], ['Array>', '[[Int]]', (code: any) => `Value.fromI32Matrix(${code})`], - [ - 'Array>', - '[[BigInt]]', - (code: any) => `Value.fromBigIntMatrix(${code})`, - ], - [ - 'Array>', - '[[String]]', - (code: any) => `Value.fromStringMatrix(${code})`, - ], + ['Array>', '[[BigInt]]', (code: any) => `Value.fromBigIntMatrix(${code})`], + ['Array>', '[[String]]', (code: any) => `Value.fromStringMatrix(${code})`], ['Array>', '[[ID]]', (code: any) => `Value.fromStringMatrix(${code})`], [ 'Array>', '[[BigDecimal]]', (code: any) => `Value.fromBigDecimalMatrix(${code})`, ], - [ - 'Array>', - /\[\[.*\]\]/, - (code: any) => `Value.fromStringMatrix(${code})`, - ], + ['Array>', /\[\[.*\]\]/, (code: any) => `Value.fromStringMatrix(${code})`], ['Array>', null, (code: any) => `Value.fromStringMatrix(${code})`], // is this overwriting the Array null below? // Arrays @@ -342,11 +322,7 @@ const ASSEMBLYSCRIPT_TO_VALUE = [ ['Array', '[BigInt]', (code: any) => `Value.fromBigIntArray(${code})`], ['Array', '[String]', (code: any) => `Value.fromStringArray(${code})`], ['Array', '[ID]', (code: any) => `Value.fromStringArray(${code})`], - [ - 'Array', - '[BigDecimal]', - (code: any) => `Value.fromBigDecimalArray(${code})`, - ], + ['Array', '[BigDecimal]', (code: any) => `Value.fromBigDecimalArray(${code})`], ['Array', /\[.*\]/, (code: any) => `Value.fromStringArray(${code})`], ['Array', null, (code: any) => `Value.fromStringArray(${code})`], @@ -361,7 +337,7 @@ const ASSEMBLYSCRIPT_TO_VALUE = [ ['string', 'ID', (code: any) => `Value.fromString(${code})`], ['BigDecimal', 'BigDecimal', (code: any) => `Value.fromBigDecimal(${code})`], ['string', /.*/, (code: any) => `Value.fromString(${code})`], -] +]; const CONVERSIONS = { ethereum: { @@ -374,9 +350,9 @@ const CONVERSIONS = { Value: { AssemblyScript: VALUE_TO_ASSEMBLYSCRIPT, }, -} as const +} as const; /** * Type conversions */ -export default immutable.fromJS(CONVERSIONS) +export default immutable.fromJS(CONVERSIONS); diff --git a/packages/cli/src/codegen/types/index.test.ts b/packages/cli/src/codegen/types/index.test.ts index a3a0926c..b74dadc6 100644 --- a/packages/cli/src/codegen/types/index.test.ts +++ b/packages/cli/src/codegen/types/index.test.ts @@ -1,805 +1,715 @@ -import * as codegen from '.' +import * as codegen from '.'; describe('ethereum.Value -> AssemblyScript', () => { // Scalar values test('address -> Address', () => { - expect(codegen.ethereumToAsc('x', 'address')).toBe('x.toAddress()') - expect(codegen.ascTypeForEthereum('address')).toBe('Address') - }) + expect(codegen.ethereumToAsc('x', 'address')).toBe('x.toAddress()'); + expect(codegen.ascTypeForEthereum('address')).toBe('Address'); + }); test('bool -> boolean', () => { - expect(codegen.ethereumToAsc('x', 'bool')).toBe('x.toBoolean()') - expect(codegen.ascTypeForEthereum('bool')).toBe('boolean') - }) + expect(codegen.ethereumToAsc('x', 'bool')).toBe('x.toBoolean()'); + expect(codegen.ascTypeForEthereum('bool')).toBe('boolean'); + }); test('byte -> Bytes', () => { - expect(codegen.ethereumToAsc('x', 'byte')).toBe('x.toBytes()') - expect(codegen.ascTypeForEthereum('byte')).toBe('Bytes') - }) + expect(codegen.ethereumToAsc('x', 'byte')).toBe('x.toBytes()'); + expect(codegen.ascTypeForEthereum('byte')).toBe('Bytes'); + }); test('bytes -> Bytes', () => { - expect(codegen.ethereumToAsc('x', 'bytes')).toBe('x.toBytes()') - expect(codegen.ascTypeForEthereum('bytes')).toBe('Bytes') - }) + expect(codegen.ethereumToAsc('x', 'bytes')).toBe('x.toBytes()'); + expect(codegen.ascTypeForEthereum('bytes')).toBe('Bytes'); + }); test('bytes0 (invalid)', () => { - expect(() => codegen.ethereumToAsc('x', 'bytes0')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes0')).toThrow() - }) + expect(() => codegen.ethereumToAsc('x', 'bytes0')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes0')).toThrow(); + }); test('bytes1..32 -> Bytes', () => { for (let i = 1; i <= 32; i++) { - expect(codegen.ethereumToAsc('x', `bytes${i}`)).toBe('x.toBytes()') - expect(codegen.ascTypeForEthereum(`bytes${i}`)).toBe('Bytes') + expect(codegen.ethereumToAsc('x', `bytes${i}`)).toBe('x.toBytes()'); + expect(codegen.ascTypeForEthereum(`bytes${i}`)).toBe('Bytes'); } - }) + }); test('bytes33 (invalid)', () => { - expect(() => codegen.ethereumToAsc('x', 'bytes33')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes33')).toThrow() - }) + expect(() => codegen.ethereumToAsc('x', 'bytes33')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes33')).toThrow(); + }); test('int8..32, uint8..uint24 -> i32', () => { for (let i = 8; i <= 32; i += 8) { - expect(codegen.ethereumToAsc('x', `int${i}`)).toBe('x.toI32()') - expect(codegen.ascTypeForEthereum(`int${i}`)).toBe('i32') + expect(codegen.ethereumToAsc('x', `int${i}`)).toBe('x.toI32()'); + expect(codegen.ascTypeForEthereum(`int${i}`)).toBe('i32'); } for (let i = 8; i <= 24; i += 8) { - expect(codegen.ethereumToAsc('x', `uint${i}`)).toBe('x.toI32()') - expect(codegen.ascTypeForEthereum(`uint${i}`)).toBe('i32') + expect(codegen.ethereumToAsc('x', `uint${i}`)).toBe('x.toI32()'); + expect(codegen.ascTypeForEthereum(`uint${i}`)).toBe('i32'); } - }) + }); test('uint32 -> BigInt', () => { - expect(codegen.ethereumToAsc('x', `uint32`)).toBe('x.toBigInt()') - expect(codegen.ascTypeForEthereum('uint32')).toBe('BigInt') - }) + expect(codegen.ethereumToAsc('x', `uint32`)).toBe('x.toBigInt()'); + expect(codegen.ascTypeForEthereum('uint32')).toBe('BigInt'); + }); test('(u)int40..256 -> BigInt', () => { for (let i = 40; i <= 256; i += 8) { - expect(codegen.ethereumToAsc('x', `int${i}`)).toBe('x.toBigInt()') - expect(codegen.ethereumToAsc('x', `uint${i}`)).toBe('x.toBigInt()') - expect(codegen.ascTypeForEthereum(`int${i}`)).toBe('BigInt') - expect(codegen.ascTypeForEthereum(`uint${i}`)).toBe('BigInt') + expect(codegen.ethereumToAsc('x', `int${i}`)).toBe('x.toBigInt()'); + expect(codegen.ethereumToAsc('x', `uint${i}`)).toBe('x.toBigInt()'); + expect(codegen.ascTypeForEthereum(`int${i}`)).toBe('BigInt'); + expect(codegen.ascTypeForEthereum(`uint${i}`)).toBe('BigInt'); } - }) + }); test('string -> String', () => { - expect(codegen.ethereumToAsc('x', 'string')).toBe('x.toString()') - expect(codegen.ascTypeForEthereum('string')).toBe('string') - }) + expect(codegen.ethereumToAsc('x', 'string')).toBe('x.toString()'); + expect(codegen.ascTypeForEthereum('string')).toBe('string'); + }); // Array values test('address[*] -> Array
', () => { - expect(codegen.ethereumToAsc('x', 'address[]')).toBe('x.toAddressArray()') - expect(codegen.ethereumToAsc('x', 'address[1]')).toBe('x.toAddressArray()') - expect(codegen.ethereumToAsc('x', 'address[123]')).toBe('x.toAddressArray()') - expect(codegen.ascTypeForEthereum('address[]')).toBe('Array
') - expect(codegen.ascTypeForEthereum('address[1]')).toBe('Array
') - expect(codegen.ascTypeForEthereum('address[123]')).toBe('Array
') - }) + expect(codegen.ethereumToAsc('x', 'address[]')).toBe('x.toAddressArray()'); + expect(codegen.ethereumToAsc('x', 'address[1]')).toBe('x.toAddressArray()'); + expect(codegen.ethereumToAsc('x', 'address[123]')).toBe('x.toAddressArray()'); + expect(codegen.ascTypeForEthereum('address[]')).toBe('Array
'); + expect(codegen.ascTypeForEthereum('address[1]')).toBe('Array
'); + expect(codegen.ascTypeForEthereum('address[123]')).toBe('Array
'); + }); test('bool[*] -> Array', () => { - expect(codegen.ethereumToAsc('x', 'bool[]')).toBe('x.toBooleanArray()') - expect(codegen.ethereumToAsc('x', 'bool[5]')).toBe('x.toBooleanArray()') - expect(codegen.ethereumToAsc('x', 'bool[275]')).toBe('x.toBooleanArray()') - expect(codegen.ascTypeForEthereum('bool[]')).toBe('Array') - expect(codegen.ascTypeForEthereum('bool[5]')).toBe('Array') - expect(codegen.ascTypeForEthereum('bool[275]')).toBe('Array') - }) + expect(codegen.ethereumToAsc('x', 'bool[]')).toBe('x.toBooleanArray()'); + expect(codegen.ethereumToAsc('x', 'bool[5]')).toBe('x.toBooleanArray()'); + expect(codegen.ethereumToAsc('x', 'bool[275]')).toBe('x.toBooleanArray()'); + expect(codegen.ascTypeForEthereum('bool[]')).toBe('Array'); + expect(codegen.ascTypeForEthereum('bool[5]')).toBe('Array'); + expect(codegen.ascTypeForEthereum('bool[275]')).toBe('Array'); + }); test('byte[*] -> Array', () => { - expect(codegen.ethereumToAsc('x', 'byte[]')).toBe('x.toBytesArray()') - expect(codegen.ethereumToAsc('x', 'byte[7]')).toBe('x.toBytesArray()') - expect(codegen.ethereumToAsc('x', 'byte[553]')).toBe('x.toBytesArray()') - expect(codegen.ascTypeForEthereum('byte[]')).toBe('Array') - expect(codegen.ascTypeForEthereum('byte[7]')).toBe('Array') - expect(codegen.ascTypeForEthereum('byte[553]')).toBe('Array') - }) + expect(codegen.ethereumToAsc('x', 'byte[]')).toBe('x.toBytesArray()'); + expect(codegen.ethereumToAsc('x', 'byte[7]')).toBe('x.toBytesArray()'); + expect(codegen.ethereumToAsc('x', 'byte[553]')).toBe('x.toBytesArray()'); + expect(codegen.ascTypeForEthereum('byte[]')).toBe('Array'); + expect(codegen.ascTypeForEthereum('byte[7]')).toBe('Array'); + expect(codegen.ascTypeForEthereum('byte[553]')).toBe('Array'); + }); test('bytes[*] -> Array', () => { - expect(codegen.ethereumToAsc('x', 'bytes[]')).toBe('x.toBytesArray()') - expect(codegen.ethereumToAsc('x', 'bytes[14]')).toBe('x.toBytesArray()') - expect(codegen.ethereumToAsc('x', 'bytes[444]')).toBe('x.toBytesArray()') - expect(codegen.ascTypeForEthereum('bytes[]')).toBe('Array') - expect(codegen.ascTypeForEthereum('bytes[14]')).toBe('Array') - expect(codegen.ascTypeForEthereum('bytes[444]')).toBe('Array') - }) + expect(codegen.ethereumToAsc('x', 'bytes[]')).toBe('x.toBytesArray()'); + expect(codegen.ethereumToAsc('x', 'bytes[14]')).toBe('x.toBytesArray()'); + expect(codegen.ethereumToAsc('x', 'bytes[444]')).toBe('x.toBytesArray()'); + expect(codegen.ascTypeForEthereum('bytes[]')).toBe('Array'); + expect(codegen.ascTypeForEthereum('bytes[14]')).toBe('Array'); + expect(codegen.ascTypeForEthereum('bytes[444]')).toBe('Array'); + }); test('bytes0[*] (invalid)', () => { - expect(() => codegen.ethereumToAsc('x', 'bytes0[]')).toThrow() - expect(() => codegen.ethereumToAsc('x', 'bytes0[83]')).toThrow() - expect(() => codegen.ethereumToAsc('x', 'bytes0[123]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes0[]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes0[83]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes0[123]')).toThrow() - }) + expect(() => codegen.ethereumToAsc('x', 'bytes0[]')).toThrow(); + expect(() => codegen.ethereumToAsc('x', 'bytes0[83]')).toThrow(); + expect(() => codegen.ethereumToAsc('x', 'bytes0[123]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes0[]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes0[83]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes0[123]')).toThrow(); + }); test('bytes1..32[*] -> Array', () => { for (let i = 1; i <= 32; i++) { - expect(codegen.ethereumToAsc('x', `bytes${i}[]`)).toBe('x.toBytesArray()') - expect(codegen.ethereumToAsc('x', `bytes${i}[7]`)).toBe('x.toBytesArray()') - expect(codegen.ethereumToAsc('x', `bytes${i}[432]`)).toBe('x.toBytesArray()') - expect(codegen.ascTypeForEthereum(`bytes${i}[]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`bytes${i}[7]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`bytes${i}[432]`)).toBe('Array') + expect(codegen.ethereumToAsc('x', `bytes${i}[]`)).toBe('x.toBytesArray()'); + expect(codegen.ethereumToAsc('x', `bytes${i}[7]`)).toBe('x.toBytesArray()'); + expect(codegen.ethereumToAsc('x', `bytes${i}[432]`)).toBe('x.toBytesArray()'); + expect(codegen.ascTypeForEthereum(`bytes${i}[]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`bytes${i}[7]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`bytes${i}[432]`)).toBe('Array'); } - }) + }); test('bytes33[*] (invalid)', () => { - expect(() => codegen.ethereumToAsc('x', 'bytes33[]')).toThrow() - expect(() => codegen.ethereumToAsc('x', 'bytes33[58]')).toThrow() - expect(() => codegen.ethereumToAsc('x', 'bytes33[394]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes33[]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes33[58]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes33[394]')).toThrow() - }) + expect(() => codegen.ethereumToAsc('x', 'bytes33[]')).toThrow(); + expect(() => codegen.ethereumToAsc('x', 'bytes33[58]')).toThrow(); + expect(() => codegen.ethereumToAsc('x', 'bytes33[394]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes33[]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes33[58]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes33[394]')).toThrow(); + }); test('int8..32[*], uint8..24[*] -> Array', () => { for (let i = 8; i <= 32; i += 8) { - expect(codegen.ethereumToAsc('x', `int${i}[]`)).toBe('x.toI32Array()') - expect(codegen.ethereumToAsc('x', `int${i}[6]`)).toBe('x.toI32Array()') - expect(codegen.ethereumToAsc('x', `int${i}[4638]`)).toBe('x.toI32Array()') - expect(codegen.ascTypeForEthereum(`int${i}[]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`int${i}[6]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`int${i}[4638]`)).toBe('Array') + expect(codegen.ethereumToAsc('x', `int${i}[]`)).toBe('x.toI32Array()'); + expect(codegen.ethereumToAsc('x', `int${i}[6]`)).toBe('x.toI32Array()'); + expect(codegen.ethereumToAsc('x', `int${i}[4638]`)).toBe('x.toI32Array()'); + expect(codegen.ascTypeForEthereum(`int${i}[]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`int${i}[6]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`int${i}[4638]`)).toBe('Array'); } for (let i = 8; i <= 24; i += 8) { - expect(codegen.ethereumToAsc('x', `uint${i}[]`)).toBe('x.toI32Array()') - expect(codegen.ethereumToAsc('x', `uint${i}[6]`)).toBe('x.toI32Array()') - expect(codegen.ethereumToAsc('x', `uint${i}[593]`)).toBe('x.toI32Array()') - expect(codegen.ascTypeForEthereum(`uint${i}[]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`uint${i}[6]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`uint${i}[593]`)).toBe('Array') + expect(codegen.ethereumToAsc('x', `uint${i}[]`)).toBe('x.toI32Array()'); + expect(codegen.ethereumToAsc('x', `uint${i}[6]`)).toBe('x.toI32Array()'); + expect(codegen.ethereumToAsc('x', `uint${i}[593]`)).toBe('x.toI32Array()'); + expect(codegen.ascTypeForEthereum(`uint${i}[]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`uint${i}[6]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`uint${i}[593]`)).toBe('Array'); } - }) + }); test('uint32[*] -> Array', () => { - expect(codegen.ethereumToAsc('x', `uint32[]`)).toBe('x.toBigIntArray()') - expect(codegen.ethereumToAsc('x', `uint32[6]`)).toBe('x.toBigIntArray()') - expect(codegen.ethereumToAsc('x', `uint32[593]`)).toBe('x.toBigIntArray()') - expect(codegen.ascTypeForEthereum(`uint32[]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`uint32[6]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`uint32[593]`)).toBe('Array') - }) + expect(codegen.ethereumToAsc('x', `uint32[]`)).toBe('x.toBigIntArray()'); + expect(codegen.ethereumToAsc('x', `uint32[6]`)).toBe('x.toBigIntArray()'); + expect(codegen.ethereumToAsc('x', `uint32[593]`)).toBe('x.toBigIntArray()'); + expect(codegen.ascTypeForEthereum(`uint32[]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`uint32[6]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`uint32[593]`)).toBe('Array'); + }); test('(u)int40..256[*] -> Array', () => { for (let i = 40; i <= 256; i += 8) { - expect(codegen.ethereumToAsc('x', `int${i}[]`)).toBe('x.toBigIntArray()') - expect(codegen.ethereumToAsc('x', `int${i}[7]`)).toBe('x.toBigIntArray()') - expect(codegen.ethereumToAsc('x', `int${i}[6833]`)).toBe('x.toBigIntArray()') - expect(codegen.ascTypeForEthereum(`int${i}[]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`int${i}[7]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`int${i}[6833]`)).toBe('Array') - - expect(codegen.ethereumToAsc('x', `uint${i}[]`)).toBe('x.toBigIntArray()') - expect(codegen.ethereumToAsc('x', `uint${i}[23]`)).toBe('x.toBigIntArray()') - expect(codegen.ethereumToAsc('x', `uint${i}[467]`)).toBe('x.toBigIntArray()') - expect(codegen.ascTypeForEthereum(`uint${i}[]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`uint${i}[23]`)).toBe('Array') - expect(codegen.ascTypeForEthereum(`uint${i}[467]`)).toBe('Array') + expect(codegen.ethereumToAsc('x', `int${i}[]`)).toBe('x.toBigIntArray()'); + expect(codegen.ethereumToAsc('x', `int${i}[7]`)).toBe('x.toBigIntArray()'); + expect(codegen.ethereumToAsc('x', `int${i}[6833]`)).toBe('x.toBigIntArray()'); + expect(codegen.ascTypeForEthereum(`int${i}[]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`int${i}[7]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`int${i}[6833]`)).toBe('Array'); + + expect(codegen.ethereumToAsc('x', `uint${i}[]`)).toBe('x.toBigIntArray()'); + expect(codegen.ethereumToAsc('x', `uint${i}[23]`)).toBe('x.toBigIntArray()'); + expect(codegen.ethereumToAsc('x', `uint${i}[467]`)).toBe('x.toBigIntArray()'); + expect(codegen.ascTypeForEthereum(`uint${i}[]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`uint${i}[23]`)).toBe('Array'); + expect(codegen.ascTypeForEthereum(`uint${i}[467]`)).toBe('Array'); } - }) + }); test('string[*] -> Array', () => { - expect(codegen.ethereumToAsc('x', 'string[]')).toBe('x.toStringArray()') - expect(codegen.ethereumToAsc('x', 'string[4]')).toBe('x.toStringArray()') - expect(codegen.ethereumToAsc('x', 'string[754]')).toBe('x.toStringArray()') - expect(codegen.ascTypeForEthereum('string[]')).toBe('Array') - expect(codegen.ascTypeForEthereum('string[4]')).toBe('Array') - expect(codegen.ascTypeForEthereum('string[754]')).toBe('Array') - }) + expect(codegen.ethereumToAsc('x', 'string[]')).toBe('x.toStringArray()'); + expect(codegen.ethereumToAsc('x', 'string[4]')).toBe('x.toStringArray()'); + expect(codegen.ethereumToAsc('x', 'string[754]')).toBe('x.toStringArray()'); + expect(codegen.ascTypeForEthereum('string[]')).toBe('Array'); + expect(codegen.ascTypeForEthereum('string[4]')).toBe('Array'); + expect(codegen.ascTypeForEthereum('string[754]')).toBe('Array'); + }); // Multi dimensional arrays test('address[*][*] -> Array>', () => { - expect(codegen.ethereumToAsc('x', 'address[][]')).toBe('x.toAddressMatrix()') - expect(codegen.ethereumToAsc('x', 'address[5][]')).toBe('x.toAddressMatrix()') - expect(codegen.ethereumToAsc('x', 'address[][4]')).toBe('x.toAddressMatrix()') - expect(codegen.ethereumToAsc('x', 'address[1][2]')).toBe('x.toAddressMatrix()') - expect(codegen.ethereumToAsc('x', 'address[123][321]')).toBe('x.toAddressMatrix()') - - expect(codegen.ascTypeForEthereum('address[][]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('address[5][]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('address[][4]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('address[1][2]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('address[123][321]')).toBe('Array>') - }) + expect(codegen.ethereumToAsc('x', 'address[][]')).toBe('x.toAddressMatrix()'); + expect(codegen.ethereumToAsc('x', 'address[5][]')).toBe('x.toAddressMatrix()'); + expect(codegen.ethereumToAsc('x', 'address[][4]')).toBe('x.toAddressMatrix()'); + expect(codegen.ethereumToAsc('x', 'address[1][2]')).toBe('x.toAddressMatrix()'); + expect(codegen.ethereumToAsc('x', 'address[123][321]')).toBe('x.toAddressMatrix()'); + + expect(codegen.ascTypeForEthereum('address[][]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('address[5][]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('address[][4]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('address[1][2]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('address[123][321]')).toBe('Array>'); + }); test('bool[*][*] -> Array>', () => { - expect(codegen.ethereumToAsc('x', 'bool[][]')).toBe('x.toBooleanMatrix()') - expect(codegen.ethereumToAsc('x', 'bool[1][]')).toBe('x.toBooleanMatrix()') - expect(codegen.ethereumToAsc('x', 'bool[][3]')).toBe('x.toBooleanMatrix()') - expect(codegen.ethereumToAsc('x', 'bool[5][2]')).toBe('x.toBooleanMatrix()') - expect(codegen.ethereumToAsc('x', 'bool[275][572]')).toBe('x.toBooleanMatrix()') - - expect(codegen.ascTypeForEthereum('bool[][]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('bool[1][]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('bool[][3]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('bool[5][2]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('bool[275][572]')).toBe('Array>') - }) + expect(codegen.ethereumToAsc('x', 'bool[][]')).toBe('x.toBooleanMatrix()'); + expect(codegen.ethereumToAsc('x', 'bool[1][]')).toBe('x.toBooleanMatrix()'); + expect(codegen.ethereumToAsc('x', 'bool[][3]')).toBe('x.toBooleanMatrix()'); + expect(codegen.ethereumToAsc('x', 'bool[5][2]')).toBe('x.toBooleanMatrix()'); + expect(codegen.ethereumToAsc('x', 'bool[275][572]')).toBe('x.toBooleanMatrix()'); + + expect(codegen.ascTypeForEthereum('bool[][]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('bool[1][]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('bool[][3]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('bool[5][2]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('bool[275][572]')).toBe('Array>'); + }); test('byte[*][*] -> Array>', () => { - expect(codegen.ethereumToAsc('x', 'byte[][]')).toBe('x.toBytesMatrix()') - expect(codegen.ethereumToAsc('x', 'byte[7][]')).toBe('x.toBytesMatrix()') - expect(codegen.ethereumToAsc('x', 'byte[][8]')).toBe('x.toBytesMatrix()') - expect(codegen.ethereumToAsc('x', 'byte[553][355]')).toBe('x.toBytesMatrix()') + expect(codegen.ethereumToAsc('x', 'byte[][]')).toBe('x.toBytesMatrix()'); + expect(codegen.ethereumToAsc('x', 'byte[7][]')).toBe('x.toBytesMatrix()'); + expect(codegen.ethereumToAsc('x', 'byte[][8]')).toBe('x.toBytesMatrix()'); + expect(codegen.ethereumToAsc('x', 'byte[553][355]')).toBe('x.toBytesMatrix()'); - expect(codegen.ascTypeForEthereum('byte[][]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('byte[7][]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('byte[][8]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('byte[553][355]')).toBe('Array>') - }) + expect(codegen.ascTypeForEthereum('byte[][]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('byte[7][]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('byte[][8]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('byte[553][355]')).toBe('Array>'); + }); test('bytes[*][*] -> Array>', () => { - expect(codegen.ethereumToAsc('x', 'bytes[][]')).toBe('x.toBytesMatrix()') - expect(codegen.ethereumToAsc('x', 'bytes[14][]')).toBe('x.toBytesMatrix()') - expect(codegen.ethereumToAsc('x', 'bytes[][41]')).toBe('x.toBytesMatrix()') - expect(codegen.ethereumToAsc('x', 'bytes[444][555]')).toBe('x.toBytesMatrix()') + expect(codegen.ethereumToAsc('x', 'bytes[][]')).toBe('x.toBytesMatrix()'); + expect(codegen.ethereumToAsc('x', 'bytes[14][]')).toBe('x.toBytesMatrix()'); + expect(codegen.ethereumToAsc('x', 'bytes[][41]')).toBe('x.toBytesMatrix()'); + expect(codegen.ethereumToAsc('x', 'bytes[444][555]')).toBe('x.toBytesMatrix()'); - expect(codegen.ascTypeForEthereum('bytes[][]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('bytes[14][]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('bytes[][41]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('bytes[444][555]')).toBe('Array>') - }) + expect(codegen.ascTypeForEthereum('bytes[][]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('bytes[14][]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('bytes[][41]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('bytes[444][555]')).toBe('Array>'); + }); test('bytes0[*][*] (invalid)', () => { - expect(() => codegen.ethereumToAsc('x', 'bytes0[][]')).toThrow() - expect(() => codegen.ethereumToAsc('x', 'bytes0[83][]')).toThrow() - expect(() => codegen.ethereumToAsc('x', 'bytes0[][83]')).toThrow() - expect(() => codegen.ethereumToAsc('x', 'bytes0[123][321]')).toThrow() + expect(() => codegen.ethereumToAsc('x', 'bytes0[][]')).toThrow(); + expect(() => codegen.ethereumToAsc('x', 'bytes0[83][]')).toThrow(); + expect(() => codegen.ethereumToAsc('x', 'bytes0[][83]')).toThrow(); + expect(() => codegen.ethereumToAsc('x', 'bytes0[123][321]')).toThrow(); - expect(() => codegen.ascTypeForEthereum('bytes0[][]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes0[83][]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes0[][83]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes0[123][321]')).toThrow() - }) + expect(() => codegen.ascTypeForEthereum('bytes0[][]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes0[83][]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes0[][83]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes0[123][321]')).toThrow(); + }); test('bytes1..32[*][*] -> Array>', () => { for (let i = 1; i <= 32; i++) { - expect(codegen.ethereumToAsc('x', `bytes${i}[][]`)).toBe('x.toBytesMatrix()') - expect(codegen.ethereumToAsc('x', `bytes${i}[7][]`)).toBe('x.toBytesMatrix()') - expect(codegen.ethereumToAsc('x', `bytes${i}[][7]`)).toBe('x.toBytesMatrix()') - expect(codegen.ethereumToAsc('x', `bytes${i}[432][234]`)).toBe('x.toBytesMatrix()') - - expect(codegen.ascTypeForEthereum(`bytes${i}[][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`bytes${i}[6][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`bytes${i}[][7]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`bytes${i}[432][234]`)).toBe( - 'Array>', - ) + expect(codegen.ethereumToAsc('x', `bytes${i}[][]`)).toBe('x.toBytesMatrix()'); + expect(codegen.ethereumToAsc('x', `bytes${i}[7][]`)).toBe('x.toBytesMatrix()'); + expect(codegen.ethereumToAsc('x', `bytes${i}[][7]`)).toBe('x.toBytesMatrix()'); + expect(codegen.ethereumToAsc('x', `bytes${i}[432][234]`)).toBe('x.toBytesMatrix()'); + + expect(codegen.ascTypeForEthereum(`bytes${i}[][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`bytes${i}[6][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`bytes${i}[][7]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`bytes${i}[432][234]`)).toBe('Array>'); } - }) + }); test('bytes33[*][*] (invalid)', () => { - expect(() => codegen.ethereumToAsc('x', 'bytes33[][]')).toThrow() - expect(() => codegen.ethereumToAsc('x', 'bytes33[58][]')).toThrow() - expect(() => codegen.ethereumToAsc('x', 'bytes33[][85]')).toThrow() - expect(() => codegen.ethereumToAsc('x', 'bytes33[394][493]')).toThrow() + expect(() => codegen.ethereumToAsc('x', 'bytes33[][]')).toThrow(); + expect(() => codegen.ethereumToAsc('x', 'bytes33[58][]')).toThrow(); + expect(() => codegen.ethereumToAsc('x', 'bytes33[][85]')).toThrow(); + expect(() => codegen.ethereumToAsc('x', 'bytes33[394][493]')).toThrow(); - expect(() => codegen.ascTypeForEthereum('bytes33[][]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes33[58][]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes33[][85]')).toThrow() - expect(() => codegen.ascTypeForEthereum('bytes33[394][493]')).toThrow() - }) + expect(() => codegen.ascTypeForEthereum('bytes33[][]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes33[58][]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes33[][85]')).toThrow(); + expect(() => codegen.ascTypeForEthereum('bytes33[394][493]')).toThrow(); + }); test('int8..32[*][*], uint8..24[*][*] -> Array>', () => { for (let i = 8; i <= 32; i += 8) { - expect(codegen.ethereumToAsc('x', `int${i}[][]`)).toBe('x.toI32Matrix()') - expect(codegen.ethereumToAsc('x', `int${i}[6][]`)).toBe('x.toI32Matrix()') - expect(codegen.ethereumToAsc('x', `int${i}[][6]`)).toBe('x.toI32Matrix()') - expect(codegen.ethereumToAsc('x', `int${i}[4638][8364]`)).toBe('x.toI32Matrix()') - - expect(codegen.ascTypeForEthereum(`int${i}[][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`int${i}[6][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`int${i}[][6]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`int${i}[4638][8364]`)).toBe('Array>') + expect(codegen.ethereumToAsc('x', `int${i}[][]`)).toBe('x.toI32Matrix()'); + expect(codegen.ethereumToAsc('x', `int${i}[6][]`)).toBe('x.toI32Matrix()'); + expect(codegen.ethereumToAsc('x', `int${i}[][6]`)).toBe('x.toI32Matrix()'); + expect(codegen.ethereumToAsc('x', `int${i}[4638][8364]`)).toBe('x.toI32Matrix()'); + + expect(codegen.ascTypeForEthereum(`int${i}[][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`int${i}[6][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`int${i}[][6]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`int${i}[4638][8364]`)).toBe('Array>'); } for (let i = 8; i <= 24; i += 8) { - expect(codegen.ethereumToAsc('x', `uint${i}[][]`)).toBe('x.toI32Matrix()') - expect(codegen.ethereumToAsc('x', `uint${i}[6][]`)).toBe('x.toI32Matrix()') - expect(codegen.ethereumToAsc('x', `uint${i}[][6]`)).toBe('x.toI32Matrix()') - expect(codegen.ethereumToAsc('x', `uint${i}[593][395]`)).toBe('x.toI32Matrix()') - - expect(codegen.ascTypeForEthereum(`uint${i}[][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`uint${i}[6][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`uint${i}[][6]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`uint${i}[593][395]`)).toBe('Array>') + expect(codegen.ethereumToAsc('x', `uint${i}[][]`)).toBe('x.toI32Matrix()'); + expect(codegen.ethereumToAsc('x', `uint${i}[6][]`)).toBe('x.toI32Matrix()'); + expect(codegen.ethereumToAsc('x', `uint${i}[][6]`)).toBe('x.toI32Matrix()'); + expect(codegen.ethereumToAsc('x', `uint${i}[593][395]`)).toBe('x.toI32Matrix()'); + + expect(codegen.ascTypeForEthereum(`uint${i}[][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`uint${i}[6][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`uint${i}[][6]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`uint${i}[593][395]`)).toBe('Array>'); } - }) + }); test('uint32[*][*] -> Array>', () => { - expect(codegen.ethereumToAsc('x', `uint32[][]`)).toBe('x.toBigIntMatrix()') - expect(codegen.ethereumToAsc('x', `uint32[6][]`)).toBe('x.toBigIntMatrix()') - expect(codegen.ethereumToAsc('x', `uint32[][6]`)).toBe('x.toBigIntMatrix()') - expect(codegen.ethereumToAsc('x', `uint32[593][395]`)).toBe('x.toBigIntMatrix()') + expect(codegen.ethereumToAsc('x', `uint32[][]`)).toBe('x.toBigIntMatrix()'); + expect(codegen.ethereumToAsc('x', `uint32[6][]`)).toBe('x.toBigIntMatrix()'); + expect(codegen.ethereumToAsc('x', `uint32[][6]`)).toBe('x.toBigIntMatrix()'); + expect(codegen.ethereumToAsc('x', `uint32[593][395]`)).toBe('x.toBigIntMatrix()'); - expect(codegen.ascTypeForEthereum(`uint32[][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`uint32[6][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`uint32[][5]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`uint32[593][395]`)).toBe('Array>') - }) + expect(codegen.ascTypeForEthereum(`uint32[][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`uint32[6][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`uint32[][5]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`uint32[593][395]`)).toBe('Array>'); + }); test('(u)int40..256[*][*] -> Array>', () => { for (let i = 40; i <= 256; i += 8) { - expect(codegen.ethereumToAsc('x', `int${i}[][]`)).toBe('x.toBigIntMatrix()') - expect(codegen.ethereumToAsc('x', `int${i}[7][]`)).toBe('x.toBigIntMatrix()') - expect(codegen.ethereumToAsc('x', `int${i}[][7]`)).toBe('x.toBigIntMatrix()') - expect(codegen.ethereumToAsc('x', `int${i}[6833][3386]`)).toBe('x.toBigIntMatrix()') - - expect(codegen.ascTypeForEthereum(`int${i}[][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`int${i}[7][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`int${i}[][7]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`int${i}[6833][3386]`)).toBe( - 'Array>', - ) - - expect(codegen.ethereumToAsc('x', `uint${i}[][]`)).toBe('x.toBigIntMatrix()') - expect(codegen.ethereumToAsc('x', `uint${i}[23][]`)).toBe('x.toBigIntMatrix()') - expect(codegen.ethereumToAsc('x', `uint${i}[][32]`)).toBe('x.toBigIntMatrix()') - expect(codegen.ethereumToAsc('x', `uint${i}[467][764]`)).toBe('x.toBigIntMatrix()') - - expect(codegen.ascTypeForEthereum(`uint${i}[][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`uint${i}[23][]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`uint${i}[][32]`)).toBe('Array>') - expect(codegen.ascTypeForEthereum(`uint${i}[467][764]`)).toBe( - 'Array>', - ) + expect(codegen.ethereumToAsc('x', `int${i}[][]`)).toBe('x.toBigIntMatrix()'); + expect(codegen.ethereumToAsc('x', `int${i}[7][]`)).toBe('x.toBigIntMatrix()'); + expect(codegen.ethereumToAsc('x', `int${i}[][7]`)).toBe('x.toBigIntMatrix()'); + expect(codegen.ethereumToAsc('x', `int${i}[6833][3386]`)).toBe('x.toBigIntMatrix()'); + + expect(codegen.ascTypeForEthereum(`int${i}[][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`int${i}[7][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`int${i}[][7]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`int${i}[6833][3386]`)).toBe('Array>'); + + expect(codegen.ethereumToAsc('x', `uint${i}[][]`)).toBe('x.toBigIntMatrix()'); + expect(codegen.ethereumToAsc('x', `uint${i}[23][]`)).toBe('x.toBigIntMatrix()'); + expect(codegen.ethereumToAsc('x', `uint${i}[][32]`)).toBe('x.toBigIntMatrix()'); + expect(codegen.ethereumToAsc('x', `uint${i}[467][764]`)).toBe('x.toBigIntMatrix()'); + + expect(codegen.ascTypeForEthereum(`uint${i}[][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`uint${i}[23][]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`uint${i}[][32]`)).toBe('Array>'); + expect(codegen.ascTypeForEthereum(`uint${i}[467][764]`)).toBe('Array>'); } - }) + }); test('string[*][*] -> Array>', () => { - expect(codegen.ethereumToAsc('x', 'string[][]')).toBe('x.toStringMatrix()') - expect(codegen.ethereumToAsc('x', 'string[4][]')).toBe('x.toStringMatrix()') - expect(codegen.ethereumToAsc('x', 'string[][3]')).toBe('x.toStringMatrix()') - expect(codegen.ethereumToAsc('x', 'string[754][457]')).toBe('x.toStringMatrix()') - - expect(codegen.ascTypeForEthereum('string[][]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('string[4][]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('string[][3]')).toBe('Array>') - expect(codegen.ascTypeForEthereum('string[754][457]')).toBe('Array>') - }) -}) + expect(codegen.ethereumToAsc('x', 'string[][]')).toBe('x.toStringMatrix()'); + expect(codegen.ethereumToAsc('x', 'string[4][]')).toBe('x.toStringMatrix()'); + expect(codegen.ethereumToAsc('x', 'string[][3]')).toBe('x.toStringMatrix()'); + expect(codegen.ethereumToAsc('x', 'string[754][457]')).toBe('x.toStringMatrix()'); + + expect(codegen.ascTypeForEthereum('string[][]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('string[4][]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('string[][3]')).toBe('Array>'); + expect(codegen.ascTypeForEthereum('string[754][457]')).toBe('Array>'); + }); +}); describe('AssemblyScript -> ethereum.Value', () => { // Scalar values test('Address -> address', () => { - expect(codegen.ethereumFromAsc('x', 'address')).toBe('ethereum.Value.fromAddress(x)') - }) + expect(codegen.ethereumFromAsc('x', 'address')).toBe('ethereum.Value.fromAddress(x)'); + }); test('boolean -> bool', () => { - expect(codegen.ethereumFromAsc('x', 'bool')).toBe('ethereum.Value.fromBoolean(x)') - }) + expect(codegen.ethereumFromAsc('x', 'bool')).toBe('ethereum.Value.fromBoolean(x)'); + }); test('Bytes -> byte', () => { - expect(codegen.ethereumFromAsc('x', 'byte')).toBe('ethereum.Value.fromFixedBytes(x)') - }) + expect(codegen.ethereumFromAsc('x', 'byte')).toBe('ethereum.Value.fromFixedBytes(x)'); + }); test('Bytes -> bytes', () => { - expect(codegen.ethereumFromAsc('x', 'bytes')).toBe('ethereum.Value.fromBytes(x)') - }) + expect(codegen.ethereumFromAsc('x', 'bytes')).toBe('ethereum.Value.fromBytes(x)'); + }); test('Bytes -> bytes0 (invalid)', () => { - expect(() => codegen.ethereumFromAsc('x', 'bytes0')).toThrow() - }) + expect(() => codegen.ethereumFromAsc('x', 'bytes0')).toThrow(); + }); test('Bytes -> bytes1..32', () => { for (let i = 1; i <= 32; i++) { - expect(codegen.ethereumFromAsc('x', `bytes${i}`)).toBe( - 'ethereum.Value.fromFixedBytes(x)', - ) + expect(codegen.ethereumFromAsc('x', `bytes${i}`)).toBe('ethereum.Value.fromFixedBytes(x)'); } - }) + }); test('Bytes -> bytes33 (invalid)', () => { - expect(() => codegen.ethereumFromAsc('x', 'bytes33')).toThrow() - }) + expect(() => codegen.ethereumFromAsc('x', 'bytes33')).toThrow(); + }); test('i32 -> int8..32, uint8..24', () => { for (let i = 8; i <= 32; i += 8) { - expect(codegen.ethereumFromAsc('x', `int${i}`)).toBe(`ethereum.Value.fromI32(x)`) + expect(codegen.ethereumFromAsc('x', `int${i}`)).toBe(`ethereum.Value.fromI32(x)`); } for (let i = 8; i <= 24; i += 8) { expect(codegen.ethereumFromAsc('x', `uint${i}`)).toBe( `ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(x))`, - ) + ); } - }) + }); test('BigInt -> uint32', () => { - expect(codegen.ethereumFromAsc('x', `uint32`)).toBe( - `ethereum.Value.fromUnsignedBigInt(x)`, - ) - }) + expect(codegen.ethereumFromAsc('x', `uint32`)).toBe(`ethereum.Value.fromUnsignedBigInt(x)`); + }); test('BigInt -> (u)int40..256', () => { for (let i = 40; i <= 256; i += 8) { - expect(codegen.ethereumFromAsc('x', `int${i}`)).toBe( - `ethereum.Value.fromSignedBigInt(x)`, - ) - expect(codegen.ethereumFromAsc('x', `uint${i}`)).toBe( - `ethereum.Value.fromUnsignedBigInt(x)`, - ) + expect(codegen.ethereumFromAsc('x', `int${i}`)).toBe(`ethereum.Value.fromSignedBigInt(x)`); + expect(codegen.ethereumFromAsc('x', `uint${i}`)).toBe(`ethereum.Value.fromUnsignedBigInt(x)`); } - }) + }); test('String -> string', () => { - expect(codegen.ethereumFromAsc('x', 'string')).toBe('ethereum.Value.fromString(x)') - }) + expect(codegen.ethereumFromAsc('x', 'string')).toBe('ethereum.Value.fromString(x)'); + }); // Array values test('Array
-> address[*]', () => { - expect(codegen.ethereumFromAsc('x', 'address[]')).toBe( - 'ethereum.Value.fromAddressArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'address[1]')).toBe( - 'ethereum.Value.fromAddressArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'address[123]')).toBe( - 'ethereum.Value.fromAddressArray(x)', - ) - }) + expect(codegen.ethereumFromAsc('x', 'address[]')).toBe('ethereum.Value.fromAddressArray(x)'); + expect(codegen.ethereumFromAsc('x', 'address[1]')).toBe('ethereum.Value.fromAddressArray(x)'); + expect(codegen.ethereumFromAsc('x', 'address[123]')).toBe('ethereum.Value.fromAddressArray(x)'); + }); test('Array -> bool[*]', () => { - expect(codegen.ethereumFromAsc('x', 'bool[]')).toBe( - 'ethereum.Value.fromBooleanArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'bool[5]')).toBe( - 'ethereum.Value.fromBooleanArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'bool[275]')).toBe( - 'ethereum.Value.fromBooleanArray(x)', - ) - }) + expect(codegen.ethereumFromAsc('x', 'bool[]')).toBe('ethereum.Value.fromBooleanArray(x)'); + expect(codegen.ethereumFromAsc('x', 'bool[5]')).toBe('ethereum.Value.fromBooleanArray(x)'); + expect(codegen.ethereumFromAsc('x', 'bool[275]')).toBe('ethereum.Value.fromBooleanArray(x)'); + }); test('Array -> byte[*]', () => { - expect(codegen.ethereumFromAsc('x', 'byte[]')).toBe( - 'ethereum.Value.fromFixedBytesArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'byte[7]')).toBe( - 'ethereum.Value.fromFixedBytesArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'byte[553]')).toBe( - 'ethereum.Value.fromFixedBytesArray(x)', - ) - }) + expect(codegen.ethereumFromAsc('x', 'byte[]')).toBe('ethereum.Value.fromFixedBytesArray(x)'); + expect(codegen.ethereumFromAsc('x', 'byte[7]')).toBe('ethereum.Value.fromFixedBytesArray(x)'); + expect(codegen.ethereumFromAsc('x', 'byte[553]')).toBe('ethereum.Value.fromFixedBytesArray(x)'); + }); test('Array -> bytes[*]', () => { - expect(codegen.ethereumFromAsc('x', 'bytes[]')).toBe( - 'ethereum.Value.fromBytesArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'bytes[14]')).toBe( - 'ethereum.Value.fromBytesArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'bytes[444]')).toBe( - 'ethereum.Value.fromBytesArray(x)', - ) - }) + expect(codegen.ethereumFromAsc('x', 'bytes[]')).toBe('ethereum.Value.fromBytesArray(x)'); + expect(codegen.ethereumFromAsc('x', 'bytes[14]')).toBe('ethereum.Value.fromBytesArray(x)'); + expect(codegen.ethereumFromAsc('x', 'bytes[444]')).toBe('ethereum.Value.fromBytesArray(x)'); + }); test('bytes0[*] (invalid)', () => { - expect(() => codegen.ethereumFromAsc('x', 'bytes0[]')).toThrow() - expect(() => codegen.ethereumFromAsc('x', 'bytes0[83]')).toThrow() - expect(() => codegen.ethereumFromAsc('x', 'bytes0[123]')).toThrow() - }) + expect(() => codegen.ethereumFromAsc('x', 'bytes0[]')).toThrow(); + expect(() => codegen.ethereumFromAsc('x', 'bytes0[83]')).toThrow(); + expect(() => codegen.ethereumFromAsc('x', 'bytes0[123]')).toThrow(); + }); test('Array -> bytes1..32[*]', () => { for (let i = 1; i <= 32; i++) { expect(codegen.ethereumFromAsc('x', `bytes${i}[]`)).toBe( 'ethereum.Value.fromFixedBytesArray(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `bytes${i}[7]`)).toBe( 'ethereum.Value.fromFixedBytesArray(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `bytes${i}[432]`)).toBe( 'ethereum.Value.fromFixedBytesArray(x)', - ) + ); } - }) + }); test('bytes33[*] (invalid)', () => { - expect(() => codegen.ethereumFromAsc('x', 'bytes33[]')).toThrow() - expect(() => codegen.ethereumFromAsc('x', 'bytes33[58]')).toThrow() - expect(() => codegen.ethereumFromAsc('x', 'bytes33[394]')).toThrow() - }) + expect(() => codegen.ethereumFromAsc('x', 'bytes33[]')).toThrow(); + expect(() => codegen.ethereumFromAsc('x', 'bytes33[58]')).toThrow(); + expect(() => codegen.ethereumFromAsc('x', 'bytes33[394]')).toThrow(); + }); test('Array -> int8..32[*], uint8..24[*]', () => { for (let i = 8; i <= 32; i += 8) { - expect(codegen.ethereumFromAsc('x', `int${i}[]`)).toBe( - 'ethereum.Value.fromI32Array(x)', - ) - expect(codegen.ethereumFromAsc('x', `int${i}[6]`)).toBe( - 'ethereum.Value.fromI32Array(x)', - ) - expect(codegen.ethereumFromAsc('x', `int${i}[4638]`)).toBe( - 'ethereum.Value.fromI32Array(x)', - ) + expect(codegen.ethereumFromAsc('x', `int${i}[]`)).toBe('ethereum.Value.fromI32Array(x)'); + expect(codegen.ethereumFromAsc('x', `int${i}[6]`)).toBe('ethereum.Value.fromI32Array(x)'); + expect(codegen.ethereumFromAsc('x', `int${i}[4638]`)).toBe('ethereum.Value.fromI32Array(x)'); } for (let i = 8; i <= 24; i += 8) { - expect(codegen.ethereumFromAsc('x', `uint${i}[]`)).toBe( - 'ethereum.Value.fromI32Array(x)', - ) - expect(codegen.ethereumFromAsc('x', `uint${i}[6]`)).toBe( - 'ethereum.Value.fromI32Array(x)', - ) - expect(codegen.ethereumFromAsc('x', `uint${i}[593]`)).toBe( - 'ethereum.Value.fromI32Array(x)', - ) + expect(codegen.ethereumFromAsc('x', `uint${i}[]`)).toBe('ethereum.Value.fromI32Array(x)'); + expect(codegen.ethereumFromAsc('x', `uint${i}[6]`)).toBe('ethereum.Value.fromI32Array(x)'); + expect(codegen.ethereumFromAsc('x', `uint${i}[593]`)).toBe('ethereum.Value.fromI32Array(x)'); } - }) + }); test('Array -> uint32[*]', () => { expect(codegen.ethereumFromAsc('x', `uint32[]`)).toBe( 'ethereum.Value.fromUnsignedBigIntArray(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint32[6]`)).toBe( 'ethereum.Value.fromUnsignedBigIntArray(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint32[593]`)).toBe( 'ethereum.Value.fromUnsignedBigIntArray(x)', - ) - }) + ); + }); test('Array -> (u)int40..256[*]', () => { for (let i = 40; i <= 256; i += 8) { expect(codegen.ethereumFromAsc('x', `int${i}[]`)).toBe( 'ethereum.Value.fromSignedBigIntArray(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `int${i}[7]`)).toBe( 'ethereum.Value.fromSignedBigIntArray(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `int${i}[6833]`)).toBe( 'ethereum.Value.fromSignedBigIntArray(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint${i}[]`)).toBe( 'ethereum.Value.fromUnsignedBigIntArray(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint${i}[23]`)).toBe( 'ethereum.Value.fromUnsignedBigIntArray(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint${i}[467]`)).toBe( 'ethereum.Value.fromUnsignedBigIntArray(x)', - ) + ); } - }) + }); test('Array -> string[*]', () => { - expect(codegen.ethereumFromAsc('x', 'string[]')).toBe( - 'ethereum.Value.fromStringArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'string[4]')).toBe( - 'ethereum.Value.fromStringArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'string[754]')).toBe( - 'ethereum.Value.fromStringArray(x)', - ) - }) + expect(codegen.ethereumFromAsc('x', 'string[]')).toBe('ethereum.Value.fromStringArray(x)'); + expect(codegen.ethereumFromAsc('x', 'string[4]')).toBe('ethereum.Value.fromStringArray(x)'); + expect(codegen.ethereumFromAsc('x', 'string[754]')).toBe('ethereum.Value.fromStringArray(x)'); + }); // Multidimensional arrays test('Array> -> address[*][*]', () => { - expect(codegen.ethereumFromAsc('x', 'address[][]')).toBe( - 'ethereum.Value.fromAddressMatrix(x)', - ) + expect(codegen.ethereumFromAsc('x', 'address[][]')).toBe('ethereum.Value.fromAddressMatrix(x)'); expect(codegen.ethereumFromAsc('x', 'address[1][]')).toBe( 'ethereum.Value.fromAddressMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', 'address[][2]')).toBe( 'ethereum.Value.fromAddressMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', 'address[123][321]')).toBe( 'ethereum.Value.fromAddressMatrix(x)', - ) - }) + ); + }); test('Array> -> bool[*][*]', () => { - expect(codegen.ethereumFromAsc('x', 'bool[][]')).toBe( - 'ethereum.Value.fromBooleanMatrix(x)', - ) - expect(codegen.ethereumFromAsc('x', 'bool[5][]')).toBe( - 'ethereum.Value.fromBooleanMatrix(x)', - ) - expect(codegen.ethereumFromAsc('x', 'bool[][5]')).toBe( - 'ethereum.Value.fromBooleanMatrix(x)', - ) + expect(codegen.ethereumFromAsc('x', 'bool[][]')).toBe('ethereum.Value.fromBooleanMatrix(x)'); + expect(codegen.ethereumFromAsc('x', 'bool[5][]')).toBe('ethereum.Value.fromBooleanMatrix(x)'); + expect(codegen.ethereumFromAsc('x', 'bool[][5]')).toBe('ethereum.Value.fromBooleanMatrix(x)'); expect(codegen.ethereumFromAsc('x', 'bool[275][572]')).toBe( 'ethereum.Value.fromBooleanMatrix(x)', - ) - }) + ); + }); test('Array> -> byte[*][*]', () => { - expect(codegen.ethereumFromAsc('x', 'byte[][]')).toBe( - 'ethereum.Value.fromFixedBytesMatrix(x)', - ) + expect(codegen.ethereumFromAsc('x', 'byte[][]')).toBe('ethereum.Value.fromFixedBytesMatrix(x)'); expect(codegen.ethereumFromAsc('x', 'byte[7][]')).toBe( 'ethereum.Value.fromFixedBytesMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', 'byte[][6]')).toBe( 'ethereum.Value.fromFixedBytesMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', 'byte[553][355]')).toBe( 'ethereum.Value.fromFixedBytesMatrix(x)', - ) - }) + ); + }); test('Array> -> bytes[*][*]', () => { - expect(codegen.ethereumFromAsc('x', 'bytes[][]')).toBe( - 'ethereum.Value.fromBytesMatrix(x)', - ) - expect(codegen.ethereumFromAsc('x', 'bytes[14][]')).toBe( - 'ethereum.Value.fromBytesMatrix(x)', - ) - expect(codegen.ethereumFromAsc('x', 'bytes[][41]')).toBe( - 'ethereum.Value.fromBytesMatrix(x)', - ) + expect(codegen.ethereumFromAsc('x', 'bytes[][]')).toBe('ethereum.Value.fromBytesMatrix(x)'); + expect(codegen.ethereumFromAsc('x', 'bytes[14][]')).toBe('ethereum.Value.fromBytesMatrix(x)'); + expect(codegen.ethereumFromAsc('x', 'bytes[][41]')).toBe('ethereum.Value.fromBytesMatrix(x)'); expect(codegen.ethereumFromAsc('x', 'bytes[444][333]')).toBe( 'ethereum.Value.fromBytesMatrix(x)', - ) - }) + ); + }); test('bytes0[*][*] (invalid)', () => { - expect(() => codegen.ethereumFromAsc('x', 'bytes0[][]')).toThrow() - expect(() => codegen.ethereumFromAsc('x', 'bytes0[83][]')).toThrow() - expect(() => codegen.ethereumFromAsc('x', 'bytes0[][38]')).toThrow() - expect(() => codegen.ethereumFromAsc('x', 'bytes0[123][321]')).toThrow() - }) + expect(() => codegen.ethereumFromAsc('x', 'bytes0[][]')).toThrow(); + expect(() => codegen.ethereumFromAsc('x', 'bytes0[83][]')).toThrow(); + expect(() => codegen.ethereumFromAsc('x', 'bytes0[][38]')).toThrow(); + expect(() => codegen.ethereumFromAsc('x', 'bytes0[123][321]')).toThrow(); + }); test('Array> -> bytes1..32[*][*]', () => { for (let i = 1; i <= 32; i++) { expect(codegen.ethereumFromAsc('x', `bytes${i}[][]`)).toBe( 'ethereum.Value.fromFixedBytesMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `bytes${i}[7][]`)).toBe( 'ethereum.Value.fromFixedBytesMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `bytes${i}[][7]`)).toBe( 'ethereum.Value.fromFixedBytesMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `bytes${i}[432][234]`)).toBe( 'ethereum.Value.fromFixedBytesMatrix(x)', - ) + ); } - }) + }); test('bytes33[*][*] (invalid)', () => { - expect(() => codegen.ethereumFromAsc('x', 'bytes33[][]')).toThrow() - expect(() => codegen.ethereumFromAsc('x', 'bytes33[58][]')).toThrow() - expect(() => codegen.ethereumFromAsc('x', 'bytes33[][85]')).toThrow() - expect(() => codegen.ethereumFromAsc('x', 'bytes33[394][493]')).toThrow() - }) + expect(() => codegen.ethereumFromAsc('x', 'bytes33[][]')).toThrow(); + expect(() => codegen.ethereumFromAsc('x', 'bytes33[58][]')).toThrow(); + expect(() => codegen.ethereumFromAsc('x', 'bytes33[][85]')).toThrow(); + expect(() => codegen.ethereumFromAsc('x', 'bytes33[394][493]')).toThrow(); + }); test('Array> -> int8..32[*][*], uint8..24[*][*]', () => { for (let i = 8; i <= 32; i += 8) { - expect(codegen.ethereumFromAsc('x', `int${i}[][]`)).toBe( - 'ethereum.Value.fromI32Matrix(x)', - ) - expect(codegen.ethereumFromAsc('x', `int${i}[6][]`)).toBe( - 'ethereum.Value.fromI32Matrix(x)', - ) - expect(codegen.ethereumFromAsc('x', `int${i}[][5]`)).toBe( - 'ethereum.Value.fromI32Matrix(x)', - ) + expect(codegen.ethereumFromAsc('x', `int${i}[][]`)).toBe('ethereum.Value.fromI32Matrix(x)'); + expect(codegen.ethereumFromAsc('x', `int${i}[6][]`)).toBe('ethereum.Value.fromI32Matrix(x)'); + expect(codegen.ethereumFromAsc('x', `int${i}[][5]`)).toBe('ethereum.Value.fromI32Matrix(x)'); expect(codegen.ethereumFromAsc('x', `int${i}[4638][8364]`)).toBe( 'ethereum.Value.fromI32Matrix(x)', - ) + ); } for (let i = 8; i <= 24; i += 8) { - expect(codegen.ethereumFromAsc('x', `uint${i}[][]`)).toBe( - 'ethereum.Value.fromI32Matrix(x)', - ) - expect(codegen.ethereumFromAsc('x', `uint${i}[6][]`)).toBe( - 'ethereum.Value.fromI32Matrix(x)', - ) - expect(codegen.ethereumFromAsc('x', `uint${i}[][5]`)).toBe( - 'ethereum.Value.fromI32Matrix(x)', - ) + expect(codegen.ethereumFromAsc('x', `uint${i}[][]`)).toBe('ethereum.Value.fromI32Matrix(x)'); + expect(codegen.ethereumFromAsc('x', `uint${i}[6][]`)).toBe('ethereum.Value.fromI32Matrix(x)'); + expect(codegen.ethereumFromAsc('x', `uint${i}[][5]`)).toBe('ethereum.Value.fromI32Matrix(x)'); expect(codegen.ethereumFromAsc('x', `uint${i}[593][395]`)).toBe( 'ethereum.Value.fromI32Matrix(x)', - ) + ); } - }) + }); test('Array> -> uint32[*][*]', () => { expect(codegen.ethereumFromAsc('x', `uint32[][]`)).toBe( 'ethereum.Value.fromUnsignedBigIntMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint32[6][]`)).toBe( 'ethereum.Value.fromUnsignedBigIntMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint32[][5]`)).toBe( 'ethereum.Value.fromUnsignedBigIntMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint32[593][395]`)).toBe( 'ethereum.Value.fromUnsignedBigIntMatrix(x)', - ) - }) + ); + }); test('Array> -> (u)int40..256[*][*]', () => { for (let i = 40; i <= 256; i += 8) { expect(codegen.ethereumFromAsc('x', `int${i}[][]`)).toBe( 'ethereum.Value.fromSignedBigIntMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `int${i}[8][]`)).toBe( 'ethereum.Value.fromSignedBigIntMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `int${i}[][7]`)).toBe( 'ethereum.Value.fromSignedBigIntMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `int${i}[6833][3386]`)).toBe( 'ethereum.Value.fromSignedBigIntMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint${i}[][]`)).toBe( 'ethereum.Value.fromUnsignedBigIntMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint${i}[23][]`)).toBe( 'ethereum.Value.fromUnsignedBigIntMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint${i}[][32]`)).toBe( 'ethereum.Value.fromUnsignedBigIntMatrix(x)', - ) + ); expect(codegen.ethereumFromAsc('x', `uint${i}[467][764]`)).toBe( 'ethereum.Value.fromUnsignedBigIntMatrix(x)', - ) + ); } - }) + }); test('Array> -> string[*][*]', () => { - expect(codegen.ethereumFromAsc('x', 'string[]')).toBe( - 'ethereum.Value.fromStringArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'string[4]')).toBe( - 'ethereum.Value.fromStringArray(x)', - ) - expect(codegen.ethereumFromAsc('x', 'string[754]')).toBe( - 'ethereum.Value.fromStringArray(x)', - ) - }) -}) + expect(codegen.ethereumFromAsc('x', 'string[]')).toBe('ethereum.Value.fromStringArray(x)'); + expect(codegen.ethereumFromAsc('x', 'string[4]')).toBe('ethereum.Value.fromStringArray(x)'); + expect(codegen.ethereumFromAsc('x', 'string[754]')).toBe('ethereum.Value.fromStringArray(x)'); + }); +}); describe('Value -> AssemblyScript', () => { test('BigDecimal -> BigDecimal', () => { - expect(codegen.valueToAsc('x', 'BigDecimal')).toBe('x.toBigDecimal()') - }) + expect(codegen.valueToAsc('x', 'BigDecimal')).toBe('x.toBigDecimal()'); + }); test('[BigDecimal] -> Array', () => { - expect(codegen.valueToAsc('x', '[BigDecimal]')).toBe('x.toBigDecimalArray()') - }) + expect(codegen.valueToAsc('x', '[BigDecimal]')).toBe('x.toBigDecimalArray()'); + }); test('String -> string', () => { - expect(codegen.valueToAsc('x', 'string')).toBe('x.toString()') - }) + expect(codegen.valueToAsc('x', 'string')).toBe('x.toString()'); + }); test('[String] -> Array', () => { - expect(codegen.valueToAsc('x', '[String]')).toBe('x.toStringArray()') - }) -}) + expect(codegen.valueToAsc('x', '[String]')).toBe('x.toStringArray()'); + }); +}); describe('AssemblyScript -> Value', () => { test('BigDecimal -> BigDecimal', () => { - expect(codegen.valueFromAsc('x', 'BigDecimal')).toBe('Value.fromBigDecimal(x)') - expect(codegen.valueTypeForAsc('BigDecimal')).toBe('BigDecimal') - }) + expect(codegen.valueFromAsc('x', 'BigDecimal')).toBe('Value.fromBigDecimal(x)'); + expect(codegen.valueTypeForAsc('BigDecimal')).toBe('BigDecimal'); + }); test('Array -> [BigDecimal]', () => { - expect(codegen.valueFromAsc('x', '[BigDecimal]')).toBe('Value.fromBigDecimalArray(x)') - expect(codegen.valueTypeForAsc('Array')).toBe('[BigDecimal]') - }) + expect(codegen.valueFromAsc('x', '[BigDecimal]')).toBe('Value.fromBigDecimalArray(x)'); + expect(codegen.valueTypeForAsc('Array')).toBe('[BigDecimal]'); + }); test('string -> String', () => { - expect(codegen.valueFromAsc('x', 'String')).toBe('Value.fromString(x)') - expect(codegen.valueTypeForAsc('string')).toBe('String') - }) + expect(codegen.valueFromAsc('x', 'String')).toBe('Value.fromString(x)'); + expect(codegen.valueTypeForAsc('string')).toBe('String'); + }); test('Array -> [String]', () => { - expect(codegen.valueFromAsc('x', '[String]')).toBe('Value.fromStringArray(x)') - expect(codegen.valueTypeForAsc('Array')).toBe('[String]') - }) -}) + expect(codegen.valueFromAsc('x', '[String]')).toBe('Value.fromStringArray(x)'); + expect(codegen.valueTypeForAsc('Array')).toBe('[String]'); + }); +}); diff --git a/packages/cli/src/codegen/types/index.ts b/packages/cli/src/codegen/types/index.ts index aa26fc7d..95d12122 100644 --- a/packages/cli/src/codegen/types/index.ts +++ b/packages/cli/src/codegen/types/index.ts @@ -1,18 +1,15 @@ -import immutable from 'immutable' - -import TYPE_CONVERSIONS from './conversions' +import immutable from 'immutable'; +import TYPE_CONVERSIONS from './conversions'; // Conversion utilities const conversionsForTypeSystems = (fromTypeSystem: string, toTypeSystem: string) => { - let conversions = TYPE_CONVERSIONS.getIn([fromTypeSystem, toTypeSystem]) + const conversions = TYPE_CONVERSIONS.getIn([fromTypeSystem, toTypeSystem]); if (conversions === undefined) { - throw new Error( - `Conversions from '${fromTypeSystem}' to '${toTypeSystem}' are not supported`, - ) + throw new Error(`Conversions from '${fromTypeSystem}' to '${toTypeSystem}' are not supported`); } - return conversions as immutable.Collection -} + return conversions as immutable.Collection; +}; const objectifyConversion = ( fromTypeSystem: string, @@ -29,93 +26,86 @@ const objectifyConversion = ( type: conversion.get(1), }, convert: conversion.get(2), - }) -} + }); +}; const findConversionFromType = ( fromTypeSystem: string, toTypeSystem: string, fromType: string, ): immutable.Collection => { - let conversions = conversionsForTypeSystems(fromTypeSystem, toTypeSystem) + const conversions = conversionsForTypeSystems(fromTypeSystem, toTypeSystem); - let conversion = conversions.find(conversion => + const conversion = conversions.find(conversion => typeof conversion.get(0) === 'string' ? conversion.get(0) === fromType - : Boolean(fromType.match(conversion.get(0))), - ) + : !!fromType.match(conversion.get(0)), + ); if (conversion === undefined) { throw new Error( `Conversion from '${fromTypeSystem}' to '${toTypeSystem}' for ` + `source type '${fromType}' is not supported`, - ) + ); } - return objectifyConversion(fromTypeSystem, toTypeSystem, conversion) -} + return objectifyConversion(fromTypeSystem, toTypeSystem, conversion); +}; const findConversionToType = ( fromTypeSystem: string, toTypeSystem: string, toType: string, ): immutable.Collection => { - let conversions = conversionsForTypeSystems(fromTypeSystem, toTypeSystem) + const conversions = conversionsForTypeSystems(fromTypeSystem, toTypeSystem); - let conversion = conversions.find(conversion => + const conversion = conversions.find(conversion => typeof conversion.get(1) === 'string' ? conversion.get(1) === toType - : Boolean(toType.match(conversion.get(1))), - ) + : !!toType.match(conversion.get(1)), + ); if (conversion === undefined) { throw new Error( `Conversion from '${fromTypeSystem}' to '${toTypeSystem}' for ` + `target type '${toType}' is not supported`, - ) + ); } - return objectifyConversion(fromTypeSystem, toTypeSystem, conversion) -} + return objectifyConversion(fromTypeSystem, toTypeSystem, conversion); +}; // High-level type system API export const ascTypeForProtocol = (protocol: string, protocolType: string) => - findConversionFromType(protocol, 'AssemblyScript', protocolType).getIn([ - 'to', - 'type', - ]) as string + findConversionFromType(protocol, 'AssemblyScript', protocolType).getIn(['to', 'type']) as string; // TODO: this can be removed/replaced by the function above export const ascTypeForEthereum = (ethereumType: string) => - ascTypeForProtocol('ethereum', ethereumType) + ascTypeForProtocol('ethereum', ethereumType); export const ethereumTypeForAsc = (ascType: string) => findConversionFromType('AssemblyScript', 'ethereum', ascType).getIn(['to', 'type']) as | string - | RegExp + | RegExp; -export const ethereumToAsc = ( - code: string, - ethereumType: string, - internalType?: string, -) => +export const ethereumToAsc = (code: string, ethereumType: string, internalType?: string) => findConversionFromType('ethereum', 'AssemblyScript', ethereumType).get('convert')( code, internalType, - ) + ); export const ethereumFromAsc = (code: string, ethereumType: string) => - findConversionToType('AssemblyScript', 'ethereum', ethereumType).get('convert')(code) + findConversionToType('AssemblyScript', 'ethereum', ethereumType).get('convert')(code); export const ascTypeForValue = (valueType: string) => - findConversionFromType('Value', 'AssemblyScript', valueType).getIn(['to', 'type']) + findConversionFromType('Value', 'AssemblyScript', valueType).getIn(['to', 'type']); export const valueTypeForAsc = (ascType: string) => - findConversionFromType('AssemblyScript', 'Value', ascType).getIn(['to', 'type']) + findConversionFromType('AssemblyScript', 'Value', ascType).getIn(['to', 'type']); export const valueToAsc = (code: string, valueType: string) => - findConversionFromType('Value', 'AssemblyScript', valueType).get('convert')(code) + findConversionFromType('Value', 'AssemblyScript', valueType).get('convert')(code); export const valueFromAsc = (code: string, valueType: string) => - findConversionToType('AssemblyScript', 'Value', valueType).get('convert')(code) + findConversionToType('AssemblyScript', 'Value', valueType).get('convert')(code); diff --git a/packages/cli/src/codegen/typescript.ts b/packages/cli/src/codegen/typescript.ts index 99a30b85..039cc082 100644 --- a/packages/cli/src/codegen/typescript.ts +++ b/packages/cli/src/codegen/typescript.ts @@ -1,11 +1,11 @@ class Param { constructor(public name: string, public type: string | NamedType | NullableType) { - this.name = name - this.type = type + this.name = name; + this.type = type; } toString() { - return `${this.name}: ${this.type.toString()}` + return `${this.name}: ${this.type.toString()}`; } } @@ -16,10 +16,10 @@ class Method { public returnType: string | NamedType | null | undefined, public body: string, ) { - this.name = name - this.params = params || [] - this.returnType = returnType - this.body = body || '' + this.name = name; + this.params = params || []; + this.returnType = returnType; + this.body = body || ''; } toString() { @@ -28,7 +28,7 @@ class Method { this.returnType ? `: ${this.returnType.toString()}` : '' } {${this.body} } -` +`; } } @@ -39,10 +39,10 @@ class StaticMethod { public returnType: NamedType | NullableType, public body: string, ) { - this.name = name - this.params = params || [] - this.returnType = returnType || 'void' - this.body = body || '' + this.name = name; + this.params = params || []; + this.returnType = returnType || 'void'; + this.body = body || ''; } toString() { @@ -51,76 +51,74 @@ class StaticMethod { this.returnType ? `: ${this.returnType.toString()}` : '' } {${this.body} } -` +`; } } interface ClassOptions { - extends?: string - export?: boolean + extends?: string; + export?: boolean; } class Class { - public extends: string | undefined - public methods: string[] - public members: any[] - public export: boolean + public extends: string | undefined; + public methods: string[]; + public members: any[]; + public export: boolean; constructor(public name: string, options: ClassOptions) { - this.name = name - this.extends = options.extends - this.methods = [] - this.members = [] - this.export = options.export || false + this.name = name; + this.extends = options.extends; + this.methods = []; + this.members = []; + this.export = options.export || false; } addMember(member: any) { - this.members.push(member) + this.members.push(member); } addMethod(method: any) { - this.methods.push(method) + this.methods.push(method); } toString() { return ` -${this.export ? 'export' : ''} class ${this.name}${ - this.extends ? ` extends ${this.extends}` : '' - } { +${this.export ? 'export' : ''} class ${this.name}${this.extends ? ` extends ${this.extends}` : ''} { ${this.members.map(member => member.toString()).join('\n')} ${this.methods.map(method => method.toString()).join('')} } -` +`; } } class ClassMember { constructor(public name: string, public type: string) { - this.name = name - this.type = type + this.name = name; + this.type = type; } toString() { - return ` ${this.name}: ${this.type.toString()}` + return ` ${this.name}: ${this.type.toString()}`; } } class NamedType { constructor(public name: string) { - this.name = name + this.name = name; } toString() { - return this.name + return this.name; } capitalize() { - this.name = this.name.charAt(0).toUpperCase() + this.name.slice(1) - return this + this.name = this.name.charAt(0).toUpperCase() + this.name.slice(1); + return this; } isPrimitive() { - let primitives = [ + const primitives = [ 'boolean', 'u8', 'i8', @@ -134,93 +132,93 @@ class NamedType { 'f64', 'usize', 'isize', - ] - return primitives.includes(this.name) + ]; + return primitives.includes(this.name); } } class ArrayType { - public name: string + public name: string; constructor(public inner: NamedType) { - this.inner = inner - this.name = `Array<${inner.toString()}>` + this.inner = inner; + this.name = `Array<${inner.toString()}>`; } toString() { - return this.name + return this.name; } } class NullableType { constructor(public inner: NamedType | ArrayType) { - this.inner = inner + this.inner = inner; } toString() { - return `${this.inner.toString()} | null` + return `${this.inner.toString()} | null`; } } class ModuleImports { constructor(public nameOrNames: string | string[], public module: string) { - this.nameOrNames = nameOrNames - this.module = module + this.nameOrNames = nameOrNames; + this.module = module; } toString() { return `import { ${ typeof this.nameOrNames === 'string' ? this.nameOrNames : this.nameOrNames.join(',') - } } from "${this.module}"` + } } from "${this.module}"`; } } -const namedType = (name: string) => new NamedType(name) -const arrayType = (name: NamedType) => new ArrayType(name) -const param = (name: string, type: string | NamedType) => new Param(name, type) +const namedType = (name: string) => new NamedType(name); +const arrayType = (name: NamedType) => new ArrayType(name); +const param = (name: string, type: string | NamedType) => new Param(name, type); const method = ( name: string, params: Param[], returnType: string | NamedType | null | undefined, body: string, -) => new Method(name, params, returnType, body) +) => new Method(name, params, returnType, body); const staticMethod = ( name: string, params: Param[], returnType: NamedType | NullableType, body: string, -) => new StaticMethod(name, params, returnType, body) -const klass = (name: string, options: ClassOptions) => new Class(name, options) -const klassMember = (name: string, type: string) => new ClassMember(name, type) -const nullableType = (type: NamedType | ArrayType) => new NullableType(type) +) => new StaticMethod(name, params, returnType, body); +const klass = (name: string, options: ClassOptions) => new Class(name, options); +const klassMember = (name: string, type: string) => new ClassMember(name, type); +const nullableType = (type: NamedType | ArrayType) => new NullableType(type); const moduleImports = (nameOrNames: string | string[], module: string) => - new ModuleImports(nameOrNames, module) + new ModuleImports(nameOrNames, module); const GENERATED_FILE_NOTE = ` // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -` +`; export { - // Types - Param, - Method, - StaticMethod, - Class, - ClassMember, - NamedType, - NullableType, ArrayType, - ModuleImports, - // Code generators - namedType, arrayType, + Class, + ClassMember, + // Utilities + GENERATED_FILE_NOTE, klass, klassMember, + Method, method, - staticMethod, - param, - nullableType, + ModuleImports, moduleImports, - // Utilities - GENERATED_FILE_NOTE, -} + NamedType, + // Code generators + namedType, + NullableType, + nullableType, + // Types + Param, + param, + StaticMethod, + staticMethod, +}; diff --git a/packages/cli/src/codegen/util.test.ts b/packages/cli/src/codegen/util.test.ts index da1538b5..e6d8f80b 100644 --- a/packages/cli/src/codegen/util.test.ts +++ b/packages/cli/src/codegen/util.test.ts @@ -1,4 +1,4 @@ -import { disambiguateNames, unrollTuple } from './util' +import { disambiguateNames, unrollTuple } from './util'; describe('Codegen utilities', () => { test('Name disambiguation', () => { @@ -8,7 +8,7 @@ describe('Codegen utilities', () => { getName: x => x, setName: (_x, name) => name, }), - ).toEqual(['a', 'b', 'c']) + ).toEqual(['a', 'b', 'c']); expect( disambiguateNames({ @@ -16,7 +16,7 @@ describe('Codegen utilities', () => { getName: x => x, setName: (_x, name) => name, }), - ).toEqual(['a', 'a1', 'a2']) + ).toEqual(['a', 'a1', 'a2']); expect( disambiguateNames({ @@ -27,16 +27,16 @@ describe('Codegen utilities', () => { ], getName: event => event.name, setName: (event, name) => { - event.name = name - return event + event.name = name; + return event; }, }), ).toEqual([ { name: 'ExampleEvent', inputs: [] }, { name: 'ExampleEvent1', inputs: [{ type: 'uint256' }] }, { name: 'ExampleEvent2', inputs: [{ type: 'uint96' }] }, - ]) - }) + ]); + }); test('Tuple unrolling', () => { expect( @@ -45,7 +45,7 @@ describe('Codegen utilities', () => { path: ['value'], index: 0, }), - ).toEqual([]) + ).toEqual([]); expect( unrollTuple({ @@ -57,7 +57,7 @@ describe('Codegen utilities', () => { path: ['value'], index: 0, }), - ).toEqual([{ path: ['value', 'a'], type: 'string' }]) + ).toEqual([{ path: ['value', 'a'], type: 'string' }]); expect( unrollTuple({ @@ -75,7 +75,7 @@ describe('Codegen utilities', () => { ).toEqual([ { path: ['value', 'a'], type: 'string' }, { path: ['value', 'b'], type: 'uint256' }, - ]) + ]); expect( unrollTuple({ @@ -107,6 +107,6 @@ describe('Codegen utilities', () => { { path: ['value', 'b'], type: 'uint256' }, { path: ['value', 'c', 'value0'], type: 'bytes32' }, { path: ['value', 'c', 'd', 'd1'], type: 'uint72' }, - ]) - }) -}) + ]); + }); +}); diff --git a/packages/cli/src/codegen/util.ts b/packages/cli/src/codegen/util.ts index dfbbdca5..0fc8b5c4 100644 --- a/packages/cli/src/codegen/util.ts +++ b/packages/cli/src/codegen/util.ts @@ -3,53 +3,52 @@ export function disambiguateNames({ getName, setName, }: { - values: T[] - getName: (value: T, index: number) => string - setName: (value: T, name: string) => void + values: T[]; + getName: (value: T, index: number) => string; + setName: (value: T, name: string) => void; }) { - let collisionCounter = new Map() + const collisionCounter = new Map(); return values.map((value, index) => { - let name = getName(value, index) - let counter = collisionCounter.get(name) + const name = getName(value, index); + const counter = collisionCounter.get(name); if (counter === undefined) { - collisionCounter.set(name, 1) - return setName(value, name) - } else { - collisionCounter.set(name, counter + 1) - return setName(value, `${name}${counter}`) + collisionCounter.set(name, 1); + return setName(value, name); } - }) + collisionCounter.set(name, counter + 1); + return setName(value, `${name}${counter}`); + }); } export function isTupleType(t: string) { - return t === 'tuple' + return t === 'tuple'; } export function containsTupleType(t: string) { - return isTupleType(t) || isTupleArrayType(t) || isTupleMatrixType(t) + return isTupleType(t) || isTupleArrayType(t) || isTupleMatrixType(t); } export function isTupleArrayType(t: string) { - return t.match(/^tuple\[([0-9]+)?\]$/) + return t.match(/^tuple\[([0-9]+)?\]$/); } export function isTupleMatrixType(t: string) { - return t.match(/^tuple\[([0-9]+)?\]\[([0-9]+)?\]$/) + return t.match(/^tuple\[([0-9]+)?\]\[([0-9]+)?\]$/); } export const unrollTuple = ({ path, value, }: { - path: string[] - index: number // TODO: index is unused, do we really need it? - value: any + path: string[]; + index: number; // TODO: index is unused, do we really need it? + value: any; }) => value.components.reduce((acc: any[], component: any, index: number) => { - let name = component.name || `value${index}` + const name = component.name || `value${index}`; return acc.concat( component.type === 'tuple' ? unrollTuple({ path: [...path, name], index, value: component }) : [{ path: [...path, name], type: component.type }], - ) - }, []) + ); + }, []); diff --git a/packages/cli/src/command-helpers/abi.ts b/packages/cli/src/command-helpers/abi.ts index a78c2dee..40ad57fe 100644 --- a/packages/cli/src/command-helpers/abi.ts +++ b/packages/cli/src/command-helpers/abi.ts @@ -1,7 +1,7 @@ -import { withSpinner } from './spinner' -import fetch from 'node-fetch' -import immutable from 'immutable' -import ABI from '../protocols/ethereum/abi' +import immutable from 'immutable'; +import fetch from 'node-fetch'; +import ABI from '../protocols/ethereum/abi'; +import { withSpinner } from './spinner'; export const loadAbiFromEtherscan = async ( ABICtor: typeof ABI, @@ -13,26 +13,19 @@ export const loadAbiFromEtherscan = async ( `Failed to fetch ABI from Etherscan`, `Warnings while fetching ABI from Etherscan`, async () => { - const scanApiUrl = getEtherscanLikeAPIUrl(network) - let result = await fetch( - `${scanApiUrl}?module=contract&action=getabi&address=${address}`, - ) - let json = await result.json() + const scanApiUrl = getEtherscanLikeAPIUrl(network); + const result = await fetch(`${scanApiUrl}?module=contract&action=getabi&address=${address}`); + const json = await result.json(); // Etherscan returns a JSON object that has a `status`, a `message` and // a `result` field. The `status` is '0' in case of errors and '1' in // case of success if (json.status === '1') { - return new ABICtor( - 'Contract', - undefined, - immutable.fromJS(JSON.parse(json.result)), - ) - } else { - throw new Error('ABI not found, try loading it from a local file') + return new ABICtor('Contract', undefined, immutable.fromJS(JSON.parse(json.result))); } + throw new Error('ABI not found, try loading it from a local file'); }, - ) + ); export const loadAbiFromBlockScout = async ( ABICtor: typeof ABI, @@ -44,66 +37,61 @@ export const loadAbiFromBlockScout = async ( `Failed to fetch ABI from BlockScout`, `Warnings while fetching ABI from BlockScout`, async () => { - let result = await fetch( + const result = await fetch( `https://blockscout.com/${network.replace( '-', '/', )}/api?module=contract&action=getabi&address=${address}`, - ) - let json = await result.json() + ); + const json = await result.json(); // BlockScout returns a JSON object that has a `status`, a `message` and // a `result` field. The `status` is '0' in case of errors and '1' in // case of success if (json.status === '1') { - return new ABICtor( - 'Contract', - undefined, - immutable.fromJS(JSON.parse(json.result)), - ) - } else { - throw new Error('ABI not found, try loading it from a local file') + return new ABICtor('Contract', undefined, immutable.fromJS(JSON.parse(json.result))); } + throw new Error('ABI not found, try loading it from a local file'); }, - ) + ); const getEtherscanLikeAPIUrl = (network: string) => { switch (network) { case 'mainnet': - return `https://api.etherscan.io/api` + return `https://api.etherscan.io/api`; case 'arbitrum-one': - return `https://api.arbiscan.io/api` + return `https://api.arbiscan.io/api`; case 'bsc': - return `https://api.bscscan.com/api` + return `https://api.bscscan.com/api`; case 'matic': - return `https://api.polygonscan.com/api` + return `https://api.polygonscan.com/api`; case 'mumbai': - return `https://api-testnet.polygonscan.com/api` + return `https://api-testnet.polygonscan.com/api`; case 'aurora': - return `https://api.aurorascan.dev/api` + return `https://api.aurorascan.dev/api`; case 'aurora-testnet': - return `https://api-testnet.aurorascan.dev/api` + return `https://api-testnet.aurorascan.dev/api`; case 'optimism-kovan': - return `https://api-kovan-optimistic.etherscan.io/api` + return `https://api-kovan-optimistic.etherscan.io/api`; case 'optimism': - return `https://api-optimistic.etherscan.io/api` + return `https://api-optimistic.etherscan.io/api`; case 'moonbeam': - return `https://api-moonbeam.moonscan.io/api` + return `https://api-moonbeam.moonscan.io/api`; case 'moonriver': - return `https://api-moonriver.moonscan.io/api` + return `https://api-moonriver.moonscan.io/api`; case 'mbase': - return `https://api-moonbase.moonscan.io/api` + return `https://api-moonbase.moonscan.io/api`; case 'avalanche': - return `https://api.snowtrace.io/api` + return `https://api.snowtrace.io/api`; case 'fuji': - return `https://api-testnet.snowtrace.io/api` + return `https://api-testnet.snowtrace.io/api`; case 'gnosis': - return `https://api.gnosisscan.io/api` + return `https://api.gnosisscan.io/api`; case 'fantom': - return `https://api.ftmscan.com/api` + return `https://api.ftmscan.com/api`; case 'fantom-testnet': - return `https://api-testnet.ftmscan.com/api` + return `https://api-testnet.ftmscan.com/api`; default: - return `https://api-${network}.etherscan.io/api` + return `https://api-${network}.etherscan.io/api`; } -} +}; diff --git a/packages/cli/src/command-helpers/auth.ts b/packages/cli/src/command-helpers/auth.ts index 24c3a3f5..8c738212 100644 --- a/packages/cli/src/command-helpers/auth.ts +++ b/packages/cli/src/command-helpers/auth.ts @@ -1,47 +1,46 @@ -import * as toolbox from 'gluegun' -import { normalizeNodeUrl } from './node' +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import * as toolbox from 'gluegun'; +import { normalizeNodeUrl } from './node'; -import fs from 'fs' -import path from 'path' -import os from 'os' -const homedir = os.homedir() +const homedir = os.homedir(); -const CONFIG_PATH = path.join(homedir, '/.graph-cli.json') +const CONFIG_PATH = path.join(homedir, '/.graph-cli.json'); const getConfig = () => { - let config + let config; try { - config = JSON.parse(fs.readFileSync(CONFIG_PATH).toString()) + config = JSON.parse(fs.readFileSync(CONFIG_PATH).toString()); } catch { - config = {} + config = {}; } - return config -} + return config; +}; export const identifyDeployKey = async (node: string, deployKey: string) => { // Determine the deploy key to use, if any: // - First try using --deploy-key, if provided // - Then see if we have a deploy key set for the Graph node if (deployKey !== undefined) { - return deployKey - } else { - try { - node = normalizeNodeUrl(node) - const config = getConfig() - return config[node] - } catch (e) { - toolbox.print.warning(`Could not get deploy key: ${e.message}`) - toolbox.print.info(`Continuing without a deploy key\n`) - } + return deployKey; } -} + try { + node = normalizeNodeUrl(node); + const config = getConfig(); + return config[node]; + } catch (e) { + toolbox.print.warning(`Could not get deploy key: ${e.message}`); + toolbox.print.info(`Continuing without a deploy key\n`); + } +}; export const saveDeployKey = async (node: string, deployKey: string) => { try { - node = normalizeNodeUrl(node) - const config = getConfig() - config[node] = deployKey - fs.writeFileSync(CONFIG_PATH, JSON.stringify(config)) + node = normalizeNodeUrl(node); + const config = getConfig(); + config[node] = deployKey; + fs.writeFileSync(CONFIG_PATH, JSON.stringify(config)); } catch (e) { - throw new Error(`Error storing deploy key: ${e.message}`) + throw new Error(`Error storing deploy key: ${e.message}`); } -} +}; diff --git a/packages/cli/src/command-helpers/compiler.ts b/packages/cli/src/command-helpers/compiler.ts index 80861014..67fd8703 100644 --- a/packages/cli/src/command-helpers/compiler.ts +++ b/packages/cli/src/command-helpers/compiler.ts @@ -1,17 +1,17 @@ -const URL = require('url').URL -import ipfsHttpClient from 'ipfs-http-client' -import * as toolbox from 'gluegun' -import Compiler from '../compiler' -import Protocol from '../protocols' +import { URL } from 'url'; +import * as toolbox from 'gluegun'; +import ipfsHttpClient from 'ipfs-http-client'; +import Compiler from '../compiler'; +import Protocol from '../protocols'; interface CreateCompilerOptions { - ipfs: any - headers?: any - outputDir: string - outputFormat: string - skipMigrations: boolean - blockIpfsMethods?: boolean - protocol: Protocol + ipfs: any; + headers?: any; + outputDir: string; + outputFormat: string; + skipMigrations: boolean; + blockIpfsMethods?: boolean; + protocol: Protocol; } // Helper function to construct a subgraph compiler @@ -28,33 +28,33 @@ export function createCompiler( }: CreateCompilerOptions, ) { // Parse the IPFS URL - let url + let url; try { - url = ipfs ? new URL(ipfs) : undefined + url = ipfs ? new URL(ipfs) : undefined; } catch (e) { toolbox.print.error(`Invalid IPFS URL: ${ipfs} -The IPFS URL must be of the following format: http(s)://host[:port]/[path]`) - return null +The IPFS URL must be of the following format: http(s)://host[:port]/[path]`); + return null; } // Connect to the IPFS node (if a node address was provided) ipfs = ipfs ? ipfsHttpClient({ - protocol: url.protocol.replace(/[:]+$/, ''), - host: url.hostname, - port: url.port, - 'api-path': url.pathname.replace(/\/$/, '') + '/api/v0/', + protocol: url?.protocol.replace(/[:]+$/, ''), + host: url?.hostname, + port: url?.port, + 'api-path': url?.pathname.replace(/\/$/, '') + '/api/v0/', headers, }) - : undefined + : undefined; return new Compiler({ ipfs, subgraphManifest: manifest, - outputDir: outputDir, - outputFormat: outputFormat, + outputDir, + outputFormat, skipMigrations, blockIpfsMethods, protocol, - }) + }); } diff --git a/packages/cli/src/command-helpers/data-sources.ts b/packages/cli/src/command-helpers/data-sources.ts index 033f7a23..41643495 100644 --- a/packages/cli/src/command-helpers/data-sources.ts +++ b/packages/cli/src/command-helpers/data-sources.ts @@ -1,16 +1,16 @@ -import immutable from 'immutable' -import { loadManifest } from '../migrations/util/load-manifest' -import Protocol from '../protocols' +import immutable from 'immutable'; +import { loadManifest } from '../migrations/util/load-manifest'; +import Protocol from '../protocols'; // Loads manifest from file path and returns all: // - data sources // - templates // In a single list. export const fromFilePath = async (manifestPath: string) => { - const { dataSources = [], templates = [] } = await loadManifest(manifestPath) + const { dataSources = [], templates = [] } = await loadManifest(manifestPath); - return dataSources.concat(templates) -} + return dataSources.concat(templates); +}; const extractDataSourceByType = ( manifest: immutable.Map, @@ -22,17 +22,15 @@ const extractDataSourceByType = ( .reduce( (dataSources: any[], dataSource: any, dataSourceIndex: number) => protocol.isValidKindName(dataSource.get('kind')) - ? dataSources.push( - immutable.Map({ path: [dataSourceType, dataSourceIndex], dataSource }), - ) + ? dataSources.push(immutable.Map({ path: [dataSourceType, dataSourceIndex], dataSource })) : dataSources, immutable.List(), - ) + ); // Extracts data sources and templates from a immutable manifest data structure export const fromManifest = (manifest: immutable.Map, protocol: Protocol) => { - const dataSources = extractDataSourceByType(manifest, 'dataSources', protocol) - const templates = extractDataSourceByType(manifest, 'templates', protocol) + const dataSources = extractDataSourceByType(manifest, 'dataSources', protocol); + const templates = extractDataSourceByType(manifest, 'templates', protocol); - return dataSources.concat(templates) -} + return dataSources.concat(templates); +}; diff --git a/packages/cli/src/command-helpers/fs.ts b/packages/cli/src/command-helpers/fs.ts index 1c6d4eb1..c2d7a820 100644 --- a/packages/cli/src/command-helpers/fs.ts +++ b/packages/cli/src/command-helpers/fs.ts @@ -1,5 +1,5 @@ -import path from 'path' +import path from 'path'; -const displayPath = (p: string) => path.relative(process.cwd(), p) +const displayPath = (p: string) => path.relative(process.cwd(), p); -export { displayPath } +export { displayPath }; diff --git a/packages/cli/src/command-helpers/gluegun.ts b/packages/cli/src/command-helpers/gluegun.ts index 0fe124e3..1b84d702 100644 --- a/packages/cli/src/command-helpers/gluegun.ts +++ b/packages/cli/src/command-helpers/gluegun.ts @@ -24,29 +24,29 @@ // options has a string value; if so, it pushes it to the front of the // parameters array and returns the result of that. -import { GluegunParameters } from 'gluegun' +import { GluegunParameters } from 'gluegun'; export const fixParameters = ( parameters: GluegunParameters, booleanOptions: Record, ) => { - let unexpectedStringOptions = Object.keys(booleanOptions) + const unexpectedStringOptions = Object.keys(booleanOptions) .filter(key => typeof booleanOptions[key] === 'string') - .map(key => ({ key, value: booleanOptions[key] })) + .map(key => ({ key, value: booleanOptions[key] })); - let optionNames = unexpectedStringOptions + const optionNames = unexpectedStringOptions .map(({ key }) => `--` + key.replace(/([A-Z])/, '-$1').toLowerCase()) - .join(', ') + .join(', '); if (unexpectedStringOptions.length > 1) { throw new Error( `Unexpected value provided for one or more of ${optionNames}. See --help for more information.`, - ) + ); } else if (unexpectedStringOptions.length == 1) { - let params = parameters.array - params!.unshift(unexpectedStringOptions[0].value) - return params! + const params = parameters.array; + params!.unshift(unexpectedStringOptions[0].value); + return params!; } else { - return parameters.array! + return parameters.array!; } -} +}; diff --git a/packages/cli/src/command-helpers/ipfs-http-client.d.ts b/packages/cli/src/command-helpers/ipfs-http-client.d.ts index b04a8258..8ea1763d 100644 --- a/packages/cli/src/command-helpers/ipfs-http-client.d.ts +++ b/packages/cli/src/command-helpers/ipfs-http-client.d.ts @@ -1 +1 @@ -declare module 'ipfs-http-client' +declare module 'ipfs-http-client'; diff --git a/packages/cli/src/command-helpers/ipfs.ts b/packages/cli/src/command-helpers/ipfs.ts index d5a2f30f..79658893 100644 --- a/packages/cli/src/command-helpers/ipfs.ts +++ b/packages/cli/src/command-helpers/ipfs.ts @@ -1,3 +1,3 @@ -const DEFAULT_IPFS_URL = 'https://api.thegraph.com/ipfs/' as const +const DEFAULT_IPFS_URL = 'https://api.thegraph.com/ipfs/' as const; -export { DEFAULT_IPFS_URL } +export { DEFAULT_IPFS_URL }; diff --git a/packages/cli/src/command-helpers/jsonrpc.ts b/packages/cli/src/command-helpers/jsonrpc.ts index 1bc9a816..6308e34f 100644 --- a/packages/cli/src/command-helpers/jsonrpc.ts +++ b/packages/cli/src/command-helpers/jsonrpc.ts @@ -1,5 +1,5 @@ -import jayson from 'jayson' -import { print } from 'gluegun' +import { print } from 'gluegun'; +import jayson from 'jayson'; export function createJsonRpcClient(url: URL): jayson.Client | null { const params = { @@ -8,19 +8,15 @@ export function createJsonRpcClient(url: URL): jayson.Client | null { path: url.pathname, // username may be empty auth: url.password ? `${url.username}:${url.password}` : undefined, - } + }; if (url.protocol === 'https:') { - return jayson.Client.https(params) - } else if (url.protocol === 'http:') { - return jayson.Client.http(params) - } else { - print.error( - `Unsupported protocol: ${url.protocol.substring(0, url.protocol.length - 1)}`, - ) - print.error( - 'The Graph Node URL must be of the following format: http(s)://host[:port]/[path]', - ) - return null + return jayson.Client.https(params); + } + if (url.protocol === 'http:') { + return jayson.Client.http(params); } + print.error(`Unsupported protocol: ${url.protocol.substring(0, url.protocol.length - 1)}`); + print.error('The Graph Node URL must be of the following format: http(s)://host[:port]/[path]'); + return null; } diff --git a/packages/cli/src/command-helpers/network.test.ts b/packages/cli/src/command-helpers/network.test.ts index 653cf4bb..abfa8eee 100644 --- a/packages/cli/src/command-helpers/network.test.ts +++ b/packages/cli/src/command-helpers/network.test.ts @@ -1,7 +1,7 @@ -import { initNetworksConfig, updateSubgraphNetwork } from './network' -import * as toolbox from 'gluegun' -import yaml from 'yaml' -import path from 'path' +import path from 'path'; +import * as toolbox from 'gluegun'; +import yaml from 'yaml'; +import { initNetworksConfig, updateSubgraphNetwork } from './network'; const SUBGRAPH_PATH_BASE = path.join( __dirname, @@ -11,75 +11,75 @@ const SUBGRAPH_PATH_BASE = path.join( '..', 'examples', 'example-subgraph', -) +); describe('initNetworksConfig', () => { beforeAll(async () => { - await initNetworksConfig(toolbox, SUBGRAPH_PATH_BASE, 'address') - }) + await initNetworksConfig(toolbox, SUBGRAPH_PATH_BASE, 'address'); + }); afterAll(async () => { - toolbox.filesystem.remove(`${SUBGRAPH_PATH_BASE}/networks.json`) - }) + toolbox.filesystem.remove(`${SUBGRAPH_PATH_BASE}/networks.json`); + }); test('generates networks.json from subgraph.yaml', () => { - expect(toolbox.filesystem.exists(`${SUBGRAPH_PATH_BASE}/networks.json`)).toBe('file') - }) + expect(toolbox.filesystem.exists(`${SUBGRAPH_PATH_BASE}/networks.json`)).toBe('file'); + }); test('Populates the networks.json file with the data from subgraph.yaml', async () => { - let networksStr = toolbox.filesystem.read(`${SUBGRAPH_PATH_BASE}/networks.json`) - let networks = JSON.parse(networksStr!) + const networksStr = toolbox.filesystem.read(`${SUBGRAPH_PATH_BASE}/networks.json`); + const networks = JSON.parse(networksStr!); - let expected = { + const expected = { mainnet: { ExampleSubgraph: { address: '0x22843e74c59580b3eaf6c233fa67d8b7c561a835' }, }, - } + }; - expect(networks).toStrictEqual(expected) - }) -}) + expect(networks).toStrictEqual(expected); + }); +}); describe('updateSubgraphNetwork', () => { beforeAll(async () => { - let content = { + const content = { optimism: { ExampleSubgraph: { address: '0x12345...' }, }, - } + }; - toolbox.filesystem.write(`${SUBGRAPH_PATH_BASE}/networks.json`, content) + toolbox.filesystem.write(`${SUBGRAPH_PATH_BASE}/networks.json`, content); toolbox.filesystem.copy( `${SUBGRAPH_PATH_BASE}/subgraph.yaml`, `${SUBGRAPH_PATH_BASE}/subgraph_copy.yaml`, - ) - }) + ); + }); afterAll(async () => { - toolbox.filesystem.remove(`${SUBGRAPH_PATH_BASE}/networks.json`) - toolbox.filesystem.remove(`${SUBGRAPH_PATH_BASE}/subgraph_copy.yaml`) - }) + toolbox.filesystem.remove(`${SUBGRAPH_PATH_BASE}/networks.json`); + toolbox.filesystem.remove(`${SUBGRAPH_PATH_BASE}/subgraph_copy.yaml`); + }); test('Updates subgraph.yaml', async () => { - let manifest = `${SUBGRAPH_PATH_BASE}/subgraph_copy.yaml` - let networksFie = `${SUBGRAPH_PATH_BASE}/networks.json` - let subgraph = toolbox.filesystem.read(manifest) - let subgraphObj = yaml.parse(subgraph!) + const manifest = `${SUBGRAPH_PATH_BASE}/subgraph_copy.yaml`; + const networksFie = `${SUBGRAPH_PATH_BASE}/networks.json`; + let subgraph = toolbox.filesystem.read(manifest); + let subgraphObj = yaml.parse(subgraph!); - let network = subgraphObj.dataSources[0].network - let address = subgraphObj.dataSources[0].source.address + let network = subgraphObj.dataSources[0].network; + let address = subgraphObj.dataSources[0].source.address; - expect(network).toBe('mainnet') - expect(address).toBe('0x22843e74c59580b3eaf6c233fa67d8b7c561a835') + expect(network).toBe('mainnet'); + expect(address).toBe('0x22843e74c59580b3eaf6c233fa67d8b7c561a835'); - await updateSubgraphNetwork(toolbox, manifest, 'optimism', networksFie, 'address') + await updateSubgraphNetwork(toolbox, manifest, 'optimism', networksFie, 'address'); - subgraph = toolbox.filesystem.read(manifest) - subgraphObj = yaml.parse(subgraph!) + subgraph = toolbox.filesystem.read(manifest); + subgraphObj = yaml.parse(subgraph!); - network = subgraphObj.dataSources[0].network - address = subgraphObj.dataSources[0].source.address + network = subgraphObj.dataSources[0].network; + address = subgraphObj.dataSources[0].source.address; - expect(network).toBe('optimism') - expect(address).toBe('0x12345...') - }) -}) + expect(network).toBe('optimism'); + expect(address).toBe('0x12345...'); + }); +}); diff --git a/packages/cli/src/command-helpers/network.ts b/packages/cli/src/command-helpers/network.ts index f2e67950..bec2c7a4 100644 --- a/packages/cli/src/command-helpers/network.ts +++ b/packages/cli/src/command-helpers/network.ts @@ -1,7 +1,7 @@ -import path from 'path' -import yaml from 'yaml' -import { step, withSpinner } from './spinner' -import { GluegunFilesystem, GluegunPatching } from 'gluegun' +import path from 'path'; +import { GluegunFilesystem, GluegunPatching } from 'gluegun'; +import yaml from 'yaml'; +import { step, withSpinner } from './spinner'; export const updateSubgraphNetwork = async ( toolbox: { filesystem: GluegunFilesystem; patching: GluegunPatching }, @@ -15,66 +15,59 @@ export const updateSubgraphNetwork = async ( `Failed to update sources network`, `Warnings while updating sources network`, async spinner => { - let allNetworks - - step(spinner, `Reading networks config`) - allNetworks = await toolbox.filesystem.read(networksFile, 'json') - let networkConfig = allNetworks[network] + step(spinner, `Reading networks config`); + const allNetworks = await toolbox.filesystem.read(networksFile, 'json'); + const networkConfig = allNetworks[network]; // Exit if the network passed with --network does not exits in networks.json if (!networkConfig) { - throw new Error(`Network '${network}' was not found in '${networksFile}'`) + throw new Error(`Network '${network}' was not found in '${networksFile}'`); } await toolbox.patching.update(manifest, content => { - let subgraph = yaml.parse(content) - let networkSources = Object.keys(networkConfig) - let subgraphSources = subgraph.dataSources.map((value: any) => value.name) + const subgraph = yaml.parse(content); + const networkSources = Object.keys(networkConfig); + const subgraphSources = subgraph.dataSources.map((value: any) => value.name); // Update the dataSources network config subgraph.dataSources = subgraph.dataSources.map((source: any) => { if (!networkSources.includes(source.name)) { throw new Error( `'${source.name}' was not found in the '${network}' configuration, please update!`, - ) + ); } if (hasChanges(identifierName, network, networkConfig[source.name], source)) { - step(spinner, `Update '${source.name}' network configuration`) - source.network = network - source.source = source.source.abi ? { abi: source.source.abi } : {} - Object.assign(source.source, networkConfig[source.name]) + step(spinner, `Update '${source.name}' network configuration`); + source.network = network; + source.source = source.source.abi ? { abi: source.source.abi } : {}; + Object.assign(source.source, networkConfig[source.name]); } else { - step(spinner, `Skip '${source.name}': No changes to network configuration`) + step(spinner, `Skip '${source.name}': No changes to network configuration`); } - return source - }) + return source; + }); // All data sources shoud be on the same network, // so we have to update the network of all templates too. - if (subgraph.templates) { - subgraph.templates = subgraph.templates.map((template: any) => ({ - ...template, - network, - })) - } + subgraph.templates &&= subgraph.templates.map((template: any) => ({ + ...template, + network, + })); - let unsusedSources = networkSources.filter(x => !subgraphSources.includes(x)) + const unsusedSources = networkSources.filter(x => !subgraphSources.includes(x)); unsusedSources.forEach(source => { - step( - spinner, - `dataSource '${source}' from '${networksFile}' not found in ${manifest}`, - ) - }) - - let yaml_doc = new yaml.Document() - yaml_doc.contents = subgraph - return yaml_doc.toString() - }) + step(spinner, `dataSource '${source}' from '${networksFile}' not found in ${manifest}`); + }); + + const yaml_doc = new yaml.Document(); + yaml_doc.contents = subgraph; + return yaml_doc.toString(); + }); }, - ) + ); export const initNetworksConfig = async ( toolbox: { filesystem: GluegunFilesystem }, @@ -86,8 +79,8 @@ export const initNetworksConfig = async ( `Failed to initialize networks config`, `Warnings while initializing networks config`, async () => { - let subgraphStr = toolbox.filesystem.read(path.join(directory, 'subgraph.yaml')) - let subgraph = yaml.parse(subgraphStr!) + const subgraphStr = toolbox.filesystem.read(path.join(directory, 'subgraph.yaml')); + const subgraph = yaml.parse(subgraphStr!); const networks = subgraph.dataSources.reduce( (acc: any, source: any) => @@ -100,31 +93,26 @@ export const initNetworksConfig = async ( }, }), {}, - ) + ); - toolbox.filesystem.write(`${directory}/networks.json`, networks) + toolbox.filesystem.write(`${directory}/networks.json`, networks); - return true + return true; }, - ) + ); // Checks if any network attribute has been changed -function hasChanges( - identifierName: string, - network: string, - networkConfig: any, - dataSource: any, -) { - let networkChanged = dataSource.network !== network +function hasChanges(identifierName: string, network: string, networkConfig: any, dataSource: any) { + const networkChanged = dataSource.network !== network; // Return directly if the network is different - if (networkChanged) return networkChanged + if (networkChanged) return networkChanged; - let addressChanged = networkConfig[identifierName] !== dataSource.source[identifierName] + const addressChanged = networkConfig[identifierName] !== dataSource.source[identifierName]; - let startBlockChanged = networkConfig.startBlock !== dataSource.source.startBlock + const startBlockChanged = networkConfig.startBlock !== dataSource.source.startBlock; - return networkChanged || addressChanged || startBlockChanged + return networkChanged || addressChanged || startBlockChanged; } export const updateNetworksFile = async ( @@ -136,10 +124,10 @@ export const updateNetworksFile = async ( ) => { await toolbox.patching.update(networksFile, config => { if (Object.keys(config).includes(network)) { - Object.assign(config[network], { [dataSource]: { address } }) + Object.assign(config[network], { [dataSource]: { address } }); } else { - Object.assign(config, { [network]: { [dataSource]: { address } } }) + Object.assign(config, { [network]: { [dataSource]: { address } } }); } - return config - }) -} + return config; + }); +}; diff --git a/packages/cli/src/command-helpers/node.ts b/packages/cli/src/command-helpers/node.ts index b24c3648..7be16638 100644 --- a/packages/cli/src/command-helpers/node.ts +++ b/packages/cli/src/command-helpers/node.ts @@ -1,12 +1,12 @@ -import { URL } from 'url' -import { print } from 'gluegun' +import { URL } from 'url'; +import { print } from 'gluegun'; -const SUBGRAPH_STUDIO_URL = 'https://api.studio.thegraph.com/deploy/' -const HOSTED_SERVICE_URL = 'https://api.thegraph.com/deploy/' +const SUBGRAPH_STUDIO_URL = 'https://api.studio.thegraph.com/deploy/'; +const HOSTED_SERVICE_URL = 'https://api.thegraph.com/deploy/'; -export const validateNodeUrl = (node: string) => new URL(node) +export const validateNodeUrl = (node: string) => new URL(node); -export const normalizeNodeUrl = (node: string) => new URL(node).toString() +export const normalizeNodeUrl = (node: string) => new URL(node).toString(); export function chooseNodeUrl({ product, @@ -14,33 +14,33 @@ export function chooseNodeUrl({ node, allowSimpleName, }: { - product: string - studio: string - node?: string - allowSimpleName?: boolean + product: string; + studio: string; + node?: string; + allowSimpleName?: boolean; }) { if (node) { try { - validateNodeUrl(node) + validateNodeUrl(node); } catch (e) { - print.error(`Graph node "${node}" is invalid: ${e.message}`) - process.exit(1) + print.error(`Graph node "${node}" is invalid: ${e.message}`); + process.exit(1); } } else { if (studio) { - product = 'subgraph-studio' + product = 'subgraph-studio'; } switch (product) { case 'subgraph-studio': - node = SUBGRAPH_STUDIO_URL - break + node = SUBGRAPH_STUDIO_URL; + break; case 'hosted-service': - node = HOSTED_SERVICE_URL - break + node = HOSTED_SERVICE_URL; + break; } } - if ((node && node.match(/studio/)) || product === 'subgraph-studio') { - allowSimpleName = true + if (node?.match(/studio/) || product === 'subgraph-studio') { + allowSimpleName = true; } - return { node, allowSimpleName } + return { node, allowSimpleName }; } diff --git a/packages/cli/src/command-helpers/scaffold.ts b/packages/cli/src/command-helpers/scaffold.ts index 9ced08c6..7ea4e1b1 100644 --- a/packages/cli/src/command-helpers/scaffold.ts +++ b/packages/cli/src/command-helpers/scaffold.ts @@ -1,17 +1,16 @@ -import fs from 'fs-extra' -import path from 'path' -import prettier from 'prettier' -import yaml from 'yaml' - -import { Spinner, step } from './spinner' -import Scaffold from '../scaffold' -import { generateEventIndexingHandlers } from '../scaffold/mapping' -import { generateEventType, abiEvents } from '../scaffold/schema' -import { generateTestsFiles } from '../scaffold/tests' -import { strings } from 'gluegun' -import { Map } from 'immutable' -import Protocol from '../protocols' -import ABI from '../protocols/ethereum/abi' +import path from 'path'; +import fs from 'fs-extra'; +import { strings } from 'gluegun'; +import { Map } from 'immutable'; +import prettier from 'prettier'; +import yaml from 'yaml'; +import Protocol from '../protocols'; +import ABI from '../protocols/ethereum/abi'; +import Scaffold from '../scaffold'; +import { generateEventIndexingHandlers } from '../scaffold/mapping'; +import { abiEvents, generateEventType } from '../scaffold/schema'; +import { generateTestsFiles } from '../scaffold/tests'; +import { Spinner, step } from './spinner'; export const generateDataSource = async ( protocol: Protocol, @@ -20,7 +19,7 @@ export const generateDataSource = async ( contractAddress: string, abi: ABI, ) => { - const protocolManifest = protocol.getManifestScaffold() + const protocolManifest = protocol.getManifestScaffold(); return Map.of( 'kind', @@ -31,10 +30,9 @@ export const generateDataSource = async ( network, 'source', yaml.parse( - prettier.format( - protocolManifest.source({ contract: contractAddress, contractName }), - { parser: 'yaml' }, - ), + prettier.format(protocolManifest.source({ contract: contractAddress, contractName }), { + parser: 'yaml', + }), ), 'mapping', yaml.parse( @@ -42,8 +40,8 @@ export const generateDataSource = async ( parser: 'yaml', }), ), - ).asMutable() -} + ).asMutable(); +}; export const generateScaffold = async ( { @@ -56,18 +54,18 @@ export const generateScaffold = async ( contractName = 'Contract', node, }: { - protocolInstance: Protocol - abi: ABI - contract: string - network: string - subgraphName: string - indexEvents: boolean - contractName?: string - node: string + protocolInstance: Protocol; + abi: ABI; + contract: string; + network: string; + subgraphName: string; + indexEvents: boolean; + contractName?: string; + node: string; }, spinner: Spinner, ) => { - step(spinner, 'Generate subgraph') + step(spinner, 'Generate subgraph'); const scaffold = new Scaffold({ protocol: protocolInstance, @@ -78,52 +76,44 @@ export const generateScaffold = async ( contractName, subgraphName, node, - }) + }); - return scaffold.generate() -} + return scaffold.generate(); +}; -const writeScaffoldDirectory = async ( - scaffold: any, - directory: string, - spinner: Spinner, -) => { +const writeScaffoldDirectory = async (scaffold: any, directory: string, spinner: Spinner) => { // Create directory itself - await fs.mkdirs(directory) + await fs.mkdirs(directory); - let promises = Object.keys(scaffold).map(async basename => { - let content = scaffold[basename] - let filename = path.join(directory, basename) + const promises = Object.keys(scaffold).map(async basename => { + const content = scaffold[basename]; + const filename = path.join(directory, basename); // Write file or recurse into subdirectory if (typeof content === 'string') { - await fs.writeFile(filename, content, { encoding: 'utf-8' }) + await fs.writeFile(filename, content, 'utf-8'); } else if (content == null) { - return // continue loop + return; // continue loop } else { - writeScaffoldDirectory(content, path.join(directory, basename), spinner) + writeScaffoldDirectory(content, path.join(directory, basename), spinner); } - }) + }); - await Promise.all(promises) -} + await Promise.all(promises); +}; -export const writeScaffold = async ( - scaffold: any, - directory: string, - spinner: Spinner, -) => { - step(spinner, `Write subgraph to directory`) - await writeScaffoldDirectory(scaffold, directory, spinner) -} +export const writeScaffold = async (scaffold: any, directory: string, spinner: Spinner) => { + step(spinner, `Write subgraph to directory`); + await writeScaffoldDirectory(scaffold, directory, spinner); +}; export const writeABI = async (abi: ABI, contractName: string) => { - let data = prettier.format(JSON.stringify(abi.data), { + const data = prettier.format(JSON.stringify(abi.data), { parser: 'json', - }) + }); - await fs.writeFile(`./abis/${contractName}.json`, data, { encoding: 'utf-8' }) -} + await fs.writeFile(`./abis/${contractName}.json`, data, 'utf-8'); +}; export const writeSchema = async ( abi: ABI, @@ -133,19 +123,19 @@ export const writeSchema = async ( ) => { const events = protocol.hasEvents() ? abiEvents(abi) - .filter(event => entities.indexOf(event.get('name')) === -1) + .filter(event => !entities.includes(event.get('name'))) .toJS() - : [] + : []; - let data = prettier.format( + const data = prettier.format( events.map(event => generateEventType(event, protocol.name)).join('\n\n'), { parser: 'graphql', }, - ) + ); - await fs.appendFile(schemaPath, data, { encoding: 'utf-8' }) -} + await fs.appendFile(schemaPath, data, { encoding: 'utf-8' }); +}; export const writeMapping = async ( abi: ABI, @@ -155,38 +145,30 @@ export const writeMapping = async ( ) => { const events = protocol.hasEvents() ? abiEvents(abi) - .filter(event => entities.indexOf(event.get('name')) === -1) + .filter(event => !entities.includes(event.get('name'))) .toJS() - : [] + : []; - let mapping = prettier.format(generateEventIndexingHandlers(events, contractName), { + const mapping = prettier.format(generateEventIndexingHandlers(events, contractName), { parser: 'typescript', semi: false, - }) + }); - await fs.writeFile(`./src/${strings.kebabCase(contractName)}.ts`, mapping, { - encoding: 'utf-8', - }) -} + await fs.writeFile(`./src/${strings.kebabCase(contractName)}.ts`, mapping, 'utf-8'); +}; -export const writeTestsFiles = async ( - abi: ABI, - protocol: Protocol, - contractName: string, -) => { - const hasEvents = protocol.hasEvents() - const events = hasEvents ? abiEvents(abi).toJS() : [] +export const writeTestsFiles = async (abi: ABI, protocol: Protocol, contractName: string) => { + const hasEvents = protocol.hasEvents(); + const events = hasEvents ? abiEvents(abi).toJS() : []; if (events.length > 0) { // If a contract is added to a subgraph that has no tests folder - await fs.ensureDir('./tests/') + await fs.ensureDir('./tests/'); - const testsFiles = generateTestsFiles(contractName, events, true) + const testsFiles = generateTestsFiles(contractName, events, true); for (const [fileName, content] of Object.entries(testsFiles)) { - await fs.writeFile(`./tests/${fileName}`, content, { - encoding: 'utf-8', - }) + await fs.writeFile(`./tests/${fileName}`, content, 'utf-8'); } } -} +}; diff --git a/packages/cli/src/command-helpers/spinner.ts b/packages/cli/src/command-helpers/spinner.ts index 4062ee48..29552fdf 100644 --- a/packages/cli/src/command-helpers/spinner.ts +++ b/packages/cli/src/command-helpers/spinner.ts @@ -1,18 +1,18 @@ -import * as toolbox from 'gluegun' +import * as toolbox from 'gluegun'; -export type Spinner = ReturnType +export type Spinner = ReturnType; export const step = (spinner: Spinner, subject: string, text?: string) => { if (text) { spinner.stopAndPersist({ text: toolbox.print.colors.muted(`${subject} ${text}`), - }) + }); } else { - spinner.stopAndPersist({ text: toolbox.print.colors.muted(subject) }) + spinner.stopAndPersist({ text: toolbox.print.colors.muted(subject) }); } - spinner.start() - return spinner -} + spinner.start(); + return spinner; +}; // Executes the function `f` in a command-line spinner, using the // provided captions for in-progress, error and failed messages. @@ -29,34 +29,32 @@ export const withSpinner = async ( warningText: string, f: (spinner: Spinner) => Promise | any, // TODO: type result ) => { - let spinner = toolbox.print.spin(text) + const spinner = toolbox.print.spin(text); try { - let result = await f(spinner) + const result = await f(spinner); if (typeof result === 'object') { - let hasError = Object.keys(result).indexOf('error') >= 0 - let hasWarning = Object.keys(result).indexOf('warning') >= 0 - let hasResult = Object.keys(result).indexOf('result') >= 0 + const hasError = Object.keys(result).includes('error'); + const hasWarning = Object.keys(result).includes('warning'); + const hasResult = Object.keys(result).includes('result'); if (hasError) { - spinner.fail(`${errorText}: ${result.error}`) - return hasResult ? result.result : result + spinner.fail(`${errorText}: ${result.error}`); + return hasResult ? result.result : result; } if (hasWarning && hasResult) { if (result.warning !== null) { - spinner.warn(`${warningText}: ${result.warning}`) + spinner.warn(`${warningText}: ${result.warning}`); } - spinner.succeed(text) - return result.result - } else { - spinner.succeed(text) - return result + spinner.succeed(text); + return result.result; } - } else { - spinner.succeed(text) - return result + spinner.succeed(text); + return result; } + spinner.succeed(text); + return result; } catch (e) { - spinner.fail(`${errorText}: ${e.message}`) - throw e + spinner.fail(`${errorText}: ${e.message}`); + throw e; } -} +}; diff --git a/packages/cli/src/command-helpers/studio.test.ts b/packages/cli/src/command-helpers/studio.test.ts index 6c843281..efc8e06f 100644 --- a/packages/cli/src/command-helpers/studio.test.ts +++ b/packages/cli/src/command-helpers/studio.test.ts @@ -1,4 +1,4 @@ -import { validateStudioNetwork, allowedStudioNetworks } from './studio' +import { allowedStudioNetworks, validateStudioNetwork } from './studio'; describe('Version Command Helpers', () => { describe('validateStudioNetwork', () => { @@ -15,8 +15,8 @@ describe('Version Command Helpers', () => { ', ', )}`, ), - ) - }) + ); + }); test("And it's Gnosis chain", () => { expect(() => @@ -30,8 +30,8 @@ describe('Version Command Helpers', () => { ', ', )}`, ), - ) - }) + ); + }); test("And it's NOT an allowed network", () => { expect(() => @@ -45,9 +45,9 @@ describe('Version Command Helpers', () => { ', ', )}`, ), - ) - }) - }) + ); + }); + }); describe("When it's NOT studio", () => { test("And it's Rinkeby", () => { @@ -62,8 +62,8 @@ describe('Version Command Helpers', () => { ', ', )}`, ), - ) - }) + ); + }); test("And it's NOT an allowed network", () => { expect(() => @@ -77,8 +77,8 @@ describe('Version Command Helpers', () => { ', ', )}`, ), - ) - }) - }) - }) -}) + ); + }); + }); + }); +}); diff --git a/packages/cli/src/command-helpers/studio.ts b/packages/cli/src/command-helpers/studio.ts index 65871241..157b1587 100644 --- a/packages/cli/src/command-helpers/studio.ts +++ b/packages/cli/src/command-helpers/studio.ts @@ -1,25 +1,25 @@ -export const allowedStudioNetworks = ['mainnet', 'rinkeby', 'goerli', 'gnosis'] as const +export const allowedStudioNetworks = ['mainnet', 'rinkeby', 'goerli', 'gnosis'] as const; export const validateStudioNetwork = ({ studio, product, network, }: { - studio?: string | boolean - product?: string - network: string + studio?: string | boolean; + product?: string; + network: string; }) => { - let isStudio = studio || product === 'subgraph-studio' - let isAllowedNetwork = allowedStudioNetworks.includes( + const isStudio = studio || product === 'subgraph-studio'; + const isAllowedNetwork = allowedStudioNetworks.includes( // @ts-expect-error we're checking if the network is allowed network, - ) + ); if (isStudio && !isAllowedNetwork) { throw new Error( `The Subgraph Studio only allows subgraphs for these networks: ${allowedStudioNetworks.join( ', ', )}`, - ) + ); } -} +}; diff --git a/packages/cli/src/command-helpers/subgraph.ts b/packages/cli/src/command-helpers/subgraph.ts index 1cb60358..0fad46db 100644 --- a/packages/cli/src/command-helpers/subgraph.ts +++ b/packages/cli/src/command-helpers/subgraph.ts @@ -3,20 +3,19 @@ export const validateSubgraphName = ( { allowSimpleName }: { allowSimpleName?: boolean }, ) => { if (allowSimpleName) { - return name - } else { - if (name.split('/').length !== 2) { - throw new Error(`Subgraph name "${name}" needs to have the format "/${name}". + return name; + } + if (name.split('/').length !== 2) { + throw new Error(`Subgraph name "${name}" needs to have the format "/${name}". When using the Hosted Service at https://thegraph.com, is the name of your GitHub user or organization. -You can bypass this check with --allow-simple-name.`) - } +You can bypass this check with --allow-simple-name.`); } -} +}; export const getSubgraphBasename = (name: string) => { - let segments = name.split('/', 2) - return segments[segments.length - 1] -} + const segments = name.split('/', 2); + return segments[segments.length - 1]; +}; diff --git a/packages/cli/src/command-helpers/version.test.ts b/packages/cli/src/command-helpers/version.test.ts index 2ec20f96..fb6212c5 100644 --- a/packages/cli/src/command-helpers/version.test.ts +++ b/packages/cli/src/command-helpers/version.test.ts @@ -1,11 +1,11 @@ -import { assertManifestApiVersion, assertGraphTsVersion } from './version' -import * as loadManifestUtil from '../migrations/util/load-manifest' -import * as graphTsUtil from '../migrations/util/versions' +import * as loadManifestUtil from '../migrations/util/load-manifest'; +import * as graphTsUtil from '../migrations/util/versions'; +import { assertGraphTsVersion, assertManifestApiVersion } from './version'; describe('Version Command Helpers', () => { describe('assertManifestApiVersion', () => { - const fakeManifestPath = 'fake/manifest/path' - const minimumApiVersion = '0.0.5' + const fakeManifestPath = 'fake/manifest/path'; + const minimumApiVersion = '0.0.5'; describe('With just dataSources', () => { test('When all of them are less than minimum apiVersion', async () => { @@ -18,16 +18,14 @@ describe('Version Command Helpers', () => { { mapping: { apiVersion: '0.0.3' } }, ], }), - ) + ); - await expect( - assertManifestApiVersion(fakeManifestPath, minimumApiVersion), - ).rejects.toThrow( + await expect(assertManifestApiVersion(fakeManifestPath, minimumApiVersion)).rejects.toThrow( new Error( `The current version of graph-cli can't be used with mappings on apiVersion less than '${minimumApiVersion}'`, ), - ) - }) + ); + }); test('When one of them is less than minimum apiVersion', async () => { // @ts-expect-error TODO: dont pollute the globals loadManifestUtil.loadManifest = jest.fn().mockImplementation(() => @@ -38,16 +36,14 @@ describe('Version Command Helpers', () => { { mapping: { apiVersion: '0.0.5' } }, ], }), - ) + ); - await expect( - assertManifestApiVersion(fakeManifestPath, minimumApiVersion), - ).rejects.toThrow( + await expect(assertManifestApiVersion(fakeManifestPath, minimumApiVersion)).rejects.toThrow( new Error( `The current version of graph-cli can't be used with mappings on apiVersion less than '${minimumApiVersion}'`, ), - ) - }) + ); + }); test('When none of them are less than minimum apiVersion', async () => { // @ts-expect-error TODO: dont pollute the globals loadManifestUtil.loadManifest = jest.fn().mockImplementation(() => @@ -58,13 +54,13 @@ describe('Version Command Helpers', () => { { mapping: { apiVersion: '0.0.5' } }, ], }), - ) + ); - await expect( - assertManifestApiVersion(fakeManifestPath, minimumApiVersion), - ).resolves.toBe(undefined) - }) - }) + await expect(assertManifestApiVersion(fakeManifestPath, minimumApiVersion)).resolves.toBe( + undefined, + ); + }); + }); describe('With dataSources and templates', () => { describe('And the dataSources have a lower apiVersion', () => { test('When all of the templates are less than minimum apiVersion', async () => { @@ -82,7 +78,7 @@ describe('Version Command Helpers', () => { { mapping: { apiVersion: '0.0.3' } }, ], }), - ) + ); await expect( assertManifestApiVersion(fakeManifestPath, minimumApiVersion), @@ -90,8 +86,8 @@ describe('Version Command Helpers', () => { new Error( `The current version of graph-cli can't be used with mappings on apiVersion less than '${minimumApiVersion}'`, ), - ) - }) + ); + }); test('When one of the templates is less than minimum apiVersion', async () => { // @ts-expect-error TODO: dont pollute the globals loadManifestUtil.loadManifest = jest.fn().mockImplementation(() => @@ -107,7 +103,7 @@ describe('Version Command Helpers', () => { { mapping: { apiVersion: '0.0.5' } }, ], }), - ) + ); await expect( assertManifestApiVersion(fakeManifestPath, minimumApiVersion), @@ -115,8 +111,8 @@ describe('Version Command Helpers', () => { new Error( `The current version of graph-cli can't be used with mappings on apiVersion less than '${minimumApiVersion}'`, ), - ) - }) + ); + }); test('When none of the templates are less than minimum apiVersion', async () => { // @ts-expect-error TODO: dont pollute the globals loadManifestUtil.loadManifest = jest.fn().mockImplementation(() => @@ -132,7 +128,7 @@ describe('Version Command Helpers', () => { { mapping: { apiVersion: '0.0.5' } }, ], }), - ) + ); await expect( assertManifestApiVersion(fakeManifestPath, minimumApiVersion), @@ -140,9 +136,9 @@ describe('Version Command Helpers', () => { new Error( `The current version of graph-cli can't be used with mappings on apiVersion less than '${minimumApiVersion}'`, ), - ) - }) - }) + ); + }); + }); describe('And the dataSources do NOT have a lower apiVersion', () => { test('When all of the templates are less than minimum apiVersion', async () => { // @ts-expect-error TODO: dont pollute the globals @@ -159,7 +155,7 @@ describe('Version Command Helpers', () => { { mapping: { apiVersion: '0.0.3' } }, ], }), - ) + ); await expect( assertManifestApiVersion(fakeManifestPath, minimumApiVersion), @@ -167,8 +163,8 @@ describe('Version Command Helpers', () => { new Error( `The current version of graph-cli can't be used with mappings on apiVersion less than '${minimumApiVersion}'`, ), - ) - }) + ); + }); test('When one of the templates is less than minimum apiVersion', async () => { // @ts-expect-error TODO: dont pollute the globals loadManifestUtil.loadManifest = jest.fn().mockImplementation(() => @@ -184,7 +180,7 @@ describe('Version Command Helpers', () => { { mapping: { apiVersion: '0.0.5' } }, ], }), - ) + ); await expect( assertManifestApiVersion(fakeManifestPath, minimumApiVersion), @@ -192,8 +188,8 @@ describe('Version Command Helpers', () => { new Error( `The current version of graph-cli can't be used with mappings on apiVersion less than '${minimumApiVersion}'`, ), - ) - }) + ); + }); test('When none of the templates are less than minimum apiVersion', async () => { // @ts-expect-error TODO: dont pollute the globals loadManifestUtil.loadManifest = jest.fn().mockImplementation(() => @@ -209,43 +205,37 @@ describe('Version Command Helpers', () => { { mapping: { apiVersion: '0.0.5' } }, ], }), - ) + ); - await expect( - assertManifestApiVersion(fakeManifestPath, minimumApiVersion), - ).resolves.toBe(undefined) - }) - }) - }) - }) + await expect(assertManifestApiVersion(fakeManifestPath, minimumApiVersion)).resolves.toBe( + undefined, + ); + }); + }); + }); + }); describe('assertGraphTsVersion', () => { - const fakeNodeModulesDir = 'fake/path/to/node/modules' - const minimumGraphTsVersion = '0.22.0' + const fakeNodeModulesDir = 'fake/path/to/node/modules'; + const minimumGraphTsVersion = '0.22.0'; test("When the installed graph-ts version is less than what's supported", async () => { // @ts-expect-error TODO: dont pollute the globals - graphTsUtil.getGraphTsVersion = jest - .fn() - .mockImplementation(() => Promise.resolve('0.19.0')) + graphTsUtil.getGraphTsVersion = jest.fn().mockImplementation(() => Promise.resolve('0.19.0')); - await expect( - assertGraphTsVersion(fakeNodeModulesDir, minimumGraphTsVersion), - ).rejects.toThrow( + await expect(assertGraphTsVersion(fakeNodeModulesDir, minimumGraphTsVersion)).rejects.toThrow( new Error( `To use this version of the graph-cli you must upgrade the graph-ts dependency to a version greater than or equal to ${minimumGraphTsVersion} Also, you'll probably need to take a look at our AssemblyScript migration guide because of language breaking changes: https://thegraph.com/docs/developer/assemblyscript-migration-guide`, ), - ) - }) + ); + }); test('When the installed graph-ts version is a supported one', async () => { // @ts-expect-error TODO: dont pollute the globals - graphTsUtil.getGraphTsVersion = jest - .fn() - .mockImplementation(() => Promise.resolve('0.22.0')) + graphTsUtil.getGraphTsVersion = jest.fn().mockImplementation(() => Promise.resolve('0.22.0')); - await expect( - assertGraphTsVersion(fakeNodeModulesDir, minimumGraphTsVersion), - ).resolves.toBe(undefined) - }) - }) -}) + await expect(assertGraphTsVersion(fakeNodeModulesDir, minimumGraphTsVersion)).resolves.toBe( + undefined, + ); + }); + }); +}); diff --git a/packages/cli/src/command-helpers/version.ts b/packages/cli/src/command-helpers/version.ts index 45e86aa4..faec4117 100644 --- a/packages/cli/src/command-helpers/version.ts +++ b/packages/cli/src/command-helpers/version.ts @@ -1,56 +1,42 @@ -import semver from 'semver' -import * as graphTsUtil from '../migrations/util/versions' -import * as manifestUtil from '../migrations/util/load-manifest' +import semver from 'semver'; +import * as manifestUtil from '../migrations/util/load-manifest'; +import * as graphTsUtil from '../migrations/util/versions'; -export const assertManifestApiVersion = async ( - manifestPath: string, - minimumApiVersion: string, -) => { - let manifest = await manifestUtil.loadManifest(manifestPath) +export const assertManifestApiVersion = async (manifestPath: string, minimumApiVersion: string) => { + const manifest = await manifestUtil.loadManifest(manifestPath); - let lessThanMinimumVersion = (manifestApiVersion: string) => - semver.lt(manifestApiVersion, minimumApiVersion) + const lessThanMinimumVersion = (manifestApiVersion: string) => + semver.lt(manifestApiVersion, minimumApiVersion); - let isLessThanMinimumVersion = false + let isLessThanMinimumVersion = false; if (manifest) { if (manifest.dataSources && Array.isArray(manifest.dataSources)) { isLessThanMinimumVersion = manifest.dataSources.some( (dataSource: any) => - dataSource && - dataSource.mapping && - dataSource.mapping.apiVersion && - lessThanMinimumVersion(dataSource.mapping.apiVersion), - ) + dataSource?.mapping?.apiVersion && lessThanMinimumVersion(dataSource.mapping.apiVersion), + ); } if (manifest.templates && Array.isArray(manifest.templates)) { - isLessThanMinimumVersion = - isLessThanMinimumVersion || - manifest.templates.some( - (template: any) => - template && - template.mapping && - template.mapping.apiVersion && - lessThanMinimumVersion(template.mapping.apiVersion), - ) + isLessThanMinimumVersion ||= manifest.templates.some( + (template: any) => + template?.mapping?.apiVersion && lessThanMinimumVersion(template.mapping.apiVersion), + ); } } if (isLessThanMinimumVersion) { throw new Error( `The current version of graph-cli can't be used with mappings on apiVersion less than '${minimumApiVersion}'`, - ) + ); } -} +}; -export const assertGraphTsVersion = async ( - sourceDir: string, - minimumGraphTsVersion: string, -) => { - let graphTsVersion +export const assertGraphTsVersion = async (sourceDir: string, minimumGraphTsVersion: string) => { + let graphTsVersion; try { - graphTsVersion = await graphTsUtil.getGraphTsVersion(sourceDir) + graphTsVersion = await graphTsUtil.getGraphTsVersion(sourceDir); } catch (_) { // We only do the assertion if `graph-ts` is installed. } @@ -58,13 +44,10 @@ export const assertGraphTsVersion = async ( // Coerce needed because we may be dealing with an alpha version // and in the `semver` library, this would return true when comparing // the same version. - if ( - graphTsVersion && - semver.lt(semver.coerce(graphTsVersion)!, minimumGraphTsVersion) - ) { + if (graphTsVersion && semver.lt(semver.coerce(graphTsVersion)!, minimumGraphTsVersion)) { throw new Error( `To use this version of the graph-cli you must upgrade the graph-ts dependency to a version greater than or equal to ${minimumGraphTsVersion} Also, you'll probably need to take a look at our AssemblyScript migration guide because of language breaking changes: https://thegraph.com/docs/developer/assemblyscript-migration-guide`, - ) + ); } -} +}; diff --git a/packages/cli/src/commands/add.ts b/packages/cli/src/commands/add.ts index 3b43fc1e..d5f1c0b8 100644 --- a/packages/cli/src/commands/add.ts +++ b/packages/cli/src/commands/add.ts @@ -1,21 +1,21 @@ -import chalk from 'chalk' -import { GluegunToolbox } from 'gluegun' -import immutable from 'immutable' -import { withSpinner } from '../command-helpers/spinner' -import Subgraph from '../subgraph' -import Protocol from '../protocols' -import * as DataSourcesExtractor from '../command-helpers/data-sources' +import chalk from 'chalk'; +import { GluegunToolbox } from 'gluegun'; +import immutable from 'immutable'; +import { loadAbiFromBlockScout, loadAbiFromEtherscan } from '../command-helpers/abi'; +import * as DataSourcesExtractor from '../command-helpers/data-sources'; +import { fixParameters } from '../command-helpers/gluegun'; +import { updateNetworksFile } from '../command-helpers/network'; import { generateDataSource, writeABI, - writeSchema, writeMapping, + writeSchema, writeTestsFiles, -} from '../command-helpers/scaffold' -import { loadAbiFromEtherscan, loadAbiFromBlockScout } from '../command-helpers/abi' -import EthereumABI from '../protocols/ethereum/abi' -import { fixParameters } from '../command-helpers/gluegun' -import { updateNetworksFile } from '../command-helpers/network' +} from '../command-helpers/scaffold'; +import { withSpinner } from '../command-helpers/spinner'; +import Protocol from '../protocols'; +import EthereumABI from '../protocols/ethereum/abi'; +import Subgraph from '../subgraph'; const HELP = ` ${chalk.bold('graph add')}
[] @@ -27,142 +27,126 @@ ${chalk.dim('Options:')} --merge-entities Whether to merge entities with the same name (default: false) --network-file Networks config file path (default: "./networks.json") -h, --help Show usage information -` +`; export interface AddOptions { - abi?: string - contractName?: string - mergeEntities?: boolean - networkFile?: string - help?: boolean + abi?: string; + contractName?: string; + mergeEntities?: boolean; + networkFile?: string; + help?: boolean; } export default { description: 'Adds a new datasource to a subgraph', run: async (toolbox: GluegunToolbox) => { // Obtain tools - let { print, system } = toolbox + const { print, system } = toolbox; // Read CLI parameters - let { abi, contractName, h, help, mergeEntities, networkFile } = - toolbox.parameters.options + let { abi, contractName, h, help, mergeEntities, networkFile } = toolbox.parameters.options; - contractName = contractName || 'Contract' + contractName ||= 'Contract'; try { fixParameters(toolbox.parameters, { h, help, mergeEntities, - }) + }); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } - let address = toolbox.parameters.first || toolbox.parameters.array?.[0] - let manifestPath = - toolbox.parameters.second || toolbox.parameters.array?.[1] || './subgraph.yaml' + const address = toolbox.parameters.first || toolbox.parameters.array?.[0]; + const manifestPath = + toolbox.parameters.second || toolbox.parameters.array?.[1] || './subgraph.yaml'; // Show help text if requested if (help || h) { - print.info(HELP) - return + print.info(HELP); + return; } // Validate the address if (!address) { - print.error('No contract address provided') - process.exitCode = 1 - return + print.error('No contract address provided'); + process.exitCode = 1; + return; } - const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifestPath) - let protocol = Protocol.fromDataSources(dataSourcesAndTemplates) - let manifest = await Subgraph.load(manifestPath, { protocol }) - let network = manifest.result.getIn(['dataSources', 0, 'network']) as any - let result = manifest.result.asMutable() + const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifestPath); + const protocol = Protocol.fromDataSources(dataSourcesAndTemplates); + const manifest = await Subgraph.load(manifestPath, { protocol }); + const network = manifest.result.getIn(['dataSources', 0, 'network']) as any; + const result = manifest.result.asMutable(); - let entities = getEntities(manifest) - let contractNames = getContractNames(manifest) - if (contractNames.indexOf(contractName) !== -1) { + const entities = getEntities(manifest); + const contractNames = getContractNames(manifest); + if (contractNames.includes(contractName)) { print.error( `Datasource or template with name ${contractName} already exists, please choose a different name`, - ) - process.exitCode = 1 - return + ); + process.exitCode = 1; + return; } - let ethabi = null + let ethabi = null; if (abi) { - ethabi = EthereumABI.load(contractName, abi) + ethabi = EthereumABI.load(contractName, abi); + } else if (network === 'poa-core') { + ethabi = await loadAbiFromBlockScout(EthereumABI, network, address); } else { - if (network === 'poa-core') { - ethabi = await loadAbiFromBlockScout(EthereumABI, network, address) - } else { - ethabi = await loadAbiFromEtherscan(EthereumABI, network, address) - } + ethabi = await loadAbiFromEtherscan(EthereumABI, network, address); } - let { collisionEntities, onlyCollisions, abiData } = updateEventNamesOnCollision( + const { collisionEntities, onlyCollisions, abiData } = updateEventNamesOnCollision( toolbox, ethabi, entities, contractName, mergeEntities, - ) - ethabi.data = abiData + ); + ethabi.data = abiData; - await writeABI(ethabi, contractName) - await writeSchema( - ethabi, - protocol, - result.getIn(['schema', 'file']) as any, - collisionEntities, - ) - await writeMapping(ethabi, protocol, contractName, collisionEntities) - await writeTestsFiles(ethabi, protocol, contractName) - - let dataSources = result.get('dataSources') - let dataSource = await generateDataSource( - protocol, - contractName, - network, - address, - ethabi, - ) + await writeABI(ethabi, contractName); + await writeSchema(ethabi, protocol, result.getIn(['schema', 'file']) as any, collisionEntities); + await writeMapping(ethabi, protocol, contractName, collisionEntities); + await writeTestsFiles(ethabi, protocol, contractName); + + const dataSources = result.get('dataSources'); + const dataSource = await generateDataSource(protocol, contractName, network, address, ethabi); // Handle the collisions edge case by copying another data source yaml data if (mergeEntities && onlyCollisions) { - let firstDataSource = dataSources.get(0) - let source = dataSource.get('source') as any - let mapping = firstDataSource.get('mapping').asMutable() + const firstDataSource = dataSources.get(0); + const source = dataSource.get('source') as any; + const mapping = firstDataSource.get('mapping').asMutable(); // Save the address of the new data source - source.abi = firstDataSource.get('source').get('abi') + source.abi = firstDataSource.get('source').get('abi'); - dataSource.set('mapping', mapping) - dataSource.set('source', source) + dataSource.set('mapping', mapping); + dataSource.set('source', source); } - result.set('dataSources', dataSources.push(dataSource)) + result.set('dataSources', dataSources.push(dataSource)); - await Subgraph.write(result, manifestPath) + await Subgraph.write(result, manifestPath); // Update networks.json - const networksFile = networkFile || './networks.json' - await updateNetworksFile(toolbox, network, contractName, address, networksFile) + const networksFile = networkFile || './networks.json'; + await updateNetworksFile(toolbox, network, contractName, address, networksFile); // Detect Yarn and/or NPM - let yarn = system.which('yarn') - let npm = system.which('npm') + const yarn = system.which('yarn'); + const npm = system.which('npm'); if (!yarn && !npm) { - print.error( - `Neither Yarn nor NPM were found on your system. Please install one of them.`, - ) - process.exitCode = 1 - return + print.error(`Neither Yarn nor NPM were found on your system. Please install one of them.`); + process.exitCode = 1; + return; } await withSpinner( @@ -170,28 +154,28 @@ export default { 'Failed to run codegen', 'Warning during codegen', async () => { - await system.run(yarn ? 'yarn codegen' : 'npm run codegen') + await system.run(yarn ? 'yarn codegen' : 'npm run codegen'); }, - ) + ); }, -} +}; const getEntities = (manifest: any) => { - let dataSources = manifest.result.get('dataSources', immutable.List()) - let templates = manifest.result.get('templates', immutable.List()) + const dataSources = manifest.result.get('dataSources', immutable.List()); + const templates = manifest.result.get('templates', immutable.List()); return dataSources .concat(templates) .map((dataSource: any) => dataSource.getIn(['mapping', 'entities'])) - .flatten() -} + .flatten(); +}; const getContractNames = (manifest: any) => { - let dataSources = manifest.result.get('dataSources', immutable.List()) - let templates = manifest.result.get('templates', immutable.List()) + const dataSources = manifest.result.get('dataSources', immutable.List()); + const templates = manifest.result.get('templates', immutable.List()); - return dataSources.concat(templates).map((dataSource: any) => dataSource.get('name')) -} + return dataSources.concat(templates).map((dataSource: any) => dataSource.get('name')); +}; const updateEventNamesOnCollision = ( toolbox: GluegunToolbox, @@ -200,37 +184,37 @@ const updateEventNamesOnCollision = ( contractName: string, mergeEntities: boolean, ) => { - let abiData = ethabi.data - let { print } = toolbox - let collisionEntities = [] - let onlyCollisions = true + let abiData = ethabi.data; + const { print } = toolbox; + const collisionEntities = []; + let onlyCollisions = true; for (let i = 0; i < abiData.size; i++) { - let dataRow = abiData.get(i).asMutable() + const dataRow = abiData.get(i).asMutable(); if (dataRow.get('type') === 'event') { - if (entities.indexOf(dataRow.get('name')) !== -1) { - if (entities.indexOf(`${contractName}${dataRow.get('name')}`) !== -1) { + if (entities.includes(dataRow.get('name'))) { + if (entities.includes(`${contractName}${dataRow.get('name')}`)) { print.error(`Contract name ('${contractName}') - + event name ('${dataRow.get('name')}') entity already exists.`) - process.exitCode = 1 - break + + event name ('${dataRow.get('name')}') entity already exists.`); + process.exitCode = 1; + break; } if (mergeEntities) { - collisionEntities.push(dataRow.get('name')) - abiData = abiData.asImmutable().delete(i) // needs to be immutable when deleting, yes you read that right - https://github.com/immutable-js/immutable-js/issues/1901 - i-- // deletion also shifts values to the left - continue + collisionEntities.push(dataRow.get('name')); + abiData = abiData.asImmutable().delete(i); // needs to be immutable when deleting, yes you read that right - https://github.com/immutable-js/immutable-js/issues/1901 + i--; // deletion also shifts values to the left + continue; } else { - dataRow.set('name', `${contractName}${dataRow.get('name')}`) + dataRow.set('name', `${contractName}${dataRow.get('name')}`); } } else { - onlyCollisions = false + onlyCollisions = false; } } - abiData = abiData.asMutable().set(i, dataRow) + abiData = abiData.asMutable().set(i, dataRow); } - return { abiData, collisionEntities, onlyCollisions } -} + return { abiData, collisionEntities, onlyCollisions }; +}; diff --git a/packages/cli/src/commands/auth.ts b/packages/cli/src/commands/auth.ts index 915aea1a..aa2c8e7d 100644 --- a/packages/cli/src/commands/auth.ts +++ b/packages/cli/src/commands/auth.ts @@ -1,13 +1,11 @@ -import chalk from 'chalk' -import { GluegunToolbox } from 'gluegun' -import { saveDeployKey } from '../command-helpers/auth' -import { chooseNodeUrl } from '../command-helpers/node' -import { fixParameters } from '../command-helpers/gluegun' +import chalk from 'chalk'; +import { GluegunToolbox } from 'gluegun'; +import { saveDeployKey } from '../command-helpers/auth'; +import { fixParameters } from '../command-helpers/gluegun'; +import { chooseNodeUrl } from '../command-helpers/node'; const HELP = ` -${chalk.bold('graph auth')} [options] ${chalk.bold('')} ${chalk.bold( - '', -)} +${chalk.bold('graph auth')} [options] ${chalk.bold('')} ${chalk.bold('')} ${chalk.dim('Options:')} @@ -15,15 +13,15 @@ ${chalk.dim('Options:')} Selects the product for which to authenticate --studio Shortcut for --product subgraph-studio -h, --help Show usage information -` +`; export interface AuthOptions { - product?: 'subgraph-studio' | 'hosted-service' - studio?: boolean - help?: boolean + product?: 'subgraph-studio' | 'hosted-service'; + studio?: boolean; + help?: boolean; // not a cli arg - node?: string - deployKey?: string + node?: string; + deployKey?: string; } const processForm = async ( @@ -48,53 +46,53 @@ const processForm = async ( message: 'Deploy key', skip: deployKey !== undefined, }, - ] + ]; try { - const answers = await toolbox.prompt.ask(questions) - return answers + const answers = await toolbox.prompt.ask(questions); + return answers; } catch (e) { - return undefined + return undefined; } -} +}; export default { description: 'Sets the deploy key to use when deploying to a Graph node', run: async (toolbox: GluegunToolbox) => { // Obtain tools - const { print } = toolbox + const { print } = toolbox; // Read CLI parameters - const { product, studio, h, help } = toolbox.parameters.options + const { product, studio, h, help } = toolbox.parameters.options; // Show help text if requested if (help || h) { - print.info(HELP) - return + print.info(HELP); + return; } - let firstParam: string, secondParam: string + let firstParam: string, secondParam: string; try { - ;[firstParam, secondParam] = fixParameters(toolbox.parameters, { + [firstParam, secondParam] = fixParameters(toolbox.parameters, { h, help, studio, - }) + }); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } // if user specifies --product or --studio then deployKey is the first parameter - let node: string | undefined - let deployKey + let node: string | undefined; + let deployKey; if (product || studio) { - ;({ node } = chooseNodeUrl({ product, studio, node })) - deployKey = firstParam + ({ node } = chooseNodeUrl({ product, studio, node })); + deployKey = firstParam; } else { - node = firstParam - deployKey = secondParam + node = firstParam; + deployKey = secondParam; } if (!node || !deployKey) { @@ -103,40 +101,38 @@ export default { studio, node, deployKey, - }) + }); if (inputs === undefined) { - process.exit(1) + process.exit(1); } if (!node) { - ;({ node } = chooseNodeUrl({ + ({ node } = chooseNodeUrl({ product: inputs.product, studio, node, - })) - } - if (!deployKey) { - deployKey = inputs.deployKey + })); } + deployKey ||= inputs.deployKey; } if (!deployKey) { - print.error(`No deploy key provided`) - print.info(HELP) - process.exitCode = 1 - return + print.error(`No deploy key provided`); + print.info(HELP); + process.exitCode = 1; + return; } if (deployKey.length > 200) { - print.error(`Deploy key must not exceed 200 characters`) - process.exitCode = 1 - return + print.error(`Deploy key must not exceed 200 characters`); + process.exitCode = 1; + return; } try { - await saveDeployKey(node!, deployKey) - print.success(`Deploy key set for ${node}`) + await saveDeployKey(node!, deployKey); + print.success(`Deploy key set for ${node}`); } catch (e) { - print.error(e) - process.exitCode = 1 + print.error(e); + process.exitCode = 1; } }, -} +}; diff --git a/packages/cli/src/commands/binary-install-raw.d.ts b/packages/cli/src/commands/binary-install-raw.d.ts index e1e4ff25..7596d84a 100644 --- a/packages/cli/src/commands/binary-install-raw.d.ts +++ b/packages/cli/src/commands/binary-install-raw.d.ts @@ -1 +1 @@ -declare module 'binary-install-raw' +declare module 'binary-install-raw'; diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index eeab48e2..031c9140 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -1,13 +1,13 @@ -import chalk from 'chalk' -import { GluegunToolbox } from 'gluegun' -import { createCompiler } from '../command-helpers/compiler' -import { fixParameters } from '../command-helpers/gluegun' -import { updateSubgraphNetwork } from '../command-helpers/network' -import * as DataSourcesExtractor from '../command-helpers/data-sources' -import Protocol from '../protocols' -import debug from '../debug' +import chalk from 'chalk'; +import { GluegunToolbox } from 'gluegun'; +import { createCompiler } from '../command-helpers/compiler'; +import * as DataSourcesExtractor from '../command-helpers/data-sources'; +import { fixParameters } from '../command-helpers/gluegun'; +import { updateSubgraphNetwork } from '../command-helpers/network'; +import debug from '../debug'; +import Protocol from '../protocols'; -let buildDebug = debug('graph-cli:build') +const buildDebug = debug('graph-cli:build'); const HELP = ` ${chalk.bold('graph build')} [options] ${chalk.bold('[]')} @@ -22,24 +22,24 @@ Options: -w, --watch Regenerate types when subgraph files change (default: false) --network Network configuration to use from the networks config file --network-file Networks config file path (default: "./networks.json") -` +`; export interface BuildOptions { - help?: boolean - ipfs?: string - outputDir?: string - outputFormat?: string - skipMigrations?: boolean - watch?: boolean - network?: string - networkFile?: string + help?: boolean; + ipfs?: string; + outputDir?: string; + outputFormat?: string; + skipMigrations?: boolean; + watch?: boolean; + network?: string; + networkFile?: string; } export default { description: 'Builds a subgraph and (optionally) uploads it to IPFS', run: async (toolbox: GluegunToolbox) => { // Obtain tools - const { filesystem, print } = toolbox + const { filesystem, print } = toolbox; // Parse CLI parameters let { @@ -56,95 +56,92 @@ export default { watch, network, networkFile, - } = toolbox.parameters.options + } = toolbox.parameters.options; // Support both short and long option variants - help = help || h - ipfs = ipfs || i - outputDir = outputDir || o - outputFormat = outputFormat || t - watch = watch || w + help ||= h; + ipfs ||= i; + outputDir ||= o; + outputFormat ||= t; + watch ||= w; - let manifest + let manifest; try { - ;[manifest] = fixParameters(toolbox.parameters, { + [manifest] = fixParameters(toolbox.parameters, { h, help, w, watch, - }) + }); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } // Fall back to default values for options / parameters - outputFormat = - outputFormat && ['wasm', 'wast'].indexOf(outputFormat) >= 0 ? outputFormat : 'wasm' - outputDir = outputDir && outputDir !== '' ? outputDir : filesystem.path('build') + outputFormat = outputFormat && ['wasm', 'wast'].includes(outputFormat) ? outputFormat : 'wasm'; + outputDir = outputDir && outputDir !== '' ? outputDir : filesystem.path('build'); manifest = - manifest !== undefined && manifest !== '' - ? manifest - : filesystem.resolve('subgraph.yaml') + manifest !== undefined && manifest !== '' ? manifest : filesystem.resolve('subgraph.yaml'); networkFile = networkFile !== undefined && networkFile !== '' ? networkFile - : filesystem.resolve('networks.json') + : filesystem.resolve('networks.json'); // Show help text if requested if (help) { - print.info(HELP) - return + print.info(HELP); + return; } - let protocol + let protocol; try { - const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest) + const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest); - protocol = Protocol.fromDataSources(dataSourcesAndTemplates) + protocol = Protocol.fromDataSources(dataSourcesAndTemplates); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } - buildDebug('Detected protocol "%s" (%o)', protocol.name, protocol) + buildDebug('Detected protocol "%s" (%o)', protocol.name, protocol); if (network && filesystem.exists(networkFile) !== 'file') { - print.error(`Network file '${networkFile}' does not exists or is not a file!`) - process.exitCode = 1 - return + print.error(`Network file '${networkFile}' does not exists or is not a file!`); + process.exitCode = 1; + return; } if (network) { - let identifierName = protocol.getContract()!.identifierName() - await updateSubgraphNetwork(toolbox, manifest, network, networkFile, identifierName) + const identifierName = protocol.getContract()!.identifierName(); + await updateSubgraphNetwork(toolbox, manifest, network, networkFile, identifierName); } - let compiler = createCompiler(manifest, { + const compiler = createCompiler(manifest, { ipfs, outputDir, outputFormat, skipMigrations, protocol, - }) + }); // Exit with an error code if the compiler couldn't be created if (!compiler) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Watch subgraph files for changes or additions, trigger // compile (if watch argument specified) if (watch) { - await compiler.watchAndCompile() + await compiler.watchAndCompile(); } else { - let result = await compiler.compile() + const result = await compiler.compile(); if (result === false) { - process.exitCode = 1 + process.exitCode = 1; } } }, -} +}; diff --git a/packages/cli/src/commands/codegen.ts b/packages/cli/src/commands/codegen.ts index e5f53cab..25afd640 100644 --- a/packages/cli/src/commands/codegen.ts +++ b/packages/cli/src/commands/codegen.ts @@ -1,15 +1,12 @@ -import chalk from 'chalk' -import path from 'path' -import { GluegunToolbox } from 'gluegun' -import TypeGenerator from '../type-generator' -import Protocol from '../protocols' -import { fixParameters } from '../command-helpers/gluegun' -import * as DataSourcesExtractor from '../command-helpers/data-sources' -import debug from '../debug' -import { - assertManifestApiVersion, - assertGraphTsVersion, -} from '../command-helpers/version' +import path from 'path'; +import chalk from 'chalk'; +import { GluegunToolbox } from 'gluegun'; +import * as DataSourcesExtractor from '../command-helpers/data-sources'; +import { fixParameters } from '../command-helpers/gluegun'; +import { assertGraphTsVersion, assertManifestApiVersion } from '../command-helpers/version'; +import debug from '../debug'; +import Protocol from '../protocols'; +import TypeGenerator from '../type-generator'; const HELP = ` ${chalk.bold('graph codegen')} [options] ${chalk.bold('[]')} @@ -20,50 +17,39 @@ Options: -w, --watch Regenerate types when subgraph files change (default: false) -u, --uncrashable Generate Float Subgraph Uncrashable helper file -uc, --uncrashable-config Directory for uncrashable config (default: ./uncrashable-config.yaml) - ` + `; export interface CodeGenOptions { - help?: boolean - outputDir?: string - skipMigrations?: boolean - watch?: boolean - uncrashable?: boolean - uncrashableConfig?: string + help?: boolean; + outputDir?: string; + skipMigrations?: boolean; + watch?: boolean; + uncrashable?: boolean; + uncrashableConfig?: string; } -let codegenDebug = debug('graph-cli:codegen') +const codegenDebug = debug('graph-cli:codegen'); export default { description: 'Generates AssemblyScript types for a subgraph', run: async (toolbox: GluegunToolbox) => { // Obtain tools - const { filesystem, print } = toolbox + const { filesystem, print } = toolbox; // Read CLI parameters - let { - h, - help, - o, - outputDir, - skipMigrations, - w, - watch, - u, - uncrashable, - uc, - uncrashableConfig, - } = toolbox.parameters.options + let { h, help, o, outputDir, skipMigrations, w, watch, u, uncrashable, uc, uncrashableConfig } = + toolbox.parameters.options; // Support both long and short option variants - help = help || h - outputDir = outputDir || o - watch = watch || w - uncrashable = uncrashable || u - let uncrashable_config = uncrashableConfig || uc + help ||= h; + outputDir ||= o; + watch ||= w; + uncrashable ||= u; + let uncrashable_config = uncrashableConfig || uc; - let manifest + let manifest; try { - ;[manifest] = fixParameters(toolbox.parameters, { + [manifest] = fixParameters(toolbox.parameters, { h, help, skipMigrations, @@ -71,37 +57,33 @@ export default { watch, u, uncrashable, - }) + }); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } - codegenDebug('Initialized codegen manifest: %o', manifest) + codegenDebug('Initialized codegen manifest: %o', manifest); // Fall back to default values for options / parameters outputDir = - outputDir !== undefined && outputDir !== '' - ? outputDir - : filesystem.path('generated') + outputDir !== undefined && outputDir !== '' ? outputDir : filesystem.path('generated'); manifest = - manifest !== undefined && manifest !== '' - ? manifest - : filesystem.resolve('subgraph.yaml') + manifest !== undefined && manifest !== '' ? manifest : filesystem.resolve('subgraph.yaml'); uncrashable_config = uncrashable_config !== undefined && uncrashable_config !== '' ? uncrashable_config - : filesystem.resolve('uncrashable-config.yaml') + : filesystem.resolve('uncrashable-config.yaml'); // Show help text if requested if (help) { - print.info(HELP) - return + print.info(HELP); + return; } - let protocol + let protocol; try { // Checks to make sure codegen doesn't run against // older subgraphs (both apiVersion and graph-ts version). @@ -109,35 +91,33 @@ export default { // We don't want codegen to run without these conditions // because that would mean the CLI would generate code to // the wrong AssemblyScript version. - await assertManifestApiVersion(manifest, '0.0.5') - await assertGraphTsVersion(path.dirname(manifest), '0.25.0') + await assertManifestApiVersion(manifest, '0.0.5'); + await assertGraphTsVersion(path.dirname(manifest), '0.25.0'); - const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest) + const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest); - protocol = Protocol.fromDataSources(dataSourcesAndTemplates) + protocol = Protocol.fromDataSources(dataSourcesAndTemplates); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } - let generator = new TypeGenerator({ + const generator = new TypeGenerator({ subgraphManifest: manifest, - outputDir: outputDir, + outputDir, skipMigrations, protocol, uncrashable, uncrashableConfig: uncrashable_config, - }) + }); // Watch working directory for file updates or additions, trigger // type generation (if watch argument specified) if (watch) { - await generator.watchAndGenerateTypes() - } else { - if (!(await generator.generateTypes())) { - process.exitCode = 1 - } + await generator.watchAndGenerateTypes(); + } else if (!(await generator.generateTypes())) { + process.exitCode = 1; } }, -} +}; diff --git a/packages/cli/src/commands/create.ts b/packages/cli/src/commands/create.ts index 490ff267..95407352 100644 --- a/packages/cli/src/commands/create.ts +++ b/packages/cli/src/commands/create.ts @@ -1,9 +1,9 @@ -import { URL } from 'url' -import chalk from 'chalk' -import { GluegunToolbox } from 'gluegun' -import { validateNodeUrl } from '../command-helpers/node' -import { identifyDeployKey as identifyAccessToken } from '../command-helpers/auth' -import { createJsonRpcClient } from '../command-helpers/jsonrpc' +import { URL } from 'url'; +import chalk from 'chalk'; +import { GluegunToolbox } from 'gluegun'; +import { identifyDeployKey as identifyAccessToken } from '../command-helpers/auth'; +import { createJsonRpcClient } from '../command-helpers/jsonrpc'; +import { validateNodeUrl } from '../command-helpers/node'; const HELP = ` ${chalk.bold('graph create')} ${chalk.dim('[options]')} ${chalk.bold('')} @@ -13,98 +13,97 @@ ${chalk.dim('Options:')} --access-token Graph access token -h, --help Show usage information -g, --node Graph node to create the subgraph in -` +`; export interface CreateOptions { - accessToken?: string - help?: boolean - node?: string + accessToken?: string; + help?: boolean; + node?: string; } export default { description: 'Registers a subgraph name', run: async (toolbox: GluegunToolbox) => { // Obtain tools - const { print } = toolbox + const { print } = toolbox; // Read CLI parameters - let { accessToken, g, h, help, node } = toolbox.parameters.options - let subgraphName = toolbox.parameters.first + let { accessToken, g, h, help, node } = toolbox.parameters.options; + const subgraphName = toolbox.parameters.first; // Support both long and short option variants - node = node || g - help = help || h + node ||= g; + help ||= h; // Show help text if requested if (help) { - print.info(HELP) - return + print.info(HELP); + return; } // Validate the subgraph name if (!subgraphName) { - print.error('No subgraph name provided') - print.info(HELP) - process.exitCode = 1 - return + print.error('No subgraph name provided'); + print.info(HELP); + process.exitCode = 1; + return; } // Validate node if (!node) { - print.error(`No Graph node provided`) - print.info(HELP) - process.exitCode = 1 - return + print.error(`No Graph node provided`); + print.info(HELP); + process.exitCode = 1; + return; } try { - validateNodeUrl(node) + validateNodeUrl(node); } catch (e) { - print.error(`Graph node "${node}" is invalid: ${e.message}`) - process.exitCode = 1 - return + print.error(`Graph node "${node}" is invalid: ${e.message}`); + process.exitCode = 1; + return; } - let requestUrl = new URL(node) - let client = createJsonRpcClient(requestUrl) + const requestUrl = new URL(node); + const client = createJsonRpcClient(requestUrl); // Exit with an error code if the client couldn't be created if (!client) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Use the access token, if one is set - accessToken = await identifyAccessToken(node, accessToken) + accessToken = await identifyAccessToken(node, accessToken); if (accessToken !== undefined && accessToken !== null) { // @ts-expect-error options property seems to exist - client.options.headers = { Authorization: `Bearer ${accessToken}` } + client.options.headers = { Authorization: `Bearer ${accessToken}` }; } - let spinner = print.spin(`Creating subgraph in Graph node: ${requestUrl}`) + const spinner = print.spin(`Creating subgraph in Graph node: ${requestUrl}`); client.request( 'subgraph_create', { name: subgraphName }, - function ( + ( // @ts-expect-error TODO: why are the arguments not typed? requestError, // @ts-expect-error TODO: why are the arguments not typed? jsonRpcError, - // TODO: why are the arguments not typed? // TODO: this argument is unused, but removing it fails the basic-event-handlers tests - // @ts-expect-error - res, - ) { + // @ts-expect-error TODO: why are the arguments not typed? + _res, + ) => { if (jsonRpcError) { - spinner.fail(`Error creating the subgraph: ${jsonRpcError.message}`) - process.exitCode = 1 + spinner.fail(`Error creating the subgraph: ${jsonRpcError.message}`); + process.exitCode = 1; } else if (requestError) { - spinner.fail(`HTTP error creating the subgraph: ${requestError.code}`) - process.exitCode = 1 + spinner.fail(`HTTP error creating the subgraph: ${requestError.code}`); + process.exitCode = 1; } else { - spinner.stop() - print.success(`Created subgraph: ${subgraphName}`) + spinner.stop(); + print.success(`Created subgraph: ${subgraphName}`); } }, - ) + ); }, -} +}; diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index 9a6e8cb6..bda55909 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -1,22 +1,18 @@ -const URL = require('url').URL -import chalk from 'chalk' -import path from 'path' -import { GluegunToolbox } from 'gluegun' - -import { identifyDeployKey } from '../command-helpers/auth' -import { createCompiler } from '../command-helpers/compiler' -import { fixParameters } from '../command-helpers/gluegun' -import { createJsonRpcClient } from '../command-helpers/jsonrpc' -import { chooseNodeUrl } from '../command-helpers/node' -import { DEFAULT_IPFS_URL } from '../command-helpers/ipfs' -import { - assertManifestApiVersion, - assertGraphTsVersion, -} from '../command-helpers/version' -import * as DataSourcesExtractor from '../command-helpers/data-sources' -import { validateStudioNetwork } from '../command-helpers/studio' -import Protocol from '../protocols' -import { updateSubgraphNetwork } from '../command-helpers/network' +import path from 'path'; +import { URL } from 'url'; +import chalk from 'chalk'; +import { GluegunToolbox } from 'gluegun'; +import { identifyDeployKey } from '../command-helpers/auth'; +import { createCompiler } from '../command-helpers/compiler'; +import * as DataSourcesExtractor from '../command-helpers/data-sources'; +import { fixParameters } from '../command-helpers/gluegun'; +import { DEFAULT_IPFS_URL } from '../command-helpers/ipfs'; +import { createJsonRpcClient } from '../command-helpers/jsonrpc'; +import { updateSubgraphNetwork } from '../command-helpers/network'; +import { chooseNodeUrl } from '../command-helpers/node'; +import { validateStudioNetwork } from '../command-helpers/studio'; +import { assertGraphTsVersion, assertManifestApiVersion } from '../command-helpers/version'; +import Protocol from '../protocols'; const HELP = ` ${chalk.bold('graph deploy')} [options] ${chalk.bold('')} ${chalk.bold( @@ -40,23 +36,23 @@ Options: -w, --watch Regenerate types when subgraph files change (default: false) --network Network configuration to use from the networks config file --network-file Networks config file path (default: "./networks.json") -` +`; export interface DeployOptions { - product?: 'subgraph-studio' | 'hosted-service' - studio?: boolean - node?: string - deployKey?: string - versionLabel?: string - help?: boolean - ipfs?: string - headers?: Record - debugFork?: boolean - outputDir?: string - skipMigrations?: boolean - watch?: boolean - network?: string - networkFile?: string + product?: 'subgraph-studio' | 'hosted-service'; + studio?: boolean; + node?: string; + deployKey?: string; + versionLabel?: string; + help?: boolean; + ipfs?: string; + headers?: Record; + debugFork?: boolean; + outputDir?: string; + skipMigrations?: boolean; + watch?: boolean; + network?: string; + networkFile?: string; } const processForm = async ( @@ -81,21 +77,21 @@ const processForm = async ( message: 'Version Label (e.g. v0.0.1)', skip: versionLabel !== undefined, }, - ] + ]; try { - const answers = await toolbox.prompt.ask(questions) - return answers + const answers = await toolbox.prompt.ask(questions); + return answers; } catch (e) { - return undefined + return undefined; } -} +}; export default { description: 'Deploys the subgraph to a Graph node', run: async (toolbox: GluegunToolbox) => { // Obtain tools - const { filesystem, print } = toolbox + const { filesystem, print } = toolbox; // Parse CLI parameters let { @@ -121,117 +117,113 @@ export default { debugFork, network, networkFile, - } = toolbox.parameters.options + } = toolbox.parameters.options; // Support both long and short option variants - help = help || h - ipfs = ipfs || i || DEFAULT_IPFS_URL - headers = headers || hdr || '{}' - node = node || g - outputDir = outputDir || o - watch = watch || w - versionLabel = versionLabel || l + help ||= h; + ipfs = ipfs || i || DEFAULT_IPFS_URL; + headers = headers || hdr || '{}'; + node ||= g; + outputDir ||= o; + watch ||= w; + versionLabel ||= l; try { - headers = JSON.parse(headers) + headers = JSON.parse(headers); } catch (e) { - print.error('Please make sure headers is a valid JSON value') - process.exitCode = 1 - return + print.error('Please make sure headers is a valid JSON value'); + process.exitCode = 1; + return; } - let subgraphName: string, manifest: string + let subgraphName: string, manifest: string; try { - ;[subgraphName, manifest] = fixParameters(toolbox.parameters, { + [subgraphName, manifest] = fixParameters(toolbox.parameters, { h, help, w, watch, studio, - }) + }); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } // Fall back to default values for options / parameters - outputDir = outputDir && outputDir !== '' ? outputDir : filesystem.path('build') + outputDir = outputDir && outputDir !== '' ? outputDir : filesystem.path('build'); manifest = - manifest !== undefined && manifest !== '' - ? manifest - : filesystem.resolve('subgraph.yaml') + manifest !== undefined && manifest !== '' ? manifest : filesystem.resolve('subgraph.yaml'); networkFile = networkFile !== undefined && networkFile !== '' ? networkFile - : filesystem.resolve('networks.json') + : filesystem.resolve('networks.json'); try { - const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest) + const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest); for (const { network } of dataSourcesAndTemplates) { - validateStudioNetwork({ studio, product, network }) + validateStudioNetwork({ studio, product, network }); } } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } // Show help text if requested if (help) { - print.info(HELP) - return + print.info(HELP); + return; } - ;({ node } = chooseNodeUrl({ product, studio, node })) + ({ node } = chooseNodeUrl({ product, studio, node })); if (!node) { const inputs = await processForm(toolbox, { product, studio, node, versionLabel: 'skip', // determine label requirement later - }) + }); if (inputs === undefined) { - process.exit(1) + process.exit(1); } - product = inputs.product - ;({ node } = chooseNodeUrl({ + product = inputs.product; + ({ node } = chooseNodeUrl({ product, studio, node, - })) + })); } // Validate the subgraph name if (!subgraphName) { print.error( - `No subgraph ${ - product == 'subgraph-studio' || studio ? 'slug' : 'name' - } provided`, - ) - print.info(HELP) - process.exitCode = 1 - return + `No subgraph ${product == 'subgraph-studio' || studio ? 'slug' : 'name'} provided`, + ); + print.info(HELP); + process.exitCode = 1; + return; } // Validate node if (!node) { - print.error(`No Graph node provided`) - print.info(HELP) - process.exitCode = 1 - return + print.error(`No Graph node provided`); + print.info(HELP); + process.exitCode = 1; + return; } // Validate IPFS if (!ipfs) { - print.error(`No IPFS node provided`) - print.info(HELP) - process.exitCode = 1 - return + print.error(`No IPFS node provided`); + print.info(HELP); + process.exitCode = 1; + return; } - let protocol + let protocol; try { // Checks to make sure deploy doesn't run against // older subgraphs (both apiVersion and graph-ts version). @@ -239,27 +231,27 @@ export default { // We don't want the deploy to run without these conditions // because that would mean the CLI would try to compile code // using the wrong AssemblyScript compiler. - await assertManifestApiVersion(manifest, '0.0.5') - await assertGraphTsVersion(path.dirname(manifest), '0.25.0') + await assertManifestApiVersion(manifest, '0.0.5'); + await assertGraphTsVersion(path.dirname(manifest), '0.25.0'); - const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest) + const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest); - protocol = Protocol.fromDataSources(dataSourcesAndTemplates) + protocol = Protocol.fromDataSources(dataSourcesAndTemplates); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } if (network) { - let identifierName = protocol.getContract()!.identifierName() - await updateSubgraphNetwork(toolbox, manifest, network, networkFile, identifierName) + const identifierName = protocol.getContract()!.identifierName(); + await updateSubgraphNetwork(toolbox, manifest, network, networkFile, identifierName); } - const isStudio = node.match(/studio/) - const isHostedService = node.match(/thegraph.com/) && !isStudio + const isStudio = node.match(/studio/); + const isHostedService = node.match(/thegraph.com/) && !isStudio; - let compiler = createCompiler(manifest, { + const compiler = createCompiler(manifest, { ipfs, headers, outputDir, @@ -267,12 +259,12 @@ export default { skipMigrations, blockIpfsMethods: isStudio, // Network does not support publishing subgraphs with IPFS methods protocol, - }) + }); // Exit with an error code if the compiler couldn't be created if (!compiler) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Ask for label if not on hosted service @@ -282,34 +274,34 @@ export default { studio, node, versionLabel, - }) + }); if (inputs === undefined) { - process.exit(1) + process.exit(1); } - versionLabel = inputs.versionLabel + versionLabel = inputs.versionLabel; } - let requestUrl = new URL(node) - const client = createJsonRpcClient(requestUrl) + const requestUrl = new URL(node); + const client = createJsonRpcClient(requestUrl); // Exit with an error code if the client couldn't be created if (!client) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Use the deploy key, if one is set if (!deployKey && accessToken) { - deployKey = accessToken // backwards compatibility + deployKey = accessToken; // backwards compatibility } - deployKey = await identifyDeployKey(node, deployKey) + deployKey = await identifyDeployKey(node, deployKey); if (deployKey !== undefined && deployKey !== null) { // @ts-expect-error options property seems to exist - client.options.headers = { Authorization: 'Bearer ' + deployKey } + client.options.headers = { Authorization: 'Bearer ' + deployKey }; } - let deploySubgraph = async (ipfsHash: string) => { - let spinner = print.spin(`Deploying to Graph node ${requestUrl}`) + const deploySubgraph = async (ipfsHash: string) => { + const spinner = print.spin(`Deploying to Graph node ${requestUrl}`); // `Failed to deploy to Graph node ${requestUrl}`, client.request( 'subgraph_deploy', @@ -328,38 +320,36 @@ export default { res, ) => { if (jsonRpcError) { - spinner.fail( - `Failed to deploy to Graph node ${requestUrl}: ${jsonRpcError.message}`, - ) + spinner.fail(`Failed to deploy to Graph node ${requestUrl}: ${jsonRpcError.message}`); // Provide helpful advice when the subgraph has not been created yet if (jsonRpcError.message.match(/subgraph name not found/)) { if (isHostedService) { print.info(` -You may need to create it at https://thegraph.com/explorer/dashboard.`) +You may need to create it at https://thegraph.com/explorer/dashboard.`); } else { print.info(` Make sure to create the subgraph first by running the following command: -$ graph create --node ${node} ${subgraphName}`) +$ graph create --node ${node} ${subgraphName}`); } } - process.exitCode = 1 + process.exitCode = 1; } else if (requestError) { - spinner.fail(`HTTP error deploying the subgraph ${requestError.code}`) - process.exitCode = 1 + spinner.fail(`HTTP error deploying the subgraph ${requestError.code}`); + process.exitCode = 1; } else { - spinner.stop() + spinner.stop(); - const base = requestUrl.protocol + '//' + requestUrl.hostname - let playground = res.playground - let queries = res.queries + const base = requestUrl.protocol + '//' + requestUrl.hostname; + let playground = res.playground; + let queries = res.queries; // Add a base URL if graph-node did not return the full URL if (playground.charAt(0) === ':') { - playground = base + playground + playground = base + playground; } if (queries.charAt(0) === ':') { - queries = base + queries + queries = base + queries; } if (isHostedService) { @@ -367,32 +357,32 @@ $ graph create --node ${node} ${subgraphName}`) `Deployed to ${chalk.blue( `https://thegraph.com/explorer/subgraph/${subgraphName}`, )}`, - ) + ); } else { - print.success(`Deployed to ${chalk.blue(`${playground}`)}`) + print.success(`Deployed to ${chalk.blue(String(playground))}`); } - print.info('\nSubgraph endpoints:') - print.info(`Queries (HTTP): ${queries}`) - print.info(``) + print.info('\nSubgraph endpoints:'); + print.info(`Queries (HTTP): ${queries}`); + print.info(``); } }, - ) - } + ); + }; if (watch) { await compiler.watchAndCompile(async ipfsHash => { if (ipfsHash !== undefined) { - await deploySubgraph(ipfsHash) + await deploySubgraph(ipfsHash); } - }) + }); } else { - let result = await compiler.compile() + const result = await compiler.compile(); if (result === undefined || result === false) { // Compilation failed, not deploying. - process.exitCode = 1 - return + process.exitCode = 1; + return; } - await deploySubgraph(result) + await deploySubgraph(result); } }, -} +}; diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 4ba61c2a..845276c9 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -1,31 +1,31 @@ -import chalk from 'chalk' -import os from 'os' -import path from 'path' -import { GluegunToolbox } from 'gluegun' -import fs from 'fs' -import * as graphCli from '../cli' -import { getSubgraphBasename, validateSubgraphName } from '../command-helpers/subgraph' -import * as DataSourcesExtractor from '../command-helpers/data-sources' -import { validateStudioNetwork } from '../command-helpers/studio' -import { initNetworksConfig } from '../command-helpers/network' -import { withSpinner } from '../command-helpers/spinner' -import { fixParameters } from '../command-helpers/gluegun' -import { chooseNodeUrl } from '../command-helpers/node' -import { loadAbiFromEtherscan, loadAbiFromBlockScout } from '../command-helpers/abi' -import { generateScaffold, writeScaffold } from '../command-helpers/scaffold' -import { abiEvents } from '../scaffold/schema' -import { validateContract } from '../validation' -import Protocol, { ProtocolName } from '../protocols' -import debug from '../debug' -import EthereumABI from '../protocols/ethereum/abi' -import { ContractCtor } from '../protocols/contract' - -const protocolChoices = Array.from(Protocol.availableProtocols().keys()) -const availableNetworks = Protocol.availableNetworks() - -const DEFAULT_EXAMPLE_SUBGRAPH = 'ethereum/gravatar' - -let initDebug = debug('graph-cli:init') +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import chalk from 'chalk'; +import { GluegunToolbox } from 'gluegun'; +import * as graphCli from '../cli'; +import { loadAbiFromBlockScout, loadAbiFromEtherscan } from '../command-helpers/abi'; +import * as DataSourcesExtractor from '../command-helpers/data-sources'; +import { fixParameters } from '../command-helpers/gluegun'; +import { initNetworksConfig } from '../command-helpers/network'; +import { chooseNodeUrl } from '../command-helpers/node'; +import { generateScaffold, writeScaffold } from '../command-helpers/scaffold'; +import { withSpinner } from '../command-helpers/spinner'; +import { validateStudioNetwork } from '../command-helpers/studio'; +import { getSubgraphBasename, validateSubgraphName } from '../command-helpers/subgraph'; +import debug from '../debug'; +import Protocol, { ProtocolName } from '../protocols'; +import { ContractCtor } from '../protocols/contract'; +import EthereumABI from '../protocols/ethereum/abi'; +import { abiEvents } from '../scaffold/schema'; +import { validateContract } from '../validation'; + +const protocolChoices = Array.from(Protocol.availableProtocols().keys()); +const availableNetworks = Protocol.availableNetworks(); + +const DEFAULT_EXAMPLE_SUBGRAPH = 'ethereum/gravatar'; + +const initDebug = debug('graph-cli:init'); const HELP = ` ${chalk.bold('graph init')} [options] [subgraph-name] [directory] @@ -65,7 +65,7 @@ ${chalk.dim.underline('Cosmos:')} --network <${availableNetworks.get('cosmos')!.join('|')}> Selects the network the contract is deployed to -` +`; const processInitForm = async ( toolbox: GluegunToolbox, @@ -84,52 +84,52 @@ const processInitForm = async ( subgraphName, contractName, }: { - protocol: ProtocolName - product: string - studio: string - node: string - abi: EthereumABI - allowSimpleName: boolean - directory: string - contract: string - indexEvents: boolean - fromExample: string | boolean - network: string - subgraphName: string - contractName: string + protocol: ProtocolName; + product: string; + studio: string; + node: string; + abi: EthereumABI; + allowSimpleName: boolean; + directory: string; + contract: string; + indexEvents: boolean; + fromExample: string | boolean; + network: string; + subgraphName: string; + contractName: string; }, ): Promise< | { - abi: EthereumABI - protocolInstance: Protocol - subgraphName: string - directory: string - studio: string - product: string - network: string - contract: string - indexEvents: boolean - contractName: string + abi: EthereumABI; + protocolInstance: Protocol; + subgraphName: string; + directory: string; + studio: string; + product: string; + network: string; + contract: string; + indexEvents: boolean; + contractName: string; } | undefined > => { - let abiFromEtherscan: EthereumABI | undefined = undefined - let abiFromFile = undefined - let protocolInstance!: Protocol - let ProtocolContract: ContractCtor - let ABI: typeof EthereumABI + let abiFromEtherscan: EthereumABI | undefined = undefined; + let abiFromFile = undefined; + let protocolInstance!: Protocol; + let ProtocolContract: ContractCtor; + let ABI: typeof EthereumABI; - let questions = [ + const questions = [ { type: 'select', name: 'protocol', message: 'Protocol', choices: protocolChoices, skip: protocolChoices.includes(protocol), - result: (value: string) => { - protocol = protocol || value - protocolInstance = new Protocol(protocol) - return protocol + result: (value: ProtocolName) => { + protocol ||= value; + protocolInstance = new Protocol(protocol); + return protocol; }, }, { @@ -149,40 +149,39 @@ const processInitForm = async ( // For now we only support NEAR subgraphs in the Hosted Service if (protocol === 'near') { // Can be overwritten because the question will be skipped (product === undefined) - product = 'hosted-service' - return product + product = 'hosted-service'; + return product; } if (value == 'subgraph-studio') { - allowSimpleName = true + allowSimpleName = true; } - product = value as any - return value + product = value as any; + return value; }, }, { type: 'input', name: 'subgraphName', - message: () => - product == 'subgraph-studio' || studio ? 'Subgraph slug' : 'Subgraph name', + message: () => (product == 'subgraph-studio' || studio ? 'Subgraph slug' : 'Subgraph name'), initial: subgraphName, validate: (name: string) => { try { - validateSubgraphName(name, { allowSimpleName }) - return true + validateSubgraphName(name, { allowSimpleName }); + return true; } catch (e) { return `${e.message} Examples: $ graph init ${os.userInfo().username}/${name} - $ graph init ${name} --allow-simple-name` + $ graph init ${name} --allow-simple-name`; } }, result: (value: string) => { - subgraphName = value - return value + subgraphName = value; + return value; }, }, { @@ -204,21 +203,21 @@ const processInitForm = async ( 'Generating list of available networks for protocol "%s" (%M)', protocol, availableNetworks.get(protocol as any), - ) + ); return ( // @ts-expect-error TODO: wait what? availableNetworks .get(protocol) // Get networks related to the chosen protocol. // @ts-expect-error TODO: wait what? .toArray() - ) // Needed because of gluegun. It can't even receive a JS iterable. + ); // Needed because of gluegun. It can't even receive a JS iterable. }, skip: fromExample !== undefined, initial: network || 'mainnet', result: (value: string) => { - network = value - return value + network = value; + return value; }, }, // TODO: @@ -230,27 +229,27 @@ const processInitForm = async ( type: 'input', name: 'contract', message: () => { - ProtocolContract = protocolInstance.getContract()! - return `Contract ${ProtocolContract.identifierName()}` + ProtocolContract = protocolInstance.getContract()!; + return `Contract ${ProtocolContract.identifierName()}`; }, skip: () => fromExample !== undefined || !protocolInstance.hasContract(), initial: contract, validate: async (value: string) => { if (fromExample !== undefined || !protocolInstance.hasContract()) { - return true + return true; } // Validate whether the contract is valid - const { valid, error } = validateContract(value, ProtocolContract) + const { valid, error } = validateContract(value, ProtocolContract); - return valid ? true : error + return valid ? true : error; }, result: async (value: string) => { if (fromExample !== undefined) { - return value + return value; } - ABI = protocolInstance.getABI() + ABI = protocolInstance.getABI(); // Try loading the ABI from Etherscan, if none was provided if (protocolInstance.hasABIs() && !abi) { @@ -259,11 +258,13 @@ const processInitForm = async ( // TODO: this variable is never used anywhere, what happens? // abiFromBlockScout = await loadAbiFromBlockScout(ABI, network, value) } else { - abiFromEtherscan = await loadAbiFromEtherscan(ABI, network!, value) + abiFromEtherscan = await loadAbiFromEtherscan(ABI, network!, value); } - } catch (e) {} + } catch (e) { + // noop + } } - return value + return value; }, }, { @@ -272,19 +273,17 @@ const processInitForm = async ( message: 'ABI file (path)', initial: abi, skip: () => - !protocolInstance.hasABIs() || - fromExample !== undefined || - abiFromEtherscan !== undefined, + !protocolInstance.hasABIs() || fromExample !== undefined || abiFromEtherscan !== undefined, validate: async (value: string) => { if (fromExample || abiFromEtherscan || !protocolInstance.hasABIs()) { - return true + return true; } try { - abiFromFile = loadAbiFromFile(toolbox, ABI, value) - return true + abiFromFile = loadAbiFromFile(toolbox, ABI, value); + return true; } catch (e) { - return e.message + return e.message; } }, }, @@ -296,8 +295,8 @@ const processInitForm = async ( skip: () => fromExample !== undefined || !protocolInstance.hasContract(), validate: (value: string) => value && value.length > 0, result: (value: string) => { - contractName = value - return value + contractName = value; + return value; }, }, { @@ -307,50 +306,46 @@ const processInitForm = async ( initial: true, skip: () => !!indexEvents, result: (value: boolean) => { - indexEvents = value - return value + indexEvents = value; + return value; }, }, - ] + ]; try { - let answers = await toolbox.prompt.ask( + const answers = await toolbox.prompt.ask( // @ts-expect-error questions do somehow fit questions, - ) + ); return { ...(answers as any), // necessary answers are here abi: (abiFromEtherscan || abiFromFile)!, protocolInstance, - } + }; } catch (e) { - return undefined + return undefined; } -} +}; -const loadAbiFromFile = ( - toolbox: GluegunToolbox, - ABI: typeof EthereumABI, - filename: string, -) => { - let exists = toolbox.filesystem.exists(filename) +const loadAbiFromFile = (toolbox: GluegunToolbox, ABI: typeof EthereumABI, filename: string) => { + const exists = toolbox.filesystem.exists(filename); if (!exists) { - throw Error('File does not exist.') + throw Error('File does not exist.'); } else if (exists === 'dir') { - throw Error('Path points to a directory, not a file.') + throw Error('Path points to a directory, not a file.'); } else if (exists === 'other') { - throw Error('Not sure what this path points to.') + throw Error('Not sure what this path points to.'); } else { - return ABI.load('Contract', filename) + return ABI.load('Contract', filename); } -} +}; export default { description: 'Creates a new subgraph with basic scaffolding', run: async (toolbox: GluegunToolbox) => { // Obtain tools - const { print, system } = toolbox + const { print, system } = toolbox; // Read CLI parameters let { @@ -368,69 +363,65 @@ export default { help, indexEvents, network, - } = toolbox.parameters.options + } = toolbox.parameters.options; - node = node || g - ;({ node, allowSimpleName } = chooseNodeUrl({ + node ||= g; + ({ node, allowSimpleName } = chooseNodeUrl({ product, studio, node, allowSimpleName, - })) + })); if (fromContract && fromExample) { - print.error(`Only one of --from-example and --from-contract can be used at a time.`) - process.exitCode = 1 - return + print.error(`Only one of --from-example and --from-contract can be used at a time.`); + process.exitCode = 1; + return; } - let subgraphName, directory + let subgraphName, directory; try { - ;[subgraphName, directory] = fixParameters(toolbox.parameters, { + [subgraphName, directory] = fixParameters(toolbox.parameters, { allowSimpleName, help, h, indexEvents, studio, - }) + }); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } // Show help text if requested if (help || h) { - print.info(HELP) - return + print.info(HELP); + return; } // Detect git - let git = system.which('git') + const git = system.which('git'); if (git === null) { - print.error( - `Git was not found on your system. Please install 'git' so it is in $PATH.`, - ) - process.exitCode = 1 - return + print.error(`Git was not found on your system. Please install 'git' so it is in $PATH.`); + process.exitCode = 1; + return; } // Detect Yarn and/or NPM - let yarn = system.which('yarn') - let npm = system.which('npm') + const yarn = system.which('yarn'); + const npm = system.which('npm'); if (!yarn && !npm) { - print.error( - `Neither Yarn nor NPM were found on your system. Please install one of them.`, - ) - process.exitCode = 1 - return + print.error(`Neither Yarn nor NPM were found on your system. Please install one of them.`); + process.exitCode = 1; + return; } - let commands = { + const commands = { install: yarn ? 'yarn' : 'npm install', codegen: yarn ? 'yarn codegen' : 'npm run codegen', deploy: yarn ? 'yarn deploy' : 'npm run deploy', - } + }; // If all parameters are provided from the command-line, // go straight to creating the subgraph from the example @@ -439,7 +430,7 @@ export default { toolbox, { fromExample, allowSimpleName, directory, subgraphName, studio, product }, { commands }, - ) + ); } // If all parameters are provided from the command-line, @@ -450,33 +441,33 @@ export default { `Protocol '${protocol}' is not supported, choose from these options: ${protocolChoices.join( ', ', )}`, - ) - process.exitCode = 1 - return + ); + process.exitCode = 1; + return; } - const protocolInstance = new Protocol(protocol) + const protocolInstance = new Protocol(protocol); if (protocolInstance.hasABIs()) { - const ABI = protocolInstance.getABI() + const ABI = protocolInstance.getABI(); if (abi) { try { - abi = loadAbiFromFile(toolbox, ABI, abi) + abi = loadAbiFromFile(toolbox, ABI, abi); } catch (e) { - print.error(`Failed to load ABI: ${e.message}`) - process.exitCode = 1 - return + print.error(`Failed to load ABI: ${e.message}`); + process.exitCode = 1; + return; } } else { try { if (network === 'poa-core') { - abi = await loadAbiFromBlockScout(ABI, network, fromContract) + abi = await loadAbiFromBlockScout(ABI, network, fromContract); } else { - abi = await loadAbiFromEtherscan(ABI, network, fromContract) + abi = await loadAbiFromEtherscan(ABI, network, fromContract); } } catch (e) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } } } @@ -498,11 +489,11 @@ export default { product, }, { commands, addContract: false }, - ) + ); } // Otherwise, take the user through the interactive form - let inputs = await processInitForm(toolbox, { + const inputs = await processInitForm(toolbox, { protocol, product, studio, @@ -516,34 +507,34 @@ export default { network, subgraphName, contractName, - }) + }); // Exit immediately when the form is cancelled if (inputs === undefined) { - process.exit(1) + process.exit(1); } - print.info('———') + print.info('———'); if (fromExample) { await initSubgraphFromExample( toolbox, { - fromExample: fromExample, + fromExample, subgraphName: inputs.subgraphName, directory: inputs.directory, studio: inputs.studio, product: inputs.product, }, { commands }, - ) + ); } else { - ;({ node, allowSimpleName } = chooseNodeUrl({ + ({ node, allowSimpleName } = chooseNodeUrl({ product: inputs.product, studio, node, allowSimpleName, - })) + })); await initSubgraphFromContract( toolbox, { @@ -561,10 +552,10 @@ export default { product: inputs.product, }, { commands, addContract: true }, - ) + ); } }, -} +}; const revalidateSubgraphName = async ( toolbox: GluegunToolbox, @@ -573,18 +564,18 @@ const revalidateSubgraphName = async ( ) => { // Fail if the subgraph name is invalid try { - validateSubgraphName(subgraphName, { allowSimpleName }) - return true + validateSubgraphName(subgraphName, { allowSimpleName }); + return true; } catch (e) { toolbox.print.error(`${e.message} Examples: $ graph init ${os.userInfo().username}/${subgraphName} - $ graph init ${subgraphName} --allow-simple-name`) - return false + $ graph init ${subgraphName} --allow-simple-name`); + return false; } -} +}; const initRepository = async (toolbox: GluegunToolbox, directory: string) => await withSpinner( @@ -594,18 +585,18 @@ const initRepository = async (toolbox: GluegunToolbox, directory: string) => async () => { // Remove .git dir in --from-example mode; in --from-contract, we're // starting from an empty directory - let gitDir = path.join(directory, '.git') + const gitDir = path.join(directory, '.git'); if (toolbox.filesystem.exists(gitDir)) { - toolbox.filesystem.remove(gitDir) + toolbox.filesystem.remove(gitDir); } - await toolbox.system.run('git init', { cwd: directory }) - await toolbox.system.run('git add --all', { cwd: directory }) + await toolbox.system.run('git init', { cwd: directory }); + await toolbox.system.run('git add --all', { cwd: directory }); await toolbox.system.run('git commit -m "Initial commit"', { cwd: directory, - }) - return true + }); + return true; }, - ) + ); // Only used for local testing / continuous integration. // @@ -614,9 +605,9 @@ const initRepository = async (toolbox: GluegunToolbox, directory: string) => // https://docs.npmjs.com/cli/v7/commands/npm-link. const npmLinkToLocalCli = async (toolbox: GluegunToolbox, directory: string) => { if (process.env.GRAPH_CLI_TESTS) { - await toolbox.system.run('npm link @graphprotocol/graph-cli', { cwd: directory }) + await toolbox.system.run('npm link @graphprotocol/graph-cli', { cwd: directory }); } -} +}; const installDependencies = async ( toolbox: GluegunToolbox, @@ -629,27 +620,23 @@ const installDependencies = async ( `Warnings while installing dependencies`, async () => { // Links to local graph-cli if we're running the automated tests - await npmLinkToLocalCli(toolbox, directory) + await npmLinkToLocalCli(toolbox, directory); - await toolbox.system.run(installCommand, { cwd: directory }) - return true + await toolbox.system.run(installCommand, { cwd: directory }); + return true; }, - ) + ); -const runCodegen = async ( - toolbox: GluegunToolbox, - directory: string, - codegenCommand: string, -) => +const runCodegen = async (toolbox: GluegunToolbox, directory: string, codegenCommand: string) => await withSpinner( `Generate ABI and schema types with ${toolbox.print.colors.muted(codegenCommand)}`, `Failed to generate code from ABI and GraphQL schema`, `Warnings while generating code from ABI and GraphQL schema`, async () => { - await toolbox.system.run(codegenCommand, { cwd: directory }) - return true + await toolbox.system.run(codegenCommand, { cwd: directory }); + return true; }, - ) + ); const printNextSteps = ( toolbox: GluegunToolbox, @@ -658,22 +645,22 @@ const printNextSteps = ( commands, }: { commands: { - install: string - codegen: string - deploy: string - } + install: string; + codegen: string; + deploy: string; + }; }, ) => { - const { print } = toolbox + const { print } = toolbox; - let relativeDir = path.relative(process.cwd(), directory) + const relativeDir = path.relative(process.cwd(), directory); // Print instructions print.success( ` Subgraph ${print.colors.blue(subgraphName)} created in ${print.colors.blue(relativeDir)} `, - ) + ); print.info(`Next steps: 1. Run \`${print.colors.muted('graph auth')}\` to authenticate with your deploy key. @@ -682,8 +669,8 @@ Subgraph ${print.colors.blue(subgraphName)} created in ${print.colors.blue(relat 3. Run \`${print.colors.muted(commands.deploy)}\` to deploy the subgraph. -Make sure to visit the documentation on https://thegraph.com/docs/ for further information.`) -} +Make sure to visit the documentation on https://thegraph.com/docs/ for further information.`); +}; const initSubgraphFromExample = async ( toolbox: GluegunToolbox, @@ -695,76 +682,72 @@ const initSubgraphFromExample = async ( studio, product, }: { - fromExample: string | boolean - allowSimpleName?: boolean - subgraphName: string - directory: string - studio: string - product: string + fromExample: string | boolean; + allowSimpleName?: boolean; + subgraphName: string; + directory: string; + studio: string; + product: string; }, { commands, }: { commands: { - install: string - codegen: string - deploy: string - } + install: string; + codegen: string; + deploy: string; + }; }, ) => { - let { filesystem, print, system } = toolbox + const { filesystem, print, system } = toolbox; // Fail if the subgraph name is invalid - if ( - !revalidateSubgraphName(toolbox, subgraphName, { allowSimpleName: !!allowSimpleName }) - ) { - process.exitCode = 1 - return + if (!revalidateSubgraphName(toolbox, subgraphName, { allowSimpleName: !!allowSimpleName })) { + process.exitCode = 1; + return; } // Fail if the output directory already exists if (filesystem.exists(directory)) { - print.error(`Directory or file "${directory}" already exists`) - process.exitCode = 1 - return + print.error(`Directory or file "${directory}" already exists`); + process.exitCode = 1; + return; } // Clone the example subgraph repository - let cloned = await withSpinner( + const cloned = await withSpinner( `Cloning example subgraph`, `Failed to clone example subgraph`, `Warnings while cloning example subgraph`, async () => { // Create a temporary directory - const prefix = path.join(os.tmpdir(), 'example-subgraph-') - const tmpDir = fs.mkdtempSync(prefix) + const prefix = path.join(os.tmpdir(), 'example-subgraph-'); + const tmpDir = fs.mkdtempSync(prefix); try { - await system.run( - `git clone http://github.com/graphprotocol/example-subgraphs ${tmpDir}`, - ) + await system.run(`git clone http://github.com/graphprotocol/example-subgraphs ${tmpDir}`); // If an example is not specified, use the default one if (fromExample === undefined || fromExample === true) { - fromExample = DEFAULT_EXAMPLE_SUBGRAPH + fromExample = DEFAULT_EXAMPLE_SUBGRAPH; } - const exampleSubgraphPath = path.join(tmpDir, String(fromExample)) + const exampleSubgraphPath = path.join(tmpDir, String(fromExample)); if (!filesystem.exists(exampleSubgraphPath)) { - return { result: false, error: `Example not found: ${fromExample}` } + return { result: false, error: `Example not found: ${fromExample}` }; } - filesystem.copy(exampleSubgraphPath, directory) - return true + filesystem.copy(exampleSubgraphPath, directory); + return true; } finally { - filesystem.remove(tmpDir) + filesystem.remove(tmpDir); } }, - ) + ); if (!cloned) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } try { @@ -772,84 +755,84 @@ const initSubgraphFromExample = async ( // we'll check it's network anyway. If it's a studio subgraph we're dealing with. const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath( path.join(directory, 'subgraph.yaml'), - ) + ); for (const { network } of dataSourcesAndTemplates) { - validateStudioNetwork({ studio, product, network }) + validateStudioNetwork({ studio, product, network }); } } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } - let networkConf = await initNetworksConfig(toolbox, directory, 'address') + const networkConf = await initNetworksConfig(toolbox, directory, 'address'); if (networkConf !== true) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Update package.json to match the subgraph name - let prepared = await withSpinner( + const prepared = await withSpinner( `Update subgraph name and commands in package.json`, `Failed to update subgraph name and commands in package.json`, `Warnings while updating subgraph name and commands in package.json`, async () => { try { // Load package.json - let pkgJsonFilename = filesystem.path(directory, 'package.json') - let pkgJson = await filesystem.read(pkgJsonFilename, 'json') + const pkgJsonFilename = filesystem.path(directory, 'package.json'); + const pkgJson = await filesystem.read(pkgJsonFilename, 'json'); - pkgJson.name = getSubgraphBasename(subgraphName) + pkgJson.name = getSubgraphBasename(subgraphName); Object.keys(pkgJson.scripts).forEach(name => { - pkgJson.scripts[name] = pkgJson.scripts[name].replace('example', subgraphName) - }) - delete pkgJson['license'] - delete pkgJson['repository'] + pkgJson.scripts[name] = pkgJson.scripts[name].replace('example', subgraphName); + }); + delete pkgJson['license']; + delete pkgJson['repository']; // Remove example's cli in favor of the local one (added via `npm link`) if (process.env.GRAPH_CLI_TESTS) { - delete pkgJson['devDependencies']['@graphprotocol/graph-cli'] + delete pkgJson['devDependencies']['@graphprotocol/graph-cli']; } // Write package.json - filesystem.write(pkgJsonFilename, pkgJson, { jsonIndent: 2 }) - return true + filesystem.write(pkgJsonFilename, pkgJson, { jsonIndent: 2 }); + return true; } catch (e) { - print.error(`Failed to preconfigure the subgraph: ${e}`) - filesystem.remove(directory) - return false + print.error(`Failed to preconfigure the subgraph: ${e}`); + filesystem.remove(directory); + return false; } }, - ) + ); if (!prepared) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Initialize a fresh Git repository - let repo = await initRepository(toolbox, directory) + const repo = await initRepository(toolbox, directory); if (repo !== true) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Install dependencies - let installed = await installDependencies(toolbox, directory, commands.install) + const installed = await installDependencies(toolbox, directory, commands.install); if (installed !== true) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Run code-generation - let codegen = await runCodegen(toolbox, directory, commands.codegen) + const codegen = await runCodegen(toolbox, directory, commands.codegen); if (codegen !== true) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } - printNextSteps(toolbox, { subgraphName, directory }, { commands }) -} + printNextSteps(toolbox, { subgraphName, directory }, { commands }); +}; const initSubgraphFromContract = async ( toolbox: GluegunToolbox, @@ -867,44 +850,44 @@ const initSubgraphFromContract = async ( studio, product, }: { - protocolInstance: Protocol - allowSimpleName: boolean - subgraphName: string - directory: string - abi: EthereumABI - network: string - contract: string - indexEvents: boolean - contractName: string - node: string - studio: string - product: string + protocolInstance: Protocol; + allowSimpleName: boolean; + subgraphName: string; + directory: string; + abi: EthereumABI; + network: string; + contract: string; + indexEvents: boolean; + contractName: string; + node: string; + studio: string; + product: string; }, { commands, addContract, }: { commands: { - install: string - codegen: string - deploy: string - } - addContract: boolean + install: string; + codegen: string; + deploy: string; + }; + addContract: boolean; }, ) => { - let { print } = toolbox + const { print } = toolbox; // Fail if the subgraph name is invalid if (!revalidateSubgraphName(toolbox, subgraphName, { allowSimpleName })) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Fail if the output directory already exists if (toolbox.filesystem.exists(directory)) { - print.error(`Directory or file "${directory}" already exists`) - process.exitCode = 1 - return + print.error(`Directory or file "${directory}" already exists`); + process.exitCode = 1; + return; } if ( @@ -914,29 +897,29 @@ const initSubgraphFromContract = async ( abiEvents(abi).length === 0) ) { // Fail if the ABI does not contain any events - print.error(`ABI does not contain any events`) - process.exitCode = 1 - return + print.error(`ABI does not contain any events`); + process.exitCode = 1; + return; } // We can validate this before the scaffold because we receive // the network from the form or via command line argument. // We don't need to read the manifest in this case. try { - validateStudioNetwork({ studio, product, network }) + validateStudioNetwork({ studio, product, network }); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } // Scaffold subgraph - let scaffold = await withSpinner( + const scaffold = await withSpinner( `Create subgraph scaffold`, `Failed to create subgraph scaffold`, `Warnings while creating subgraph scaffold`, async spinner => { - let scaffold = await generateScaffold( + const scaffold = await generateScaffold( { protocolInstance, subgraphName, @@ -948,72 +931,72 @@ const initSubgraphFromContract = async ( node, }, spinner, - ) - await writeScaffold(scaffold, directory, spinner) - return true + ); + await writeScaffold(scaffold, directory, spinner); + return true; }, - ) + ); if (scaffold !== true) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } if (protocolInstance.hasContract()) { - let identifierName = protocolInstance.getContract()!.identifierName() - let networkConf = await initNetworksConfig(toolbox, directory, identifierName) + const identifierName = protocolInstance.getContract()!.identifierName(); + const networkConf = await initNetworksConfig(toolbox, directory, identifierName); if (networkConf !== true) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } } // Initialize a fresh Git repository - let repo = await initRepository(toolbox, directory) + const repo = await initRepository(toolbox, directory); if (repo !== true) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Install dependencies - let installed = await installDependencies(toolbox, directory, commands.install) + const installed = await installDependencies(toolbox, directory, commands.install); if (installed !== true) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Run code-generation - let codegen = await runCodegen(toolbox, directory, commands.codegen) + const codegen = await runCodegen(toolbox, directory, commands.codegen); if (codegen !== true) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } while (addContract) { - addContract = await addAnotherContract(toolbox, { protocolInstance, directory }) + addContract = await addAnotherContract(toolbox, { protocolInstance, directory }); } - printNextSteps(toolbox, { subgraphName, directory }, { commands }) -} + printNextSteps(toolbox, { subgraphName, directory }, { commands }); +}; const addAnotherContract = async ( toolbox: GluegunToolbox, { protocolInstance, directory }: { protocolInstance: Protocol; directory: string }, ) => { - const addContractConfirmation = await toolbox.prompt.confirm('Add another contract?') + const addContractConfirmation = await toolbox.prompt.confirm('Add another contract?'); if (addContractConfirmation) { - let abiFromFile: boolean = false - let ProtocolContract = protocolInstance.getContract()! + let abiFromFile = false; + const ProtocolContract = protocolInstance.getContract()!; - let questions = [ + const questions = [ { type: 'input', name: 'contract', message: () => `Contract ${ProtocolContract.identifierName()}`, validate: async (value: string) => { // Validate whether the contract is valid - const { valid, error } = validateContract(value, ProtocolContract) - return valid ? true : error + const { valid, error } = validateContract(value, ProtocolContract); + return valid ? true : error; }, }, { @@ -1022,8 +1005,8 @@ const addAnotherContract = async ( message: 'Provide local ABI path?', choices: ['yes', 'no'], result: (value: string) => { - abiFromFile = value === 'yes' ? true : false - return abiFromFile + abiFromFile = value === 'yes' ? true : false; + return abiFromFile; }, }, { @@ -1039,39 +1022,39 @@ const addAnotherContract = async ( initial: 'Contract', validate: (value: string) => value && value.length > 0, }, - ] + ]; // Get the cwd before process.chdir in order to switch back in the end of command execution - const cwd = process.cwd() + const cwd = process.cwd(); try { - let { abi, contract, contractName } = await toolbox.prompt.ask( + const { abi, contract, contractName } = await toolbox.prompt.ask( // @ts-expect-error questions do somehow fit questions, - ) + ); if (fs.existsSync(directory)) { - process.chdir(directory) + process.chdir(directory); } - let commandLine = ['add', contract, '--contract-name', contractName] + const commandLine = ['add', contract, '--contract-name', contractName]; if (abiFromFile) { if (abi.includes(directory)) { - commandLine.push('--abi', path.normalize(abi.replace(directory, ''))) + commandLine.push('--abi', path.normalize(abi.replace(directory, ''))); } else { - commandLine.push('--abi', abi) + commandLine.push('--abi', abi); } } - await graphCli.run(commandLine) + await graphCli.run(commandLine); } catch (e) { - toolbox.print.error(e) - process.exit(1) + toolbox.print.error(e); + process.exit(1); } finally { - process.chdir(cwd) + process.chdir(cwd); } } - return addContractConfirmation -} + return addContractConfirmation; +}; diff --git a/packages/cli/src/commands/local.ts b/packages/cli/src/commands/local.ts index b2536932..cd9f7b20 100644 --- a/packages/cli/src/commands/local.ts +++ b/packages/cli/src/commands/local.ts @@ -1,18 +1,17 @@ -import chalk from 'chalk' -import compose from 'docker-compose' -import http from 'http' -import net from 'net' -import tmp from 'tmp-promise' -import path from 'path' -import stripAnsi from 'strip-ansi' -import { spawn, ChildProcess } from 'child_process' -import { GluegunToolbox } from 'gluegun' - -import { fixParameters } from '../command-helpers/gluegun' -import { step, withSpinner } from '../command-helpers/spinner' +import { ChildProcess, spawn } from 'child_process'; +import http from 'http'; +import net from 'net'; +import path from 'path'; +import chalk from 'chalk'; +import compose from 'docker-compose'; +import { GluegunToolbox } from 'gluegun'; +import stripAnsi from 'strip-ansi'; +import tmp from 'tmp-promise'; +import { fixParameters } from '../command-helpers/gluegun'; +import { step, withSpinner } from '../command-helpers/spinner'; // Clean up temporary files even when an uncaught exception occurs -tmp.setGracefulCleanup() +tmp.setGracefulCleanup(); const HELP = ` ${chalk.bold('graph local')} [options] ${chalk.bold('')} @@ -30,28 +29,27 @@ Options: --skip-wait-for-ethereum Don't wait for Ethereum to be up at localhost:18545 (optional) --skip-wait-for-postgres Don't wait for Postgres to be up at localhost:15432 (optional) --timeout Time to wait for service containers. (optional, defaults to 120000 milliseconds) -` +`; export interface LocalOptions { - help?: boolean - nodeLogs?: boolean - ethereumLogs?: boolean - composeFile?: string - nodeImage?: string - standaloneNode?: string - standaloneNodeArgs?: string - skipWaitForIpfs?: boolean - skipWaitForEthereum?: boolean - skipWaitForPostgres?: boolean - timeout?: number + help?: boolean; + nodeLogs?: boolean; + ethereumLogs?: boolean; + composeFile?: string; + nodeImage?: string; + standaloneNode?: string; + standaloneNodeArgs?: string; + skipWaitForIpfs?: boolean; + skipWaitForEthereum?: boolean; + skipWaitForPostgres?: boolean; + timeout?: number; } export default { - description: - 'Runs local tests against a Graph Node environment (using Ganache by default)', + description: 'Runs local tests against a Graph Node environment (using Ganache by default)', run: async (toolbox: GluegunToolbox) => { // Obtain tools - const { filesystem, print } = toolbox + const { filesystem, print } = toolbox; // Parse CLI parameters let { @@ -67,13 +65,13 @@ export default { standaloneNode, standaloneNodeArgs, timeout, - } = toolbox.parameters.options + } = toolbox.parameters.options; // Support both short and long option variants - help = help || h + help ||= h; // Extract test command - let params = fixParameters(toolbox.parameters, { + const params = fixParameters(toolbox.parameters, { ethereumLogs, h, help, @@ -81,59 +79,57 @@ export default { skipWaitForEthereum, skipWaitForIpfs, skipWaitForPostgres, - }) + }); // Show help text if requested if (help) { - print.info(HELP) - return + print.info(HELP); + return; } if (params.length == 0) { - print.error(`Test command not provided as the last argument`) - process.exitCode = 1 - return + print.error(`Test command not provided as the last argument`); + process.exitCode = 1; + return; } - let testCommand = params[0] + const testCommand = params[0]; // Obtain the Docker Compose file for services that the tests run against - composeFile = - composeFile || - path.join( - __dirname, - '..', - '..', - 'resources', - 'test', - standaloneNode ? 'docker-compose-standalone-node.yml' : 'docker-compose.yml', - ) + composeFile ||= path.join( + __dirname, + '..', + '..', + 'resources', + 'test', + standaloneNode ? 'docker-compose-standalone-node.yml' : 'docker-compose.yml', + ); // parse timeout. Defaults to 120 seconds - timeout = Math.abs(parseInt(timeout)) || 120000 + timeout = Math.abs(parseInt(timeout)) || 120_000; if (!filesystem.exists(composeFile)) { - print.error(`Docker Compose file \`${composeFile}\` not found`) - process.exitCode = 1 - return + print.error(`Docker Compose file \`${composeFile}\` not found`); + process.exitCode = 1; + return; } // Create temporary directory to operate in - let { path: tempdir } = await tmp.dir({ prefix: 'graph-test', unsafeCleanup: true }) + const { path: tempdir } = await tmp.dir({ prefix: 'graph-test', unsafeCleanup: true }); try { - await configureTestEnvironment(toolbox, tempdir, composeFile, nodeImage) + await configureTestEnvironment(toolbox, tempdir, composeFile, nodeImage); } catch (e) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Bring up test environment try { - await startTestEnvironment(tempdir) + await startTestEnvironment(tempdir); } catch (e) { - print.error(e) - process.exitCode = 1 - return + print.error(e); + process.exitCode = 1; + return; } // Wait for test environment to come up @@ -143,115 +139,106 @@ export default { skipWaitForIpfs, skipWaitForPostgres, timeout, - }) + }); } catch (e) { - await stopTestEnvironment(tempdir) - process.exitCode = 1 - return + await stopTestEnvironment(tempdir); + process.exitCode = 1; + return; } // Bring up Graph Node separately, if a standalone node is used - let nodeProcess - let nodeOutputChunks: Buffer[] = [] + let nodeProcess; + const nodeOutputChunks: Buffer[] = []; if (standaloneNode) { try { - nodeProcess = await startGraphNode( - standaloneNode, - standaloneNodeArgs, - nodeOutputChunks, - ) + nodeProcess = await startGraphNode(standaloneNode, standaloneNodeArgs, nodeOutputChunks); } catch (e) { - toolbox.print.error('') - toolbox.print.error(' Graph Node') - toolbox.print.error(' ----------') - toolbox.print.error( - indent(' ', Buffer.concat(nodeOutputChunks).toString('utf-8')), - ) - toolbox.print.error('') - await stopTestEnvironment(tempdir) - process.exitCode = 1 - return + toolbox.print.error(''); + toolbox.print.error(' Graph Node'); + toolbox.print.error(' ----------'); + toolbox.print.error(indent(' ', Buffer.concat(nodeOutputChunks).toString('utf-8'))); + toolbox.print.error(''); + await stopTestEnvironment(tempdir); + process.exitCode = 1; + return; } } // Wait for Graph Node to come up try { - await waitForGraphNode(timeout) + await waitForGraphNode(timeout); } catch (e) { - toolbox.print.error('') - toolbox.print.error(' Graph Node') - toolbox.print.error(' ----------') + toolbox.print.error(''); + toolbox.print.error(' Graph Node'); + toolbox.print.error(' ----------'); toolbox.print.error( - indent( - ' ', - await collectGraphNodeLogs(tempdir, standaloneNode, nodeOutputChunks), - ), - ) - toolbox.print.error('') - await stopTestEnvironment(tempdir) - process.exitCode = 1 - return + indent(' ', await collectGraphNodeLogs(tempdir, standaloneNode, nodeOutputChunks)), + ); + toolbox.print.error(''); + await stopTestEnvironment(tempdir); + process.exitCode = 1; + return; } // Run tests - let result = await runTests(testCommand) + const result = await runTests(testCommand); // Bring down Graph Node, if a standalone node is used if (nodeProcess) { try { - await stopGraphNode(nodeProcess) + await stopGraphNode(nodeProcess); } catch (e) { // do nothing (the spinner already logs the problem) } } if (result.exitCode == 0) { - toolbox.print.success('✔ Tests passed') + toolbox.print.success('✔ Tests passed'); } else { - toolbox.print.error('✖ Tests failed') + toolbox.print.error('✖ Tests failed'); } // Capture logs nodeLogs = nodeLogs || result.exitCode !== 0 ? await collectGraphNodeLogs(tempdir, standaloneNode, nodeOutputChunks) - : undefined - ethereumLogs = ethereumLogs ? await collectEthereumLogs(tempdir) : undefined + : undefined; + ethereumLogs = ethereumLogs ? await collectEthereumLogs(tempdir) : undefined; // Bring down the test environment try { - await stopTestEnvironment(tempdir) + await stopTestEnvironment(tempdir); } catch (e) { // do nothing (the spinner already logs the problem) } if (nodeLogs) { - toolbox.print.info('') - toolbox.print.info(' Graph node') - toolbox.print.info(' ----------') - toolbox.print.info('') - toolbox.print.info(indent(' ', nodeLogs)) + toolbox.print.info(''); + toolbox.print.info(' Graph node'); + toolbox.print.info(' ----------'); + toolbox.print.info(''); + toolbox.print.info(indent(' ', nodeLogs)); } if (ethereumLogs) { - toolbox.print.info('') - toolbox.print.info(' Ethereum') - toolbox.print.info(' --------') - toolbox.print.info('') - toolbox.print.info(indent(' ', ethereumLogs)) + toolbox.print.info(''); + toolbox.print.info(' Ethereum'); + toolbox.print.info(' --------'); + toolbox.print.info(''); + toolbox.print.info(indent(' ', ethereumLogs)); } // Always print the test output - toolbox.print.info('') - toolbox.print.info(' Output') - toolbox.print.info(' ------') - toolbox.print.info('') - toolbox.print.info(indent(' ', result.output)) + toolbox.print.info(''); + toolbox.print.info(' Output'); + toolbox.print.info(' ------'); + toolbox.print.info(''); + toolbox.print.info(indent(' ', result.output)); // Propagate the exit code from the test run - process.exitCode = result.exitCode + process.exitCode = result.exitCode; }, -} +}; /** * Indents all lines of a string @@ -262,7 +249,7 @@ const indent = (indentation: string, str: string) => .map(s => `${indentation}${s}`) // Remove whitespace from empty lines .map(s => s.replace(/^\s+$/g, '')) - .join('\n') + .join('\n'); const configureTestEnvironment = async ( toolbox: GluegunToolbox, @@ -276,10 +263,10 @@ const configureTestEnvironment = async ( `Warnings configuring test environment`, async () => { // Temporary compose file - let tempComposeFile = path.join(tempdir, 'compose', 'docker-compose.yml') + const tempComposeFile = path.join(tempdir, 'compose', 'docker-compose.yml'); // Copy the compose file to the temporary directory - toolbox.filesystem.copy(composeFile, tempComposeFile) + toolbox.filesystem.copy(composeFile, tempComposeFile); // Substitute the graph-node image with the custom one, if appropriate if (nodeImage) { @@ -287,32 +274,32 @@ const configureTestEnvironment = async ( tempComposeFile, 'graphprotocol/graph-node:latest', nodeImage, - ) + ); } }, - ) + ); const waitFor = async (timeout: number, testFn: () => void) => { - let deadline = Date.now() + timeout - let error: Error | undefined = undefined + const deadline = Date.now() + timeout; + let error: Error | undefined = undefined; return new Promise((resolve, reject) => { const check = async () => { if (Date.now() > deadline) { - reject(error) + reject(error); } else { try { - let result = await testFn() - resolve(result) + const result = await testFn(); + resolve(result); } catch (e) { - error = e - setTimeout(check, 500) + error = e; + setTimeout(check, 500); } } - } + }; - setTimeout(check, 0) - }) -} + setTimeout(check, 0); + }); +}; const startTestEnvironment = async (tempdir: string) => await withSpinner( @@ -323,9 +310,9 @@ const startTestEnvironment = async (tempdir: string) => // Bring up the test environment await compose.upAll({ cwd: path.join(tempdir, 'compose'), - }) + }); }, - ) + ); const waitForTestEnvironment = async ({ skipWaitForEthereum, @@ -333,10 +320,10 @@ const waitForTestEnvironment = async ({ skipWaitForPostgres, timeout, }: { - skipWaitForEthereum: boolean - skipWaitForIpfs: boolean - skipWaitForPostgres: boolean - timeout: number + skipWaitForEthereum: boolean; + skipWaitForIpfs: boolean; + skipWaitForPostgres: boolean; + timeout: number; }) => await withSpinner( `Wait for test environment`, @@ -345,7 +332,7 @@ const waitForTestEnvironment = async ({ async spinner => { // Wait 10s for IPFS (if desired) if (skipWaitForIpfs) { - step(spinner, 'Skip waiting for IPFS') + step(spinner, 'Skip waiting for IPFS'); } else { await waitFor( timeout, @@ -353,19 +340,19 @@ const waitForTestEnvironment = async ({ new Promise((resolve, reject) => { http .get('http://localhost:15001/api/v0/version', () => { - resolve() + resolve(); }) .on('error', e => { - reject(new Error(`Could not connect to IPFS: ${e}`)) - }) + reject(new Error(`Could not connect to IPFS: ${e}`)); + }); }), - ) - step(spinner, 'IPFS is up') + ); + step(spinner, 'IPFS is up'); } // Wait 10s for Ethereum (if desired) if (skipWaitForEthereum) { - step(spinner, 'Skip waiting for Ethereum') + step(spinner, 'Skip waiting for Ethereum'); } else { await waitFor( timeout, @@ -373,39 +360,37 @@ const waitForTestEnvironment = async ({ new Promise((resolve, reject) => { http .get('http://localhost:18545', () => { - resolve() + resolve(); }) .on('error', e => { - reject(new Error(`Could not connect to Ethereum: ${e}`)) - }) + reject(new Error(`Could not connect to Ethereum: ${e}`)); + }); }), - ) - step(spinner, 'Ethereum is up') + ); + step(spinner, 'Ethereum is up'); } // Wait 10s for Postgres (if desired) if (skipWaitForPostgres) { - step(spinner, 'Skip waiting for Postgres') + step(spinner, 'Skip waiting for Postgres'); } else { await waitFor( timeout, async () => new Promise((resolve, reject) => { try { - let socket = net.connect(15432, 'localhost', () => resolve()) - socket.on('error', e => - reject(new Error(`Could not connect to Postgres: ${e}`)), - ) - socket.end() + const socket = net.connect(15_432, 'localhost', () => resolve()); + socket.on('error', e => reject(new Error(`Could not connect to Postgres: ${e}`))); + socket.end(); } catch (e) { - reject(new Error(`Could not connect to Postgres: ${e}`)) + reject(new Error(`Could not connect to Postgres: ${e}`)); } }), - ) - step(spinner, 'Postgres is up') + ); + step(spinner, 'Postgres is up'); } }, - ) + ); const stopTestEnvironment = async (tempdir: string) => await withSpinner( @@ -416,14 +401,14 @@ const stopTestEnvironment = async (tempdir: string) => // Our containers do not respond quickly to the SIGTERM which `down` tries before timing out // and killing them, so speed things up by sending a SIGKILL right away. try { - await compose.kill({ cwd: path.join(tempdir, 'compose') }) + await compose.kill({ cwd: path.join(tempdir, 'compose') }); } catch (e) { // Do nothing, we will just try to run 'down' // to bring down the environment } - await compose.down({ cwd: path.join(tempdir, 'compose') }) + await compose.down({ cwd: path.join(tempdir, 'compose') }); }, - ) + ); const startGraphNode = async ( standaloneNode: string, @@ -435,7 +420,7 @@ const startGraphNode = async ( `Failed to start Graph node`, `Warnings starting Graph node`, async spinner => { - let defaultArgs = [ + const defaultArgs = [ '--ipfs', 'localhost:15001', '--postgres-url', @@ -452,33 +437,33 @@ const startGraphNode = async ( '18030', '--metrics-port', '18040', - ] + ]; - let defaultEnv = { + const defaultEnv = { GRAPH_LOG: 'debug', GRAPH_MAX_API_VERSION: '0.0.5', - } + }; - let args = standaloneNodeArgs ? standaloneNodeArgs.split(' ') : defaultArgs - let env = { ...defaultEnv, ...process.env } + const args = standaloneNodeArgs ? standaloneNodeArgs.split(' ') : defaultArgs; + const env = { ...defaultEnv, ...process.env }; - let nodeProcess = spawn(standaloneNode, args, { + const nodeProcess = spawn(standaloneNode, args, { cwd: process.cwd(), env, - }) + }); - step(spinner, 'Graph node:', `${nodeProcess.spawnargs.join(' ')}`) + step(spinner, 'Graph node:', String(nodeProcess.spawnargs.join(' '))); - nodeProcess.stdout.on('data', data => nodeOutputChunks.push(Buffer.from(data))) - nodeProcess.stderr.on('data', data => nodeOutputChunks.push(Buffer.from(data))) + nodeProcess.stdout.on('data', data => nodeOutputChunks.push(Buffer.from(data))); + nodeProcess.stderr.on('data', data => nodeOutputChunks.push(Buffer.from(data))); nodeProcess.on('error', e => { - nodeOutputChunks.push(Buffer.from(`${e}`, 'utf-8')) - }) + nodeOutputChunks.push(Buffer.from(String(e), 'utf-8')); + }); // Return the node child process - return nodeProcess + return nodeProcess; }, - ) + ); const waitForGraphNode = async (timeout: number) => await withSpinner( @@ -492,11 +477,11 @@ const waitForGraphNode = async (timeout: number) => new Promise((resolve, reject) => { http .get('http://localhost:18000', { timeout }, () => resolve()) - .on('error', e => reject(e)) + .on('error', e => reject(e)); }), - ) + ); }, - ) + ); const stopGraphNode = async (nodeProcess: ChildProcess) => await withSpinner( @@ -504,9 +489,9 @@ const stopGraphNode = async (nodeProcess: ChildProcess) => `Failed to stop Graph node`, `Warnings stopping Graph node`, async () => { - nodeProcess.kill(9) + nodeProcess.kill(9); }, - ) + ); const collectGraphNodeLogs = async ( tempdir: string, @@ -515,24 +500,23 @@ const collectGraphNodeLogs = async ( ) => { if (standaloneNode) { // Pull the logs from the captured output - return stripAnsi(Buffer.concat(nodeOutputChunks).toString('utf-8')) - } else { - // Pull the logs from docker compose - let logs = await compose.logs('graph-node', { - follow: false, - cwd: path.join(tempdir, 'compose'), - }) - return stripAnsi(logs.out.trim()).replace(/graph-node_1 \| /g, '') + return stripAnsi(Buffer.concat(nodeOutputChunks).toString('utf-8')); } -} + // Pull the logs from docker compose + const logs = await compose.logs('graph-node', { + follow: false, + cwd: path.join(tempdir, 'compose'), + }); + return stripAnsi(logs.out.trim()).replace(/graph-node_1 {2}\| /g, ''); +}; const collectEthereumLogs = async (tempdir: string) => { - let logs = await compose.logs('ethereum', { + const logs = await compose.logs('ethereum', { follow: false, cwd: path.join(tempdir, 'compose'), - }) - return stripAnsi(logs.out.trim()).replace(/ethereum_1 \| /g, '') -} + }); + return stripAnsi(logs.out.trim()).replace(/ethereum_1 {2}\| /g, ''); +}; const runTests = async (testCommand: string) => await withSpinner( @@ -541,15 +525,15 @@ const runTests = async (testCommand: string) => `Warnings running tests`, async () => new Promise(resolve => { - const output: Buffer[] = [] - let testProcess = spawn(`${testCommand}`, { shell: true }) - testProcess.stdout.on('data', data => output.push(Buffer.from(data))) - testProcess.stderr.on('data', data => output.push(Buffer.from(data))) + const output: Buffer[] = []; + const testProcess = spawn(String(testCommand), { shell: true }); + testProcess.stdout.on('data', data => output.push(Buffer.from(data))); + testProcess.stderr.on('data', data => output.push(Buffer.from(data))); testProcess.on('close', code => { resolve({ exitCode: code, output: Buffer.concat(output).toString('utf-8'), - }) - }) + }); + }); }), - ) + ); diff --git a/packages/cli/src/commands/remove.ts b/packages/cli/src/commands/remove.ts index c802f3cd..80055515 100644 --- a/packages/cli/src/commands/remove.ts +++ b/packages/cli/src/commands/remove.ts @@ -1,9 +1,9 @@ -import { URL } from 'url' -import chalk from 'chalk' -import { GluegunToolbox } from 'gluegun' -import { validateNodeUrl } from '../command-helpers/node' -import { identifyDeployKey as identifyAccessToken } from '../command-helpers/auth' -import { createJsonRpcClient } from '../command-helpers/jsonrpc' +import { URL } from 'url'; +import chalk from 'chalk'; +import { GluegunToolbox } from 'gluegun'; +import { identifyDeployKey as identifyAccessToken } from '../command-helpers/auth'; +import { createJsonRpcClient } from '../command-helpers/jsonrpc'; +import { validateNodeUrl } from '../command-helpers/node'; const HELP = ` ${chalk.bold('graph remove')} ${chalk.dim('[options]')} ${chalk.bold('')} @@ -13,99 +13,98 @@ ${chalk.dim('Options:')} --access-token Graph access token -h, --help Show usage information -g, --node Graph node to create the subgraph in -` +`; export interface RemoveOptions { - accessToken?: string - help?: boolean - node?: string + accessToken?: string; + help?: boolean; + node?: string; } export default { description: 'Unregisters a subgraph name', run: async (toolbox: GluegunToolbox) => { // Obtain tools - const { print } = toolbox + const { print } = toolbox; // Read CLI parameters - let { accessToken, g, h, help, node } = toolbox.parameters.options - let subgraphName = toolbox.parameters.first + let { accessToken, g, h, help, node } = toolbox.parameters.options; + const subgraphName = toolbox.parameters.first; // Support both long and short option variants - help = help || h - node = node || g + help ||= h; + node ||= g; // Show help text if requested if (help) { - print.info(HELP) - return + print.info(HELP); + return; } // Validate the subgraph name if (!subgraphName) { - print.error('No subgraph name provided') - print.info(HELP) - process.exitCode = 1 - return + print.error('No subgraph name provided'); + print.info(HELP); + process.exitCode = 1; + return; } // Validate node if (!node) { - print.error(`No Graph node provided`) - print.info(HELP) - process.exitCode = 1 - return + print.error(`No Graph node provided`); + print.info(HELP); + process.exitCode = 1; + return; } try { - validateNodeUrl(node) + validateNodeUrl(node); } catch (e) { - print.error(`Graph node "${node}" is invalid: ${e.message}`) - process.exitCode = 1 - return + print.error(`Graph node "${node}" is invalid: ${e.message}`); + process.exitCode = 1; + return; } - let requestUrl = new URL(node) - let client = createJsonRpcClient(requestUrl) + const requestUrl = new URL(node); + const client = createJsonRpcClient(requestUrl); // Exit with an error code if the client couldn't be created if (!client) { - process.exitCode = 1 - return + process.exitCode = 1; + return; } // Use the access token, if one is set - accessToken = await identifyAccessToken(node, accessToken) + accessToken = await identifyAccessToken(node, accessToken); if (accessToken !== undefined && accessToken !== null) { // @ts-expect-error options property seems to exist - client.options.headers = { Authorization: `Bearer ${accessToken}` } + client.options.headers = { Authorization: `Bearer ${accessToken}` }; } - let spinner = print.spin(`Creating subgraph in Graph node: ${requestUrl}`) + const spinner = print.spin(`Creating subgraph in Graph node: ${requestUrl}`); client.request( 'subgraph_remove', { name: subgraphName }, - function ( + ( // @ts-expect-error TODO: why are the arguments not typed? requestError, // @ts-expect-error TODO: why are the arguments not typed? jsonRpcError, - // TODO: why are the arguments not typed? // TODO: this argument is unused, but removing it from the commands/create.ts fails the basic-event-handlers tests. // I'll therefore leave it in here too until we figure out the weirdness - // @ts-expect-error - res, - ) { + // @ts-expect-error TODO: why are the arguments not typed? + _res, + ) => { if (jsonRpcError) { - spinner.fail(`Error removing the subgraph: ${jsonRpcError.message}`) - process.exitCode = 1 + spinner.fail(`Error removing the subgraph: ${jsonRpcError.message}`); + process.exitCode = 1; } else if (requestError) { - spinner.fail(`HTTP error removing the subgraph: ${requestError.code}`) - process.exitCode = 1 + spinner.fail(`HTTP error removing the subgraph: ${requestError.code}`); + process.exitCode = 1; } else { - spinner.stop() - print.success(`Removed subgraph: ${subgraphName}`) + spinner.stop(); + print.success(`Removed subgraph: ${subgraphName}`); } }, - ) + ); }, -} +}; diff --git a/packages/cli/src/commands/test.ts b/packages/cli/src/commands/test.ts index ca03966f..0048a753 100644 --- a/packages/cli/src/commands/test.ts +++ b/packages/cli/src/commands/test.ts @@ -1,13 +1,13 @@ -import { Binary } from 'binary-install-raw' -import os from 'os' -import chalk from 'chalk' -import fetch from 'node-fetch' -import { filesystem, GluegunToolbox, patching, print, system } from 'gluegun' -import { fixParameters } from '../command-helpers/gluegun' -import path from 'path' -import semver from 'semver' -import { spawn, exec } from 'child_process' -import yaml from 'js-yaml' +import { exec, spawn } from 'child_process'; +import os from 'os'; +import path from 'path'; +import { Binary } from 'binary-install-raw'; +import chalk from 'chalk'; +import { filesystem, GluegunToolbox, patching, print, system } from 'gluegun'; +import yaml from 'js-yaml'; +import fetch from 'node-fetch'; +import semver from 'semver'; +import { fixParameters } from '../command-helpers/gluegun'; const HELP = ` ${chalk.bold('graph test')} ${chalk.dim('[options]')} ${chalk.bold('')} @@ -20,42 +20,42 @@ ${chalk.dim('Options:')} -l, --logs Logs to the console information about the OS, CPU model and download url (debugging purposes) -r, --recompile Force-recompile tests -v, --version Choose the version of the rust binary that you want to be downloaded/used - ` + `; export interface TestOptions { - coverage?: boolean - docker?: boolean - force?: boolean - help?: boolean - logs?: boolean - recompile?: boolean - version?: string + coverage?: boolean; + docker?: boolean; + force?: boolean; + help?: boolean; + logs?: boolean; + recompile?: boolean; + version?: string; // not a cli arg - testsFolder: string - cachePath: string - latestVersion?: string + testsFolder: string; + cachePath: string; + latestVersion?: string; } export default { description: 'Runs rust binary for subgraph testing', run: async (toolbox: GluegunToolbox) => { // Read CLI parameters - let { c, coverage, d, docker, f, force, h, help, l, logs, r, recompile, v, version } = - toolbox.parameters.options + const { c, coverage, d, docker, f, force, h, help, l, logs, r, recompile, v, version } = + toolbox.parameters.options; - const testsFolder = './tests' - let opts: TestOptions = { + const testsFolder = './tests'; + const opts: TestOptions = { testsFolder, cachePath: path.join(testsFolder, '.latest.json'), - } + }; // Support both long and short option variants - opts.coverage = coverage || c - opts.docker = docker || d - opts.force = force || f - opts.help = help || h - opts.logs = logs || l - opts.recompile = recompile || r - opts.version = version || v + opts.coverage = coverage || c; + opts.docker = docker || d; + opts.force = force || f; + opts.help = help || h; + opts.logs = logs || l; + opts.recompile = recompile || r; + opts.version = version || v; // Fix if a boolean flag (e.g -c, --coverage) has an argument try { fixParameters(toolbox.parameters, { @@ -71,116 +71,116 @@ export default { logs, r, recompile, - }) + }); } catch (e) { - print.error(e.message) - process.exitCode = 1 - return + print.error(e.message); + process.exitCode = 1; + return; } - let datasource = toolbox.parameters.first || toolbox.parameters.array?.[0] + const datasource = toolbox.parameters.first || toolbox.parameters.array?.[0]; // Show help text if requested if (opts.help) { - print.info(HELP) - return + print.info(HELP); + return; } // Check if matchstick.yaml config exists if (filesystem.exists('matchstick.yaml')) { try { // Load the config - let config = await yaml.load(filesystem.read('matchstick.yaml', 'utf8')!) + const config = await yaml.load(filesystem.read('matchstick.yaml', 'utf8')!); // Check if matchstick.yaml and testsFolder not null - if (config && config.testsFolder) { + if (config?.testsFolder) { // assign test folder from matchstick.yaml if present - opts.testsFolder = config.testsFolder + opts.testsFolder = config.testsFolder; } } catch (error) { print.info( 'A problem occurred while reading matchstick.yaml. Please attend to the errors below:', - ) - print.error(error.message) - process.exit(1) + ); + print.error(error.message); + process.exit(1); } } - setVersionFromCache(opts) + setVersionFromCache(opts); // Fetch the latest version tag if version is not specified with -v/--version or if the version is not cached if (opts.force || (!opts.version && !opts.latestVersion)) { - print.info('Fetching latest version tag') - let result = await fetch( + print.info('Fetching latest version tag'); + const result = await fetch( 'https://api.github.com/repos/LimeChain/matchstick/releases/latest', - ) - let json = await result.json() - opts.latestVersion = json.tag_name + ); + const json = await result.json(); + opts.latestVersion = json.tag_name; filesystem.file(opts.cachePath, { content: { version: json.tag_name, timestamp: Date.now(), }, - }) + }); } if (opts.docker) { - runDocker(datasource, opts) + runDocker(datasource, opts); } else { - runBinary(datasource, opts) + runBinary(datasource, opts); } }, -} +}; async function setVersionFromCache(opts: TestOptions) { if (filesystem.exists(opts.cachePath) == 'file') { - let cached = filesystem.read(opts.cachePath, 'json') + const cached = filesystem.read(opts.cachePath, 'json'); // Get the cache age in days - let cacheAge = (Date.now() - cached.timestamp) / (1000 * 60 * 60 * 24) + const cacheAge = (Date.now() - cached.timestamp) / (1000 * 60 * 60 * 24); // If cache age is less than 1 day, use the cached version if (cacheAge < 1) { - opts.latestVersion = cached.version + opts.latestVersion = cached.version; } } } async function runBinary(datasource: string | undefined, opts: TestOptions) { - let coverageOpt = opts.coverage - let forceOpt = opts.force - let logsOpt = opts.logs - let versionOpt = opts.version - let latestVersion = opts.latestVersion - let recompileOpt = opts.recompile + const coverageOpt = opts.coverage; + const forceOpt = opts.force; + const logsOpt = opts.logs; + const versionOpt = opts.version; + const latestVersion = opts.latestVersion; + const recompileOpt = opts.recompile; - const platform = await getPlatform(logsOpt) + const platform = await getPlatform(logsOpt); const url = `https://github.com/LimeChain/matchstick/releases/download/${ versionOpt || latestVersion - }/${platform}` + }/${platform}`; if (logsOpt) { - print.info(`Download link: ${url}`) + print.info(`Download link: ${url}`); } - let binary = new Binary(platform, url, versionOpt || latestVersion) - forceOpt ? await binary.install(true) : await binary.install(false) - let args = new Array() + const binary = new Binary(platform, url, versionOpt || latestVersion); + forceOpt ? await binary.install(true) : await binary.install(false); + const args = []; - if (coverageOpt) args.push('-c') - if (recompileOpt) args.push('-r') - if (datasource) args.push(datasource) - args.length > 0 ? binary.run(...args) : binary.run() + if (coverageOpt) args.push('-c'); + if (recompileOpt) args.push('-r'); + if (datasource) args.push(datasource); + args.length > 0 ? binary.run(...args) : binary.run(); } async function getPlatform(logsOpt: boolean | undefined) { - const type = os.type() - const arch = os.arch() - const cpuCore = os.cpus()[0] - const isAppleSilicon = arch === 'arm64' && /Apple (M1|M2|processor)/.test(cpuCore.model) - const linuxInfo = type === 'Linux' ? await getLinuxInfo() : {} - const linuxDistro = linuxInfo.name - const release = linuxInfo.version || os.release() - const majorVersion = parseInt(linuxInfo.version || '', 10) || semver.major(release) + const type = os.type(); + const arch = os.arch(); + const cpuCore = os.cpus()[0]; + const isAppleSilicon = arch === 'arm64' && /Apple (M1|M2|processor)/.test(cpuCore.model); + const linuxInfo = type === 'Linux' ? await getLinuxInfo() : {}; + const linuxDistro = linuxInfo.name; + const release = linuxInfo.version || os.release(); + const majorVersion = parseInt(linuxInfo.version || '', 10) || semver.major(release); if (logsOpt) { print.info( @@ -189,30 +189,31 @@ async function getPlatform(logsOpt: boolean | undefined) { }\nOS arch: ${arch}\nOS release: ${release}\nOS major version: ${majorVersion}\nCPU model: ${ cpuCore.model }`, - ) + ); } if (arch === 'x64' || isAppleSilicon) { if (type === 'Darwin') { if (majorVersion === 18 || majorVersion === 19) { - return 'binary-macos-10.15' // GitHub dropped support for macOS 10.14 in Actions, but it seems 10.15 binary works on 10.14 too - } else if (isAppleSilicon) { - return 'binary-macos-11-m1' + return 'binary-macos-10.15'; // GitHub dropped support for macOS 10.14 in Actions, but it seems 10.15 binary works on 10.14 too } - return 'binary-macos-11' - } else if (type === 'Linux') { + if (isAppleSilicon) { + return 'binary-macos-11-m1'; + } + return 'binary-macos-11'; + } + if (type === 'Linux') { if (majorVersion === 18) { - return 'binary-linux-18' + return 'binary-linux-18'; } if (majorVersion === 22) { - return 'binary-linux-22' - } else { - return 'binary-linux-20' + return 'binary-linux-22'; } + return 'binary-linux-20'; } } - throw new Error(`Unsupported platform: ${type} ${arch} ${majorVersion}`) + throw new Error(`Unsupported platform: ${type} ${arch} ${majorVersion}`); } /** @@ -225,81 +226,81 @@ async function getPlatform(logsOpt: boolean | undefined) { * ``` */ interface LinuxInfo { - name?: string - version?: string + name?: string; + version?: string; } async function getLinuxInfo(): Promise { try { - let result = await system.run("cat /etc/*-release | grep -E '(^VERSION|^NAME)='", { + const result = await system.run("cat /etc/*-release | grep -E '(^VERSION|^NAME)='", { trim: true, - }) - let infoArray = result + }); + const infoArray = result .replace(/['"]+/g, '') .split('\n') - .map(p => p.split('=')) - let linuxInfo: LinuxInfo = {} + .map(p => p.split('=')); + const linuxInfo: LinuxInfo = {}; infoArray.forEach(val => { - linuxInfo[val[0].toLowerCase() as keyof LinuxInfo] = val[1] - }) + linuxInfo[val[0].toLowerCase() as keyof LinuxInfo] = val[1]; + }); - return linuxInfo + return linuxInfo; } catch (error) { - print.error(`Error fetching the Linux version:\n ${error}`) - process.exit(1) + print.error(`Error fetching the Linux version:\n ${error}`); + process.exit(1); } } async function runDocker(datasource: string | undefined, opts: TestOptions) { - let coverageOpt = opts.coverage - let forceOpt = opts.force - let versionOpt = opts.version - let latestVersion = opts.latestVersion - let recompileOpt = opts.recompile + const coverageOpt = opts.coverage; + const forceOpt = opts.force; + const versionOpt = opts.version; + const latestVersion = opts.latestVersion; + const recompileOpt = opts.recompile; // Remove binary-install-raw binaries, because docker has permission issues // when building the docker images - filesystem.remove('./node_modules/binary-install-raw/bin') + filesystem.remove('./node_modules/binary-install-raw/bin'); // Get current working directory - let current_folder = filesystem.cwd() + const current_folder = filesystem.cwd(); // Declate dockerfilePath with default location - let dockerfilePath = path.join(opts.testsFolder || 'tests', '.docker/Dockerfile') + const dockerfilePath = path.join(opts.testsFolder || 'tests', '.docker/Dockerfile'); // Check if the Dockerfil already exists - let dockerfileExists = filesystem.exists(dockerfilePath) + const dockerfileExists = filesystem.exists(dockerfilePath); // Generate the Dockerfile only if it doesn't exists, // version flag and/or force flag is passed. if (!dockerfileExists || versionOpt || forceOpt) { - await dockerfile(dockerfilePath, versionOpt, latestVersion) + await dockerfile(dockerfilePath, versionOpt, latestVersion); } // Run a command to check if matchstick image already exists exec('docker images -q matchstick', (_error, stdout, _stderr) => { // Collect all(if any) flags and options that have to be passed to the matchstick binary - let testArgs = '' - if (coverageOpt) testArgs = testArgs + ' -c' - if (recompileOpt) testArgs = testArgs + ' -r' - if (datasource) testArgs = testArgs + ' ' + datasource + let testArgs = ''; + if (coverageOpt) testArgs = testArgs + ' -c'; + if (recompileOpt) testArgs = testArgs + ' -r'; + if (datasource) testArgs = testArgs + ' ' + datasource; // Build the `docker run` command options and flags - let dockerRunOpts = [ + const dockerRunOpts = [ 'run', '-it', '--rm', '--mount', `type=bind,source=${current_folder},target=/matchstick`, - ] + ]; if (testArgs !== '') { - dockerRunOpts.push('-e') - dockerRunOpts.push(`ARGS=${testArgs.trim()}`) + dockerRunOpts.push('-e'); + dockerRunOpts.push(`ARGS=${testArgs.trim()}`); } - dockerRunOpts.push('matchstick') + dockerRunOpts.push('matchstick'); // If a matchstick image does not exists, the command returns an empty string, // else it'll return the image ID. Skip `docker build` if an image already exists @@ -308,8 +309,8 @@ async function runDocker(datasource: string | undefined, opts: TestOptions) { if (!dockerfileExists || stdout === '' || versionOpt || forceOpt) { if (stdout !== '') { exec('docker image rm matchstick', (_error, stdout, _stderr) => { - print.info(chalk.bold(`Removing matchstick image\n${stdout}`)) - }) + print.info(chalk.bold(`Removing matchstick image\n${stdout}`)); + }); } // Build a docker image. If the process has executed successfully // run a container from that image. @@ -317,15 +318,15 @@ async function runDocker(datasource: string | undefined, opts: TestOptions) { stdio: 'inherit', }).on('close', code => { if (code === 0) { - spawn('docker', dockerRunOpts, { stdio: 'inherit' }) + spawn('docker', dockerRunOpts, { stdio: 'inherit' }); } - }) + }); } else { - print.info('Docker image already exists. Skipping `docker build` command.') + print.info('Docker image already exists. Skipping `docker build` command.'); // Run the container from the existing matchstick docker image - spawn('docker', dockerRunOpts, { stdio: 'inherit' }) + spawn('docker', dockerRunOpts, { stdio: 'inherit' }); } - }) + }); } // Downloads Dockerfile template from the demo-subgraph repo @@ -335,37 +336,34 @@ async function dockerfile( versionOpt: string | undefined, latestVersion: string | undefined, ) { - let spinner = print.spin('Generating Dockerfile...') + const spinner = print.spin('Generating Dockerfile...'); try { // Fetch the Dockerfile template content from the demo-subgraph repo - let content = await fetch( + const content = await fetch( 'https://raw.githubusercontent.com/LimeChain/demo-subgraph/main/Dockerfile', ).then(response => { if (response.ok) { - return response.text() - } else { - throw new Error( - `Status Code: ${response.status}, with error: ${response.statusText}`, - ) + return response.text(); } - }) + throw new Error(`Status Code: ${response.status}, with error: ${response.statusText}`); + }); // Write the Dockerfile - filesystem.write(dockerfilePath, content) + filesystem.write(dockerfilePath, content); // Replaces the version placeholders await patching.replace( dockerfilePath, '', versionOpt || latestVersion || 'unknown', - ) + ); } catch (error) { spinner.fail( `A problem occurred while generating the Dockerfile. Please attend to the errors below:\n ${error.message}`, - ) - process.exit(1) + ); + process.exit(1); } - spinner.succeed('Successfully generated Dockerfile.') + spinner.succeed('Successfully generated Dockerfile.'); } diff --git a/packages/cli/src/compiler/asc.ts b/packages/cli/src/compiler/asc.ts index f4fc7758..a33ccaa4 100644 --- a/packages/cli/src/compiler/asc.ts +++ b/packages/cli/src/compiler/asc.ts @@ -1,63 +1,57 @@ -import * as asc from 'assemblyscript/cli/asc' +import * as asc from 'assemblyscript/cli/asc'; const createExitHandler = (inputFile: string) => () => { throw new Error(`The AssemblyScript compiler crashed when compiling this file: '${inputFile}' Suggestion: try to comment the whole file and uncomment it little by little while re-running the graph-cli until you isolate the line where the problem happens. Also, please contact us so we can make the CLI better by handling errors like this. You can reach out in any of these links: - Discord channel: https://discord.gg/eM8CA6WA9r -- Github issues: https://github.com/graphprotocol/graph-cli/issues`) -} +- Github issues: https://github.com/graphprotocol/graph-cli/issues`); +}; const setupExitHandler = (exitHandler: (code: number) => void) => - process.addListener('exit', exitHandler) + process.addListener('exit', exitHandler); const removeExitHandler = (exitHandler: (code: number) => void) => - process.removeListener('exit', exitHandler) + process.removeListener('exit', exitHandler); // Important note, the `asc.main` callback function parameter is synchronous, // that's why this function doesn't need to be `async` and the throw works properly. const assemblyScriptCompiler = (argv: string[], options: asc.APIOptions) => asc.main(argv, options, err => { if (err) { - throw err + throw err; } - return 0 - }) + return 0; + }); const compilerDefaults = { stdout: process.stdout, stderr: process.stdout, -} +}; // You MUST call this function once before compiling anything. // Internally it just delegates to the AssemblyScript compiler // which just delegates to the binaryen lib. export const ready = async () => { - await asc.ready -} + await asc.ready; +}; export interface CompileOptions { - inputFile: string - global: string - baseDir: string - libs: string - outputFile: string + inputFile: string; + global: string; + baseDir: string; + libs: string; + outputFile: string; } // For now this function doesn't check if `asc` is ready, because // it requires an asynchronous wait. Whenever you call this function, // it doesn't matter how many times, just make sure you call `ready` // once before everything.. -export const compile = ({ - inputFile, - global, - baseDir, - libs, - outputFile, -}: CompileOptions) => { - const exitHandler = createExitHandler(inputFile) +export const compile = ({ inputFile, global, baseDir, libs, outputFile }: CompileOptions) => { + const exitHandler = createExitHandler(inputFile); - setupExitHandler(exitHandler) + setupExitHandler(exitHandler); const compilerArgs = [ '--explicitStart', @@ -74,10 +68,10 @@ export const compile = ({ outputFile, '--optimize', '--debug', - ] + ]; - assemblyScriptCompiler(compilerArgs, compilerDefaults) + assemblyScriptCompiler(compilerArgs, compilerDefaults); // only if compiler succeded, that is, when the line above doesn't throw - removeExitHandler(exitHandler) -} + removeExitHandler(exitHandler); +}; diff --git a/packages/cli/src/compiler/index.ts b/packages/cli/src/compiler/index.ts index ae62dee3..4629dd03 100644 --- a/packages/cli/src/compiler/index.ts +++ b/packages/cli/src/compiler/index.ts @@ -1,45 +1,45 @@ -import chalk from 'chalk' -import crypto from 'crypto' -import fs from 'fs-extra' -import immutable from 'immutable' -import path from 'path' -import yaml from 'js-yaml' -import * as toolbox from 'gluegun' -import { Spinner, step, withSpinner } from '../command-helpers/spinner' -import Subgraph from '../subgraph' -import Watcher from '../watcher' -import { applyMigrations } from '../migrations' -import * as asc from './asc' -import debug from '../debug' -import Protocol from '../protocols' - -let compilerDebug = debug('graph-cli:compiler') +import crypto from 'crypto'; +import path from 'path'; +import chalk from 'chalk'; +import fs from 'fs-extra'; +import * as toolbox from 'gluegun'; +import immutable from 'immutable'; +import yaml from 'js-yaml'; +import { Spinner, step, withSpinner } from '../command-helpers/spinner'; +import debug from '../debug'; +import { applyMigrations } from '../migrations'; +import Protocol from '../protocols'; +import Subgraph from '../subgraph'; +import Watcher from '../watcher'; +import * as asc from './asc'; + +const compilerDebug = debug('graph-cli:compiler'); interface CompilerOptions { - ipfs: any - subgraphManifest: string - outputDir: string - outputFormat: string - skipMigrations: boolean - blockIpfsMethods?: boolean - protocol: Protocol + ipfs: any; + subgraphManifest: string; + outputDir: string; + outputFormat: string; + skipMigrations: boolean; + blockIpfsMethods?: boolean; + protocol: Protocol; } export default class Compiler { - private ipfs: any - private sourceDir: string - private blockIpfsMethods?: boolean - private libsDirs: string[] - private globalsFile: string - private protocol: Protocol - private ABI: any + private ipfs: any; + private sourceDir: string; + private blockIpfsMethods?: boolean; + private libsDirs: string[]; + private globalsFile: string; + private protocol: Protocol; + private ABI: any; constructor(private options: CompilerOptions) { - this.options = options - this.ipfs = options.ipfs - this.sourceDir = path.dirname(options.subgraphManifest) - this.blockIpfsMethods = options.blockIpfsMethods - this.libsDirs = [] + this.options = options; + this.ipfs = options.ipfs; + this.sourceDir = path.dirname(options.subgraphManifest); + this.blockIpfsMethods = options.blockIpfsMethods; + this.libsDirs = []; if (options.protocol.name !== 'substreams') { for ( @@ -50,55 +50,53 @@ export default class Compiler { dir = path.dirname(dir) === dir ? undefined : path.dirname(dir) ) { if (fs.existsSync(path.join(dir, 'node_modules'))) { - this.libsDirs.push(path.join(dir, 'node_modules')) + this.libsDirs.push(path.join(dir, 'node_modules')); } } if (this.libsDirs.length === 0) { - throw Error( - `could not locate \`node_modules\` in parent directories of subgraph manifest`, - ) + throw Error(`could not locate \`node_modules\` in parent directories of subgraph manifest`); } - const globalsFile = path.join('@graphprotocol', 'graph-ts', 'global', 'global.ts') + const globalsFile = path.join('@graphprotocol', 'graph-ts', 'global', 'global.ts'); const globalsLib = this.libsDirs.find(item => { - return fs.existsSync(path.join(item, globalsFile)) - }) + return fs.existsSync(path.join(item, globalsFile)); + }); if (!globalsLib) { throw Error( 'Could not locate `@graphprotocol/graph-ts` package in parent directories of subgraph manifest.', - ) + ); } - this.globalsFile = path.join(globalsLib, globalsFile) + this.globalsFile = path.join(globalsLib, globalsFile); } // @ts-expect-error assigned or not, we dont care if (!this.globalsFile) { - throw new Error('Globals file is missing.') + throw new Error('Globals file is missing.'); } - this.protocol = this.options.protocol - this.ABI = this.protocol.getABI() + this.protocol = this.options.protocol; + this.ABI = this.protocol.getABI(); - process.on('uncaughtException', function (e) { - toolbox.print.error(`UNCAUGHT EXCEPTION: ${e}`) - }) + process.on('uncaughtException', e => { + toolbox.print.error(`UNCAUGHT EXCEPTION: ${e}`); + }); } subgraphDir(parent: string, subgraph: immutable.Map) { - return path.join(parent, subgraph.get('name')) + return path.join(parent, subgraph.get('name')); } displayPath(p: string) { - return path.relative(process.cwd(), p) + return path.relative(process.cwd(), p); } cacheKeyForFile(filename: string) { - let hash = crypto.createHash('sha1') - hash.update(fs.readFileSync(filename)) - return hash.digest('hex') + const hash = crypto.createHash('sha1'); + hash.update(fs.readFileSync(filename)); + return hash.digest('hex'); } async compile() { @@ -107,115 +105,112 @@ export default class Compiler { await applyMigrations({ sourceDir: this.sourceDir, manifestFile: this.options.subgraphManifest, - }) + }); } - let subgraph = await this.loadSubgraph() - let compiledSubgraph = await this.compileSubgraph(subgraph) - let localSubgraph = await this.writeSubgraphToOutputDirectory( + const subgraph = await this.loadSubgraph(); + const compiledSubgraph = await this.compileSubgraph(subgraph); + const localSubgraph = await this.writeSubgraphToOutputDirectory( this.options.protocol, compiledSubgraph, - ) + ); if (this.ipfs !== undefined) { - let ipfsHash = await this.uploadSubgraphToIPFS(localSubgraph) - this.completed(ipfsHash) - return ipfsHash - } else { - this.completed(path.join(this.options.outputDir, 'subgraph.yaml')) - return true + const ipfsHash = await this.uploadSubgraphToIPFS(localSubgraph); + this.completed(ipfsHash); + return ipfsHash; } + this.completed(path.join(this.options.outputDir, 'subgraph.yaml')); + return true; } catch (e) { - toolbox.print.error(e) - return false + toolbox.print.error(e); + return false; } } completed(ipfsHashOrPath: string) { - toolbox.print.info('') - toolbox.print.success(`Build completed: ${chalk.blue(ipfsHashOrPath)}`) - toolbox.print.info('') + toolbox.print.info(''); + toolbox.print.success(`Build completed: ${chalk.blue(ipfsHashOrPath)}`); + toolbox.print.info(''); } async loadSubgraph({ quiet } = { quiet: false }) { - const subgraphLoadOptions = { protocol: this.protocol, skipValidation: false } + const subgraphLoadOptions = { protocol: this.protocol, skipValidation: false }; if (quiet) { - return (await Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions)) - .result - } else { - const manifestPath = this.displayPath(this.options.subgraphManifest) - - return await withSpinner( - `Load subgraph from ${manifestPath}`, - `Failed to load subgraph from ${manifestPath}`, - `Warnings loading subgraph from ${manifestPath}`, - async () => { - return Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions) - }, - ) + return (await Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions)).result; } + const manifestPath = this.displayPath(this.options.subgraphManifest); + + return await withSpinner( + `Load subgraph from ${manifestPath}`, + `Failed to load subgraph from ${manifestPath}`, + `Warnings loading subgraph from ${manifestPath}`, + async () => { + return Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions); + }, + ); } async getFilesToWatch() { try { - let files = [] - let subgraph = await this.loadSubgraph({ quiet: true }) + const files = []; + const subgraph = await this.loadSubgraph({ quiet: true }); // Add the subgraph manifest file - files.push(this.options.subgraphManifest) + files.push(this.options.subgraphManifest); // Add all file paths specified in manifest - files.push(path.resolve(subgraph.getIn(['schema', 'file']))) + files.push(path.resolve(subgraph.getIn(['schema', 'file']))); subgraph.get('dataSources').map((dataSource: any) => { - files.push(dataSource.getIn(['mapping', 'file'])) + files.push(dataSource.getIn(['mapping', 'file'])); // Only watch ABI related files if the target protocol has support/need for them. if (this.protocol.hasABIs()) { dataSource.getIn(['mapping', 'abis']).map((abi: any) => { - files.push(abi.get('file')) - }) + files.push(abi.get('file')); + }); } - }) + }); // Make paths absolute - return files.map(file => path.resolve(file)) + return files.map(file => path.resolve(file)); } catch (e) { - throw Error(`Failed to load subgraph: ${e.message}`) + throw Error(`Failed to load subgraph: ${e.message}`); } } async watchAndCompile(onCompiled?: (ipfsHash: string) => void) { - let compiler = this - let spinner: Spinner + const compiler = this; + let spinner: Spinner; // Create watcher and recompile once and then on every change to a watched file - let watcher = new Watcher({ + const watcher = new Watcher({ onReady: () => (spinner = toolbox.print.spin('Watching subgraph files')), onTrigger: async changedFile => { if (changedFile !== undefined) { - spinner.info(`File change detected: ${this.displayPath(changedFile)}\n`) + spinner.info(`File change detected: ${this.displayPath(changedFile)}\n`); } - let ipfsHash = await compiler.compile() - onCompiled?.(ipfsHash) - spinner.start() + const ipfsHash = await compiler.compile(); + onCompiled?.(ipfsHash); + spinner.start(); }, onCollectFiles: async () => await compiler.getFilesToWatch(), onError: error => { - spinner.stop() - toolbox.print.error(`${error.message}\n`) - spinner.start() + spinner.stop(); + toolbox.print.error(`${error.message}\n`); + spinner.start(); }, - }) + }); // Catch keyboard interrupt: close watcher and exit process process.on('SIGINT', () => { - watcher.close() - process.exit() - }) + watcher.close(); + process.exit(); + }); try { - await watcher.watch() + await watcher.watch(); } catch (e) { - toolbox.print.error(`${e.message}`) + toolbox.print.error(String(e.message)); } } @@ -226,13 +221,13 @@ export default class Compiler { targetDir: string, spinner: Spinner, ) { - let absoluteSourceFile = path.resolve(sourceDir, maybeRelativeFile) - let relativeSourceFile = path.relative(sourceDir, absoluteSourceFile) - let targetFile = path.join(targetDir, relativeSourceFile) - step(spinner, 'Write subgraph file', this.displayPath(targetFile)) - fs.mkdirsSync(path.dirname(targetFile)) - fs.writeFileSync(targetFile, data) - return targetFile + const absoluteSourceFile = path.resolve(sourceDir, maybeRelativeFile); + const relativeSourceFile = path.relative(sourceDir, absoluteSourceFile); + const targetFile = path.join(targetDir, relativeSourceFile); + step(spinner, 'Write subgraph file', this.displayPath(targetFile)); + fs.mkdirsSync(path.dirname(targetFile)); + fs.writeFileSync(targetFile, data); + return targetFile; } async compileSubgraph(subgraph: any) { @@ -242,9 +237,9 @@ export default class Compiler { `Warnings while compiling subgraph`, async spinner => { // Cache compiled files so identical input files are only compiled once - let compiledFiles = new Map() + const compiledFiles = new Map(); - await asc.ready() + await asc.ready(); subgraph = subgraph.update('dataSources', (dataSources: any[]) => dataSources.map((dataSource: any) => @@ -258,26 +253,21 @@ export default class Compiler { ), ), ), - ) + ); subgraph = subgraph.update('templates', (templates: any) => templates === undefined ? templates : templates.map((template: any) => template.updateIn(['mapping', 'file'], (mappingPath: string) => - this._compileTemplateMapping( - template, - mappingPath, - compiledFiles, - spinner, - ), + this._compileTemplateMapping(template, mappingPath, compiledFiles, spinner), ), ), - ) + ); - return subgraph + return subgraph; }, - ) + ); } _compileDataSourceMapping( @@ -288,55 +278,45 @@ export default class Compiler { spinner: Spinner, ) { if (protocol.name == 'substreams') { - return + return; } try { - let dataSourceName = dataSource.getIn(['name']) + const dataSourceName = dataSource.getIn(['name']); - let baseDir = this.sourceDir - let absoluteMappingPath = path.resolve(baseDir, mappingPath) - let inputFile = path.relative(baseDir, absoluteMappingPath) - this._validateMappingContent(absoluteMappingPath) + const baseDir = this.sourceDir; + const absoluteMappingPath = path.resolve(baseDir, mappingPath); + const inputFile = path.relative(baseDir, absoluteMappingPath); + this._validateMappingContent(absoluteMappingPath); // If the file has already been compiled elsewhere, just use that output // file and return early - let inputCacheKey = this.cacheKeyForFile(absoluteMappingPath) - let alreadyCompiled = compiledFiles.has(inputCacheKey) + const inputCacheKey = this.cacheKeyForFile(absoluteMappingPath); + const alreadyCompiled = compiledFiles.has(inputCacheKey); if (alreadyCompiled) { - let outFile = compiledFiles.get(inputCacheKey) + const outFile = compiledFiles.get(inputCacheKey); step( spinner, 'Compile data source:', `${dataSourceName} => ${this.displayPath(outFile)} (already compiled)`, - ) - return outFile + ); + return outFile; } - let outFile = path.resolve( + const outFile = path.resolve( this.subgraphDir(this.options.outputDir, dataSource), - this.options.outputFormat == 'wasm' - ? `${dataSourceName}.wasm` - : `${dataSourceName}.wast`, - ) + this.options.outputFormat == 'wasm' ? `${dataSourceName}.wasm` : `${dataSourceName}.wast`, + ); - step( - spinner, - 'Compile data source:', - `${dataSourceName} => ${this.displayPath(outFile)}`, - ) + step(spinner, 'Compile data source:', `${dataSourceName} => ${this.displayPath(outFile)}`); - let outputFile = path.relative(baseDir, outFile) + const outputFile = path.relative(baseDir, outFile); // Create output directory - try { - fs.mkdirsSync(path.dirname(outFile)) - } catch (e) { - throw e - } + fs.mkdirsSync(path.dirname(outFile)); - let libs = this.libsDirs.join(',') - let global = path.relative(baseDir, this.globalsFile) + const libs = this.libsDirs.join(','); + const global = path.relative(baseDir, this.globalsFile); asc.compile({ inputFile, @@ -344,14 +324,14 @@ export default class Compiler { baseDir, libs, outputFile, - }) + }); // Remember the output file to avoid compiling the same file again - compiledFiles.set(inputCacheKey, outFile) + compiledFiles.set(inputCacheKey, outFile); - return outFile + return outFile; } catch (e) { - throw Error(`Failed to compile data source mapping: ${e.message}`) + throw Error(`Failed to compile data source mapping: ${e.message}`); } } @@ -362,53 +342,47 @@ export default class Compiler { spinner: Spinner, ) { try { - let templateName = template.get('name') + const templateName = template.get('name'); - let baseDir = this.sourceDir - let absoluteMappingPath = path.resolve(baseDir, mappingPath) - let inputFile = path.relative(baseDir, absoluteMappingPath) - this._validateMappingContent(absoluteMappingPath) + const baseDir = this.sourceDir; + const absoluteMappingPath = path.resolve(baseDir, mappingPath); + const inputFile = path.relative(baseDir, absoluteMappingPath); + this._validateMappingContent(absoluteMappingPath); // If the file has already been compiled elsewhere, just use that output // file and return early - let inputCacheKey = this.cacheKeyForFile(absoluteMappingPath) - let alreadyCompiled = compiledFiles.has(inputCacheKey) + const inputCacheKey = this.cacheKeyForFile(absoluteMappingPath); + const alreadyCompiled = compiledFiles.has(inputCacheKey); if (alreadyCompiled) { - let outFile = compiledFiles.get(inputCacheKey) + const outFile = compiledFiles.get(inputCacheKey); step( spinner, 'Compile data source template:', `${templateName} => ${this.displayPath(outFile)} (already compiled)`, - ) - return outFile + ); + return outFile; } - let outFile = path.resolve( + const outFile = path.resolve( this.options.outputDir, 'templates', templateName, - this.options.outputFormat == 'wasm' - ? `${templateName}.wasm` - : `${templateName}.wast`, - ) + this.options.outputFormat == 'wasm' ? `${templateName}.wasm` : `${templateName}.wast`, + ); step( spinner, 'Compile data source template:', `${templateName} => ${this.displayPath(outFile)}`, - ) + ); - let outputFile = path.relative(baseDir, outFile) + const outputFile = path.relative(baseDir, outFile); // Create output directory - try { - fs.mkdirsSync(path.dirname(outFile)) - } catch (e) { - throw e - } + fs.mkdirsSync(path.dirname(outFile)); - let libs = this.libsDirs.join(',') - let global = path.relative(baseDir, this.globalsFile) + const libs = this.libsDirs.join(','); + const global = path.relative(baseDir, this.globalsFile); asc.compile({ inputFile, @@ -416,38 +390,30 @@ export default class Compiler { baseDir, libs, outputFile, - }) + }); // Remember the output file to avoid compiling the same file again - compiledFiles.set(inputCacheKey, outFile) + compiledFiles.set(inputCacheKey, outFile); - return outFile + return outFile; } catch (e) { - throw Error(`Failed to compile data source template: ${e.message}`) + throw Error(`Failed to compile data source template: ${e.message}`); } } _validateMappingContent(filePath: string) { - const data = fs.readFileSync(filePath) - if ( - this.blockIpfsMethods && - (data.includes('ipfs.cat') || data.includes('ipfs.map')) - ) { + const data = fs.readFileSync(filePath); + if (this.blockIpfsMethods && (data.includes('ipfs.cat') || data.includes('ipfs.map'))) { throw Error(` Subgraph Studio does not support mappings with ipfs methods. Please remove all instances of ipfs.cat and ipfs.map from ${filePath} - `) + `); } } - async writeSubgraphToOutputDirectory( - protocol: Protocol, - subgraph: immutable.Map, - ) { - const displayDir = `${this.displayPath(this.options.outputDir)}${ - toolbox.filesystem.separator - }` + async writeSubgraphToOutputDirectory(protocol: Protocol, subgraph: immutable.Map) { + const displayDir = `${this.displayPath(this.options.outputDir)}${toolbox.filesystem.separator}`; return await withSpinner( `Write compiled subgraph to ${displayDir}`, @@ -456,18 +422,18 @@ export default class Compiler { async spinner => { // Copy schema and update its path subgraph = subgraph.updateIn(['schema', 'file'], schemaFile => { - const schemaFilePath = path.resolve(this.sourceDir, schemaFile as string) - const schemaFileName = path.basename(schemaFile as string) - const targetFile = path.resolve(this.options.outputDir, schemaFileName) - step(spinner, 'Copy schema file', this.displayPath(targetFile)) - fs.copyFileSync(schemaFilePath, targetFile) - return path.relative(this.options.outputDir, targetFile) - }) + const schemaFilePath = path.resolve(this.sourceDir, schemaFile as string); + const schemaFileName = path.basename(schemaFile as string); + const targetFile = path.resolve(this.options.outputDir, schemaFileName); + step(spinner, 'Copy schema file', this.displayPath(targetFile)); + fs.copyFileSync(schemaFilePath, targetFile); + return path.relative(this.options.outputDir, targetFile); + }); // Copy data source files and update their paths subgraph = subgraph.update('dataSources', (dataSources: any[]) => dataSources.map(dataSource => { - let updatedDataSource = dataSource + let updatedDataSource = dataSource; if (this.protocol.hasABIs()) { updatedDataSource = updatedDataSource @@ -475,8 +441,8 @@ export default class Compiler { .updateIn(['mapping', 'abis'], (abis: any[]) => abis.map((abi: any) => abi.update('file', (abiFile: string) => { - abiFile = path.resolve(this.sourceDir, abiFile) - let abiData = this.ABI.load(abi.get('name'), abiFile) + abiFile = path.resolve(this.sourceDir, abiFile); + const abiData = this.ABI.load(abi.get('name'), abiFile); return path.relative( this.options.outputDir, this._writeSubgraphFile( @@ -486,10 +452,10 @@ export default class Compiler { this.subgraphDir(this.options.outputDir, dataSource), spinner, ), - ) + ); }), ), - ) + ); } if (protocol.name == 'substreams') { @@ -497,8 +463,8 @@ export default class Compiler { // Write data source ABIs to the output directory .updateIn(['source', 'package'], (substreamsPackage: any) => substreamsPackage.update('file', (packageFile: string) => { - packageFile = path.resolve(this.sourceDir, packageFile) - let packageContent = fs.readFileSync(packageFile) + packageFile = path.resolve(this.sourceDir, packageFile); + const packageContent = fs.readFileSync(packageFile); return path.relative( this.options.outputDir, @@ -509,32 +475,27 @@ export default class Compiler { this.subgraphDir(this.options.outputDir, dataSource), spinner, ), - ) + ); }), - ) + ); - return updatedDataSource + return updatedDataSource; } // The mapping file is already being written to the output // directory by the AssemblyScript compiler - return updatedDataSource.updateIn( - ['mapping', 'file'], - (mappingFile: string) => - path.relative( - this.options.outputDir, - path.resolve(this.sourceDir, mappingFile), - ), - ) + return updatedDataSource.updateIn(['mapping', 'file'], (mappingFile: string) => + path.relative(this.options.outputDir, path.resolve(this.sourceDir, mappingFile)), + ); }), - ) + ); // Copy template files and update their paths subgraph = subgraph.update('templates', templates => templates === undefined ? templates : templates.map((template: any) => { - let updatedTemplate = template + let updatedTemplate = template; if (this.protocol.hasABIs()) { updatedTemplate = updatedTemplate @@ -542,8 +503,8 @@ export default class Compiler { .updateIn(['mapping', 'abis'], (abis: any[]) => abis.map(abi => abi.update('file', (abiFile: string) => { - abiFile = path.resolve(this.sourceDir, abiFile) - let abiData = this.ABI.load(abi.get('name'), abiFile) + abiFile = path.resolve(this.sourceDir, abiFile); + const abiData = this.ABI.load(abi.get('name'), abiFile); return path.relative( this.options.outputDir, this._writeSubgraphFile( @@ -553,33 +514,28 @@ export default class Compiler { this.subgraphDir(this.options.outputDir, template), spinner, ), - ) + ); }), ), - ) + ); } // The mapping file is already being written to the output // directory by the AssemblyScript compiler - return updatedTemplate.updateIn( - ['mapping', 'file'], - (mappingFile: string) => - path.relative( - this.options.outputDir, - path.resolve(this.sourceDir, mappingFile), - ), - ) + return updatedTemplate.updateIn(['mapping', 'file'], (mappingFile: string) => + path.relative(this.options.outputDir, path.resolve(this.sourceDir, mappingFile)), + ); }), - ) + ); // Write the subgraph manifest itself - let outputFilename = path.join(this.options.outputDir, 'subgraph.yaml') - step(spinner, 'Write subgraph manifest', this.displayPath(outputFilename)) - await Subgraph.write(subgraph, outputFilename) + const outputFilename = path.join(this.options.outputDir, 'subgraph.yaml'); + step(spinner, 'Write subgraph manifest', this.displayPath(outputFilename)); + await Subgraph.write(subgraph, outputFilename); - return subgraph + return subgraph; }, - ) + ); } async uploadSubgraphToIPFS(subgraph: immutable.Map) { @@ -589,10 +545,10 @@ export default class Compiler { `Warnings while uploading subgraph to IPFS`, async spinner => { // Cache uploaded IPFS files so identical files are only uploaded once - let uploadedFiles = new Map() + const uploadedFiles = new Map(); // Collect all source (path -> hash) updates to apply them later - let updates = [] + const updates = []; // Upload the schema to IPFS updates.push({ @@ -602,26 +558,22 @@ export default class Compiler { uploadedFiles, spinner, ), - }) + }); if (this.protocol.hasABIs()) { - for (let [i, dataSource] of subgraph.get('dataSources').entries()) { - for (let [j, abi] of dataSource.getIn(['mapping', 'abis']).entries()) { + for (const [i, dataSource] of subgraph.get('dataSources').entries()) { + for (const [j, abi] of dataSource.getIn(['mapping', 'abis']).entries()) { updates.push({ keyPath: ['dataSources', i, 'mapping', 'abis', j, 'file'], - value: await this._uploadFileToIPFS( - abi.get('file'), - uploadedFiles, - spinner, - ), - }) + value: await this._uploadFileToIPFS(abi.get('file'), uploadedFiles, spinner), + }); } } } // Upload all mappings if (this.protocol.name !== 'substreams') { - for (let [i, dataSource] of subgraph.get('dataSources').entries()) { + for (const [i, dataSource] of subgraph.get('dataSources').entries()) { updates.push({ keyPath: ['dataSources', i, 'mapping', 'file'], value: await this._uploadFileToIPFS( @@ -629,10 +581,10 @@ export default class Compiler { uploadedFiles, spinner, ), - }) + }); } } else { - for (let [i, dataSource] of subgraph.get('dataSources').entries()) { + for (const [i, dataSource] of subgraph.get('dataSources').entries()) { updates.push({ keyPath: ['dataSources', i, 'source', 'package', 'file'], value: await this._uploadFileToIPFS( @@ -640,21 +592,17 @@ export default class Compiler { uploadedFiles, spinner, ), - }) + }); } } - for (let [i, template] of subgraph.get('templates', immutable.List()).entries()) { + for (const [i, template] of subgraph.get('templates', immutable.List()).entries()) { if (this.protocol.hasABIs()) { - for (let [j, abi] of template.getIn(['mapping', 'abis']).entries()) { + for (const [j, abi] of template.getIn(['mapping', 'abis']).entries()) { updates.push({ keyPath: ['templates', i, 'mapping', 'abis', j, 'file'], - value: await this._uploadFileToIPFS( - abi.get('file'), - uploadedFiles, - spinner, - ), - }) + value: await this._uploadFileToIPFS(abi.get('file'), uploadedFiles, spinner), + }); } } @@ -665,18 +613,18 @@ export default class Compiler { uploadedFiles, spinner, ), - }) + }); } // Apply all updates to the subgraph - for (let update of updates) { - subgraph = subgraph.setIn(update.keyPath, update.value) + for (const update of updates) { + subgraph = subgraph.setIn(update.keyPath, update.value); } // Upload the subgraph itself - return await this._uploadSubgraphDefinitionToIPFS(subgraph) + return await this._uploadSubgraphDefinitionToIPFS(subgraph); }, - ) + ); } async _uploadFileToIPFS( @@ -688,46 +636,42 @@ export default class Compiler { 'Resolving IPFS file "%s" from output dir "%s"', maybeRelativeFile, this.options.outputDir, - ) - let absoluteFile = path.resolve(this.options.outputDir, maybeRelativeFile) - step(spinner, 'Add file to IPFS', this.displayPath(absoluteFile)) + ); + const absoluteFile = path.resolve(this.options.outputDir, maybeRelativeFile); + step(spinner, 'Add file to IPFS', this.displayPath(absoluteFile)); - let uploadCacheKey = this.cacheKeyForFile(absoluteFile) - let alreadyUploaded = uploadedFiles.has(uploadCacheKey) + const uploadCacheKey = this.cacheKeyForFile(absoluteFile); + const alreadyUploaded = uploadedFiles.has(uploadCacheKey); if (!alreadyUploaded) { // @ts-expect-error Buffer.from with Buffer data can indeed accept utf-8 - let content = Buffer.from(await fs.readFile(absoluteFile), 'utf-8') - let hash = await this._uploadToIPFS({ + const content = Buffer.from(await fs.readFile(absoluteFile), 'utf-8'); + const hash = await this._uploadToIPFS({ path: path.relative(this.options.outputDir, absoluteFile), - content: content, - }) + content, + }); - uploadedFiles.set(uploadCacheKey, hash) + uploadedFiles.set(uploadCacheKey, hash); } - let hash = uploadedFiles.get(uploadCacheKey) - step( - spinner, - ' ..', - `${hash}${alreadyUploaded ? ' (already uploaded)' : ''}`, - ) - return immutable.fromJS({ '/': `/ipfs/${hash}` }) + const hash = uploadedFiles.get(uploadCacheKey); + step(spinner, ' ..', `${hash}${alreadyUploaded ? ' (already uploaded)' : ''}`); + return immutable.fromJS({ '/': `/ipfs/${hash}` }); } async _uploadSubgraphDefinitionToIPFS(subgraph: immutable.Map) { - let str = yaml.safeDump(subgraph.toJS(), { noRefs: true, sortKeys: true }) - let file = { path: 'subgraph.yaml', content: Buffer.from(str, 'utf-8') } - return await this._uploadToIPFS(file) + const str = yaml.safeDump(subgraph.toJS(), { noRefs: true, sortKeys: true }); + const file = { path: 'subgraph.yaml', content: Buffer.from(str, 'utf-8') }; + return await this._uploadToIPFS(file); } async _uploadToIPFS(file: { path: string; content: Buffer }) { try { - let hash = (await this.ipfs.add([file]))[0].hash - await this.ipfs.pin.add(hash) - return hash + const hash = (await this.ipfs.add([file]))[0].hash; + await this.ipfs.pin.add(hash); + return hash; } catch (e) { - throw Error(`Failed to upload file to IPFS: ${e.message}`) + throw Error(`Failed to upload file to IPFS: ${e.message}`); } } } diff --git a/packages/cli/src/debug.ts b/packages/cli/src/debug.ts index 60b5148b..a7c57e94 100644 --- a/packages/cli/src/debug.ts +++ b/packages/cli/src/debug.ts @@ -1,15 +1,15 @@ -import debugFactory from 'debug' +import debugFactory from 'debug'; debugFactory.formatters.L = immutableList => { - return JSON.stringify(immutableList) -} + return JSON.stringify(immutableList); +}; debugFactory.formatters.M = immutableMap => { if (immutableMap.toMap != null) { - return JSON.stringify(immutableMap.toMap()) + return JSON.stringify(immutableMap.toMap()); } - return immutableMap -} + return immutableMap; +}; -export default debugFactory +export default debugFactory; diff --git a/packages/cli/src/migrations.ts b/packages/cli/src/migrations.ts index 5ca3be68..30f1f8d5 100644 --- a/packages/cli/src/migrations.ts +++ b/packages/cli/src/migrations.ts @@ -1,4 +1,4 @@ -import { withSpinner, step } from './command-helpers/spinner' +import { step, withSpinner } from './command-helpers/spinner'; const MIGRATIONS = [ import('./migrations/mapping_api_version_0_0_1'), @@ -8,31 +8,26 @@ const MIGRATIONS = [ import('./migrations/mapping_api_version_0_0_5'), import('./migrations/spec_version_0_0_2'), import('./migrations/spec_version_0_0_3'), -] +]; -export const applyMigrations = async (options: { - sourceDir: string - manifestFile: string -}) => +export const applyMigrations = async (options: { sourceDir: string; manifestFile: string }) => await withSpinner( `Apply migrations`, `Failed to apply migrations`, `Warnings while applying migraitons`, async spinner => { await MIGRATIONS.reduce(async (previousPromise, migrationImport) => { - await previousPromise - const { default: migration } = await migrationImport - let skipHint = await migration.predicate(options) + await previousPromise; + const { default: migration } = await migrationImport; + const skipHint = await migration.predicate(options); if (typeof skipHint !== 'string' && skipHint) { - step(spinner, 'Apply migration:', migration.name) - await migration.apply(options) + step(spinner, 'Apply migration:', migration.name); + await migration.apply(options); + } else if (typeof skipHint === 'string') { + step(spinner, 'Skip migration:', `${migration.name} (${skipHint})`); } else { - if (typeof skipHint === 'string') { - step(spinner, 'Skip migration:', `${migration.name} (${skipHint})`) - } else { - step(spinner, 'Skip migration:', `${migration.name}`) - } + step(spinner, 'Skip migration:', String(migration.name)); } - }, Promise.resolve()) + }, Promise.resolve()); }, - ) + ); diff --git a/packages/cli/src/migrations/mapping_api_version_0_0_1.ts b/packages/cli/src/migrations/mapping_api_version_0_0_1.ts index 0ae6d4d2..df54f46a 100644 --- a/packages/cli/src/migrations/mapping_api_version_0_0_1.ts +++ b/packages/cli/src/migrations/mapping_api_version_0_0_1.ts @@ -1,29 +1,25 @@ -import semver from 'semver' -import * as toolbox from 'gluegun' -import { getGraphTsVersion } from './util/versions' -import { loadManifest } from './util/load-manifest' +/* eslint-disable */ + +import * as toolbox from 'gluegun'; +import semver from 'semver'; +import { loadManifest } from './util/load-manifest'; +import { getGraphTsVersion } from './util/versions'; // If any of the manifest apiVersions are 0.0.1, replace them with 0.0.2 export default { name: 'Bump mapping apiVersion from 0.0.1 to 0.0.2', - predicate: async ({ - sourceDir, - manifestFile, - }: { - sourceDir: string - manifestFile: string - }) => { + predicate: async ({ sourceDir, manifestFile }: { sourceDir: string; manifestFile: string }) => { // Obtain the graph-ts version, if possible - let graphTsVersion + let graphTsVersion; try { - graphTsVersion = await getGraphTsVersion(sourceDir) + graphTsVersion = await getGraphTsVersion(sourceDir); } catch (_) { // If we cannot obtain the version, return a hint that the graph-ts // hasn't been installed yet - return 'graph-ts dependency not installed yet' + return 'graph-ts dependency not installed yet'; } - let manifest = await loadManifest(manifestFile) + const manifest = await loadManifest(manifestFile); return ( // Only migrate if the graph-ts version is > 0.5.1... semver.gt(graphTsVersion, '0.5.1') && @@ -50,7 +46,7 @@ export default { template.mapping.apiVersion === '0.0.1'), false, ))) - ) + ); }, apply: async ({ manifestFile }: { manifestFile: string }) => { // Make sure we catch all variants; we could load the manifest @@ -62,18 +58,18 @@ export default { // @ts-expect-error toolbox patching seems to accept RegExp new RegExp('apiVersion: 0.0.1', 'g'), 'apiVersion: 0.0.2', - ) + ); await toolbox.patching.replace( manifestFile, // @ts-expect-error toolbox patching seems to accept RegExp new RegExp("apiVersion: '0.0.1'", 'g'), "apiVersion: '0.0.2'", - ) + ); await toolbox.patching.replace( manifestFile, // @ts-expect-error toolbox patching seems to accept RegExp new RegExp('apiVersion: "0.0.1"', 'g'), 'apiVersion: "0.0.2"', - ) + ); }, -} +}; diff --git a/packages/cli/src/migrations/mapping_api_version_0_0_2.ts b/packages/cli/src/migrations/mapping_api_version_0_0_2.ts index 9599e9ca..e8de263e 100644 --- a/packages/cli/src/migrations/mapping_api_version_0_0_2.ts +++ b/packages/cli/src/migrations/mapping_api_version_0_0_2.ts @@ -1,29 +1,25 @@ -import semver from 'semver' -import * as toolbox from 'gluegun' -import { loadManifest } from './util/load-manifest' -import { getGraphTsVersion } from './util/versions' +/* eslint-disable */ + +import * as toolbox from 'gluegun'; +import semver from 'semver'; +import { loadManifest } from './util/load-manifest'; +import { getGraphTsVersion } from './util/versions'; // If any of the manifest apiVersions are 0.0.2, replace them with 0.0.3 export default { name: 'Bump mapping apiVersion from 0.0.2 to 0.0.3', - predicate: async ({ - sourceDir, - manifestFile, - }: { - sourceDir: string - manifestFile: string - }) => { + predicate: async ({ sourceDir, manifestFile }: { sourceDir: string; manifestFile: string }) => { // Obtain the graph-ts version, if possible - let graphTsVersion + let graphTsVersion; try { - graphTsVersion = await getGraphTsVersion(sourceDir) + graphTsVersion = await getGraphTsVersion(sourceDir); } catch (_) { // If we cannot obtain the version, return a hint that the graph-ts // hasn't been installed yet - return 'graph-ts dependency not installed yet' + return 'graph-ts dependency not installed yet'; } - let manifest = await loadManifest(manifestFile) + const manifest = await loadManifest(manifestFile); return ( // Only migrate if the graph-ts version is > 0.12.0... semver.gt(graphTsVersion, '0.12.0') && @@ -50,7 +46,7 @@ export default { template.mapping.apiVersion === '0.0.2'), false, ))) - ) + ); }, apply: async ({ manifestFile }: { manifestFile: string }) => { // Make sure we catch all variants; we could load the manifest @@ -62,18 +58,18 @@ export default { // @ts-expect-error toolbox patching seems to accept RegExp new RegExp('apiVersion: 0.0.2', 'g'), 'apiVersion: 0.0.3', - ) + ); await toolbox.patching.replace( manifestFile, // @ts-expect-error toolbox patching seems to accept RegExp new RegExp("apiVersion: '0.0.2'", 'g'), "apiVersion: '0.0.3'", - ) + ); await toolbox.patching.replace( manifestFile, // @ts-expect-error toolbox patching seems to accept RegExp new RegExp('apiVersion: "0.0.2"', 'g'), 'apiVersion: "0.0.3"', - ) + ); }, -} +}; diff --git a/packages/cli/src/migrations/mapping_api_version_0_0_3.ts b/packages/cli/src/migrations/mapping_api_version_0_0_3.ts index d107cacf..6974c05c 100644 --- a/packages/cli/src/migrations/mapping_api_version_0_0_3.ts +++ b/packages/cli/src/migrations/mapping_api_version_0_0_3.ts @@ -1,29 +1,25 @@ -import semver from 'semver' -import * as toolbox from 'gluegun' -import { loadManifest } from './util/load-manifest' -import { getGraphTsVersion } from './util/versions' +/* eslint-disable */ + +import * as toolbox from 'gluegun'; +import semver from 'semver'; +import { loadManifest } from './util/load-manifest'; +import { getGraphTsVersion } from './util/versions'; // If any of the manifest apiVersions are 0.0.3, replace them with 0.0.4 export default { name: 'Bump mapping apiVersion from 0.0.3 to 0.0.4', - predicate: async ({ - sourceDir, - manifestFile, - }: { - sourceDir: string - manifestFile: string - }) => { + predicate: async ({ sourceDir, manifestFile }: { sourceDir: string; manifestFile: string }) => { // Obtain the graph-ts version, if possible - let graphTsVersion + let graphTsVersion; try { - graphTsVersion = await getGraphTsVersion(sourceDir) + graphTsVersion = await getGraphTsVersion(sourceDir); } catch (_) { // If we cannot obtain the version, return a hint that the graph-ts // hasn't been installed yet - return 'graph-ts dependency not installed yet' + return 'graph-ts dependency not installed yet'; } - let manifest = await loadManifest(manifestFile) + const manifest = await loadManifest(manifestFile); return ( // Only migrate if the graph-ts version is > 0.17.0... semver.gt(graphTsVersion, '0.17.0') && @@ -50,7 +46,7 @@ export default { template.mapping.apiVersion === '0.0.3'), false, ))) - ) + ); }, apply: async ({ manifestFile }: { manifestFile: string }) => { // Make sure we catch all variants; we could load the manifest @@ -62,18 +58,18 @@ export default { // @ts-expect-error toolbox patching seems to accept RegExp new RegExp('apiVersion: 0.0.3', 'g'), 'apiVersion: 0.0.4', - ) + ); await toolbox.patching.replace( manifestFile, // @ts-expect-error toolbox patching seems to accept RegExp new RegExp("apiVersion: '0.0.3'", 'g'), "apiVersion: '0.0.4'", - ) + ); await toolbox.patching.replace( manifestFile, // @ts-expect-error toolbox patching seems to accept RegExp new RegExp('apiVersion: "0.0.3"', 'g'), 'apiVersion: "0.0.4"', - ) + ); }, -} +}; diff --git a/packages/cli/src/migrations/mapping_api_version_0_0_4.ts b/packages/cli/src/migrations/mapping_api_version_0_0_4.ts index 62020541..c9209d53 100644 --- a/packages/cli/src/migrations/mapping_api_version_0_0_4.ts +++ b/packages/cli/src/migrations/mapping_api_version_0_0_4.ts @@ -1,29 +1,25 @@ -import semver from 'semver' -import * as toolbox from 'gluegun' -import { loadManifest } from './util/load-manifest' -import { getGraphTsVersion } from './util/versions' +/* eslint-disable */ + +import * as toolbox from 'gluegun'; +import semver from 'semver'; +import { loadManifest } from './util/load-manifest'; +import { getGraphTsVersion } from './util/versions'; // If any of the manifest apiVersions are 0.0.4, replace them with 0.0.5 export default { name: 'Bump mapping apiVersion from 0.0.4 to 0.0.5', - predicate: async ({ - sourceDir, - manifestFile, - }: { - sourceDir: string - manifestFile: string - }) => { + predicate: async ({ sourceDir, manifestFile }: { sourceDir: string; manifestFile: string }) => { // Obtain the graph-ts version, if possible - let graphTsVersion + let graphTsVersion; try { - graphTsVersion = await getGraphTsVersion(sourceDir) + graphTsVersion = await getGraphTsVersion(sourceDir); } catch (_) { // If we cannot obtain the version, return a hint that the graph-ts // hasn't been installed yet - return 'graph-ts dependency not installed yet' + return 'graph-ts dependency not installed yet'; } - let manifest = await loadManifest(manifestFile) + const manifest = await loadManifest(manifestFile); return ( // Only migrate if the graph-ts version is >= 0.22.0... // Coerce needed because we may be dealing with an alpha version @@ -52,7 +48,7 @@ export default { template.mapping.apiVersion === '0.0.4'), false, ))) - ) + ); }, apply: async ({ manifestFile }: { manifestFile: string }) => { // Make sure we catch all variants; we could load the manifest @@ -64,18 +60,18 @@ export default { // @ts-expect-error toolbox patching seems to accept RegExp new RegExp('apiVersion: 0.0.4', 'g'), 'apiVersion: 0.0.5', - ) + ); await toolbox.patching.replace( manifestFile, // @ts-expect-error toolbox patching seems to accept RegExp new RegExp("apiVersion: '0.0.4'", 'g'), "apiVersion: '0.0.5'", - ) + ); await toolbox.patching.replace( manifestFile, // @ts-expect-error toolbox patching seems to accept RegExp new RegExp('apiVersion: "0.0.4"', 'g'), 'apiVersion: "0.0.5"', - ) + ); }, -} +}; diff --git a/packages/cli/src/migrations/mapping_api_version_0_0_5.ts b/packages/cli/src/migrations/mapping_api_version_0_0_5.ts index 4900d1f1..907dae77 100644 --- a/packages/cli/src/migrations/mapping_api_version_0_0_5.ts +++ b/packages/cli/src/migrations/mapping_api_version_0_0_5.ts @@ -1,29 +1,25 @@ -import semver from 'semver' -import * as toolbox from 'gluegun' -import { loadManifest } from './util/load-manifest' -import { getGraphTsVersion } from './util/versions' +/* eslint-disable */ + +import * as toolbox from 'gluegun'; +import semver from 'semver'; +import { loadManifest } from './util/load-manifest'; +import { getGraphTsVersion } from './util/versions'; // If any of the manifest apiVersions are 0.0.5, replace them with 0.0.6 export default { name: 'Bump mapping apiVersion from 0.0.5 to 0.0.6', - predicate: async ({ - sourceDir, - manifestFile, - }: { - sourceDir: string - manifestFile: string - }) => { + predicate: async ({ sourceDir, manifestFile }: { sourceDir: string; manifestFile: string }) => { // Obtain the graph-ts version, if possible - let graphTsVersion + let graphTsVersion; try { - graphTsVersion = await getGraphTsVersion(sourceDir) + graphTsVersion = await getGraphTsVersion(sourceDir); } catch (_) { // If we cannot obtain the version, return a hint that the graph-ts // hasn't been installed yet - return 'graph-ts dependency not installed yet' + return 'graph-ts dependency not installed yet'; } - let manifest = await loadManifest(manifestFile) + const manifest = await loadManifest(manifestFile); return ( // Only migrate if the graph-ts version is >= 0.24.0... // Coerce needed because we may be dealing with an alpha version @@ -52,7 +48,7 @@ export default { template.mapping.apiVersion === '0.0.5'), false, ))) - ) + ); }, apply: async ({ manifestFile }: { manifestFile: string }) => { // Make sure we catch all variants; we could load the manifest @@ -64,18 +60,18 @@ export default { // @ts-expect-error toolbox patching seems to accept RegExp new RegExp('apiVersion: 0.0.5', 'g'), 'apiVersion: 0.0.6', - ) + ); await toolbox.patching.replace( manifestFile, // @ts-expect-error toolbox patching seems to accept RegExp new RegExp("apiVersion: '0.0.5'", 'g'), "apiVersion: '0.0.6'", - ) + ); await toolbox.patching.replace( manifestFile, // @ts-expect-error toolbox patching seems to accept RegExp new RegExp('apiVersion: "0.0.5"', 'g'), 'apiVersion: "0.0.6"', - ) + ); }, -} +}; diff --git a/packages/cli/src/migrations/spec_version_0_0_2.ts b/packages/cli/src/migrations/spec_version_0_0_2.ts index 226fb1fd..f43768be 100644 --- a/packages/cli/src/migrations/spec_version_0_0_2.ts +++ b/packages/cli/src/migrations/spec_version_0_0_2.ts @@ -1,34 +1,24 @@ -import * as toolbox from 'gluegun' -import { loadManifest } from './util/load-manifest' +/* eslint-disable */ + +import * as toolbox from 'gluegun'; +import { loadManifest } from './util/load-manifest'; // Spec version to 0.0.2 uses top level templates. graph-cli no longer supports // 0.0.1 which used nested templates. export default { name: 'Bump manifest specVersion from 0.0.1 to 0.0.2', predicate: async ({ manifestFile }: { manifestFile: string }) => { - let manifest = await loadManifest(manifestFile) + const manifest = await loadManifest(manifestFile); return ( manifest && typeof manifest === 'object' && manifest.specVersion && manifest.specVersion === '0.0.1' - ) + ); }, apply: async ({ manifestFile }: { manifestFile: string }) => { - await toolbox.patching.replace( - manifestFile, - 'specVersion: 0.0.1', - 'specVersion: 0.0.2', - ) - await toolbox.patching.replace( - manifestFile, - "specVersion: '0.0.1'", - "specVersion: '0.0.2'", - ) - await toolbox.patching.replace( - manifestFile, - 'specVersion: "0.0.1"', - 'specVersion: "0.0.2"', - ) + await toolbox.patching.replace(manifestFile, 'specVersion: 0.0.1', 'specVersion: 0.0.2'); + await toolbox.patching.replace(manifestFile, "specVersion: '0.0.1'", "specVersion: '0.0.2'"); + await toolbox.patching.replace(manifestFile, 'specVersion: "0.0.1"', 'specVersion: "0.0.2"'); }, -} +}; diff --git a/packages/cli/src/migrations/spec_version_0_0_3.ts b/packages/cli/src/migrations/spec_version_0_0_3.ts index c1d9892b..d77630cd 100644 --- a/packages/cli/src/migrations/spec_version_0_0_3.ts +++ b/packages/cli/src/migrations/spec_version_0_0_3.ts @@ -1,5 +1,7 @@ -import * as toolbox from 'gluegun' -import { loadManifest } from './util/load-manifest' +/* eslint-disable */ + +import * as toolbox from 'gluegun'; +import { loadManifest } from './util/load-manifest'; // Spec version 0.0.4 uses feature management, but features are // detected and validated by the graph-node instance during subgraph @@ -10,18 +12,18 @@ import { loadManifest } from './util/load-manifest' export default { name: 'Bump manifest specVersion from 0.0.2 to 0.0.4', predicate: async ({ manifestFile }: { manifestFile: string }) => { - let manifest = await loadManifest(manifestFile) + const manifest = await loadManifest(manifestFile); return ( manifest && typeof manifest === 'object' && manifest.specVersion && (manifest.specVersion === '0.0.2' || manifest.specVersion === '0.0.3') - ) + ); }, apply: async ({ manifestFile }: { manifestFile: string }) => { await toolbox.patching.patch(manifestFile, { insert: 'specVersion: 0.0.4', replace: new RegExp(`specVersion: ['"]?0.0.[23]['"]?`), - }) + }); }, -} +}; diff --git a/packages/cli/src/migrations/util/load-manifest.ts b/packages/cli/src/migrations/util/load-manifest.ts index 2db81fd6..8bc76383 100644 --- a/packages/cli/src/migrations/util/load-manifest.ts +++ b/packages/cli/src/migrations/util/load-manifest.ts @@ -1,11 +1,10 @@ -import fs from 'fs-extra' -import path from 'path' -import yaml from 'js-yaml' +import path from 'path'; +import fs from 'fs-extra'; +import yaml from 'js-yaml'; export async function loadManifest(manifestFile: string) { if (manifestFile.match(/.js$/)) { - return require(path.resolve(manifestFile)) - } else { - return yaml.safeLoad(await fs.readFile(manifestFile, 'utf-8')) + return require(path.resolve(manifestFile)); } + return yaml.safeLoad(await fs.readFile(manifestFile, 'utf-8')); } diff --git a/packages/cli/src/migrations/util/versions.ts b/packages/cli/src/migrations/util/versions.ts index e11d1c3c..5ac6599e 100644 --- a/packages/cli/src/migrations/util/versions.ts +++ b/packages/cli/src/migrations/util/versions.ts @@ -1,8 +1,8 @@ -import path from 'path' -import fs from 'fs-extra' +import path from 'path'; +import fs from 'fs-extra'; export async function getGraphTsVersion(sourceDir: string) { - let graphTsPath!: string + let graphTsPath!: string; for ( let dir: string | undefined = path.resolve(sourceDir); @@ -11,22 +11,17 @@ export async function getGraphTsVersion(sourceDir: string) { // Continue with the parent directory, terminate after the root dir dir = path.dirname(dir) === dir ? undefined : path.dirname(dir) ) { - let graphTsNodeModulesPath = path.join( - dir, - 'node_modules', - '@graphprotocol', - 'graph-ts', - ) + const graphTsNodeModulesPath = path.join(dir, 'node_modules', '@graphprotocol', 'graph-ts'); if (fs.existsSync(graphTsNodeModulesPath)) { - graphTsPath = graphTsNodeModulesPath + graphTsPath = graphTsNodeModulesPath; // Loop until we find the first occurrence of graph-ts in node_modules - break + break; } } - let pkgJsonFile = path.join(graphTsPath, 'package.json') - let data = await fs.readFile(pkgJsonFile) - let jsonData = JSON.parse(data.toString()) - return jsonData.version + const pkgJsonFile = path.join(graphTsPath, 'package.json'); + const data = await fs.readFile(pkgJsonFile); + const jsonData = JSON.parse(data.toString()); + return jsonData.version; } diff --git a/packages/cli/src/protocols/arweave/scaffold/manifest.ts b/packages/cli/src/protocols/arweave/scaffold/manifest.ts index 962bee40..a0908bb7 100644 --- a/packages/cli/src/protocols/arweave/scaffold/manifest.ts +++ b/packages/cli/src/protocols/arweave/scaffold/manifest.ts @@ -1,5 +1,5 @@ export const source = ({ contract }: { contract: string }) => ` - owner: '${contract}'` + owner: '${contract}'`; export const mapping = () => ` apiVersion: 0.0.5 @@ -11,4 +11,4 @@ export const mapping = () => ` - handler: handleBlock transactionHandlers: - handler: handleTx - file: ./src/mapping.ts` + file: ./src/mapping.ts`; diff --git a/packages/cli/src/protocols/arweave/scaffold/mapping.ts b/packages/cli/src/protocols/arweave/scaffold/mapping.ts index 0556f0c6..1f432649 100644 --- a/packages/cli/src/protocols/arweave/scaffold/mapping.ts +++ b/packages/cli/src/protocols/arweave/scaffold/mapping.ts @@ -46,4 +46,4 @@ export const generatePlaceholderHandlers = () => entity.save(); } -` +`; diff --git a/packages/cli/src/protocols/arweave/subgraph.ts b/packages/cli/src/protocols/arweave/subgraph.ts index 235fc8d2..73862e46 100644 --- a/packages/cli/src/protocols/arweave/subgraph.ts +++ b/packages/cli/src/protocols/arweave/subgraph.ts @@ -1,22 +1,22 @@ -import immutable from 'immutable' -import { Subgraph, SubgraphOptions } from '../subgraph' +import immutable from 'immutable'; +import { Subgraph, SubgraphOptions } from '../subgraph'; export default class ArweaveSubgraph implements Subgraph { - manifest: SubgraphOptions['manifest'] - resolveFile: SubgraphOptions['resolveFile'] - protocol: SubgraphOptions['protocol'] + manifest: SubgraphOptions['manifest']; + resolveFile: SubgraphOptions['resolveFile']; + protocol: SubgraphOptions['protocol']; constructor(options: SubgraphOptions) { - this.manifest = options.manifest - this.resolveFile = options.resolveFile - this.protocol = options.protocol + this.manifest = options.manifest; + this.resolveFile = options.resolveFile; + this.protocol = options.protocol; } validateManifest() { - return immutable.List() + return immutable.List(); } handlerTypes() { - return immutable.List(['blockHandlers', 'transactionHandlers']) + return immutable.List(['blockHandlers', 'transactionHandlers']); } } diff --git a/packages/cli/src/protocols/contract.ts b/packages/cli/src/protocols/contract.ts index 6311132b..40d6dc25 100644 --- a/packages/cli/src/protocols/contract.ts +++ b/packages/cli/src/protocols/contract.ts @@ -1,9 +1,9 @@ // TODO: make sure the classes implement this type export interface ContractCtor { - new (account: string): Contract - identifierName(): string + new (account: string): Contract; + identifierName(): string; } export interface Contract { - validate(): { valid: boolean; error: string | null } + validate(): { valid: boolean; error: string | null }; } diff --git a/packages/cli/src/protocols/cosmos/scaffold/manifest.ts b/packages/cli/src/protocols/cosmos/scaffold/manifest.ts index d92463a9..d25c165f 100644 --- a/packages/cli/src/protocols/cosmos/scaffold/manifest.ts +++ b/packages/cli/src/protocols/cosmos/scaffold/manifest.ts @@ -1,5 +1,5 @@ export const source = () => ` - startBlock: 0` + startBlock: 0`; export const mapping = () => ` apiVersion: 0.0.5 @@ -8,4 +8,4 @@ export const mapping = () => ` - ExampleEntity blockHandlers: - handler: handleBlock - file: ./src/contract.ts` + file: ./src/contract.ts`; diff --git a/packages/cli/src/protocols/cosmos/scaffold/mapping.ts b/packages/cli/src/protocols/cosmos/scaffold/mapping.ts index a3087ab7..b404624d 100644 --- a/packages/cli/src/protocols/cosmos/scaffold/mapping.ts +++ b/packages/cli/src/protocols/cosmos/scaffold/mapping.ts @@ -32,4 +32,4 @@ export const generatePlaceholderHandlers = () => // entity back to the store. Fields that were not set or unset remain // unchanged, allowing for partial updates to be applied. } -` +`; diff --git a/packages/cli/src/protocols/cosmos/subgraph.ts b/packages/cli/src/protocols/cosmos/subgraph.ts index c56cc7e8..341cbfe4 100644 --- a/packages/cli/src/protocols/cosmos/subgraph.ts +++ b/packages/cli/src/protocols/cosmos/subgraph.ts @@ -1,19 +1,19 @@ -import immutable from 'immutable' -import { Subgraph, SubgraphOptions } from '../subgraph' +import immutable from 'immutable'; +import { Subgraph, SubgraphOptions } from '../subgraph'; export default class CosmosSubgraph implements Subgraph { - manifest: SubgraphOptions['manifest'] - resolveFile: SubgraphOptions['resolveFile'] - protocol: SubgraphOptions['protocol'] + manifest: SubgraphOptions['manifest']; + resolveFile: SubgraphOptions['resolveFile']; + protocol: SubgraphOptions['protocol']; constructor(options: SubgraphOptions) { - this.manifest = options.manifest - this.resolveFile = options.resolveFile - this.protocol = options.protocol + this.manifest = options.manifest; + this.resolveFile = options.resolveFile; + this.protocol = options.protocol; } validateManifest() { - return immutable.List() + return immutable.List(); } handlerTypes() { @@ -22,6 +22,6 @@ export default class CosmosSubgraph implements Subgraph { 'eventHandlers', 'transactionHandlers', 'messageHandlers', - ]) + ]); } } diff --git a/packages/cli/src/protocols/ethereum/abi.ts b/packages/cli/src/protocols/ethereum/abi.ts index 6fcd9017..4945b772 100644 --- a/packages/cli/src/protocols/ethereum/abi.ts +++ b/packages/cli/src/protocols/ethereum/abi.ts @@ -1,11 +1,10 @@ -import fs from 'fs-extra' -import immutable from 'immutable' -import path from 'path' +import path from 'path'; +import fs from 'fs-extra'; +import immutable from 'immutable'; +import AbiCodeGenerator from './codegen/abi'; -import AbiCodeGenerator from './codegen/abi' - -const TUPLE_ARRAY_PATTERN = /^tuple\[([0-9]*)\]$/ -const TUPLE_MATRIX_PATTERN = /^tuple\[([0-9]*)\]\[([0-9]*)\]$/ +const TUPLE_ARRAY_PATTERN = /^tuple\[([0-9]*)\]$/; +const TUPLE_MATRIX_PATTERN = /^tuple\[([0-9]*)\]\[([0-9]*)\]$/; const buildOldSignatureParameter = (input: immutable.Map) => { return input.get('type') === 'tuple' @@ -13,32 +12,33 @@ const buildOldSignatureParameter = (input: immutable.Map) => { .get('components') .map((component: any) => buildSignatureParameter(component)) .join(',')})` - : `${input.get('type')}` -} + : String(input.get('type')); +}; const buildSignatureParameter = (input: immutable.Map) => { if (input.get('type') === 'tuple') { return `(${input.get('indexed') ? 'indexed ' : ''}${input .get('components') .map((component: any) => buildSignatureParameter(component)) - .join(',')})` - } else if (input.get('type').match(TUPLE_ARRAY_PATTERN)) { - const length = input.get('type').match(TUPLE_ARRAY_PATTERN)[1] + .join(',')})`; + } + if (input.get('type').match(TUPLE_ARRAY_PATTERN)) { + const length = input.get('type').match(TUPLE_ARRAY_PATTERN)[1]; return `(${input.get('indexed') ? 'indexed ' : ''}${input .get('components') .map((component: any) => buildSignatureParameter(component)) - .join(',')})[${length ? length : ''}]` - } else if (input.get('type').match(TUPLE_MATRIX_PATTERN)) { - const length1 = input.get('type').match(TUPLE_MATRIX_PATTERN)[1] - const length2 = input.get('type').match(TUPLE_MATRIX_PATTERN)[2] + .join(',')})[${length ? length : ''}]`; + } + if (input.get('type').match(TUPLE_MATRIX_PATTERN)) { + const length1 = input.get('type').match(TUPLE_MATRIX_PATTERN)[1]; + const length2 = input.get('type').match(TUPLE_MATRIX_PATTERN)[2]; return `(${input.get('indexed') ? 'indexed ' : ''}${input .get('components') .map((component: any) => buildSignatureParameter(component)) - .join(',')})[${length1 ? length1 : ''}][${length2 ? length2 : ''}]` - } else { - return `${input.get('indexed') ? 'indexed ' : ''}${input.get('type')}` + .join(',')})[${length1 ? length1 : ''}][${length2 ? length2 : ''}]`; } -} + return `${input.get('indexed') ? 'indexed ' : ''}${input.get('type')}`; +}; export default class ABI { constructor( @@ -46,27 +46,27 @@ export default class ABI { public file: string | undefined, public data: immutable.Collection, ) { - this.name = name - this.file = file - this.data = data + this.name = name; + this.file = file; + this.data = data; } codeGenerator() { - return new AbiCodeGenerator(this) + return new AbiCodeGenerator(this); } static oldEventSignature(event: immutable.Map) { return `${event.get('name')}(${event .get('inputs', []) .map(buildOldSignatureParameter) - .join(',')})` + .join(',')})`; } static eventSignature(event: immutable.Map) { return `${event.get('name')}(${event .get('inputs', []) .map(buildSignatureParameter) - .join(',')})` + .join(',')})`; } /** @@ -82,77 +82,72 @@ export default class ABI { * - Multiple inputs and outputs: `example(uint256,(string,bytes32)):(bool,uint256)` */ functionSignature(fn: immutable.Map) { - let inputs = fn.get('inputs', []).map(buildSignatureParameter).join(',') - let outputs = fn.get('outputs', []).map(buildSignatureParameter).join(',') - return `${fn.get('name')}(${inputs})${outputs.length > 0 ? `:(${outputs})` : ''}` + const inputs = fn.get('inputs', []).map(buildSignatureParameter).join(','); + const outputs = fn.get('outputs', []).map(buildSignatureParameter).join(','); + return `${fn.get('name')}(${inputs})${outputs.length > 0 ? `:(${outputs})` : ''}`; } oldEventSignatures() { return this.data .filter((entry: any) => entry.get('type') === 'event') - .map(ABI.oldEventSignature) + .map(ABI.oldEventSignature); } eventSignatures() { - return this.data - .filter((entry: any) => entry.get('type') === 'event') - .map(ABI.eventSignature) + return this.data.filter((entry: any) => entry.get('type') === 'event').map(ABI.eventSignature); } callFunctions() { // An entry is a function if its type is not set or if it is one of // 'constructor', 'function' or 'fallback' - let functionTypes = immutable.Set(['constructor', 'function', 'fallback']) - let functions = this.data.filter( + const functionTypes = immutable.Set(['constructor', 'function', 'fallback']); + const functions = this.data.filter( (entry: any) => !entry.has('type') || functionTypes.includes(entry.get('type')), - ) + ); // A function is a call function if it is nonpayable, payable or // not constant - let mutabilityTypes = immutable.Set(['nonpayable', 'payable']) + const mutabilityTypes = immutable.Set(['nonpayable', 'payable']); return functions.filter( (entry: any) => - mutabilityTypes.includes(entry.get('stateMutability')) || - entry.get('constant') === false, - ) + mutabilityTypes.includes(entry.get('stateMutability')) || entry.get('constant') === false, + ); } callFunctionSignatures() { return this.callFunctions() .filter((entry: any) => entry.get('type') !== 'constructor') .map((entry: any) => { - const name = entry.get('name', '') + const name = entry.get('name', ''); const inputs = entry .get('inputs', immutable.List()) - .map((input: any) => buildSignatureParameter(input)) + .map((input: any) => buildSignatureParameter(input)); - return `${name}(${inputs.join(',')})` - }) + return `${name}(${inputs.join(',')})`; + }); } static normalized(json: any) { if (Array.isArray(json)) { - return json - } else if (json.abi !== undefined) { - return json.abi - } else if ( - json.compilerOutput !== undefined && - json.compilerOutput.abi !== undefined - ) { - return json.compilerOutput.abi - } else { - return undefined + return json; + } + if (json.abi !== undefined) { + return json.abi; + } + if (json.compilerOutput?.abi) { + return json.compilerOutput.abi; } + return undefined; } static load(name: string, file: string) { - let data = JSON.parse(fs.readFileSync(file).toString()) - let abi = ABI.normalized(data) + const data = JSON.parse(fs.readFileSync(file).toString()); + const abi = ABI.normalized(data); if (abi === null || abi === undefined) { - throw Error(`No valid ABI in file: ${path.relative(process.cwd(), file)}`) + throw Error(`No valid ABI in file: ${path.relative(process.cwd(), file)}`); } - return new ABI(name, file, immutable.fromJS(abi)) + return new ABI(name, file, immutable.fromJS(abi)); } } diff --git a/packages/cli/src/protocols/ethereum/codegen/abi.test.ts b/packages/cli/src/protocols/ethereum/codegen/abi.test.ts index 5c954503..6af5a4c7 100644 --- a/packages/cli/src/protocols/ethereum/codegen/abi.test.ts +++ b/packages/cli/src/protocols/ethereum/codegen/abi.test.ts @@ -1,21 +1,20 @@ -import fs from 'fs-extra' -import path from 'path' -import immutable from 'immutable' +import path from 'path'; +import fs from 'fs-extra'; +import immutable from 'immutable'; +import * as ts from '../../../codegen/typescript'; +import ABI from '../abi'; +import AbiCodeGenerator from './abi'; -import ABI from '../abi' -import * as ts from '../../../codegen/typescript' -import AbiCodeGenerator from './abi' - -let tempdir: string -let abi: ABI -let generatedTypes: any[] +let tempdir: string; +let abi: ABI; +let generatedTypes: any[]; describe('ABI code generation', () => { beforeAll(async () => { - tempdir = await fs.mkdtemp('abi-codegen') + tempdir = await fs.mkdtemp('abi-codegen'); try { - let filename = path.join(tempdir, 'ABI.json') + const filename = path.join(tempdir, 'ABI.json'); await fs.writeFile( filename, JSON.stringify([ @@ -165,18 +164,18 @@ describe('ABI code generation', () => { }, ]), 'utf-8', - ) - abi = ABI.load('Contract', filename) - let codegen = new AbiCodeGenerator(abi) - generatedTypes = codegen.generateTypes() + ); + abi = ABI.load('Contract', filename); + const codegen = new AbiCodeGenerator(abi); + generatedTypes = codegen.generateTypes(); } finally { - await fs.remove(tempdir) + await fs.remove(tempdir); } - }) + }); afterAll(async () => { - await fs.remove(tempdir) - }) + await fs.remove(tempdir); + }); describe('Generated types', () => { test('All expected types are generated', () => { @@ -187,78 +186,71 @@ describe('ABI code generation', () => { 'Contract__getProposalsResultValue1Struct', 'Contract__getProposalsResult', 'Contract', - ]) - }) - }) + ]); + }); + }); describe('Contract class', () => { test('Exists', () => { - expect(generatedTypes.find(type => type.name === 'Contract')).toBeDefined() - }) + expect(generatedTypes.find(type => type.name === 'Contract')).toBeDefined(); + }); test('Has methods', () => { - let contract = generatedTypes.find(type => type.name === 'Contract') - expect(contract.methods).toBeInstanceOf(Array) - }) + const contract = generatedTypes.find(type => type.name === 'Contract'); + expect(contract.methods).toBeInstanceOf(Array); + }); test('Has `bind` method', () => { - let contract = generatedTypes.find(type => type.name === 'Contract') - expect(contract.methods.find((method: any) => method.name === 'bind')).toBeDefined() - }) + const contract = generatedTypes.find(type => type.name === 'Contract'); + expect(contract.methods.find((method: any) => method.name === 'bind')).toBeDefined(); + }); test('Has methods for all callable functions', () => { - let contract = generatedTypes.find(type => type.name === 'Contract') - expect(contract.methods.map((method: any) => method.name)).toContain('getProposal') - }) - }) + const contract = generatedTypes.find(type => type.name === 'Contract'); + expect(contract.methods.map((method: any) => method.name)).toContain('getProposal'); + }); + }); describe('Methods for callable functions', () => { test('Have correct parameters', () => { - let contract = generatedTypes.find(type => type.name === 'Contract') - expect(contract.methods.map((method: any) => [method.name, method.params])).toEqual( + const contract = generatedTypes.find(type => type.name === 'Contract'); + expect(contract.methods.map((method: any) => [method.name, method.params])).toEqual([ + ['bind', immutable.List([ts.param('address', 'Address')])], + ['read', immutable.List()], + ['try_read', immutable.List()], + [ + 'getProposal', + immutable.List([ + ts.param('proposalId', 'BigInt'), + ts.param('param1', 'Contract__getProposalInputParam1Struct'), + ]), + ], [ - ['bind', immutable.List([ts.param('address', 'Address')])], - ['read', immutable.List()], - ['try_read', immutable.List()], - [ - 'getProposal', - immutable.List([ - ts.param('proposalId', 'BigInt'), - ts.param('param1', 'Contract__getProposalInputParam1Struct'), - ]), - ], - [ - 'try_getProposal', - immutable.List([ - ts.param('proposalId', 'BigInt'), - ts.param('param1', 'Contract__getProposalInputParam1Struct'), - ]), - ], - ['getProposals', immutable.List()], - ['try_getProposals', immutable.List()], - ['overloaded', immutable.List([ts.param('param0', 'string')])], - ['try_overloaded', immutable.List([ts.param('param0', 'string')])], - ['overloaded1', immutable.List([ts.param('param0', 'BigInt')])], - ['try_overloaded1', immutable.List([ts.param('param0', 'BigInt')])], - ['overloaded2', immutable.List([ts.param('param0', 'Bytes')])], - ['try_overloaded2', immutable.List([ts.param('param0', 'Bytes')])], + 'try_getProposal', + immutable.List([ + ts.param('proposalId', 'BigInt'), + ts.param('param1', 'Contract__getProposalInputParam1Struct'), + ]), ], - ) - }) + ['getProposals', immutable.List()], + ['try_getProposals', immutable.List()], + ['overloaded', immutable.List([ts.param('param0', 'string')])], + ['try_overloaded', immutable.List([ts.param('param0', 'string')])], + ['overloaded1', immutable.List([ts.param('param0', 'BigInt')])], + ['try_overloaded1', immutable.List([ts.param('param0', 'BigInt')])], + ['overloaded2', immutable.List([ts.param('param0', 'Bytes')])], + ['try_overloaded2', immutable.List([ts.param('param0', 'Bytes')])], + ]); + }); test('Have correct return types', () => { - let contract = generatedTypes.find(type => type.name === 'Contract') - expect( - contract.methods.map((method: any) => [method.name, method.returnType]), - ).toEqual([ + const contract = generatedTypes.find(type => type.name === 'Contract'); + expect(contract.methods.map((method: any) => [method.name, method.returnType])).toEqual([ ['bind', ts.namedType('Contract')], ['read', ts.namedType('Bytes')], ['try_read', 'ethereum.CallResult'], ['getProposal', ts.namedType('Contract__getProposalResultValue0Struct')], - [ - 'try_getProposal', - 'ethereum.CallResult', - ], + ['try_getProposal', 'ethereum.CallResult'], ['getProposals', ts.namedType('Contract__getProposalsResult')], ['try_getProposals', 'ethereum.CallResult'], ['overloaded', ts.namedType('string')], @@ -267,56 +259,52 @@ describe('ABI code generation', () => { ['try_overloaded1', 'ethereum.CallResult'], ['overloaded2', ts.namedType('string')], ['try_overloaded2', 'ethereum.CallResult'], - ]) - }) - }) + ]); + }); + }); describe('Tuples', () => { test('Tuple types exist for function parameters', () => { let tupleType = generatedTypes.find( type => type.name === 'Contract__getProposalInputParam1Struct', - ) + ); // Verify that the tuple type has methods - expect(tupleType.methods).toBeDefined() + expect(tupleType.methods).toBeDefined(); // Verify that the tuple type has getters for all tuple fields with // the right return types - expect( - tupleType.methods.map((method: any) => [method.name, method.returnType]), - ).toEqual([ + expect(tupleType.methods.map((method: any) => [method.name, method.returnType])).toEqual([ ['get foo', 'i32'], ['get bar', 'Contract__getProposalInputParam1BarStruct'], - ]) + ]); // Inner tuple: tupleType = generatedTypes.find( type => type.name === 'Contract__getProposalInputParam1BarStruct', - ) + ); // Verify that the tuple type has methods - expect(tupleType.methods).toBeDefined() + expect(tupleType.methods).toBeDefined(); // Verify that the tuple type has getters for all tuple fields with // the right return types - expect( - tupleType.methods.map((method: any) => [method.name, method.returnType]), - ).toEqual([['get baz', 'Address']]) - }) + expect(tupleType.methods.map((method: any) => [method.name, method.returnType])).toEqual([ + ['get baz', 'Address'], + ]); + }); test('Tuple types exist for function return values', () => { - let tupleType = generatedTypes.find( + const tupleType = generatedTypes.find( type => type.name === 'Contract__getProposalResultValue0Struct', - ) + ); // Verify that the tuple type has methods - expect(tupleType.methods).toBeDefined() + expect(tupleType.methods).toBeDefined(); // Verify that the tuple type has getters for all tuple fields with // the right return types - expect( - tupleType.methods.map((method: any) => [method.name, method.returnType]), - ).toEqual([ + expect(tupleType.methods.map((method: any) => [method.name, method.returnType])).toEqual([ ['get result', 'i32'], ['get target', 'Address'], ['get data', 'Bytes'], @@ -326,17 +314,17 @@ describe('ABI code generation', () => { ['get startTime', 'BigInt'], ['get yesCount', 'BigInt'], ['get noCount', 'BigInt'], - ]) - }) + ]); + }); test('Function bodies are generated correctly for tuple arrays', () => { - let contract = generatedTypes.find(type => type.name === 'Contract') - let getter = contract.methods.find((method: any) => method.name === 'getProposals') + const contract = generatedTypes.find(type => type.name === 'Contract'); + const getter = contract.methods.find((method: any) => method.name === 'getProposals'); - expect(getter.body).not.toContain('toTupleArray') + expect(getter.body).not.toContain('toTupleArray'); expect(getter.body).toContain( 'result[1].toTupleArray()', - ) - }) - }) -}) + ); + }); + }); +}); diff --git a/packages/cli/src/protocols/ethereum/codegen/abi.ts b/packages/cli/src/protocols/ethereum/codegen/abi.ts index cb2fa1d2..3a5d52db 100644 --- a/packages/cli/src/protocols/ethereum/codegen/abi.ts +++ b/packages/cli/src/protocols/ethereum/codegen/abi.ts @@ -1,23 +1,22 @@ -import immutable from 'immutable' -import fs from 'fs' -import yaml from 'yaml' -import request from 'sync-request' -import Web3EthAbi from 'web3-eth-abi' - -import * as tsCodegen from '../../../codegen/typescript' -import * as typesCodegen from '../../../codegen/types' -import * as util from '../../../codegen/util' -import ABI from '../abi' - -const doFixtureCodegen = fs.existsSync('./fixtures.yaml') +import fs from 'fs'; +import immutable from 'immutable'; +import request from 'sync-request'; +import Web3EthAbi from 'web3-eth-abi'; +import yaml from 'yaml'; +import * as typesCodegen from '../../../codegen/types'; +import * as tsCodegen from '../../../codegen/typescript'; +import * as util from '../../../codegen/util'; +import ABI from '../abi'; + +const doFixtureCodegen = fs.existsSync('./fixtures.yaml'); export default class AbiCodeGenerator { constructor(private abi: ABI) { - this.abi = abi + this.abi = abi; } generateModuleImports() { - let imports = [ + const imports = [ tsCodegen.moduleImports( [ // Ethereum integration @@ -35,15 +34,13 @@ export default class AbiCodeGenerator { ], '@graphprotocol/graph-ts', ), - ] + ]; if (doFixtureCodegen) { - imports.push( - tsCodegen.moduleImports(['newMockEvent'], 'matchstick-as/assembly/index'), - ) + imports.push(tsCodegen.moduleImports(['newMockEvent'], 'matchstick-as/assembly/index')); } - return imports + return imports; } generateTypes() { @@ -51,7 +48,7 @@ export default class AbiCodeGenerator { ...this._generateEventTypes(), ...this._generateSmartContractClass(), ...this._generateCallTypes(), - ] + ]; } _generateCallTypes() { @@ -63,17 +60,17 @@ export default class AbiCodeGenerator { fn.get('name') || (fn.get('type') === 'constructor' ? 'constructor' : 'default'), // @ts-expect-error improve typings of disambiguateNames to handle iterables setName: (fn, name) => fn.set('_alias', name), - }) as any[] + }) as any[]; callFunctions = callFunctions.map(fn => { - let fnAlias = fn.get('_alias') - let fnClassName = `${fnAlias.charAt(0).toUpperCase()}${fnAlias.slice(1)}Call` - let tupleClasses: any[] = [] + const fnAlias = fn.get('_alias'); + const fnClassName = `${fnAlias.charAt(0).toUpperCase()}${fnAlias.slice(1)}Call`; + const tupleClasses: any[] = []; // First, generate a class with the input getters - let inputsClassName = fnClassName + '__Inputs' - let inputsClass = tsCodegen.klass(inputsClassName, { export: true }) - inputsClass.addMember(tsCodegen.klassMember('_call', fnClassName)) + const inputsClassName = fnClassName + '__Inputs'; + const inputsClass = tsCodegen.klass(inputsClassName, { export: true }); + inputsClass.addMember(tsCodegen.klassMember('_call', fnClassName)); inputsClass.addMethod( tsCodegen.method( `constructor`, @@ -81,7 +78,7 @@ export default class AbiCodeGenerator { null, `this._call = call`, ), - ) + ); // Generate getters and classes for function inputs util @@ -93,21 +90,21 @@ export default class AbiCodeGenerator { setName: (input, name) => input.set('name', name), }) .forEach((input: any, index) => { - let callInput = this._generateInputOrOutput( + const callInput = this._generateInputOrOutput( input, index, fnClassName, `call`, `inputValues`, - ) - inputsClass.addMethod(callInput.getter) - tupleClasses.push(...callInput.classes) - }) + ); + inputsClass.addMethod(callInput.getter); + tupleClasses.push(...callInput.classes); + }); // Second, generate a class with the output getters - let outputsClassName = fnClassName + '__Outputs' - let outputsClass = tsCodegen.klass(outputsClassName, { export: true }) - outputsClass.addMember(tsCodegen.klassMember('_call', fnClassName)) + const outputsClassName = fnClassName + '__Outputs'; + const outputsClass = tsCodegen.klass(outputsClassName, { export: true }); + outputsClass.addMember(tsCodegen.klassMember('_call', fnClassName)); outputsClass.addMethod( tsCodegen.method( `constructor`, @@ -115,7 +112,7 @@ export default class AbiCodeGenerator { null, `this._call = call`, ), - ) + ); // Generate getters and classes for function outputs util @@ -127,22 +124,22 @@ export default class AbiCodeGenerator { setName: (output, name) => output.set('name', name), }) .forEach((output: any, index) => { - let callInput = this._generateInputOrOutput( + const callInput = this._generateInputOrOutput( output, index, fnClassName, `call`, `outputValues`, - ) - outputsClass.addMethod(callInput.getter) - tupleClasses.push(...callInput.classes) - }) + ); + outputsClass.addMethod(callInput.getter); + tupleClasses.push(...callInput.classes); + }); // Then, generate the event class itself - let klass = tsCodegen.klass(fnClassName, { + const klass = tsCodegen.klass(fnClassName, { export: true, extends: 'ethereum.Call', - }) + }); klass.addMethod( tsCodegen.method( `get inputs`, @@ -150,7 +147,7 @@ export default class AbiCodeGenerator { tsCodegen.namedType(inputsClassName), `return new ${inputsClassName}(this)`, ), - ) + ); klass.addMethod( tsCodegen.method( `get outputs`, @@ -158,15 +155,15 @@ export default class AbiCodeGenerator { tsCodegen.namedType(outputsClassName), `return new ${outputsClassName}(this)`, ), - ) - return [klass, inputsClass, outputsClass, ...tupleClasses] - }) + ); + return [klass, inputsClass, outputsClass, ...tupleClasses]; + }); return callFunctions.reduce( // flatten the array (array, classes) => array.concat(classes), [], - ) + ); } _generateEventTypes() { @@ -178,16 +175,16 @@ export default class AbiCodeGenerator { getName: event => event.get('name'), // @ts-expect-error improve typings of disambiguateNames to handle iterables setName: (event, name) => event.set('_alias', name), - }) as any[] + }) as any[]; events = events.map(event => { - let eventClassName = event.get('_alias') - let tupleClasses: any[] = [] + const eventClassName = event.get('_alias'); + const tupleClasses: any[] = []; // First, generate a class with the param getters - let paramsClassName = eventClassName + '__Params' - let paramsClass = tsCodegen.klass(paramsClassName, { export: true }) - paramsClass.addMember(tsCodegen.klassMember('_event', eventClassName)) + const paramsClassName = eventClassName + '__Params'; + const paramsClass = tsCodegen.klass(paramsClassName, { export: true }); + paramsClass.addMember(tsCodegen.klassMember('_event', eventClassName)); paramsClass.addMethod( tsCodegen.method( `constructor`, @@ -195,51 +192,46 @@ export default class AbiCodeGenerator { null, `this._event = event`, ), - ) + ); // Enumerate inputs with duplicate names - let inputs = util.disambiguateNames({ + const inputs = util.disambiguateNames({ values: event.get('inputs'), // @ts-expect-error improve typings of disambiguateNames to handle iterables getName: (input, index) => input.get('name') || `param${index}`, // @ts-expect-error improve typings of disambiguateNames to handle iterables setName: (input, name) => input.set('name', name), - }) as any[] + }) as any[]; - let namesAndTypes: any[] = [] + const namesAndTypes: any[] = []; inputs.forEach((input, index) => { // Generate getters and classes for event params - let paramObject = this._generateInputOrOutput( + const paramObject = this._generateInputOrOutput( input, index, eventClassName, `event`, `parameters`, - ) - paramsClass.addMethod(paramObject.getter) + ); + paramsClass.addMethod(paramObject.getter); // Fixture generation if (doFixtureCodegen) { - let ethType = typesCodegen.ethereumTypeForAsc( - String(paramObject.getter.returnType), - ) - if ( - typeof ethType !== 'string' && - (ethType.test('int256') || ethType.test('uint256')) - ) { - ethType = 'int32' + let ethType = typesCodegen.ethereumTypeForAsc(String(paramObject.getter.returnType)); + if (typeof ethType !== 'string' && (ethType.test('int256') || ethType.test('uint256'))) { + ethType = 'int32'; } - namesAndTypes.push({ name: paramObject.getter.name.slice(4), type: ethType }) + namesAndTypes.push({ name: paramObject.getter.name.slice(4), type: ethType }); } - tupleClasses.push(...paramObject.classes) - }) + tupleClasses.push(...paramObject.classes); + }); // Then, generate the event class itself - let klass = tsCodegen.klass(eventClassName, { + const klass = tsCodegen.klass(eventClassName, { export: true, extends: 'ethereum.Event', - }) + }); klass.addMethod( tsCodegen.method( `get params`, @@ -247,39 +239,39 @@ export default class AbiCodeGenerator { tsCodegen.namedType(paramsClassName), `return new ${paramsClassName}(this)`, ), - ) + ); // Fixture generation if (doFixtureCodegen) { - const args = yaml.parse(fs.readFileSync('./fixtures.yaml', 'utf8')) - const blockNumber = args['blockNumber'] - const contractAddr = args['contractAddr'] - const topic0 = args['topic0'] - const apiKey = args['apiKey'] - const url = `https://api.etherscan.io/api?module=logs&action=getLogs&fromBlock=${blockNumber}&toBlock=${blockNumber}&address=${contractAddr}&${topic0}=topic0&apikey=${apiKey}` - - let resp = request('GET', url) - let body = JSON.parse(resp.getBody('utf8')) + const args = yaml.parse(fs.readFileSync('./fixtures.yaml', 'utf8')); + const blockNumber = args['blockNumber']; + const contractAddr = args['contractAddr']; + const topic0 = args['topic0']; + const apiKey = args['apiKey']; + const url = `https://api.etherscan.io/api?module=logs&action=getLogs&fromBlock=${blockNumber}&toBlock=${blockNumber}&address=${contractAddr}&${topic0}=topic0&apikey=${apiKey}`; + + const resp = request('GET', url); + const body = JSON.parse(resp.getBody('utf8')); if (body.status === '0') { - throw new Error(body.result) + throw new Error(body.result); } - let res = Web3EthAbi + const res = Web3EthAbi // @ts-expect-error decodeLog seems to exist on Web3EthAbi - .decodeLog(namesAndTypes, body.result[0].data, []) + .decodeLog(namesAndTypes, body.result[0].data, []); - let stmnts = '' + let stmnts = ''; for (let i = 0; i < namesAndTypes.length; i++) { - let code = '"' + res[i] + '"' + let code = '"' + res[i] + '"'; if (namesAndTypes[i].type.toString() == 'address') { - code = `Address.fromString(${code})` + code = `Address.fromString(${code})`; } stmnts = stmnts.concat( - `event.parameters.push(new ethereum.EventParam(\"${ + `event.parameters.push(new ethereum.EventParam("${ namesAndTypes[i].name - }\", ${typesCodegen.ethereumFromAsc(code, namesAndTypes[i].type)}));`, + }", ${typesCodegen.ethereumFromAsc(code, namesAndTypes[i].type)}));`, `\n`, - ) + ); } klass.addMethod( @@ -293,17 +285,17 @@ export default class AbiCodeGenerator { return event; `, ), - ) + ); } - return [klass, paramsClass, ...tupleClasses] - }) + return [klass, paramsClass, ...tupleClasses]; + }); return events.reduce( // flatten the array (array, classes) => array.concat(classes), [], - ) + ); } _generateInputOrOutput( @@ -314,25 +306,19 @@ export default class AbiCodeGenerator { parentField?: string, ) { // Get name and type of the param, adjusting for indexed params and missing names - let name = inputOrOutput.get('name') - let valueType = + let name = inputOrOutput.get('name'); + const valueType = parentType === 'event' && inputOrOutput.get('indexed') ? this._indexedInputType(inputOrOutput.get('type')) - : inputOrOutput.get('type') + : inputOrOutput.get('type'); if (name === undefined || name === null || name === '') { - name = parentType === 'event' ? `param${index}` : `value${index}` + name = parentType === 'event' ? `param${index}` : `value${index}`; } // Generate getters and classes for the param (classes only created for Ethereum tuple types) return util.containsTupleType(valueType) - ? this._generateTupleType( - inputOrOutput, - index, - parentClass, - parentType, - parentField, - ) + ? this._generateTupleType(inputOrOutput, index, parentClass, parentType, parentField) : { name: [], getter: tsCodegen.method( @@ -349,16 +335,11 @@ export default class AbiCodeGenerator { `, ), classes: [], - } + }; } - _tupleTypeName( - inputOrOutput: any, - index: number, - parentClass: string, - parentType: string, - ) { - return this._generateTupleType(inputOrOutput, index, parentClass, parentType, '').name + _tupleTypeName(inputOrOutput: any, index: number, parentClass: string, parentType: string) { + return this._generateTupleType(inputOrOutput, index, parentClass, parentType, '').name; } _generateTupleType( @@ -368,27 +349,27 @@ export default class AbiCodeGenerator { parentType: string, parentField?: string, ) { - let type = inputOrOutput.get('type') - let name = inputOrOutput.get('name') + const type = inputOrOutput.get('type'); + let name = inputOrOutput.get('name'); if (name === undefined || name === null || name === '') { - name = parentType === 'event' ? `param${index}` : `value${index}` + name = parentType === 'event' ? `param${index}` : `value${index}`; } - let tupleIdentifier = parentClass + tsCodegen.namedType(name).capitalize() - let tupleClassName = tupleIdentifier + 'Struct' - let tupleClasses: any[] = [] + const tupleIdentifier = parentClass + tsCodegen.namedType(name).capitalize(); + const tupleClassName = tupleIdentifier + 'Struct'; + let tupleClasses: any[] = []; - let isTupleType = util.isTupleType(type) - let returnValue = typesCodegen.ethereumToAsc( + const isTupleType = util.isTupleType(type); + const returnValue = typesCodegen.ethereumToAsc( parentType === 'tuple' ? `this[${index}]` : `this._${parentType}.${parentField}[${index}].value`, type, tupleClassName, - ) + ); // Generate getter for parent class - let tupleGetter = tsCodegen.method( + const tupleGetter = tsCodegen.method( `get ${name}`, [], util.isTupleMatrixType(type) @@ -397,46 +378,39 @@ export default class AbiCodeGenerator { ? `Array<${tupleClassName}>` : tupleClassName, ` - return ${ - isTupleType ? `changetype<${tupleClassName}>(${returnValue})` : `${returnValue}` - } + return ${isTupleType ? `changetype<${tupleClassName}>(${returnValue})` : String(returnValue)} `, - ) + ); // Generate tuple class - let baseTupleClass = tsCodegen.klass(tupleClassName, { + const baseTupleClass = tsCodegen.klass(tupleClassName, { export: true, extends: 'ethereum.Tuple', - }) + }); // Add param getters to tuple class and generate classes for each tuple parameter inputOrOutput.get('components').forEach((component: any, index: number) => { - let paramObject = this._generateInputOrOutput( - component, - index, - tupleIdentifier, - `tuple`, - ) - baseTupleClass.addMethod(paramObject.getter) - tupleClasses = tupleClasses.concat(paramObject.classes) - }) + const paramObject = this._generateInputOrOutput(component, index, tupleIdentifier, `tuple`); + baseTupleClass.addMethod(paramObject.getter); + tupleClasses = tupleClasses.concat(paramObject.classes); + }); // Combine all tuple classes generated - tupleClasses.unshift(baseTupleClass) + tupleClasses.unshift(baseTupleClass); return { name: tupleClassName, getter: tupleGetter, classes: tupleClasses, - } + }; } _generateSmartContractClass() { - let klass = tsCodegen.klass(this.abi.name, { + const klass = tsCodegen.klass(this.abi.name, { export: true, extends: 'ethereum.SmartContract', - }) - let types = immutable.List() + }); + let types = immutable.List(); klass.addMethod( tsCodegen.staticMethod( @@ -450,10 +424,10 @@ export default class AbiCodeGenerator { return new ${this.abi.name}('${this.abi.name}', address); `, ), - ) + ); // Get view/pure functions from the contract - let functions = this.callableFunctions() + let functions = this.callableFunctions(); // Disambiguate functions with duplicate names functions = util.disambiguateNames({ @@ -463,34 +437,34 @@ export default class AbiCodeGenerator { getName: fn => fn.get('name'), // @ts-expect-error improve typings of disambiguateNames to handle iterables setName: (fn, name) => fn.set('_alias', name), - }) as any + }) as any; functions.forEach(member => { - let fnName = member.get('name') - let fnAlias = member.get('_alias') - let fnSignature = this.abi.functionSignature(member) + const fnName = member.get('name'); + const fnAlias = member.get('_alias'); + const fnSignature = this.abi.functionSignature(member); // Generate a type for the result of calling the function - let returnType: any = undefined - let simpleReturnType = true - let tupleResultParentType = this.abi.name + '__' + fnAlias + 'Result' + let returnType: any = undefined; + let simpleReturnType = true; + const tupleResultParentType = this.abi.name + '__' + fnAlias + 'Result'; // Disambiguate outputs with duplicate names - let outputs = util.disambiguateNames({ + const outputs = util.disambiguateNames({ values: member.get('outputs', immutable.List()), // @ts-expect-error improve typings of disambiguateNames to handle iterables getName: (input, index) => input.get('name') || `value${index}`, // @ts-expect-error improve typings of disambiguateNames to handle iterables setName: (input, name) => input.set('name', name), - }) as any + }) as any; if (member.get('outputs', immutable.List()).size > 1) { - simpleReturnType = false + simpleReturnType = false; // Create a type dedicated to holding the return values returnType = tsCodegen.klass(this.abi.name + '__' + fnAlias + 'Result', { export: true, - }) + }); // Add a constructor to this type returnType.addMethod( @@ -507,7 +481,7 @@ export default class AbiCodeGenerator { .map((_output: any, index: number) => `this.value${index} = value${index}`) .join('\n'), ), - ) + ); // Add a `toMap(): TypedMap` function to the return type returnType.addMethod( @@ -529,7 +503,7 @@ export default class AbiCodeGenerator { return map; `, ), - ) + ); // Add value0, value1 etc. members to the type outputs @@ -539,7 +513,7 @@ export default class AbiCodeGenerator { this._getTupleParamType(output, index, tupleResultParentType), ), ) - .forEach((member: any) => returnType.addMember(member)) + .forEach((member: any) => returnType.addMember(member)); // Add getters to the type outputs @@ -553,7 +527,7 @@ export default class AbiCodeGenerator { `return this.value${index};`, ), ) - .forEach((method: any) => !!method && returnType.addMethod(method)) + .forEach((method: any) => !!method && returnType.addMethod(method)); // Create types for Tuple outputs outputs.forEach((output: any, index: number) => { @@ -566,71 +540,66 @@ export default class AbiCodeGenerator { 'function', this.abi.name, ).classes, - ) + ); } - }) + }); // Add the type to the types we'll create - types = types.push(returnType) + types = types.push(returnType); - returnType = tsCodegen.namedType(returnType.name) + returnType = tsCodegen.namedType(returnType.name); } else { - let type = outputs.get(0).get('type') + const type = outputs.get(0).get('type'); if (util.containsTupleType(type)) { // Add the Tuple type to the types we'll create - let tuple = this._generateTupleType( + const tuple = this._generateTupleType( outputs.get(0), 0, tupleResultParentType, 'function', this.abi.name, - ) - types = types.concat(tuple.classes) + ); + types = types.concat(tuple.classes); returnType = util.isTupleType(type) ? tsCodegen.namedType(tuple.name) - : `Array<${tsCodegen.namedType(tuple.name)}>` + : `Array<${tsCodegen.namedType(tuple.name)}>`; } else { - returnType = tsCodegen.namedType(typesCodegen.ascTypeForEthereum(type)) + returnType = tsCodegen.namedType(typesCodegen.ascTypeForEthereum(type)); } } // Disambiguate inputs with duplicate names - let inputs = util.disambiguateNames({ + const inputs = util.disambiguateNames({ values: member.get('inputs', immutable.List()), // @ts-expect-error improve typings of disambiguateNames to handle iterables getName: (input, index) => input.get('name') || `param${index}`, // @ts-expect-error improve typings of disambiguateNames to handle iterables setName: (input, name) => input.set('name', name), - }) as any + }) as any; // Generate a type prefix to identify the Tuple inputs to a function - let tupleInputParentType = this.abi.name + '__' + fnAlias + 'Input' + const tupleInputParentType = this.abi.name + '__' + fnAlias + 'Input'; // Create types for Tuple inputs inputs.forEach((input: any, index: number) => { if (util.containsTupleType(input.get('type'))) { types = types.concat( - this._generateTupleType( - input, - index, - tupleInputParentType, - 'function', - this.abi.name, - ).classes, - ) + this._generateTupleType(input, index, tupleInputParentType, 'function', this.abi.name) + .classes, + ); } - }) + }); // Generate and add a method that implements calling the function on // the smart contract - let params = inputs.map((input: any, index: number) => + const params = inputs.map((input: any, index: number) => tsCodegen.param( input.get('name'), this._getTupleParamType(input, index, tupleInputParentType), ), - ) + ); - let superInputs = ` + const superInputs = ` '${fnName}', '${fnSignature}', [${ @@ -642,9 +611,9 @@ export default class AbiCodeGenerator { .map((coercion: any) => coercion.toString()) .join(', ') : '' - }]` + }]`; - let methodCallBody = (isTry: boolean) => { + const methodCallBody = (isTry: boolean) => { const methodBody = ` ${ isTry @@ -659,19 +628,14 @@ export default class AbiCodeGenerator { let result = super.call(${superInputs}) return (` - }` + }`; const returnVal = simpleReturnType ? typesCodegen.ethereumToAsc( isTry ? 'value[0]' : 'result[0]', outputs.get(0).get('type'), util.isTupleArrayType(outputs.get(0).get('type')) - ? this._tupleTypeName( - outputs.get(0), - 0, - tupleResultParentType, - this.abi.name, - ) + ? this._tupleTypeName(outputs.get(0), 0, tupleResultParentType, this.abi.name) : '', ) : `new ${returnType.name}( @@ -681,14 +645,9 @@ export default class AbiCodeGenerator { isTry ? `value[${index}]` : `result[${index}]`, output.get('type'), util.isTupleArrayType(output.get('type')) - ? this._tupleTypeName( - output, - index, - tupleResultParentType, - this.abi.name, - ) + ? this._tupleTypeName(output, index, tupleResultParentType, this.abi.name) : '', - ) + ); return util.isTupleType(output.get('type')) ? `changetype<${this._tupleTypeName( output, @@ -696,21 +655,17 @@ export default class AbiCodeGenerator { tupleResultParentType, this.abi.name, )}>(${val})` - : val + : val; }) .join(', ')} - )` + )`; - const isTuple = util.isTupleType(outputs.get(0).get('type')) - return `${methodBody} ${ - isTuple ? `changetype<${returnType}>(${returnVal})` : returnVal - })` - } + const isTuple = util.isTupleType(outputs.get(0).get('type')); + return `${methodBody} ${isTuple ? `changetype<${returnType}>(${returnVal})` : returnVal})`; + }; // Generate method with an without `try_`. - klass.addMethod( - tsCodegen.method(fnAlias, params, returnType, methodCallBody(false)), - ) + klass.addMethod(tsCodegen.method(fnAlias, params, returnType, methodCallBody(false))); klass.addMethod( tsCodegen.method( 'try_' + fnAlias, @@ -718,31 +673,21 @@ export default class AbiCodeGenerator { 'ethereum.CallResult<' + returnType + '>', methodCallBody(true), ), - ) - }) + ); + }); - return [...types, klass] + return [...types, klass]; } _getTupleParamType(inputOrOutput: any, index: number, tupleParentType: string) { - const type = inputOrOutput.get('type') + const type = inputOrOutput.get('type'); return util.isTupleType(type) ? this._tupleTypeName(inputOrOutput, index, tupleParentType, this.abi.name) : util.isTupleMatrixType(type) - ? `Array>` + ? `Array>` : util.isTupleArrayType(type) - ? `Array<${this._tupleTypeName( - inputOrOutput, - index, - tupleParentType, - this.abi.name, - )}>` - : typesCodegen.ascTypeForEthereum(type) + ? `Array<${this._tupleTypeName(inputOrOutput, index, tupleParentType, this.abi.name)}>` + : typesCodegen.ascTypeForEthereum(type); } _indexedInputType(inputType: string) { @@ -756,20 +701,19 @@ export default class AbiCodeGenerator { // brackets and, optionally, a number inside the brackets inputType.match(/\[[0-9]*\]$/g) ) { - return 'bytes32' - } else { - return inputType + return 'bytes32'; } + return inputType; } callableFunctions() { - let allowedMutability = ['view', 'pure', 'nonpayable', 'constant'] + const allowedMutability = ['view', 'pure', 'nonpayable', 'constant']; return this.abi.data.filter( member => member.get('type') === 'function' && member.get('outputs', immutable.List()).size !== 0 && (allowedMutability.includes(member.get('stateMutability')) || (member.get('stateMutability') === undefined && !member.get('payable', false))), - ) + ); } } diff --git a/packages/cli/src/protocols/ethereum/codegen/template.ts b/packages/cli/src/protocols/ethereum/codegen/template.ts index 811ebdd7..5a7731dc 100644 --- a/packages/cli/src/protocols/ethereum/codegen/template.ts +++ b/packages/cli/src/protocols/ethereum/codegen/template.ts @@ -1,17 +1,17 @@ -import immutable from 'immutable' -import * as tsCodegen from '../../../codegen/typescript' +import immutable from 'immutable'; +import * as tsCodegen from '../../../codegen/typescript'; export default class EthereumTemplateCodeGen { constructor(public template: immutable.Map) { - this.template = template + this.template = template; } generateModuleImports() { - return ['Address'] + return ['Address']; } generateCreateMethod() { - const name = this.template.get('name') + const name = this.template.get('name'); return tsCodegen.staticMethod( 'create', @@ -20,11 +20,11 @@ export default class EthereumTemplateCodeGen { ` DataSourceTemplate.create('${name}', [address.toHex()]) `, - ) + ); } generateCreateWithContextMethod() { - const name = this.template.get('name') + const name = this.template.get('name'); return tsCodegen.staticMethod( 'createWithContext', @@ -36,6 +36,6 @@ export default class EthereumTemplateCodeGen { ` DataSourceTemplate.createWithContext('${name}', [address.toHex()], context) `, - ) + ); } } diff --git a/packages/cli/src/protocols/ethereum/contract.ts b/packages/cli/src/protocols/ethereum/contract.ts index a1c84a69..8bfe939f 100644 --- a/packages/cli/src/protocols/ethereum/contract.ts +++ b/packages/cli/src/protocols/ethereum/contract.ts @@ -1,25 +1,24 @@ -import { Contract } from '../contract' +import { Contract } from '../contract'; export default class EthereumContract implements Contract { static identifierName() { - return 'address' + return 'address'; } constructor(private address: string) { - this.address = address + this.address = address; } validate() { - const pattern = /^(0x)?[0-9a-fA-F]{40}$/ + const pattern = /^(0x)?[0-9a-fA-F]{40}$/; - const errorMessage = - "Must be 40 hexadecimal characters, with an optional '0x' prefix." + const errorMessage = "Must be 40 hexadecimal characters, with an optional '0x' prefix."; - const valid = pattern.test(this.address) + const valid = pattern.test(this.address); return { valid, error: valid ? null : errorMessage, - } + }; } } diff --git a/packages/cli/src/protocols/ethereum/scaffold/manifest.ts b/packages/cli/src/protocols/ethereum/scaffold/manifest.ts index 5d62dd2f..933d7040 100644 --- a/packages/cli/src/protocols/ethereum/scaffold/manifest.ts +++ b/packages/cli/src/protocols/ethereum/scaffold/manifest.ts @@ -1,16 +1,10 @@ -import { abiEvents } from '../../../scaffold/schema' -import { strings } from 'gluegun' -import ABI from '../abi' +import { strings } from 'gluegun'; +import { abiEvents } from '../../../scaffold/schema'; +import ABI from '../abi'; -export const source = ({ - contract, - contractName, -}: { - contract: string - contractName: string -}) => ` +export const source = ({ contract, contractName }: { contract: string; contractName: string }) => ` address: '${contract}' - abi: ${contractName}` + abi: ${contractName}`; export const mapping = ({ abi, contractName }: { abi: ABI; contractName: string }) => ` kind: ethereum/events @@ -31,4 +25,4 @@ export const mapping = ({ abi, contractName }: { abi: ABI; contractName: string handler: handle${event.get('_alias')}`, ) .join('')} - file: ./src/${strings.kebabCase(contractName)}.ts` + file: ./src/${strings.kebabCase(contractName)}.ts`; diff --git a/packages/cli/src/protocols/ethereum/scaffold/mapping.ts b/packages/cli/src/protocols/ethereum/scaffold/mapping.ts index 49a4d6ce..470de373 100644 --- a/packages/cli/src/protocols/ethereum/scaffold/mapping.ts +++ b/packages/cli/src/protocols/ethereum/scaffold/mapping.ts @@ -1,14 +1,14 @@ -import { generateEventFieldAssignments } from '../../../scaffold/mapping' -import ABI from '../abi' +import { generateEventFieldAssignments } from '../../../scaffold/mapping'; +import ABI from '../abi'; export const generatePlaceholderHandlers = ({ abi, events, contractName, }: { - abi: ABI - events: any[] - contractName: string + abi: ABI; + events: any[]; + contractName: string; }) => ` import { BigInt } from '@graphprotocol/graph-ts' @@ -73,4 +73,4 @@ export const generatePlaceholderHandlers = ({ export function handle${event._alias}(event: ${event._alias}): void {} `, ) - .join('\n')}` + .join('\n')}`; diff --git a/packages/cli/src/protocols/ethereum/subgraph.ts b/packages/cli/src/protocols/ethereum/subgraph.ts index 818a3588..8ed0e910 100644 --- a/packages/cli/src/protocols/ethereum/subgraph.ts +++ b/packages/cli/src/protocols/ethereum/subgraph.ts @@ -1,30 +1,25 @@ -import immutable from 'immutable' -import { Subgraph, SubgraphOptions } from '../subgraph' -import ABI from './abi' -import * as DataSourcesExtractor from '../../command-helpers/data-sources' +import immutable from 'immutable'; +import * as DataSourcesExtractor from '../../command-helpers/data-sources'; +import { Subgraph, SubgraphOptions } from '../subgraph'; +import ABI from './abi'; export default class EthereumSubgraph implements Subgraph { - public manifest: SubgraphOptions['manifest'] - public resolveFile: SubgraphOptions['resolveFile'] - public protocol: SubgraphOptions['protocol'] + public manifest: SubgraphOptions['manifest']; + public resolveFile: SubgraphOptions['resolveFile']; + public protocol: SubgraphOptions['protocol']; constructor(options: SubgraphOptions) { - this.manifest = options.manifest - this.resolveFile = options.resolveFile - this.protocol = options.protocol + this.manifest = options.manifest; + this.resolveFile = options.resolveFile; + this.protocol = options.protocol; } validateManifest() { - return this.validateAbis() - .concat(this.validateEvents()) - .concat(this.validateCallFunctions()) + return this.validateAbis().concat(this.validateEvents()).concat(this.validateCallFunctions()); } validateAbis() { - const dataSourcesAndTemplates = DataSourcesExtractor.fromManifest( - this.manifest, - this.protocol, - ) + const dataSourcesAndTemplates = DataSourcesExtractor.fromManifest(this.manifest, this.protocol); return dataSourcesAndTemplates.reduce( (errors: any[], dataSourceOrTemplate: any) => @@ -35,17 +30,15 @@ export default class EthereumSubgraph implements Subgraph { ), ), immutable.List(), - ) + ); } validateDataSourceAbis(dataSource: any, path: string) { // Validate that the the "source > abi" reference of all data sources // points to an existing ABI in the data source ABIs - let abiName = dataSource.getIn(['source', 'abi']) - let abiNames = dataSource - .getIn(['mapping', 'abis']) - .map((abi: any) => abi.get('name')) - let nameErrors = abiNames.includes(abiName) + const abiName = dataSource.getIn(['source', 'abi']); + const abiNames = dataSource.getIn(['mapping', 'abis']).map((abi: any) => abi.get('name')); + const nameErrors = abiNames.includes(abiName) ? immutable.List() : immutable.fromJS([ { @@ -58,33 +51,30 @@ ${abiNames .map((name: string) => `- ${name}`) .join('\n')}`, }, - ]) + ]); // Validate that all ABI files are valid - let fileErrors = dataSource + const fileErrors = dataSource .getIn(['mapping', 'abis']) .reduce((errors: any[], abi: any, abiIndex: number) => { try { - ABI.load(abi.get('name'), this.resolveFile(abi.get('file'))) - return errors + ABI.load(abi.get('name'), this.resolveFile(abi.get('file'))); + return errors; } catch (e) { return errors.push( immutable.fromJS({ path: [...path, 'mapping', 'abis', abiIndex, 'file'], message: e.message, }), - ) + ); } - }, immutable.List()) + }, immutable.List()); - return nameErrors.concat(fileErrors) + return nameErrors.concat(fileErrors); } validateEvents() { - const dataSourcesAndTemplates = DataSourcesExtractor.fromManifest( - this.manifest, - this.protocol, - ) + const dataSourcesAndTemplates = DataSourcesExtractor.fromManifest(this.manifest, this.protocol); return dataSourcesAndTemplates.reduce((errors: any[], dataSourceOrTemplate: any) => { return errors.concat( @@ -92,32 +82,32 @@ ${abiNames dataSourceOrTemplate.get('dataSource'), dataSourceOrTemplate.get('path'), ), - ) - }, immutable.List()) + ); + }, immutable.List()); } validateDataSourceEvents(dataSource: any, path: string) { - let abi: ABI + let abi: ABI; try { // Resolve the source ABI name into a real ABI object - let abiName = dataSource.getIn(['source', 'abi']) - let abiEntry = dataSource + const abiName = dataSource.getIn(['source', 'abi']); + const abiEntry = dataSource .getIn(['mapping', 'abis']) - .find((abi: any) => abi.get('name') === abiName) - abi = ABI.load(abiEntry.get('name'), this.resolveFile(abiEntry.get('file'))) + .find((abi: any) => abi.get('name') === abiName); + abi = ABI.load(abiEntry.get('name'), this.resolveFile(abiEntry.get('file'))); } catch (_) { // Ignore errors silently; we can't really say anything about // the events if the ABI can't even be loaded - return immutable.List() + return immutable.List(); } // Obtain event signatures from the mapping - let manifestEvents = dataSource + const manifestEvents = dataSource .getIn(['mapping', 'eventHandlers'], immutable.List()) - .map((handler: any) => handler.get('event')) + .map((handler: any) => handler.get('event')); // Obtain event signatures from the ABI - let abiEvents = abi.eventSignatures() + const abiEvents = abi.eventSignatures(); // Add errors for every manifest event signature that is not // present in the ABI @@ -138,7 +128,7 @@ ${abiEvents }), ), immutable.List(), - ) + ); } validateCallFunctions() { @@ -146,29 +136,29 @@ ${abiEvents .get('dataSources') .filter((dataSource: any) => this.protocol.isValidKindName(dataSource.get('kind'))) .reduce((errors: any[], dataSource: any, dataSourceIndex: string) => { - let path = ['dataSources', dataSourceIndex, 'callHandlers'] + const path = ['dataSources', dataSourceIndex, 'callHandlers']; - let abi: ABI + let abi: ABI; try { // Resolve the source ABI name into a real ABI object - let abiName = dataSource.getIn(['source', 'abi']) - let abiEntry = dataSource + const abiName = dataSource.getIn(['source', 'abi']); + const abiEntry = dataSource .getIn(['mapping', 'abis']) - .find((abi: any) => abi.get('name') === abiName) - abi = ABI.load(abiEntry.get('name'), this.resolveFile(abiEntry.get('file'))) + .find((abi: any) => abi.get('name') === abiName); + abi = ABI.load(abiEntry.get('name'), this.resolveFile(abiEntry.get('file'))); } catch (e) { // Ignore errors silently; we can't really say anything about // the call functions if the ABI can't even be loaded - return errors + return errors; } // Obtain event signatures from the mapping - let manifestFunctions = dataSource + const manifestFunctions = dataSource .getIn(['mapping', 'callHandlers'], immutable.List()) - .map((handler: any) => handler.get('function')) + .map((handler: any) => handler.get('function')); // Obtain event signatures from the ABI - let abiFunctions = abi.callFunctionSignatures() + const abiFunctions = abi.callFunctionSignatures(); // Add errors for every manifest event signature that is not // present in the ABI @@ -189,11 +179,11 @@ ${abiFunctions }), ), errors, - ) - }, immutable.List()) + ); + }, immutable.List()); } handlerTypes() { - return immutable.List(['blockHandlers', 'callHandlers', 'eventHandlers']) + return immutable.List(['blockHandlers', 'callHandlers', 'eventHandlers']); } } diff --git a/packages/cli/src/protocols/ethereum/type-generator.ts b/packages/cli/src/protocols/ethereum/type-generator.ts index 990c3218..ed65bbe7 100644 --- a/packages/cli/src/protocols/ethereum/type-generator.ts +++ b/packages/cli/src/protocols/ethereum/type-generator.ts @@ -1,20 +1,20 @@ -import fs from 'fs-extra' -import path from 'path' -import immutable from 'immutable' -import prettier from 'prettier' -import ABI from './abi' -import { Spinner, step, withSpinner } from '../../command-helpers/spinner' -import { GENERATED_FILE_NOTE } from '../../codegen/typescript' -import { displayPath } from '../../command-helpers/fs' -import { TypeGeneratorOptions } from '../../type-generator' +import path from 'path'; +import fs from 'fs-extra'; +import immutable from 'immutable'; +import prettier from 'prettier'; +import { GENERATED_FILE_NOTE } from '../../codegen/typescript'; +import { displayPath } from '../../command-helpers/fs'; +import { Spinner, step, withSpinner } from '../../command-helpers/spinner'; +import { TypeGeneratorOptions } from '../../type-generator'; +import ABI from './abi'; export default class EthereumTypeGenerator { - private sourceDir: TypeGeneratorOptions['sourceDir'] - private outputDir: TypeGeneratorOptions['outputDir'] + private sourceDir: TypeGeneratorOptions['sourceDir']; + private outputDir: TypeGeneratorOptions['outputDir']; constructor(options: TypeGeneratorOptions) { - this.sourceDir = options.sourceDir - this.outputDir = options.outputDir + this.sourceDir = options.sourceDir; + this.outputDir = options.outputDir; } async loadABIs(subgraph: immutable.Map) { @@ -33,35 +33,29 @@ export default class EthereumTypeGenerator { .reduce( (abis: any[], abi: any) => abis.push( - this._loadABI( - dataSource, - abi.get('name'), - abi.get('file'), - spinner, - ), + this._loadABI(dataSource, abi.get('name'), abi.get('file'), spinner), ), abis, ), immutable.List(), - ) + ); } catch (e) { - throw Error(`Failed to load contract ABIs: ${e.message}`) + throw Error(`Failed to load contract ABIs: ${e.message}`); } }, - ) + ); } _loadABI(dataSource: any, name: string, maybeRelativePath: string, spinner: Spinner) { try { if (this.sourceDir) { - let absolutePath = path.resolve(this.sourceDir, maybeRelativePath) - step(spinner, `Load contract ABI from`, displayPath(absolutePath)) - return { dataSource: dataSource, abi: ABI.load(name, absolutePath) } - } else { - return { dataSource: dataSource, abi: ABI.load(name, maybeRelativePath) } + const absolutePath = path.resolve(this.sourceDir, maybeRelativePath); + step(spinner, `Load contract ABI from`, displayPath(absolutePath)); + return { dataSource, abi: ABI.load(name, absolutePath) }; } + return { dataSource, abi: ABI.load(name, maybeRelativePath) }; } catch (e) { - throw Error(`Failed to load contract ABI: ${e.message}`) + throw Error(`Failed to load contract ABI: ${e.message}`); } } @@ -71,22 +65,17 @@ export default class EthereumTypeGenerator { `Failed to load data source template ABIs`, `Warnings while loading data source template ABIs`, async spinner => { - let abis = [] - for (let template of subgraph.get('templates', immutable.List())) { - for (let abi of template.getIn(['mapping', 'abis'])) { + const abis = []; + for (const template of subgraph.get('templates', immutable.List())) { + for (const abi of template.getIn(['mapping', 'abis'])) { abis.push( - this._loadDataSourceTemplateABI( - template, - abi.get('name'), - abi.get('file'), - spinner, - ), - ) + this._loadDataSourceTemplateABI(template, abi.get('name'), abi.get('file'), spinner), + ); } } - return abis + return abis; }, - ) + ); } _loadDataSourceTemplateABI( @@ -97,14 +86,13 @@ export default class EthereumTypeGenerator { ) { try { if (this.sourceDir) { - let absolutePath = path.resolve(this.sourceDir, maybeRelativePath) - step(spinner, `Load data source template ABI from`, displayPath(absolutePath)) - return { template, abi: ABI.load(name, absolutePath) } - } else { - return { template, abi: ABI.load(name, maybeRelativePath) } + const absolutePath = path.resolve(this.sourceDir, maybeRelativePath); + step(spinner, `Load data source template ABI from`, displayPath(absolutePath)); + return { template, abi: ABI.load(name, absolutePath) }; } + return { template, abi: ABI.load(name, maybeRelativePath) }; } catch (e) { - throw Error(`Failed to load data source template ABI: ${e.message}`) + throw Error(`Failed to load data source template ABI: ${e.message}`); } } @@ -116,9 +104,9 @@ export default class EthereumTypeGenerator { async spinner => { return await Promise.all( abis.map(async abi => await this._generateTypesForABI(abi, spinner)), - ) + ); }, - ) + ); } async _generateTypesForABI(abi: any, spinner: Spinner) { @@ -127,10 +115,10 @@ export default class EthereumTypeGenerator { spinner, `Generate types for contract ABI:`, `${abi.abi.name} (${displayPath(abi.abi.file)})`, - ) + ); - let codeGenerator = abi.abi.codeGenerator() - let code = prettier.format( + const codeGenerator = abi.abi.codeGenerator(); + const code = prettier.format( [ GENERATED_FILE_NOTE, ...codeGenerator.generateModuleImports(), @@ -139,18 +127,18 @@ export default class EthereumTypeGenerator { { parser: 'typescript', }, - ) + ); - let outputFile = path.join( + const outputFile = path.join( this.outputDir, abi.dataSource.get('name'), `${abi.abi.name}.ts`, - ) - step(spinner, `Write types to`, displayPath(outputFile)) - await fs.mkdirs(path.dirname(outputFile)) - await fs.writeFile(outputFile, code) + ); + step(spinner, `Write types to`, displayPath(outputFile)); + await fs.mkdirs(path.dirname(outputFile)); + await fs.writeFile(outputFile, code); } catch (e) { - throw Error(`Failed to generate types for contract ABI: ${e.message}`) + throw Error(`Failed to generate types for contract ABI: ${e.message}`); } } @@ -161,12 +149,10 @@ export default class EthereumTypeGenerator { `Warnings while generating types for data source template ABIs`, async spinner => { return await Promise.all( - abis.map( - async abi => await this._generateTypesForDataSourceTemplateABI(abi, spinner), - ), - ) + abis.map(async abi => await this._generateTypesForDataSourceTemplateABI(abi, spinner)), + ); }, - ) + ); } async _generateTypesForDataSourceTemplateABI(abi: any, spinner: Spinner) { @@ -175,10 +161,10 @@ export default class EthereumTypeGenerator { spinner, `Generate types for data source template ABI:`, `${abi.template.get('name')} > ${abi.abi.name} (${displayPath(abi.abi.file)})`, - ) + ); - let codeGenerator = abi.abi.codeGenerator() - let code = prettier.format( + const codeGenerator = abi.abi.codeGenerator(); + const code = prettier.format( [ GENERATED_FILE_NOTE, ...codeGenerator.generateModuleImports(), @@ -187,19 +173,19 @@ export default class EthereumTypeGenerator { { parser: 'typescript', }, - ) + ); - let outputFile = path.join( + const outputFile = path.join( this.outputDir, 'templates', abi.template.get('name'), `${abi.abi.name}.ts`, - ) - step(spinner, `Write types to`, displayPath(outputFile)) - await fs.mkdirs(path.dirname(outputFile)) - await fs.writeFile(outputFile, code) + ); + step(spinner, `Write types to`, displayPath(outputFile)); + await fs.mkdirs(path.dirname(outputFile)); + await fs.writeFile(outputFile, code); } catch (e) { - throw Error(`Failed to generate types for data source template ABI: ${e.message}`) + throw Error(`Failed to generate types for data source template ABI: ${e.message}`); } } } diff --git a/packages/cli/src/protocols/index.ts b/packages/cli/src/protocols/index.ts index f368c778..65a9d91d 100644 --- a/packages/cli/src/protocols/index.ts +++ b/packages/cli/src/protocols/index.ts @@ -1,60 +1,60 @@ -import immutable from 'immutable' -import ArweaveSubgraph from './arweave/subgraph' -import EthereumTypeGenerator from './ethereum/type-generator' -import EthereumTemplateCodeGen from './ethereum/codegen/template' -import EthereumABI from './ethereum/abi' -import EthereumSubgraph from './ethereum/subgraph' -import NearSubgraph from './near/subgraph' -import CosmosSubgraph from './cosmos/subgraph' -import SubstreamsSubgraph from './substreams/subgraph' -import EthereumContract from './ethereum/contract' -import NearContract from './near/contract' -import * as ArweaveManifestScaffold from './arweave/scaffold/manifest' -import * as EthereumManifestScaffold from './ethereum/scaffold/manifest' -import * as NearManifestScaffold from './near/scaffold/manifest' -import * as CosmosManifestScaffold from './cosmos/scaffold/manifest' -import * as SubstreamsManifestScaffold from './substreams/scaffold/manifest' -import * as ArweaveMappingScaffold from './arweave/scaffold/mapping' -import * as EthereumMappingScaffold from './ethereum/scaffold/mapping' -import * as NearMappingScaffold from './near/scaffold/mapping' -import * as CosmosMappingScaffold from './cosmos/scaffold/mapping' -import debug from '../debug' -import Subgraph from '../subgraph' -import { SubgraphOptions } from './subgraph' -import { ContractCtor } from './contract' - -let protocolDebug = debug('graph-cli:protocol') +import immutable from 'immutable'; +import debug from '../debug'; +import Subgraph from '../subgraph'; +import * as ArweaveManifestScaffold from './arweave/scaffold/manifest'; +import * as ArweaveMappingScaffold from './arweave/scaffold/mapping'; +import ArweaveSubgraph from './arweave/subgraph'; +import { ContractCtor } from './contract'; +import * as CosmosManifestScaffold from './cosmos/scaffold/manifest'; +import * as CosmosMappingScaffold from './cosmos/scaffold/mapping'; +import CosmosSubgraph from './cosmos/subgraph'; +import EthereumABI from './ethereum/abi'; +import EthereumTemplateCodeGen from './ethereum/codegen/template'; +import EthereumContract from './ethereum/contract'; +import * as EthereumManifestScaffold from './ethereum/scaffold/manifest'; +import * as EthereumMappingScaffold from './ethereum/scaffold/mapping'; +import EthereumSubgraph from './ethereum/subgraph'; +import EthereumTypeGenerator from './ethereum/type-generator'; +import NearContract from './near/contract'; +import * as NearManifestScaffold from './near/scaffold/manifest'; +import * as NearMappingScaffold from './near/scaffold/mapping'; +import NearSubgraph from './near/subgraph'; +import { SubgraphOptions } from './subgraph'; +import * as SubstreamsManifestScaffold from './substreams/scaffold/manifest'; +import SubstreamsSubgraph from './substreams/subgraph'; + +const protocolDebug = debug('graph-cli:protocol'); export default class Protocol { static fromDataSources(dataSourcesAndTemplates: any) { - const firstDataSourceKind = dataSourcesAndTemplates[0].kind - return new Protocol(firstDataSourceKind) + const firstDataSourceKind = dataSourcesAndTemplates[0].kind; + return new Protocol(firstDataSourceKind); } - name: ProtocolName + name: ProtocolName; // TODO: should assert non null? see the constructor switch default case comment - config!: ProtocolConfig + config!: ProtocolConfig; constructor(name: ProtocolName) { - this.name = Protocol.normalizeName(name)! + this.name = Protocol.normalizeName(name)!; switch (this.name) { case 'arweave': - this.config = arweaveProtocol - break + this.config = arweaveProtocol; + break; case 'cosmos': - this.config = cosmosProtocol - break + this.config = cosmosProtocol; + break; case 'ethereum': - this.config = ethereumProtocol - break + this.config = ethereumProtocol; + break; case 'near': - this.config = nearProtocol - break + this.config = nearProtocol; + break; case 'substreams': - this.config = substreamsProtocol - break + this.config = substreamsProtocol; + break; default: // Do not throw when undefined, a better error message is printed after the constructor // when validating the Subgraph itself @@ -70,7 +70,7 @@ export default class Protocol { near: ['near'], cosmos: ['cosmos'], substreams: ['substreams'], - }) as immutable.Collection + }) as immutable.Collection; } static availableNetworks() { @@ -114,110 +114,105 @@ export default class Protocol { 'juno-1', 'uni-3', // Juno testnet ], - }) as immutable.Map< - 'arweave' | 'ethereum' | 'near' | 'cosmos' | 'substreams', - string[] - > + }) as immutable.Map<'arweave' | 'ethereum' | 'near' | 'cosmos' | 'substreams', string[]>; - let allNetworks: string[] = [] + const allNetworks: string[] = []; networks.forEach(value => { - allNetworks.push(...value) - }) + allNetworks.push(...value); + }); - networks = networks.set('substreams', allNetworks) + networks = networks.set('substreams', allNetworks); - return networks + return networks; } static normalizeName(name: ProtocolName) { return Protocol.availableProtocols().findKey(possibleNames => { - return possibleNames.includes(name) - })! + return possibleNames.includes(name); + })!; } displayName() { - return this.config?.displayName + return this.config?.displayName; } // Receives a data source kind, and checks if it's valid // for the given protocol instance (this). isValidKindName(kind: string) { - return Protocol.availableProtocols().get(this.name, immutable.List()).includes(kind) + return Protocol.availableProtocols().get(this.name, immutable.List()).includes(kind); } hasABIs() { - return this.config.abi != null + return this.config.abi != null; } hasContract() { - return this.config.contract != null + return this.config.contract != null; } hasEvents() { // A problem with hasEvents usage in the codebase is that it's almost every where // where used, the ABI data is actually use after the conditional, so it seems // both concept are related. So internally, we map to this condition. - return this.hasABIs() + return this.hasABIs(); } hasTemplates() { - return this.config.getTemplateCodeGen != null + return this.config.getTemplateCodeGen != null; } hasDataSourceMappingFile() { - return this.getMappingScaffold() != null + return this.getMappingScaffold() != null; } getTypeGenerator(options: any) { if (this.config == null || this.config.getTypeGenerator == null) { - return null + return null; } - return this.config.getTypeGenerator(options) + return this.config.getTypeGenerator(options); } getTemplateCodeGen(template: any) { if (!this.hasTemplates()) { - throw new Error( - `Template data sources with kind '${this.name}' are not supported yet`, - ) + throw new Error(`Template data sources with kind '${this.name}' are not supported yet`); } - return this.config.getTemplateCodeGen?.(template) + return this.config.getTemplateCodeGen?.(template); } getABI() { - return this.config.abi + return this.config.abi; } getSubgraph(options: SubgraphOptions) { - return this.config.getSubgraph({ ...options, protocol: this }) + return this.config.getSubgraph({ ...options, protocol: this }); } getContract() { - return this.config.contract + return this.config.contract; } getManifestScaffold() { - return this.config.manifestScaffold + return this.config.manifestScaffold; } getMappingScaffold() { - return this.config.mappingScaffold + return this.config.mappingScaffold; } } -export type ProtocolName = 'arweave' | 'ethereum' | 'near' | 'cosmos' | 'substreams' +export type ProtocolName = 'arweave' | 'ethereum' | 'near' | 'cosmos' | 'substreams'; export interface ProtocolConfig { - displayName: string - abi?: any - contract?: ContractCtor - getTemplateCodeGen?: (template: any) => any - getTypeGenerator?: (options: any) => any - getSubgraph(options: SubgraphOptions): Subgraph - manifestScaffold: any - mappingScaffold: any + displayName: string; + abi?: any; + contract?: ContractCtor; + getTemplateCodeGen?: (template: any) => any; + getTypeGenerator?: (options: any) => any; + getSubgraph(options: SubgraphOptions): Subgraph; + manifestScaffold: any; + mappingScaffold: any; } const arweaveProtocol: ProtocolConfig = { @@ -227,11 +222,11 @@ const arweaveProtocol: ProtocolConfig = { getTemplateCodeGen: undefined, getTypeGenerator: undefined, getSubgraph(options) { - return new ArweaveSubgraph(options) + return new ArweaveSubgraph(options); }, manifestScaffold: ArweaveManifestScaffold, mappingScaffold: ArweaveMappingScaffold, -} +}; const cosmosProtocol: ProtocolConfig = { displayName: 'Cosmos', @@ -240,28 +235,28 @@ const cosmosProtocol: ProtocolConfig = { getTemplateCodeGen: undefined, getTypeGenerator: undefined, getSubgraph(options) { - return new CosmosSubgraph(options) + return new CosmosSubgraph(options); }, manifestScaffold: CosmosManifestScaffold, mappingScaffold: CosmosMappingScaffold, -} +}; const ethereumProtocol: ProtocolConfig = { displayName: 'Ethereum', abi: EthereumABI, contract: EthereumContract, getTemplateCodeGen(template) { - return new EthereumTemplateCodeGen(template) + return new EthereumTemplateCodeGen(template); }, getTypeGenerator(options) { - return new EthereumTypeGenerator(options) + return new EthereumTypeGenerator(options); }, getSubgraph(options) { - return new EthereumSubgraph(options) + return new EthereumSubgraph(options); }, manifestScaffold: EthereumManifestScaffold, mappingScaffold: EthereumMappingScaffold, -} +}; const nearProtocol: ProtocolConfig = { displayName: 'NEAR', @@ -270,11 +265,11 @@ const nearProtocol: ProtocolConfig = { getTypeGenerator: undefined, getTemplateCodeGen: undefined, getSubgraph(options) { - return new NearSubgraph(options) + return new NearSubgraph(options); }, manifestScaffold: NearManifestScaffold, mappingScaffold: NearMappingScaffold, -} +}; const substreamsProtocol: ProtocolConfig = { displayName: 'Substreams', @@ -283,10 +278,10 @@ const substreamsProtocol: ProtocolConfig = { getTypeGenerator: undefined, getTemplateCodeGen: undefined, getSubgraph(options) { - return new SubstreamsSubgraph(options) + return new SubstreamsSubgraph(options); }, manifestScaffold: SubstreamsManifestScaffold, mappingScaffold: undefined, -} +}; -protocolDebug('Available networks %M', Protocol.availableNetworks()) +protocolDebug('Available networks %M', Protocol.availableNetworks()); diff --git a/packages/cli/src/protocols/ipfs/codegen/file_template.ts b/packages/cli/src/protocols/ipfs/codegen/file_template.ts index c238e332..a9d0cd29 100644 --- a/packages/cli/src/protocols/ipfs/codegen/file_template.ts +++ b/packages/cli/src/protocols/ipfs/codegen/file_template.ts @@ -1,17 +1,19 @@ -import immutable from 'immutable' -import * as tsCodegen from '../../../codegen/typescript' +/* eslint-disable */ + +import immutable from 'immutable'; +import * as tsCodegen from '../../../codegen/typescript'; export default class IpfsFileTemplateCodeGen { constructor(private template: immutable.Map) { - this.template = template + this.template = template; } generateModuleImports() { - return [] + return []; } generateCreateMethod() { - const name = this.template.get('name') + const name = this.template.get('name'); return tsCodegen.staticMethod( 'create', @@ -20,11 +22,11 @@ export default class IpfsFileTemplateCodeGen { ` DataSourceTemplate.create('${name}', [cid]) `, - ) + ); } generateCreateWithContextMethod() { - const name = this.template.get('name') + const name = this.template.get('name'); return tsCodegen.staticMethod( 'createWithContext', @@ -36,6 +38,6 @@ export default class IpfsFileTemplateCodeGen { ` DataSourceTemplate.createWithContext('${name}', [cid], context) `, - ) + ); } } diff --git a/packages/cli/src/protocols/near/contract.ts b/packages/cli/src/protocols/near/contract.ts index b0926d39..67894d16 100644 --- a/packages/cli/src/protocols/near/contract.ts +++ b/packages/cli/src/protocols/near/contract.ts @@ -1,30 +1,27 @@ -import { Contract } from '../contract' +import { Contract } from '../contract'; -const MINIMUM_ACCOUNT_ID_LENGTH = 2 as const -const MAXIMUM_ACCOUNT_ID_LENGTH = 64 as const +const MINIMUM_ACCOUNT_ID_LENGTH = 2 as const; +const MAXIMUM_ACCOUNT_ID_LENGTH = 64 as const; -const RULES_URL = 'https://docs.near.org/docs/concepts/account#account-id-rules' as const +const RULES_URL = 'https://docs.near.org/docs/concepts/account#account-id-rules' as const; export default class NearContract implements Contract { static identifierName() { - return 'account' + return 'account'; } constructor(private account: string) { - this.account = account + this.account = account; } private validateLength(value: string) { - return ( - value.length >= MINIMUM_ACCOUNT_ID_LENGTH && - value.length <= MAXIMUM_ACCOUNT_ID_LENGTH - ) + return value.length >= MINIMUM_ACCOUNT_ID_LENGTH && value.length <= MAXIMUM_ACCOUNT_ID_LENGTH; } private validateFormat(value: string) { - const pattern = /^(([a-z\d]+[\-_])*[a-z\d]+\.)*([a-z\d]+[\-_])*[a-z\d]+$/ + const pattern = /^(([a-z\d]+[-_])*[a-z\d]+\.)*([a-z\d]+[-_])*[a-z\d]+$/; - return pattern.test(value) + return pattern.test(value); } validate() { @@ -32,19 +29,19 @@ export default class NearContract implements Contract { return { valid: false, error: `Account must be between '${MINIMUM_ACCOUNT_ID_LENGTH}' and '${MAXIMUM_ACCOUNT_ID_LENGTH}' characters, see ${RULES_URL}`, - } + }; } if (!this.validateFormat(this.account)) { return { valid: false, error: `Account must conform to the rules on ${RULES_URL}`, - } + }; } return { valid: true, error: null, - } + }; } } diff --git a/packages/cli/src/protocols/near/scaffold/manifest.ts b/packages/cli/src/protocols/near/scaffold/manifest.ts index b5d699b3..396d84e6 100644 --- a/packages/cli/src/protocols/near/scaffold/manifest.ts +++ b/packages/cli/src/protocols/near/scaffold/manifest.ts @@ -1,7 +1,7 @@ -import { strings } from 'gluegun' +import { strings } from 'gluegun'; export const source = ({ contract }: { contract: string }) => ` - account: '${contract}'` + account: '${contract}'`; export const mapping = ({ contractName }: { contractName: string }) => ` apiVersion: 0.0.5 @@ -10,4 +10,4 @@ export const mapping = ({ contractName }: { contractName: string }) => ` - ExampleEntity receiptHandlers: - handler: handleReceipt - file: ./src/${strings.kebabCase(contractName)}.ts` + file: ./src/${strings.kebabCase(contractName)}.ts`; diff --git a/packages/cli/src/protocols/near/scaffold/mapping.ts b/packages/cli/src/protocols/near/scaffold/mapping.ts index 93351a50..b45ada47 100644 --- a/packages/cli/src/protocols/near/scaffold/mapping.ts +++ b/packages/cli/src/protocols/near/scaffold/mapping.ts @@ -32,4 +32,4 @@ export const generatePlaceholderHandlers = () => // entity back to the store. Fields that were not set or unset remain // unchanged, allowing for partial updates to be applied. } -` +`; diff --git a/packages/cli/src/protocols/near/subgraph.ts b/packages/cli/src/protocols/near/subgraph.ts index 3582282d..bc5252c8 100644 --- a/packages/cli/src/protocols/near/subgraph.ts +++ b/packages/cli/src/protocols/near/subgraph.ts @@ -1,22 +1,22 @@ -import immutable from 'immutable' -import { Subgraph, SubgraphOptions } from '../subgraph' +import immutable from 'immutable'; +import { Subgraph, SubgraphOptions } from '../subgraph'; export default class NearSubgraph implements Subgraph { - public manifest: SubgraphOptions['manifest'] - public resolveFile: SubgraphOptions['resolveFile'] - public protocol: SubgraphOptions['protocol'] + public manifest: SubgraphOptions['manifest']; + public resolveFile: SubgraphOptions['resolveFile']; + public protocol: SubgraphOptions['protocol']; constructor(options: SubgraphOptions) { - this.manifest = options.manifest - this.resolveFile = options.resolveFile - this.protocol = options.protocol + this.manifest = options.manifest; + this.resolveFile = options.resolveFile; + this.protocol = options.protocol; } validateManifest() { - return immutable.List() + return immutable.List(); } handlerTypes() { - return immutable.List(['blockHandlers', 'receiptHandlers']) + return immutable.List(['blockHandlers', 'receiptHandlers']); } } diff --git a/packages/cli/src/protocols/subgraph.ts b/packages/cli/src/protocols/subgraph.ts index 1259652b..23141bd6 100644 --- a/packages/cli/src/protocols/subgraph.ts +++ b/packages/cli/src/protocols/subgraph.ts @@ -1,12 +1,12 @@ -import immutable from 'immutable' +import immutable from 'immutable'; export interface SubgraphOptions { - manifest?: any - resolveFile: (path: string) => string - protocol?: any + manifest?: any; + resolveFile: (path: string) => string; + protocol?: any; } export interface Subgraph extends SubgraphOptions { - validateManifest(): immutable.List - handlerTypes(): immutable.List + validateManifest(): immutable.List; + handlerTypes(): immutable.List; } diff --git a/packages/cli/src/protocols/substreams/scaffold/manifest.ts b/packages/cli/src/protocols/substreams/scaffold/manifest.ts index 26441432..35482236 100644 --- a/packages/cli/src/protocols/substreams/scaffold/manifest.ts +++ b/packages/cli/src/protocols/substreams/scaffold/manifest.ts @@ -1,8 +1,8 @@ export const source = () => ` package: moduleName: graph_out - file: substreams-eth-block-meta-v0.1.0.spkg` + file: substreams-eth-block-meta-v0.1.0.spkg`; export const mapping = () => ` apiVersion: 0.0.5 - kind: substreams/graph-entities` + kind: substreams/graph-entities`; diff --git a/packages/cli/src/protocols/substreams/subgraph.ts b/packages/cli/src/protocols/substreams/subgraph.ts index c36bf61c..a6f54aa0 100644 --- a/packages/cli/src/protocols/substreams/subgraph.ts +++ b/packages/cli/src/protocols/substreams/subgraph.ts @@ -1,22 +1,22 @@ -import immutable from 'immutable' -import { Subgraph, SubgraphOptions } from '../subgraph' +import immutable from 'immutable'; +import { Subgraph, SubgraphOptions } from '../subgraph'; export default class SubstreamsSubgraph implements Subgraph { - public manifest: SubgraphOptions['manifest'] - public resolveFile: SubgraphOptions['resolveFile'] - public protocol: SubgraphOptions['protocol'] + public manifest: SubgraphOptions['manifest']; + public resolveFile: SubgraphOptions['resolveFile']; + public protocol: SubgraphOptions['protocol']; constructor(options: SubgraphOptions) { - this.manifest = options.manifest - this.resolveFile = options.resolveFile - this.protocol = options.protocol + this.manifest = options.manifest; + this.resolveFile = options.resolveFile; + this.protocol = options.protocol; } validateManifest() { - return immutable.List() + return immutable.List(); } handlerTypes() { - return immutable.List([]) + return immutable.List([]); } } diff --git a/packages/cli/src/scaffold/cosmos.test.ts b/packages/cli/src/scaffold/cosmos.test.ts index ae5ebb38..a76d64c6 100644 --- a/packages/cli/src/scaffold/cosmos.test.ts +++ b/packages/cli/src/scaffold/cosmos.test.ts @@ -1,15 +1,15 @@ -import Scaffold from './index' -import Protocol from '../protocols' +import Protocol from '../protocols'; +import Scaffold from './index'; -const protocol = new Protocol('cosmos') +const protocol = new Protocol('cosmos'); const scaffoldOptions = { protocol, network: 'cosmoshub-4', contractName: 'CosmosHub', -} +}; -const scaffold = new Scaffold(scaffoldOptions) +const scaffold = new Scaffold(scaffoldOptions); describe('Cosmos subgraph scaffolding', () => { test('Manifest', () => { @@ -31,8 +31,8 @@ dataSources: blockHandlers: - handler: handleBlock file: ./src/contract.ts -`) - }) +`); + }); test('Schema (default)', () => { expect(scaffold.generateSchema()).toEqual(`\ @@ -41,8 +41,8 @@ type ExampleEntity @entity { block: Bytes! count: BigInt! } -`) - }) +`); + }); test('Mapping (default)', () => { expect(scaffold.generateMapping()).toEqual(`\ @@ -78,6 +78,6 @@ export function handleBlock(block: cosmos.Block): void { // entity back to the store. Fields that were not set or unset remain // unchanged, allowing for partial updates to be applied. } -`) - }) -}) +`); + }); +}); diff --git a/packages/cli/src/scaffold/ethereum.test.ts b/packages/cli/src/scaffold/ethereum.test.ts index 6d469689..047c007f 100644 --- a/packages/cli/src/scaffold/ethereum.test.ts +++ b/packages/cli/src/scaffold/ethereum.test.ts @@ -1,7 +1,7 @@ -import ABI from '../protocols/ethereum/abi' -import immutable from 'immutable' -import Scaffold from './index' -import Protocol from '../protocols' +import immutable from 'immutable'; +import Protocol from '../protocols'; +import ABI from '../protocols/ethereum/abi'; +import Scaffold from './index'; const TEST_EVENT = { name: 'ExampleEvent', @@ -20,28 +20,24 @@ const TEST_EVENT = { { name: 'c3', type: 'tuple', - components: [ - { name: 'c31', type: 'uint96' }, - { type: 'string' }, - { type: 'bytes32' }, - ], + components: [{ name: 'c31', type: 'uint96' }, { type: 'string' }, { type: 'bytes32' }], }, ], }, { name: 'd', type: 'string', indexed: true }, ], -} +}; const OVERLOADED_EVENT = { name: 'ExampleEvent', type: 'event', inputs: [{ name: 'a', type: 'bytes32' }], -} +}; const TEST_CONTRACT = { name: 'ExampleContract', type: 'contract', -} +}; const TEST_CALLABLE_FUNCTIONS = [ { @@ -56,20 +52,15 @@ const TEST_CALLABLE_FUNCTIONS = [ stateMutability: 'pure', outputs: [{ type: 'tuple', components: [{ type: 'uint256' }] }], }, -] +]; const TEST_ABI = new ABI( 'Contract', undefined, - immutable.fromJS([ - TEST_EVENT, - OVERLOADED_EVENT, - TEST_CONTRACT, - ...TEST_CALLABLE_FUNCTIONS, - ]), -) + immutable.fromJS([TEST_EVENT, OVERLOADED_EVENT, TEST_CONTRACT, ...TEST_CALLABLE_FUNCTIONS]), +); -const protocol = new Protocol('ethereum') +const protocol = new Protocol('ethereum'); const scaffoldOptions = { protocol, @@ -77,14 +68,14 @@ const scaffoldOptions = { contract: '0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d', network: 'kovan', contractName: 'Contract', -} +}; -const scaffold = new Scaffold(scaffoldOptions) +const scaffold = new Scaffold(scaffoldOptions); const scaffoldWithIndexEvents = new Scaffold({ ...scaffoldOptions, indexEvents: true, -}) +}); describe('Ethereum subgraph scaffolding', () => { test('Manifest', () => { @@ -115,8 +106,8 @@ dataSources: - event: ExampleEvent(bytes32) handler: handleExampleEvent1 file: ./src/contract.ts -`) - }) +`); + }); test('Schema (default)', () => { expect(scaffold.generateSchema()).toEqual(`\ @@ -126,8 +117,8 @@ type ExampleEntity @entity { a: BigInt! # uint256 b: [Bytes]! # bytes[4] } -`) - }) +`); + }); test('Schema (for indexing events)', () => { expect(scaffoldWithIndexEvents.generateSchema()).toEqual(`\ @@ -155,8 +146,8 @@ type ExampleEvent1 @entity(immutable: true) { blockTimestamp: BigInt! transactionHash: Bytes! } -`) - }) +`); + }); test('Mapping (default)', () => { expect(scaffold.generateMapping()).toEqual(`\ @@ -212,8 +203,8 @@ export function handleExampleEvent(event: ExampleEvent): void { } export function handleExampleEvent1(event: ExampleEvent1): void {} -`) - }) +`); + }); test('Mapping (for indexing events)', () => { expect(scaffoldWithIndexEvents.generateMapping()).toEqual(`\ @@ -257,13 +248,13 @@ export function handleExampleEvent1(event: ExampleEvent1Event): void { entity.save() } -`) - }) +`); + }); test('Test Files (default)', () => { - const files = scaffoldWithIndexEvents.generateTests() - const testFile = files?.['contract.test.ts'] - const utilsFile = files?.['contract-utils.ts'] + const files = scaffoldWithIndexEvents.generateTests(); + const testFile = files?.['contract.test.ts']; + const utilsFile = files?.['contract-utils.ts']; expect(testFile).toEqual(`\ import { assert, @@ -272,23 +263,23 @@ import { clearStore, beforeAll, afterAll -} from \"matchstick-as/assembly/index\" -import { BigInt, Bytes } from \"@graphprotocol/graph-ts\" -import { ExampleEvent } from \"../generated/schema\" -import { ExampleEvent as ExampleEventEvent } from \"../generated/Contract/Contract\" -import { handleExampleEvent } from \"../src/contract\" -import { createExampleEventEvent } from \"./contract-utils\" +} from "matchstick-as/assembly/index" +import { BigInt, Bytes } from "@graphprotocol/graph-ts" +import { ExampleEvent } from "../generated/schema" +import { ExampleEvent as ExampleEventEvent } from "../generated/Contract/Contract" +import { handleExampleEvent } from "../src/contract" +import { createExampleEventEvent } from "./contract-utils" // Tests structure (matchstick-as >=0.5.0) // https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 -describe(\"Describe entity assertions\", () => { +describe("Describe entity assertions", () => { beforeAll(() => { let a = BigInt.fromI32(234) let b = [Bytes.fromI32(1234567890)] - let param2 = \"Example string value\" - let c = \"ethereum.Tuple Not implemented\" - let d = \"Example string value\" + let param2 = "Example string value" + let c = "ethereum.Tuple Not implemented" + let d = "Example string value" let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d) handleExampleEvent(newExampleEventEvent) }) @@ -300,50 +291,50 @@ describe(\"Describe entity assertions\", () => { // For more test scenarios, see: // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test - test(\"ExampleEvent created and stored\", () => { - assert.entityCount(\"ExampleEvent\", 1) + test("ExampleEvent created and stored", () => { + assert.entityCount("ExampleEvent", 1) // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function assert.fieldEquals( - \"ExampleEvent\", - \"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\", - \"a\", - \"234\" + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "a", + "234" ) assert.fieldEquals( - \"ExampleEvent\", - \"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\", - \"b\", - \"[1234567890]\" + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "b", + "[1234567890]" ) assert.fieldEquals( - \"ExampleEvent\", - \"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\", - \"param2\", - \"Example string value\" + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "param2", + "Example string value" ) assert.fieldEquals( - \"ExampleEvent\", - \"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\", - \"c\", - \"ethereum.Tuple Not implemented\" + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "c", + "ethereum.Tuple Not implemented" ) assert.fieldEquals( - \"ExampleEvent\", - \"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\", - \"d\", - \"Example string value\" + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "d", + "Example string value" ) // More assert options: // https://thegraph.com/docs/en/developer/matchstick/#asserts }) }) -`) +`); expect(utilsFile).toEqual(`\ -import { newMockEvent } from \"matchstick-as\" -import { ethereum, BigInt, Bytes } from \"@graphprotocol/graph-ts\" -import { ExampleEvent, ExampleEvent1 } from \"../generated/Contract/Contract\" +import { newMockEvent } from "matchstick-as" +import { ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts" +import { ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract" export function createExampleEventEvent( a: BigInt, @@ -357,19 +348,19 @@ export function createExampleEventEvent( exampleEventEvent.parameters = new Array() exampleEventEvent.parameters.push( - new ethereum.EventParam(\"a\", ethereum.Value.fromUnsignedBigInt(a)) + new ethereum.EventParam("a", ethereum.Value.fromUnsignedBigInt(a)) ) exampleEventEvent.parameters.push( - new ethereum.EventParam(\"b\", ethereum.Value.fromBytesArray(b)) + new ethereum.EventParam("b", ethereum.Value.fromBytesArray(b)) ) exampleEventEvent.parameters.push( - new ethereum.EventParam(\"param2\", ethereum.Value.fromString(param2)) + new ethereum.EventParam("param2", ethereum.Value.fromString(param2)) ) exampleEventEvent.parameters.push( - new ethereum.EventParam(\"c\", ethereum.Value.fromTuple(c)) + new ethereum.EventParam("c", ethereum.Value.fromTuple(c)) ) exampleEventEvent.parameters.push( - new ethereum.EventParam(\"d\", ethereum.Value.fromString(d)) + new ethereum.EventParam("d", ethereum.Value.fromString(d)) ) return exampleEventEvent @@ -381,18 +372,18 @@ export function createExampleEvent1Event(a: Bytes): ExampleEvent1 { exampleEvent1Event.parameters = new Array() exampleEvent1Event.parameters.push( - new ethereum.EventParam(\"a\", ethereum.Value.fromFixedBytes(a)) + new ethereum.EventParam("a", ethereum.Value.fromFixedBytes(a)) ) return exampleEvent1Event } -`) - }) +`); + }); test('Test Files (for indexing events)', () => { - const files = scaffoldWithIndexEvents.generateTests() - const testFile = files?.['contract.test.ts'] - const utilsFile = files?.['contract-utils.ts'] + const files = scaffoldWithIndexEvents.generateTests(); + const testFile = files?.['contract.test.ts']; + const utilsFile = files?.['contract-utils.ts']; expect(testFile).toEqual(`\ import { @@ -402,23 +393,23 @@ import { clearStore, beforeAll, afterAll -} from \"matchstick-as/assembly/index\" -import { BigInt, Bytes } from \"@graphprotocol/graph-ts\" -import { ExampleEvent } from \"../generated/schema\" -import { ExampleEvent as ExampleEventEvent } from \"../generated/Contract/Contract\" -import { handleExampleEvent } from \"../src/contract\" -import { createExampleEventEvent } from \"./contract-utils\" +} from "matchstick-as/assembly/index" +import { BigInt, Bytes } from "@graphprotocol/graph-ts" +import { ExampleEvent } from "../generated/schema" +import { ExampleEvent as ExampleEventEvent } from "../generated/Contract/Contract" +import { handleExampleEvent } from "../src/contract" +import { createExampleEventEvent } from "./contract-utils" // Tests structure (matchstick-as >=0.5.0) // https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 -describe(\"Describe entity assertions\", () => { +describe("Describe entity assertions", () => { beforeAll(() => { let a = BigInt.fromI32(234) let b = [Bytes.fromI32(1234567890)] - let param2 = \"Example string value\" - let c = \"ethereum.Tuple Not implemented\" - let d = \"Example string value\" + let param2 = "Example string value" + let c = "ethereum.Tuple Not implemented" + let d = "Example string value" let newExampleEventEvent = createExampleEventEvent(a, b, param2, c, d) handleExampleEvent(newExampleEventEvent) }) @@ -430,50 +421,50 @@ describe(\"Describe entity assertions\", () => { // For more test scenarios, see: // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test - test(\"ExampleEvent created and stored\", () => { - assert.entityCount(\"ExampleEvent\", 1) + test("ExampleEvent created and stored", () => { + assert.entityCount("ExampleEvent", 1) // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function assert.fieldEquals( - \"ExampleEvent\", - \"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\", - \"a\", - \"234\" + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "a", + "234" ) assert.fieldEquals( - \"ExampleEvent\", - \"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\", - \"b\", - \"[1234567890]\" + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "b", + "[1234567890]" ) assert.fieldEquals( - \"ExampleEvent\", - \"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\", - \"param2\", - \"Example string value\" + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "param2", + "Example string value" ) assert.fieldEquals( - \"ExampleEvent\", - \"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\", - \"c\", - \"ethereum.Tuple Not implemented\" + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "c", + "ethereum.Tuple Not implemented" ) assert.fieldEquals( - \"ExampleEvent\", - \"0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1\", - \"d\", - \"Example string value\" + "ExampleEvent", + "0xa16081f360e3847006db660bae1c6d1b2e17ec2a-1", + "d", + "Example string value" ) // More assert options: // https://thegraph.com/docs/en/developer/matchstick/#asserts }) }) -`) +`); expect(utilsFile).toEqual(`\ -import { newMockEvent } from \"matchstick-as\" -import { ethereum, BigInt, Bytes } from \"@graphprotocol/graph-ts\" -import { ExampleEvent, ExampleEvent1 } from \"../generated/Contract/Contract\" +import { newMockEvent } from "matchstick-as" +import { ethereum, BigInt, Bytes } from "@graphprotocol/graph-ts" +import { ExampleEvent, ExampleEvent1 } from "../generated/Contract/Contract" export function createExampleEventEvent( a: BigInt, @@ -487,19 +478,19 @@ export function createExampleEventEvent( exampleEventEvent.parameters = new Array() exampleEventEvent.parameters.push( - new ethereum.EventParam(\"a\", ethereum.Value.fromUnsignedBigInt(a)) + new ethereum.EventParam("a", ethereum.Value.fromUnsignedBigInt(a)) ) exampleEventEvent.parameters.push( - new ethereum.EventParam(\"b\", ethereum.Value.fromBytesArray(b)) + new ethereum.EventParam("b", ethereum.Value.fromBytesArray(b)) ) exampleEventEvent.parameters.push( - new ethereum.EventParam(\"param2\", ethereum.Value.fromString(param2)) + new ethereum.EventParam("param2", ethereum.Value.fromString(param2)) ) exampleEventEvent.parameters.push( - new ethereum.EventParam(\"c\", ethereum.Value.fromTuple(c)) + new ethereum.EventParam("c", ethereum.Value.fromTuple(c)) ) exampleEventEvent.parameters.push( - new ethereum.EventParam(\"d\", ethereum.Value.fromString(d)) + new ethereum.EventParam("d", ethereum.Value.fromString(d)) ) return exampleEventEvent @@ -511,11 +502,11 @@ export function createExampleEvent1Event(a: Bytes): ExampleEvent1 { exampleEvent1Event.parameters = new Array() exampleEvent1Event.parameters.push( - new ethereum.EventParam(\"a\", ethereum.Value.fromFixedBytes(a)) + new ethereum.EventParam("a", ethereum.Value.fromFixedBytes(a)) ) return exampleEvent1Event } -`) - }) -}) +`); + }); +}); diff --git a/packages/cli/src/scaffold/index.ts b/packages/cli/src/scaffold/index.ts index 58192bbc..93df5558 100644 --- a/packages/cli/src/scaffold/index.ts +++ b/packages/cli/src/scaffold/index.ts @@ -1,50 +1,49 @@ -import prettier from 'prettier' -import { strings } from 'gluegun' +import { strings } from 'gluegun'; +import prettier from 'prettier'; +import { getSubgraphBasename } from '../command-helpers/subgraph'; +import Protocol from '../protocols'; +import ABI from '../protocols/ethereum/abi'; +import { generateEventIndexingHandlers } from './mapping'; +import { abiEvents, generateEventType, generateExampleEntityType } from './schema'; +import { generateTestsFiles } from './tests'; const GRAPH_CLI_VERSION = process.env.GRAPH_CLI_TESTS ? // JSON.stringify should remove this key, we will install the local // graph-cli for the tests using `npm link` instead of fetching from npm. undefined : // For scaffolding real subgraphs - `${module.exports.version}` - -import { abiEvents, generateEventType, generateExampleEntityType } from './schema' -import { generateEventIndexingHandlers } from './mapping' -import { generateTestsFiles } from './tests' -import Protocol from '../protocols' -import { getSubgraphBasename } from '../command-helpers/subgraph' -import ABI from '../protocols/ethereum/abi' + String(module.exports.version); export interface ScaffoldOptions { - protocol: Protocol - abi?: ABI - indexEvents?: boolean - contract?: string - network: string - contractName: string - subgraphName?: string - node?: string + protocol: Protocol; + abi?: ABI; + indexEvents?: boolean; + contract?: string; + network: string; + contractName: string; + subgraphName?: string; + node?: string; } export default class Scaffold { - protocol: Protocol - abi?: ABI - indexEvents?: boolean - contract?: string - network: string - contractName: string - subgraphName?: string - node?: string + protocol: Protocol; + abi?: ABI; + indexEvents?: boolean; + contract?: string; + network: string; + contractName: string; + subgraphName?: string; + node?: string; constructor(options: ScaffoldOptions) { - this.protocol = options.protocol - this.abi = options.abi - this.indexEvents = options.indexEvents - this.contract = options.contract - this.network = options.network - this.contractName = options.contractName - this.subgraphName = options.subgraphName - this.node = options.node + this.protocol = options.protocol; + this.abi = options.abi; + this.indexEvents = options.indexEvents; + this.contract = options.contract; + this.network = options.network; + this.contractName = options.contractName; + this.subgraphName = options.subgraphName; + this.node = options.node; } generatePackageJson() { @@ -69,16 +68,14 @@ export default class Scaffold { '@graphprotocol/graph-cli': GRAPH_CLI_VERSION, '@graphprotocol/graph-ts': `0.29.1`, }, - devDependencies: this.protocol.hasEvents() - ? { 'matchstick-as': `0.5.0` } - : undefined, + devDependencies: this.protocol.hasEvents() ? { 'matchstick-as': `0.5.0` } : undefined, }), { parser: 'json' }, - ) + ); } generateManifest() { - const protocolManifest = this.protocol.getManifestScaffold() + const protocolManifest = this.protocol.getManifestScaffold(); return prettier.format( ` @@ -93,23 +90,21 @@ dataSources: mapping: ${protocolManifest.mapping(this)} `, { parser: 'yaml' }, - ) + ); } generateSchema() { - const hasEvents = this.protocol.hasEvents() - const events = hasEvents ? abiEvents(this.abi!).toJS() : [] + const hasEvents = this.protocol.hasEvents(); + const events = hasEvents ? abiEvents(this.abi!).toJS() : []; return prettier.format( hasEvents && this.indexEvents - ? events - .map((event: any) => generateEventType(event, this.protocol.name)) - .join('\n\n') + ? events.map((event: any) => generateEventType(event, this.protocol.name)).join('\n\n') : generateExampleEntityType(this.protocol, events), { parser: 'graphql', }, - ) + ); } generateTsConfig() { @@ -119,19 +114,19 @@ dataSources: include: ['src'], }), { parser: 'json' }, - ) + ); } generateMappings() { return this.protocol.getMappingScaffold() ? { [`${strings.kebabCase(this.contractName)}.ts`]: this.generateMapping() } - : undefined + : undefined; } generateMapping() { - const hasEvents = this.protocol.hasEvents() - const events = hasEvents ? abiEvents(this.abi!).toJS() : [] - const protocolMapping = this.protocol.getMappingScaffold() + const hasEvents = this.protocol.hasEvents(); + const events = hasEvents ? abiEvents(this.abi!).toJS() : []; + const protocolMapping = this.protocol.getMappingScaffold(); return prettier.format( hasEvents && this.indexEvents @@ -141,7 +136,7 @@ dataSources: events, }), { parser: 'typescript', semi: false }, - ) + ); } generateABIs() { @@ -151,16 +146,16 @@ dataSources: parser: 'json', }), } - : undefined + : undefined; } generateTests() { - const hasEvents = this.protocol.hasEvents() - const events = hasEvents ? abiEvents(this.abi!).toJS() : [] + const hasEvents = this.protocol.hasEvents(); + const events = hasEvents ? abiEvents(this.abi!).toJS() : []; return events.length > 0 ? generateTestsFiles(this.contractName, events, this.indexEvents) - : undefined + : undefined; } generate() { @@ -172,6 +167,6 @@ dataSources: src: this.generateMappings(), abis: this.generateABIs(), tests: this.generateTests(), - } + }; } } diff --git a/packages/cli/src/scaffold/mapping.ts b/packages/cli/src/scaffold/mapping.ts index e121eac2..bd428a5e 100644 --- a/packages/cli/src/scaffold/mapping.ts +++ b/packages/cli/src/scaffold/mapping.ts @@ -1,27 +1,21 @@ -import * as util from '../codegen/util' +import * as util from '../codegen/util'; export const generateFieldAssignment = (path: string[]) => - `entity.${path.join('_')} = event.params.${path.join('.')}` + `entity.${path.join('_')} = event.params.${path.join('.')}`; -export const generateFieldAssignments = ({ - index, - input, -}: { - index: number - input: any -}) => +export const generateFieldAssignments = ({ index, input }: { index: number; input: any }) => input.type === 'tuple' ? util .unrollTuple({ value: input, index, path: [input.name || `param${index}`] }) .map(({ path }: any) => generateFieldAssignment(path)) - : generateFieldAssignment([input.name || `param${index}`]) + : generateFieldAssignment([input.name || `param${index}`]); export const generateEventFieldAssignments = (event: any) => event.inputs.reduce( (acc: any[], input: any, index: number) => acc.concat(generateFieldAssignments({ input, index })), [], - ) + ); export const generateEventIndexingHandlers = (events: any[], contractName: string) => ` @@ -35,9 +29,7 @@ export const generateEventIndexingHandlers = (events: any[], contractName: strin event => ` export function handle${event._alias}(event: ${event._alias}Event): void { - let entity = new ${ - event._alias - }(event.transaction.hash.concatI32(event.logIndex.toI32())) + let entity = new ${event._alias}(event.transaction.hash.concatI32(event.logIndex.toI32())) ${generateEventFieldAssignments(event).join('\n')} entity.blockNumber = event.block.number @@ -49,4 +41,4 @@ export const generateEventIndexingHandlers = (events: any[], contractName: strin `, ) .join('\n')} -` +`; diff --git a/packages/cli/src/scaffold/near.test.ts b/packages/cli/src/scaffold/near.test.ts index 0eca47de..6a610a9e 100644 --- a/packages/cli/src/scaffold/near.test.ts +++ b/packages/cli/src/scaffold/near.test.ts @@ -1,16 +1,16 @@ -import Scaffold from './index' -import Protocol from '../protocols' +import Protocol from '../protocols'; +import Scaffold from './index'; -const protocol = new Protocol('near') +const protocol = new Protocol('near'); const scaffoldOptions = { protocol, contract: 'abc.def.near', network: 'near-mainnet', contractName: 'Contract', -} +}; -const scaffold = new Scaffold(scaffoldOptions) +const scaffold = new Scaffold(scaffoldOptions); describe('NEAR subgraph scaffolding', () => { test('Manifest', () => { @@ -32,8 +32,8 @@ dataSources: receiptHandlers: - handler: handleReceipt file: ./src/contract.ts -`) - }) +`); + }); test('Schema (default)', () => { expect(scaffold.generateSchema()).toEqual(`\ @@ -42,8 +42,8 @@ type ExampleEntity @entity { block: Bytes! count: BigInt! } -`) - }) +`); + }); test('Mapping (default)', () => { expect(scaffold.generateMapping()).toEqual(`\ @@ -81,6 +81,6 @@ export function handleReceipt( // entity back to the store. Fields that were not set or unset remain // unchanged, allowing for partial updates to be applied. } -`) - }) -}) +`); + }); +}); diff --git a/packages/cli/src/scaffold/schema.ts b/packages/cli/src/scaffold/schema.ts index 1a9c8eb2..ab5c0848 100644 --- a/packages/cli/src/scaffold/schema.ts +++ b/packages/cli/src/scaffold/schema.ts @@ -1,7 +1,7 @@ -import immutable from 'immutable' -import { ascTypeForProtocol, valueTypeForAsc } from '../codegen/types' -import * as util from '../codegen/util' -import Protocol from '../protocols' +import immutable from 'immutable'; +import { ascTypeForProtocol, valueTypeForAsc } from '../codegen/types'; +import * as util from '../codegen/util'; +import Protocol from '../protocols'; export function abiEvents(abi: { data: immutable.Collection }) { return util.disambiguateNames({ @@ -11,46 +11,44 @@ export function abiEvents(abi: { data: immutable.Collection }) { getName: event => event.get('name'), // @ts-expect-error improve typings of disambiguateNames to handle iterables setName: (event, name) => event.set('_alias', name), - }) as unknown as immutable.List + }) as unknown as immutable.List; } export const protocolTypeToGraphQL = (protocol: string, name: string) => { - let ascType = ascTypeForProtocol(protocol, name) - return valueTypeForAsc(ascType) -} + const ascType = ascTypeForProtocol(protocol, name); + return valueTypeForAsc(ascType); +}; export const generateField = ({ name, type, protocolName, }: { - name: string - type: string - protocolName: string -}) => `${name}: ${protocolTypeToGraphQL(protocolName, type)}! # ${type}` + name: string; + type: string; + protocolName: string; +}) => `${name}: ${protocolTypeToGraphQL(protocolName, type)}! # ${type}`; export const generateEventFields = ({ index, input, protocolName, }: { - index: number - input: any - protocolName: string + index: number; + input: any; + protocolName: string; }) => input.type == 'tuple' ? util .unrollTuple({ value: input, path: [input.name || `param${index}`], index }) - .map(({ path, type }: any) => - generateField({ name: path.join('_'), type, protocolName }), - ) + .map(({ path, type }: any) => generateField({ name: path.join('_'), type, protocolName })) : [ generateField({ name: input.name || `param${index}`, type: input.type, protocolName, }), - ] + ]; export const generateEventType = (event: any, protocolName: string) => `type ${ event._alias @@ -66,7 +64,7 @@ export const generateEventType = (event: any, protocolName: string) => `type ${ blockNumber: BigInt! blockTimestamp: BigInt! transactionHash: Bytes! - }` + }`; export const generateExampleEntityType = (protocol: Protocol, events: any[]) => { if (protocol.hasABIs() && events.length > 0) { @@ -81,12 +79,11 @@ export const generateExampleEntityType = (protocol: Protocol, events: any[]) => ) .slice(0, 2) .join('\n')} -}` - } else { - return `type ExampleEntity @entity { +}`; + } + return `type ExampleEntity @entity { id: ID! block: Bytes! count: BigInt! -}` - } -} +}`; +}; diff --git a/packages/cli/src/scaffold/tests.ts b/packages/cli/src/scaffold/tests.ts index a2954e8c..2e49de69 100644 --- a/packages/cli/src/scaffold/tests.ts +++ b/packages/cli/src/scaffold/tests.ts @@ -1,33 +1,29 @@ -import prettier from 'prettier' -import { strings } from 'gluegun' -import { ascTypeForEthereum, ethereumFromAsc } from '../codegen/types' +import { strings } from 'gluegun'; +import prettier from 'prettier'; +import { ascTypeForEthereum, ethereumFromAsc } from '../codegen/types'; const VARIABLES_VALUES = { i32: 123, BigInt: 234, - Bytes: 1234567890, + Bytes: 1_234_567_890, Address: '0x0000000000000000000000000000000000000001', string: 'Example string value', bool: true, -} +}; -export const generateTestsFiles = ( - contract: any, - events: any[], - indexEvents?: boolean, -) => { +export const generateTestsFiles = (contract: any, events: any[], indexEvents?: boolean) => { const eventsTypes = events .flatMap(event => event.inputs.map((input: any) => { // If the asc type is Array we need to check if T is a native type or a custom graph-ts type // If we don't do that we may miss a type that should be imported from graph-ts - const ascType = ascTypeForEthereum(input.type) - const inner = fetchArrayInnerType(String(ascType)) - return inner ? inner[1] : ascType + const ascType = ascTypeForEthereum(input.type); + const inner = fetchArrayInnerType(String(ascType)); + return inner ? inner[1] : ascType; }), ) - .filter(type => !type.startsWith('ethereum.') && !isNativeType(type)) - const importTypes = [...new Set(eventsTypes)].join(', ') + .filter(type => !type.startsWith('ethereum.') && !isNativeType(type)); + const importTypes = [...new Set(eventsTypes)].join(', '); return { [`${strings.kebabCase(contract)}.test.ts`]: prettier.format( @@ -38,8 +34,8 @@ export const generateTestsFiles = ( generateTestHelper(contract, events, importTypes), { parser: 'typescript', semi: false }, ), - } -} + }; +}; /* Generates the arguments that will be passed to the mock event function from the event inputs. Example: @@ -51,31 +47,33 @@ export const generateTestsFiles = ( const generateArguments = (eventInputs: any[]) => { return eventInputs .map((input, index) => { - let ascType = ascTypeForEthereum(input.type) - return `let ${input.name || `param${index}`} = ${assignValue(ascType)}` + const ascType = ascTypeForEthereum(input.type); + return `let ${input.name || `param${index}`} = ${assignValue(ascType)}`; }) - .join('\n') -} + .join('\n'); +}; // Generates the value that will be assigned to a variable in generateArguments() const assignValue = (type: string): string | number | boolean => { switch (type) { case 'string': - return `"${VARIABLES_VALUES[type]}"` + return `"${VARIABLES_VALUES[type]}"`; case 'BigInt': - return `BigInt.fromI32(${VARIABLES_VALUES[type]})` + return `BigInt.fromI32(${VARIABLES_VALUES[type]})`; case 'Address': - return `Address.fromString("${VARIABLES_VALUES[type]}")` + return `Address.fromString("${VARIABLES_VALUES[type]}")`; case 'Bytes': - return `Bytes.fromI32(${VARIABLES_VALUES[type]})` - case fetchArrayInnerType(type)?.input: - const innerType = fetchArrayInnerType(type)![1] - return `[${assignValue(innerType)}]` - default: - let value = VARIABLES_VALUES[type as keyof typeof VARIABLES_VALUES] - return value ? value : `"${type} Not implemented"` + return `Bytes.fromI32(${VARIABLES_VALUES[type]})`; + case fetchArrayInnerType(type)?.input: { + const innerType = fetchArrayInnerType(type)![1]; + return `[${assignValue(innerType)}]`; + } + default: { + const value = VARIABLES_VALUES[type as keyof typeof VARIABLES_VALUES]; + return value ? value : `"${type} Not implemented"`; + } } -} +}; /* Generates the assert.fieldEquals() for a given entity and event inputs. Example: @@ -86,11 +84,7 @@ const assignValue = (type: string): string | number | boolean => { "0x0000000000000000000000000000000000000001" ) */ -const generateFieldsAssertions = ( - entity: string, - eventInputs: any[], - indexEvents?: boolean, -) => +const generateFieldsAssertions = (entity: string, eventInputs: any[], indexEvents?: boolean) => eventInputs .filter(input => input.name != 'id') .map( @@ -102,28 +96,30 @@ const generateFieldsAssertions = ( "${expectedValue(ascTypeForEthereum(input.type))}" )`, ) - .join('\n') + .join('\n'); // Returns the expected value for a given type in generateFieldsAssertions() const expectedValue = (type: string): string | number | boolean => { switch (type) { - case fetchArrayInnerType(type)?.input: - const innerType = fetchArrayInnerType(type)![1] - return `[${expectedValue(innerType)}]` - default: - let value = VARIABLES_VALUES[type as keyof typeof VARIABLES_VALUES] - return value ? value : `${type} Not implemented` + case fetchArrayInnerType(type)?.input: { + const innerType = fetchArrayInnerType(type)![1]; + return `[${expectedValue(innerType)}]`; + } + default: { + const value = VARIABLES_VALUES[type as keyof typeof VARIABLES_VALUES]; + return value ? value : `${type} Not implemented`; + } } -} +}; // Checks if the type is a native AS type or should be imported from graph-ts const isNativeType = (type: string) => { - let natives = [/i32/, /string/, /boolean/] + const natives = [/i32/, /string/, /boolean/]; - return natives.some(rx => rx.test(type)) -} + return natives.some(rx => rx.test(type)); +}; -const fetchArrayInnerType = (type: string) => type.match(/Array<(.*?)>/) +const fetchArrayInnerType = (type: string) => type.match(/Array<(.*?)>/); // Generates the example test.ts file const generateExampleTest = ( @@ -132,9 +128,9 @@ const generateExampleTest = ( indexEvents?: boolean, importTypes?: string, ) => { - const entity = indexEvents ? `${event._alias}` : 'ExampleEntity' - const eventInputs = event.inputs - const eventName = event._alias + const entity = indexEvents ? String(event._alias) : 'ExampleEntity'; + const eventInputs = event.inputs; + const eventName = event._alias; return ` import { assert, describe, test, clearStore, beforeAll, afterAll } from "matchstick-as/assembly/index" @@ -176,36 +172,36 @@ const generateExampleTest = ( // https://thegraph.com/docs/en/developer/matchstick/#asserts }) }) -` -} +`; +}; // Generates the utils helper file const generateTestHelper = (contract: string, events: any[], importTypes: string) => { - const eventsNames = events.map(event => event._alias) + const eventsNames = events.map(event => event._alias); return ` import { newMockEvent } from 'matchstick-as'; import { ethereum, ${importTypes} } from '@graphprotocol/graph-ts'; import { ${eventsNames.join(', ')} } from '../generated/${contract}/${contract}'; - ${generateMockedEvents(events).join('\n')}` -} + ${generateMockedEvents(events).join('\n')}`; +}; const generateMockedEvents = (events: any[]) => - events.reduce((acc, event) => acc.concat(generateMockedEvent(event)), []) + events.reduce((acc, event) => acc.concat(generateMockedEvent(event)), []); const generateMockedEvent = (event: any) => { - const varName = `${strings.camelCase(event._alias)}Event` + const varName = `${strings.camelCase(event._alias)}Event`; const fnArgs = event.inputs.map( (input: any, index: number) => `${input.name || `param${index}`}: ${ascTypeForEthereum(input.type)}`, - ) + ); const ascToEth = event.inputs.map( (input: any, index: number) => `${varName}.parameters.push(new ethereum.EventParam("${ input.name || `param${index}` }", ${ethereumFromAsc(input.name || `param${index}`, input.type)}))`, - ) + ); return ` export function create${event._alias}Event(${fnArgs.join(', ')}): ${event._alias} { @@ -217,5 +213,5 @@ const generateMockedEvent = (event: any) => { return ${varName}; } - ` -} + `; +}; diff --git a/packages/cli/src/schema.ts b/packages/cli/src/schema.ts index 365b638f..616e3331 100644 --- a/packages/cli/src/schema.ts +++ b/packages/cli/src/schema.ts @@ -1,7 +1,7 @@ -import fs from 'fs-extra' -import * as graphql from 'graphql/language' -import immutable from 'immutable' -import SchemaCodeGenerator from './codegen/schema' +import fs from 'fs-extra'; +import * as graphql from 'graphql/language'; +import immutable from 'immutable'; +import SchemaCodeGenerator from './codegen/schema'; export default class Schema { constructor( @@ -9,18 +9,18 @@ export default class Schema { public document: string, public ast: immutable.Collection, ) { - this.filename = filename - this.document = document - this.ast = ast + this.filename = filename; + this.document = document; + this.ast = ast; } codeGenerator() { - return new SchemaCodeGenerator(this) + return new SchemaCodeGenerator(this); } static async load(filename: string) { - let document = await fs.readFile(filename, 'utf-8') - let ast = graphql.parse(document) - return new Schema(filename, document, immutable.fromJS(ast)) + const document = await fs.readFile(filename, 'utf-8'); + const ast = graphql.parse(document); + return new Schema(filename, document, immutable.fromJS(ast)); } } diff --git a/packages/cli/src/subgraph.ts b/packages/cli/src/subgraph.ts index 41960e90..82d9a163 100644 --- a/packages/cli/src/subgraph.ts +++ b/packages/cli/src/subgraph.ts @@ -1,14 +1,14 @@ -import fs from 'fs-extra' -import immutable from 'immutable' -import path from 'path' -import yaml from 'yaml' -import { strOptions } from 'yaml/types' -import * as graphql from 'graphql/language' -import * as validation from './validation' -import debug from './debug' -import { Subgraph as ISubgraph } from './protocols/subgraph' - -let subgraphDebug = debug('graph-cli:subgraph') +import path from 'path'; +import fs from 'fs-extra'; +import * as graphql from 'graphql/language'; +import immutable from 'immutable'; +import yaml from 'yaml'; +import { strOptions } from 'yaml/types'; +import debug from './debug'; +import { Subgraph as ISubgraph } from './protocols/subgraph'; +import * as validation from './validation'; + +const subgraphDebug = debug('graph-cli:subgraph'); const throwCombinedError = (filename: string, errors: immutable.List) => { throw new Error( @@ -20,8 +20,8 @@ const throwCombinedError = (filename: string, errors: immutable.List) => { ${e.get('message').split('\n').join('\n ')}`, `Error in ${path.relative(process.cwd(), filename)}:`, ), - ) -} + ); +}; const buildCombinedWarning = (filename: string, warnings: immutable.List) => warnings.size > 0 @@ -33,79 +33,72 @@ const buildCombinedWarning = (filename: string, warnings: immutable.List) = ${w.get('message').split('\n').join('\n ')}`, `Warnings in ${path.relative(process.cwd(), filename)}:`, ) + '\n' - : null + : null; -type ResolveFile = (path: string) => string +type ResolveFile = (path: string) => string; export default class Subgraph { - static async validate( - data: any, - protocol: any, - { resolveFile }: { resolveFile: ResolveFile }, - ) { - subgraphDebug(`Validating Subgraph with protocol "%s"`, protocol) + static async validate(data: any, protocol: any, { resolveFile }: { resolveFile: ResolveFile }) { + subgraphDebug(`Validating Subgraph with protocol "%s"`, protocol); if (protocol.name == null) { return immutable.fromJS([ { path: [], message: `Unable to determine for which protocol manifest file is built for. Ensure you have at least one 'dataSources' and/or 'templates' elements defined in your subgraph.`, }, - ]) + ]); } // Parse the default subgraph schema - let schema = graphql.parse( + const schema = graphql.parse( await fs.readFile( path.join(__dirname, 'protocols', protocol.name, `manifest.graphql`), 'utf-8', ), - ) + ); // Obtain the root `SubgraphManifest` type from the schema - let rootType = schema.definitions.find(definition => { + const rootType = schema.definitions.find(definition => { // @ts-expect-error TODO: name field does not exist on definition, really? - return definition.name.value === 'SubgraphManifest' - }) + return definition.name.value === 'SubgraphManifest'; + }); // Validate the subgraph manifest using this schema - return validation.validateManifest(data, rootType, schema, protocol, { resolveFile }) + return validation.validateManifest(data, rootType, schema, protocol, { resolveFile }); } static validateSchema(manifest: any, { resolveFile }: { resolveFile: ResolveFile }) { - let filename = resolveFile(manifest.getIn(['schema', 'file'])) - const validationErrors = validation.validateSchema(filename) - let errors: immutable.Collection + const filename = resolveFile(manifest.getIn(['schema', 'file'])); + const validationErrors = validation.validateSchema(filename); + let errors: immutable.Collection; if (validationErrors.size > 0) { - errors = validationErrors.groupBy(error => error.get('entity')).sort() - let msg = errors.reduce((msg, errors, entity) => { - errors = errors.groupBy((error: any) => error.get('directive')) - let inner_msgs = errors.reduce( - (msg: string, errors: any[], directive: string) => { - return `${msg}${ - directive - ? ` + errors = validationErrors.groupBy(error => error.get('entity')).sort(); + const msg = errors.reduce((msg, errors, entity) => { + errors = errors.groupBy((error: any) => error.get('directive')); + const inner_msgs = errors.reduce((msg: string, errors: any[], directive: string) => { + return `${msg}${ + directive + ? ` ${directive}:` - : '' - } + : '' + } ${errors .map(error => error.get('message').split('\n').join('\n ')) .map(msg => `${directive ? ' ' : ''}- ${msg}`) - .join('\n ')}` - }, - ``, - ) + .join('\n ')}`; + }, ``); return `${msg} - ${entity}:${inner_msgs}` - }, `Error in ${path.relative(process.cwd(), filename)}:`) + ${entity}:${inner_msgs}`; + }, `Error in ${path.relative(process.cwd(), filename)}:`); - throw new Error(msg) + throw new Error(msg); } } static validateRepository(manifest: immutable.Collection) { - const repository = manifest.get('repository') + const repository = manifest.get('repository'); return /^https:\/\/github\.com\/graphprotocol\/example-subgraphs?$/.test(repository) ? immutable.List().push( @@ -116,7 +109,7 @@ The repository is still set to ${repository}. Please replace it with a link to your subgraph source code.`, }), ) - : immutable.List() + : immutable.List(); } static validateDescription(manifest: immutable.Collection) { @@ -130,7 +123,7 @@ The description is still the one from the example subgraph. Please update it to tell users more about your subgraph.`, }), ) - : immutable.List() + : immutable.List(); } static validateHandlers( @@ -142,55 +135,55 @@ Please update it to tell users more about your subgraph.`, .get('dataSources') .filter((dataSource: any) => protocol.isValidKindName(dataSource.get('kind'))) .reduce((errors: any, dataSource: any, dataSourceIndex: any) => { - let path = ['dataSources', dataSourceIndex, 'mapping'] - let mapping = dataSource.get('mapping') - const handlerTypes = protocolSubgraph.handlerTypes() + const path = ['dataSources', dataSourceIndex, 'mapping']; + const mapping = dataSource.get('mapping'); + const handlerTypes = protocolSubgraph.handlerTypes(); subgraphDebug( 'Validating dataSource "%s" handlers with %d handlers types defined for protocol', dataSource.get('name'), handlerTypes.size, - ) + ); if (handlerTypes.size == 0) { - return errors + return errors; } const areAllHandlersEmpty = handlerTypes .map((handlerType: any) => mapping.get(handlerType, immutable.List())) - .every((handlers: immutable.List) => handlers.isEmpty()) + .every((handlers: immutable.List) => handlers.isEmpty()); - const handlerNamesWithoutLast = handlerTypes.pop().join(', ') + const handlerNamesWithoutLast = handlerTypes.pop().join(', '); return areAllHandlersEmpty ? errors.push( immutable.fromJS({ - path: path, + path, message: `\ Mapping has no ${handlerNamesWithoutLast} or ${handlerTypes.get(-1)}. At least one such handler must be defined.`, }), ) - : errors - }, immutable.List()) + : errors; + }, immutable.List()); } static validateContractValues(manifest: any, protocol: any) { if (!protocol.hasContract()) { - return immutable.List() + return immutable.List(); } - return validation.validateContractValues(manifest, protocol) + return validation.validateContractValues(manifest, protocol); } // Validate that data source names are unique, so they don't overwrite each other. static validateUniqueDataSourceNames(manifest: any) { - let names: any[] = [] + const names: any[] = []; return manifest .get('dataSources') .reduce((errors: immutable.List, dataSource: any, dataSourceIndex: number) => { - let path = ['dataSources', dataSourceIndex, 'name'] - let name = dataSource.get('name') + const path = ['dataSources', dataSourceIndex, 'name']; + const name = dataSource.get('name'); if (names.includes(name)) { errors = errors.push( immutable.fromJS({ @@ -198,20 +191,20 @@ At least one such handler must be defined.`, message: `\ More than one data source named '${name}', data source names must be unique.`, }), - ) + ); } - names.push(name) - return errors - }, immutable.List()) + names.push(name); + return errors; + }, immutable.List()); } static validateUniqueTemplateNames(manifest: any) { - let names: any[] = [] + const names: any[] = []; return manifest .get('templates', immutable.List()) .reduce((errors: immutable.List, template: any, templateIndex: number) => { - let path = ['templates', templateIndex, 'name'] - let name = template.get('name') + const path = ['templates', templateIndex, 'name']; + const name = template.get('name'); if (names.includes(name)) { errors = errors.push( immutable.fromJS({ @@ -219,19 +212,19 @@ More than one data source named '${name}', data source names must be unique.`, message: `\ More than one template named '${name}', template names must be unique.`, }), - ) + ); } - names.push(name) - return errors - }, immutable.List()) + names.push(name); + return errors; + }, immutable.List()); } static dump(manifest: any) { - strOptions.fold.lineWidth = 90 + strOptions.fold.lineWidth = 90; // @ts-expect-error TODO: plain is the value behind the TS constant - strOptions.defaultType = 'PLAIN' + strOptions.defaultType = 'PLAIN'; - return yaml.stringify(manifest.toJS()) + return yaml.stringify(manifest.toJS()); } static async load( @@ -241,41 +234,41 @@ More than one template named '${name}', template names must be unique.`, }, ) { // Load and validate the manifest - let data = null - let has_file_data_sources = false + let data = null; + let has_file_data_sources = false; if (filename.match(/.js$/)) { - data = require(path.resolve(filename)) + data = require(path.resolve(filename)); } else { - let raw_data = await fs.readFile(filename, 'utf-8') - has_file_data_sources = raw_data.includes('kind: file') - data = yaml.parse(raw_data) + const raw_data = await fs.readFile(filename, 'utf-8'); + has_file_data_sources = raw_data.includes('kind: file'); + data = yaml.parse(raw_data); } // Helper to resolve files relative to the subgraph manifest - let resolveFile: ResolveFile = maybeRelativeFile => - path.resolve(path.dirname(filename), maybeRelativeFile) + const resolveFile: ResolveFile = maybeRelativeFile => + path.resolve(path.dirname(filename), maybeRelativeFile); // TODO: Validation for file data sources if (!has_file_data_sources) { - let manifestErrors = await Subgraph.validate(data, protocol, { resolveFile }) + const manifestErrors = await Subgraph.validate(data, protocol, { resolveFile }); if (manifestErrors.size > 0) { - throwCombinedError(filename, manifestErrors) + throwCombinedError(filename, manifestErrors); } } - let manifest = immutable.fromJS(data) as immutable.Map + const manifest = immutable.fromJS(data) as immutable.Map; // Validate the schema - Subgraph.validateSchema(manifest, { resolveFile }) + Subgraph.validateSchema(manifest, { resolveFile }); // Perform other validations const protocolSubgraph = protocol.getSubgraph({ manifest, resolveFile, - }) + }); - let errors = skipValidation + const errors = skipValidation ? immutable.List() : immutable.List.of( ...protocolSubgraph.validateManifest(), @@ -283,27 +276,27 @@ More than one template named '${name}', template names must be unique.`, ...Subgraph.validateUniqueDataSourceNames(manifest), ...Subgraph.validateUniqueTemplateNames(manifest), ...Subgraph.validateHandlers(manifest, protocol, protocolSubgraph), - ) + ); if (errors.size > 0) { - throwCombinedError(filename, errors) + throwCombinedError(filename, errors); } // Perform warning validations - let warnings = skipValidation + const warnings = skipValidation ? immutable.List() : immutable.List.of( ...Subgraph.validateRepository(manifest), ...Subgraph.validateDescription(manifest), - ) + ); return { result: manifest, warning: warnings.size > 0 ? buildCombinedWarning(filename, warnings) : null, - } + }; } static async write(manifest: any, filename: string) { - await fs.writeFile(filename, Subgraph.dump(manifest)) + await fs.writeFile(filename, Subgraph.dump(manifest)); } } diff --git a/packages/cli/src/type-generator.ts b/packages/cli/src/type-generator.ts index 11a75649..1052bbae 100644 --- a/packages/cli/src/type-generator.ts +++ b/packages/cli/src/type-generator.ts @@ -1,55 +1,53 @@ -import fs from 'fs-extra' -import immutable from 'immutable' -import path from 'path' -import prettier from 'prettier' -import * as graphql from 'graphql/language' -import * as toolbox from 'gluegun' - -import Schema from './schema' -import Subgraph from './subgraph' -import DataSourceTemplateCodeGenerator from './codegen/template' -import Watcher from './watcher' -import { Spinner, step, withSpinner } from './command-helpers/spinner' -import { applyMigrations } from './migrations' -import { GENERATED_FILE_NOTE } from './codegen/typescript' -import { displayPath } from './command-helpers/fs' -import Protocol from './protocols' - +import path from 'path'; // @ts-expect-error TODO: type out if necessary -import uncrashable from '@float-capital/float-subgraph-uncrashable/src/Index.bs.js' +import uncrashable from '@float-capital/float-subgraph-uncrashable/src/Index.bs.js'; +import fs from 'fs-extra'; +import * as toolbox from 'gluegun'; +import * as graphql from 'graphql/language'; +import immutable from 'immutable'; +import prettier from 'prettier'; +import DataSourceTemplateCodeGenerator from './codegen/template'; +import { GENERATED_FILE_NOTE } from './codegen/typescript'; +import { displayPath } from './command-helpers/fs'; +import { Spinner, step, withSpinner } from './command-helpers/spinner'; +import { applyMigrations } from './migrations'; +import Protocol from './protocols'; +import Schema from './schema'; +import Subgraph from './subgraph'; +import Watcher from './watcher'; export interface TypeGeneratorOptions { - sourceDir?: string - subgraphManifest: string - subgraph?: string - protocol: Protocol - outputDir: string - skipMigrations?: boolean - uncrashable: any - uncrashableConfig: boolean + sourceDir?: string; + subgraphManifest: string; + subgraph?: string; + protocol: Protocol; + outputDir: string; + skipMigrations?: boolean; + uncrashable: any; + uncrashableConfig: boolean; } export default class TypeGenerator { - private sourceDir: string - private options: TypeGeneratorOptions - private protocol: Protocol - private protocolTypeGenerator: any + private sourceDir: string; + private options: TypeGeneratorOptions; + private protocol: Protocol; + private protocolTypeGenerator: any; constructor(options: TypeGeneratorOptions) { - this.options = options + this.options = options; this.sourceDir = this.options.sourceDir || - (this.options.subgraphManifest && path.dirname(this.options.subgraphManifest)) + (this.options.subgraphManifest && path.dirname(this.options.subgraphManifest)); - this.protocol = this.options.protocol + this.protocol = this.options.protocol; this.protocolTypeGenerator = this.protocol?.getTypeGenerator?.({ sourceDir: this.sourceDir, outputDir: this.options.outputDir, - }) + }); - process.on('uncaughtException', function (e) { - toolbox.print.error(`UNCAUGHT EXCEPTION: ${e}`) - }) + process.on('uncaughtException', e => { + toolbox.print.error(`UNCAUGHT EXCEPTION: ${e}`); + }); } async generateTypes() { @@ -58,97 +56,88 @@ export default class TypeGenerator { await applyMigrations({ sourceDir: this.sourceDir, manifestFile: this.options.subgraphManifest, - }) + }); } - let subgraph = await this.loadSubgraph() + const subgraph = await this.loadSubgraph(); // Not all protocols support/have ABIs. if (this.protocol.hasABIs()) { - const abis = await this.protocolTypeGenerator.loadABIs(subgraph) - await this.protocolTypeGenerator.generateTypesForABIs(abis) + const abis = await this.protocolTypeGenerator.loadABIs(subgraph); + await this.protocolTypeGenerator.generateTypesForABIs(abis); } - await this.generateTypesForDataSourceTemplates(subgraph) + await this.generateTypesForDataSourceTemplates(subgraph); // Not all protocols support/have ABIs. if (this.protocol.hasABIs()) { - const templateAbis = await this.protocolTypeGenerator.loadDataSourceTemplateABIs( - subgraph, - ) - await this.protocolTypeGenerator.generateTypesForDataSourceTemplateABIs( - templateAbis, - ) + const templateAbis = await this.protocolTypeGenerator.loadDataSourceTemplateABIs(subgraph); + await this.protocolTypeGenerator.generateTypesForDataSourceTemplateABIs(templateAbis); } - let schema = await this.loadSchema(subgraph) - await this.generateTypesForSchema(schema) + const schema = await this.loadSchema(subgraph); + await this.generateTypesForSchema(schema); - toolbox.print.success('\nTypes generated successfully\n') + toolbox.print.success('\nTypes generated successfully\n'); if (this.options.uncrashable && this.options.uncrashableConfig) { - await this.generateUncrashableEntities(schema) - toolbox.print.success('\nUncrashable Helpers generated successfully\n') + await this.generateUncrashableEntities(schema); + toolbox.print.success('\nUncrashable Helpers generated successfully\n'); } - return true + return true; } catch (e) { - return false + return false; } } async generateUncrashableEntities(graphSchema: any) { - let ast = graphql.parse(graphSchema.document) - let entityDefinitions = ast['definitions'] + const ast = graphql.parse(graphSchema.document); + const entityDefinitions = ast['definitions']; return await withSpinner( `Generate Uncrashable Entity Helpers`, `Failed to generate Uncrashable Entity Helpers`, `Warnings while generating Uncrashable Entity Helpers`, async spinner => { - uncrashable.run( - entityDefinitions, - this.options.uncrashableConfig, - this.options.outputDir, - ) - let outputFile = path.join(this.options.outputDir, 'UncrashableEntityHelpers.ts') - step(spinner, 'Save uncrashable entities to', displayPath(outputFile)) + uncrashable.run(entityDefinitions, this.options.uncrashableConfig, this.options.outputDir); + const outputFile = path.join(this.options.outputDir, 'UncrashableEntityHelpers.ts'); + step(spinner, 'Save uncrashable entities to', displayPath(outputFile)); }, - ) + ); } async loadSubgraph({ quiet } = { quiet: false }) { - const subgraphLoadOptions = { protocol: this.protocol, skipValidation: false } + const subgraphLoadOptions = { protocol: this.protocol, skipValidation: false }; if (quiet) { return this.options.subgraph ? this.options.subgraph - : (await Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions)).result - } else { - const manifestPath = displayPath(this.options.subgraphManifest) - - return await withSpinner( - `Load subgraph from ${manifestPath}`, - `Failed to load subgraph from ${manifestPath}`, - `Warnings while loading subgraph from ${manifestPath}`, - async _spinner => { - return this.options.subgraph - ? this.options.subgraph - : Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions) - }, - ) + : (await Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions)).result; } + const manifestPath = displayPath(this.options.subgraphManifest); + + return await withSpinner( + `Load subgraph from ${manifestPath}`, + `Failed to load subgraph from ${manifestPath}`, + `Warnings while loading subgraph from ${manifestPath}`, + async _spinner => { + return this.options.subgraph + ? this.options.subgraph + : Subgraph.load(this.options.subgraphManifest, subgraphLoadOptions); + }, + ); } async loadSchema(subgraph: immutable.Map) { - let maybeRelativePath = subgraph.getIn(['schema', 'file']) as string - let absolutePath = path.resolve(this.sourceDir, maybeRelativePath) + const maybeRelativePath = subgraph.getIn(['schema', 'file']) as string; + const absolutePath = path.resolve(this.sourceDir, maybeRelativePath); return await withSpinner( `Load GraphQL schema from ${displayPath(absolutePath)}`, `Failed to load GraphQL schema from ${displayPath(absolutePath)}`, `Warnings while loading GraphQL schema from ${displayPath(absolutePath)}`, async _spinner => { - let absolutePath = path.resolve(this.sourceDir, maybeRelativePath) - return Schema.load(absolutePath) + const absolutePath = path.resolve(this.sourceDir, maybeRelativePath); + return Schema.load(absolutePath); }, - ) + ); } async generateTypesForSchema(schema: any) { @@ -158,8 +147,8 @@ export default class TypeGenerator { `Warnings while generating types for GraphQL schema`, async spinner => { // Generate TypeScript module from schema - let codeGenerator = schema.codeGenerator() - let code = prettier.format( + const codeGenerator = schema.codeGenerator(); + const code = prettier.format( [ GENERATED_FILE_NOTE, ...codeGenerator.generateModuleImports(), @@ -168,14 +157,14 @@ export default class TypeGenerator { { parser: 'typescript', }, - ) + ); - let outputFile = path.join(this.options.outputDir, 'schema.ts') - step(spinner, 'Write types to', displayPath(outputFile)) - await fs.mkdirs(path.dirname(outputFile)) - await fs.writeFile(outputFile, code) + const outputFile = path.join(this.options.outputDir, 'schema.ts'); + step(spinner, 'Write types to', displayPath(outputFile)); + await fs.mkdirs(path.dirname(outputFile)); + await fs.writeFile(outputFile, code); }, - ) + ); } async generateTypesForDataSourceTemplates(subgraph: immutable.Map) { @@ -185,100 +174,93 @@ export default class TypeGenerator { `Warnings while generating types for data source templates`, async spinner => { // Combine the generated code for all templates - let codeSegments = subgraph + const codeSegments = subgraph .get('templates', immutable.List()) .reduce((codeSegments: any, template: any) => { - step( - spinner, - 'Generate types for data source template', - `${template.get('name')}`, - ) + step(spinner, 'Generate types for data source template', String(template.get('name'))); - let codeGenerator = new DataSourceTemplateCodeGenerator( - template, - this.protocol, - ) + const codeGenerator = new DataSourceTemplateCodeGenerator(template, this.protocol); // Only generate module imports once, because they are identical for // all types generated for data source templates. if (codeSegments.isEmpty()) { - codeSegments = codeSegments.concat(codeGenerator.generateModuleImports()) + codeSegments = codeSegments.concat(codeGenerator.generateModuleImports()); } - return codeSegments.concat(codeGenerator.generateTypes()) - }, immutable.List()) + return codeSegments.concat(codeGenerator.generateTypes()); + }, immutable.List()); if (!codeSegments.isEmpty()) { - let code = prettier.format([GENERATED_FILE_NOTE, ...codeSegments].join('\n'), { + const code = prettier.format([GENERATED_FILE_NOTE, ...codeSegments].join('\n'), { parser: 'typescript', - }) + }); - let outputFile = path.join(this.options.outputDir, 'templates.ts') - step(spinner, `Write types for templates to`, displayPath(outputFile)) - await fs.mkdirs(path.dirname(outputFile)) - await fs.writeFile(outputFile, code) + const outputFile = path.join(this.options.outputDir, 'templates.ts'); + step(spinner, `Write types for templates to`, displayPath(outputFile)); + await fs.mkdirs(path.dirname(outputFile)); + await fs.writeFile(outputFile, code); } }, - ) + ); } async getFilesToWatch() { try { - let files = [] - let subgraph = await this.loadSubgraph({ quiet: true }) + const files = []; + const subgraph = await this.loadSubgraph({ quiet: true }); // Add the subgraph manifest file - files.push(this.options.subgraphManifest) + files.push(this.options.subgraphManifest); // Add the GraphQL schema to the watched files - files.push(subgraph.getIn(['schema', 'file'])) + files.push(subgraph.getIn(['schema', 'file'])); // Add all file paths specified in manifest subgraph.get('dataSources').map((dataSource: any) => { dataSource.getIn(['mapping', 'abis']).map((abi: any) => { - files.push(abi.get('file')) - }) - }) + files.push(abi.get('file')); + }); + }); // Make paths absolute - return files.map(file => path.resolve(file)) + return files.map(file => path.resolve(file)); } catch (e) { - throw Error(`Failed to load subgraph: ${e.message}`) + throw Error(`Failed to load subgraph: ${e.message}`); } } async watchAndGenerateTypes() { - let generator = this - let spinner: Spinner + const generator = this; + let spinner: Spinner; // Create watcher and generate types once and then on every change to a watched file - let watcher = new Watcher({ + const watcher = new Watcher({ onReady: () => (spinner = toolbox.print.spin('Watching subgraph files')), onTrigger: async changedFile => { if (changedFile !== undefined) { - spinner.info(`File change detected: ${displayPath(changedFile)}\n`) + spinner.info(`File change detected: ${displayPath(changedFile)}\n`); } - await generator.generateTypes() - spinner.start() + await generator.generateTypes(); + spinner.start(); }, onCollectFiles: async () => await generator.getFilesToWatch(), onError: error => { - spinner.stop() - toolbox.print.error(`${error}\n`) - spinner.start() + spinner.stop(); + toolbox.print.error(`${error}\n`); + spinner.start(); }, - }) + }); // Catch keyboard interrupt: close watcher and exit process process.on('SIGINT', () => { - watcher.close() - process.exit() - }) + watcher.close(); + process.exit(); + }); try { - await watcher.watch() + await watcher.watch(); } catch (e) { - toolbox.print.error(`${e.message}`) + toolbox.print.error(String(e.message)); } } } diff --git a/packages/cli/src/validation/contract.ts b/packages/cli/src/validation/contract.ts index ceef0d51..4d6948ea 100644 --- a/packages/cli/src/validation/contract.ts +++ b/packages/cli/src/validation/contract.ts @@ -1,55 +1,51 @@ -import immutable from 'immutable' -import Protocol from '../protocols' -import { ContractCtor } from '../protocols/contract' +import immutable from 'immutable'; +import Protocol from '../protocols'; +import { ContractCtor } from '../protocols/contract'; export const validateContract = (value: string, ProtocolContract: ContractCtor) => { - const contract = new ProtocolContract(value) + const contract = new ProtocolContract(value); - const { valid, error } = contract.validate() + const { valid, error } = contract.validate(); if (!valid) { return { valid, error: `Contract ${ProtocolContract.identifierName()} is invalid: ${value}\n${error}`, - } + }; } - return { valid, error } -} + return { valid, error }; +}; -export const validateContractValues = ( - manifest: immutable.Map, - protocol: Protocol, -) => { - const ProtocolContract = protocol.getContract()! +export const validateContractValues = (manifest: immutable.Map, protocol: Protocol) => { + const ProtocolContract = protocol.getContract()!; - const fieldName = ProtocolContract.identifierName() + const fieldName = ProtocolContract.identifierName(); return manifest .get('dataSources') .filter((dataSource: any) => protocol.isValidKindName(dataSource.get('kind'))) .reduce((errors: any[], dataSource: any, dataSourceIndex: number) => { - let path = ['dataSources', dataSourceIndex, 'source', fieldName] + const path = ['dataSources', dataSourceIndex, 'source', fieldName]; // No need to validate if the source has no contract field if (!dataSource.get('source').has(fieldName)) { - return errors + return errors; } - let contractValue = dataSource.getIn(['source', fieldName]) + const contractValue = dataSource.getIn(['source', fieldName]); - const { valid, error } = validateContract(contractValue, ProtocolContract) + const { valid, error } = validateContract(contractValue, ProtocolContract); // Validate whether the contract is valid for the protocol if (valid) { - return errors - } else { - return errors.push( - immutable.fromJS({ - path, - message: error, - }), - ) + return errors; } - }, immutable.List()) -} + return errors.push( + immutable.fromJS({ + path, + message: error, + }), + ); + }, immutable.List()); +}; diff --git a/packages/cli/src/validation/index.ts b/packages/cli/src/validation/index.ts index 7d08a86e..db4d9c93 100644 --- a/packages/cli/src/validation/index.ts +++ b/packages/cli/src/validation/index.ts @@ -1,5 +1,5 @@ -import { validateSchema } from './schema' -import { validateManifest } from './manifest' -import { validateContractValues, validateContract } from './contract' +import { validateContract, validateContractValues } from './contract'; +import { validateManifest } from './manifest'; +import { validateSchema } from './schema'; -export { validateSchema, validateManifest, validateContractValues, validateContract } +export { validateContract, validateContractValues, validateManifest, validateSchema }; diff --git a/packages/cli/src/validation/manifest.ts b/packages/cli/src/validation/manifest.ts index b6739fc3..52ed1bc8 100644 --- a/packages/cli/src/validation/manifest.ts +++ b/packages/cli/src/validation/manifest.ts @@ -1,17 +1,17 @@ -import immutable from 'immutable' -import yaml from 'js-yaml' -import path from 'path' +import fs from 'fs'; +import path from 'path'; +import immutable from 'immutable'; +import yaml from 'js-yaml'; +import Protocol from '../protocols'; -import Protocol from '../protocols' - -const List = immutable.List -const Map = immutable.Map +const List = immutable.List; +const Map = immutable.Map; /** * Returns a user-friendly type name for a value. */ const typeName = (value: immutable.Collection) => - List.isList(value) ? 'list' : Map.isMap(value) ? 'map' : typeof value + List.isList(value) ? 'list' : Map.isMap(value) ? 'map' : typeof value; /** * Converts an immutable or plain JavaScript value to a YAML string. @@ -21,35 +21,30 @@ const toYAML = (x: immutable.Collection) => .safeDump(typeName(x) === 'list' || typeName(x) === 'map' ? x.toJS() : x, { indent: 2, }) - .trim() + .trim(); /** * Looks up the type of a field in a GraphQL object type. */ const getFieldType = (type: immutable.Map, fieldName: string) => { - let fieldDef = type + const fieldDef = type .get('fields') - .find((field: any) => field.getIn(['name', 'value']) === fieldName) + .find((field: any) => field.getIn(['name', 'value']) === fieldName); - return fieldDef !== undefined ? fieldDef.get('type') : undefined -} + return fieldDef !== undefined ? fieldDef.get('type') : undefined; +}; /** * Resolves a type in the GraphQL schema. */ -const resolveType = ( - schema: immutable.Map, - type: immutable.Map, -): any => +const resolveType = (schema: immutable.Map, type: immutable.Map): any => type.has('type') ? resolveType(schema, type.get('type')) : type.get('kind') === 'NamedType' ? schema .get('definitions') - .find( - (def: any) => def.getIn(['name', 'value']) === type.getIn(['name', 'value']), - ) - : 'resolveType: unimplemented' + .find((def: any) => def.getIn(['name', 'value']) === type.getIn(['name', 'value'])) + : 'resolveType: unimplemented'; /** * A map of supported validators. @@ -59,21 +54,21 @@ const validators = immutable.fromJS({ (validators.get(ctx.getIn(['type', 'name', 'value'])) as any)(value, ctx), UnionTypeDefinition: (value: any, ctx: immutable.Map) => { - const unionVariants = ctx.getIn(['type', 'types']) as any[] + const unionVariants = ctx.getIn(['type', 'types']) as any[]; - let errors = List() + let errors = List(); for (const variantType of unionVariants) { - const variantErrors = validateValue(value, ctx.set('type', variantType)) + const variantErrors = validateValue(value, ctx.set('type', variantType)); // No errors found, union variant matched, early return if (variantErrors.isEmpty()) { - return List() + return List(); } - errors = errors.push(variantErrors) + errors = errors.push(variantErrors); } // Return errors from variant that matched the most - return List(errors.minBy((variantErrors: any) => variantErrors.count()) as any) + return List(errors.minBy((variantErrors: any) => variantErrors.count()) as any); }, NamedType: (value: any, ctx: immutable.Map) => @@ -102,9 +97,7 @@ const validators = immutable.fromJS({ errors.concat( validateValue( value, - ctx - .update('path', path => path.push(i)) - .update('type', type => type.get('type')), + ctx.update('path', path => path.push(i)).update('type', type => type.get('type')), ), ), List(), @@ -155,15 +148,15 @@ const validators = immutable.fromJS({ path: ctx.get('path'), message: `Expected map, found ${typeName(value)}:\n${toYAML(value)}`, }, - ]) + ]); }, EnumTypeDefinition: (value: any, ctx: immutable.Map) => { const enumValues = (ctx.getIn(['type', 'values']) as any).map((v: any) => { - return v.getIn(['name', 'value']) - }) + return v.getIn(['name', 'value']); + }); - const allowedValues = enumValues.toArray().join(', ') + const allowedValues = enumValues.toArray().join(', '); return enumValues.includes(value) ? List() @@ -172,7 +165,7 @@ const validators = immutable.fromJS({ path: ctx.get('path'), message: `Unexpected enum value: ${value}, allowed values: ${allowedValues}`, }, - ]) + ]); }, String: (value: any, ctx: immutable.Map) => @@ -197,7 +190,7 @@ const validators = immutable.fromJS({ File: (value: any, ctx: immutable.Map) => typeof value === 'string' - ? require('fs').existsSync(ctx.get('resolveFile')(value)) + ? fs.existsSync(ctx.get('resolveFile')(value)) ? List() : immutable.fromJS([ { @@ -218,35 +211,31 @@ const validators = immutable.fromJS({ : immutable.fromJS([ { path: ctx.get('path'), - message: `Expected true or false, found ${typeName(value)}:\n${toYAML( - value, - )}`, + message: `Expected true or false, found ${typeName(value)}:\n${toYAML(value)}`, }, ]), -}) +}); const validateValue = (value: any, ctx: immutable.Collection) => { - let kind = ctx.getIn(['type', 'kind']) - let validator = validators.get(kind) as any + const kind = ctx.getIn(['type', 'kind']); + const validator = validators.get(kind) as any; if (validator !== undefined) { // If the type is nullable, accept undefined and null; if the nullable // type is wrapped in a `NonNullType`, the validator for that `NonNullType` // will catch the missing/unset value if (kind !== 'NonNullType' && (value === undefined || value === null)) { - return List() - } else { - return validator(value, ctx) + return List(); } - } else { - return immutable.fromJS([ - { - path: ctx.get('path'), - message: `No validator for unsupported schema type: ${kind}`, - }, - ]) + return validator(value, ctx); } -} + return immutable.fromJS([ + { + path: ctx.get('path'), + message: `No validator for unsupported schema type: ${kind}`, + }, + ]); +}; // Transforms list of data sources like this: // [ @@ -270,19 +259,17 @@ const dataSourceListToMap = (dataSources: any[]) => dataSources.reduce( (protocolKinds, dataSource) => protocolKinds.update(Protocol.normalizeName(dataSource.kind), (networks: any) => - (networks || immutable.OrderedMap()).update( - dataSource.network, - (dataSourceNames: any) => - (dataSourceNames || immutable.OrderedSet()).add(dataSource.name), + (networks || immutable.OrderedMap()).update(dataSource.network, (dataSourceNames: any) => + (dataSourceNames || immutable.OrderedSet()).add(dataSource.name), ), ), immutable.OrderedMap(), - ) + ); const validateDataSourceProtocolAndNetworks = (value: any) => { - const dataSources = [...value.dataSources, ...(value.templates || [])] + const dataSources = [...value.dataSources, ...(value.templates || [])]; - const protocolNetworkMap = dataSourceListToMap(dataSources) + const protocolNetworkMap = dataSourceListToMap(dataSources); if (protocolNetworkMap.size > 1) { return immutable.fromJS([ @@ -305,10 +292,10 @@ ${protocolNetworkMap .join('\n')} Recommendation: Make all data sources and templates use the same protocol kind.`, }, - ]) + ]); } - const networks = protocolNetworkMap.first() + const networks = protocolNetworkMap.first(); if (networks.size > 1) { return immutable.fromJS([ @@ -327,11 +314,11 @@ ${networks .join('\n')} Recommendation: Make all data sources and templates use the same network name.`, }, - ]) + ]); } - return List() -} + return List(); +}; export const validateManifest = ( value: any, @@ -341,13 +328,13 @@ export const validateManifest = ( { resolveFile }: { resolveFile: (path: string) => string }, ) => { // Validate manifest using the GraphQL schema that defines its structure - let errors = + const errors = value !== null && value !== undefined ? validateValue( immutable.fromJS(value), immutable.fromJS({ - schema: schema, - type: type, + schema, + type, path: [], errors: [], resolveFile, @@ -359,15 +346,15 @@ export const validateManifest = ( path: [], message: `Expected non-empty value, found ${typeName(value)}:\n ${value}`, }, - ]) + ]); // Fail early because a broken manifest prevents us from performing // additional validation steps if (!errors.isEmpty()) { - return errors + return errors; } // Validate that all data sources are for the same `network` and `protocol` (kind) // (this includes _no_ network/protocol at all) - return validateDataSourceProtocolAndNetworks(value) -} + return validateDataSourceProtocolAndNetworks(value); +}; diff --git a/packages/cli/src/validation/schema.test.ts b/packages/cli/src/validation/schema.test.ts index 16d6306b..51f49f3c 100644 --- a/packages/cli/src/validation/schema.test.ts +++ b/packages/cli/src/validation/schema.test.ts @@ -1,38 +1,38 @@ -import { typeSuggestion } from './schema' +import { typeSuggestion } from './schema'; describe('Schema validation', () => { test('Type suggestions', () => { - expect(typeSuggestion('Address')).toEqual('Bytes') - expect(typeSuggestion('address')).toEqual('Bytes') - expect(typeSuggestion('bytes')).toEqual('Bytes') - expect(typeSuggestion('string')).toEqual('String') - expect(typeSuggestion('bool')).toEqual('Boolean') - expect(typeSuggestion('boolean')).toEqual('Boolean') - expect(typeSuggestion('float')).toEqual('BigDecimal') - expect(typeSuggestion('Float')).toEqual('BigDecimal') + expect(typeSuggestion('Address')).toEqual('Bytes'); + expect(typeSuggestion('address')).toEqual('Bytes'); + expect(typeSuggestion('bytes')).toEqual('Bytes'); + expect(typeSuggestion('string')).toEqual('String'); + expect(typeSuggestion('bool')).toEqual('Boolean'); + expect(typeSuggestion('boolean')).toEqual('Boolean'); + expect(typeSuggestion('float')).toEqual('BigDecimal'); + expect(typeSuggestion('Float')).toEqual('BigDecimal'); - expect(typeSuggestion(`int`)).toBe('Int') - expect(typeSuggestion(`uint`)).toBe('BigInt') - expect(typeSuggestion(`uint32`)).toBe('BigInt') + expect(typeSuggestion(`int`)).toBe('Int'); + expect(typeSuggestion(`uint`)).toBe('BigInt'); + expect(typeSuggestion(`uint32`)).toBe('BigInt'); // Test i8..i32, int8..int32 for (let i = 8; i <= 32; i += 8) { - expect(typeSuggestion(`i${i}`)).toBe('Int') - expect(typeSuggestion(`int${i}`)).toBe('Int') + expect(typeSuggestion(`i${i}`)).toBe('Int'); + expect(typeSuggestion(`int${i}`)).toBe('Int'); } // Test u8..u24, uint8..uint24 for (let i = 8; i <= 24; i += 8) { - expect(typeSuggestion(`u${i}`)).toBe('Int') - expect(typeSuggestion(`uint${i}`)).toBe('Int') + expect(typeSuggestion(`u${i}`)).toBe('Int'); + expect(typeSuggestion(`uint${i}`)).toBe('Int'); } // Test i40..i256, int40..int256, u40..u256, uint40..uint256 for (let i = 40; i <= 256; i += 8) { - expect(typeSuggestion(`i${i}`)).toBe('BigInt') - expect(typeSuggestion(`int${i}`)).toBe('BigInt') - expect(typeSuggestion(`u${i}`)).toBe('BigInt') - expect(typeSuggestion(`uint${i}`)).toBe('BigInt') + expect(typeSuggestion(`i${i}`)).toBe('BigInt'); + expect(typeSuggestion(`int${i}`)).toBe('BigInt'); + expect(typeSuggestion(`u${i}`)).toBe('BigInt'); + expect(typeSuggestion(`uint${i}`)).toBe('BigInt'); } - }) -}) + }); +}); diff --git a/packages/cli/src/validation/schema.ts b/packages/cli/src/validation/schema.ts index 1d75ad4f..35de23fe 100644 --- a/packages/cli/src/validation/schema.ts +++ b/packages/cli/src/validation/schema.ts @@ -1,20 +1,12 @@ -import fs from 'fs' -import * as graphql from 'graphql/language' -import immutable from 'immutable' +import fs from 'fs'; +import * as graphql from 'graphql/language'; +import immutable from 'immutable'; -const List = immutable.List -const Set = immutable.Set +const List = immutable.List; +const Set = immutable.Set; // Builtin scalar types -const BUILTIN_SCALAR_TYPES = [ - 'Boolean', - 'Int', - 'BigDecimal', - 'String', - 'BigInt', - 'Bytes', - 'ID', -] +const BUILTIN_SCALAR_TYPES = ['Boolean', 'Int', 'BigDecimal', 'String', 'BigInt', 'Bytes', 'ID']; // Type suggestions for common mistakes const TYPE_SUGGESTIONS = [ @@ -44,10 +36,10 @@ const TYPE_SUGGESTIONS = [ /^(u|uint|i|int)(40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)$/, 'BigInt', ], -] +]; // As a convention, the type _Schema_ is reserved to define imports on. -const RESERVED_TYPE = '_Schema_' +const RESERVED_TYPE = '_Schema_'; /** * Returns a GraphQL type suggestion for a given input type. @@ -55,24 +47,24 @@ const RESERVED_TYPE = '_Schema_' */ export const typeSuggestion = (typeName: string) => TYPE_SUGGESTIONS.filter(([pattern, _]) => { - return typeof pattern === 'string' ? pattern === typeName : typeName.match(pattern) - }).map(([_, suggestion]) => suggestion)[0] + return typeof pattern === 'string' ? pattern === typeName : typeName.match(pattern); + }).map(([_, suggestion]) => suggestion)[0]; const loadSchema = (filename: string) => { try { - return fs.readFileSync(filename, 'utf-8') + return fs.readFileSync(filename, 'utf-8'); } catch (e) { - throw new Error(`Failed to load GraphQL schema: ${e}`) + throw new Error(`Failed to load GraphQL schema: ${e}`); } -} +}; const parseSchema = (doc: string) => { try { - return graphql.parse(doc) + return graphql.parse(doc); } catch (e) { - throw new Error(`Invalid GraphQL schema: ${e}`) + throw new Error(`Invalid GraphQL schema: ${e}`); } -} +}; const validateEntityDirective = (def: any) => def.directives.find((directive: any) => directive.name.value === 'entity') @@ -83,10 +75,10 @@ const validateEntityDirective = (def: any) => entity: def.name.value, message: `Defined without @entity directive`, }, - ]) + ]); const validateEntityID = (def: any) => { - let idField = def.fields.find((field: any) => field.name.value === 'id') + const idField = def.fields.find((field: any) => field.name.value === 'id'); if (idField === undefined) { return immutable.fromJS([ @@ -95,7 +87,7 @@ const validateEntityID = (def: any) => { entity: def.name.value, message: `Missing field: id: ID!`, }, - ]) + ]); } if ( @@ -105,17 +97,16 @@ const validateEntityID = (def: any) => { idField.type.type.name.value === 'Bytes' || idField.type.type.name.value === 'String') ) { - return List() - } else { - return immutable.fromJS([ - { - loc: idField.loc, - entity: def.name.value, - message: `Field 'id': Entity ids must be of type Bytes! or String!`, - }, - ]) + return List(); } -} + return immutable.fromJS([ + { + loc: idField.loc, + entity: def.name.value, + message: `Field 'id': Entity ids must be of type Bytes! or String!`, + }, + ]); +}; const validateListFieldType = (def: any, field: any) => field.type.kind === 'NonNullType' && @@ -146,26 +137,22 @@ must have type [${field.type.type.name.value}!] Reason: Lists with null elements are not supported.`, }, ]) - : List() + : List(); const unwrapType = (type: any) => { - let innerTypeFromList = (listType: any): any => - listType.type.kind === 'NonNullType' - ? innerTypeFromNonNull(listType.type) - : listType.type + const innerTypeFromList = (listType: any): any => + listType.type.kind === 'NonNullType' ? innerTypeFromNonNull(listType.type) : listType.type; - let innerTypeFromNonNull = (nonNullType: any): any => - nonNullType.type.kind === 'ListType' - ? innerTypeFromList(nonNullType.type) - : nonNullType.type + const innerTypeFromNonNull = (nonNullType: any): any => + nonNullType.type.kind === 'ListType' ? innerTypeFromList(nonNullType.type) : nonNullType.type; // Obtain the inner-most type from the field return type.kind === 'NonNullType' ? innerTypeFromNonNull(type) : type.kind === 'ListType' ? innerTypeFromList(type) - : type -} + : type; +}; const gatherLocalTypes = (defs: readonly graphql.DefinitionNode[]) => defs @@ -179,7 +166,7 @@ const gatherLocalTypes = (defs: readonly graphql.DefinitionNode[]) => def => // @ts-expect-error TODO: name field does not exist on definition, really? def.name.value, - ) + ); const gatherImportedTypes = (defs: readonly graphql.DefinitionNode[]) => defs @@ -203,8 +190,7 @@ const gatherImportedTypes = (defs: readonly graphql.DefinitionNode[]) => ) .map((imp: any) => imp.arguments.find( - (argument: any) => - argument.name.value == 'types' && argument.value.kind == 'ListValue', + (argument: any) => argument.name.value == 'types' && argument.value.kind == 'ListValue', ), ) .map((arg: any) => @@ -213,8 +199,7 @@ const gatherImportedTypes = (defs: readonly graphql.DefinitionNode[]) => ? type.value : type.kind == 'ObjectValue' && type.fields.find( - (field: any) => - field.name.value == 'as' && field.value.kind == 'StringValue', + (field: any) => field.name.value == 'as' && field.value.kind == 'StringValue', ) ? type.fields.find((field: any) => field.name.value == 'as').value.value : undefined, @@ -225,12 +210,12 @@ const gatherImportedTypes = (defs: readonly graphql.DefinitionNode[]) => (flattened, types_args) => flattened.concat( types_args.reduce((flattened: any, types_arg: any[]) => { - types_arg.forEach(type => (type ? flattened.push(type) : undefined)) - return flattened + types_arg.forEach(type => (type ? flattened.push(type) : undefined)); + return flattened; }, []), ), [], - ) + ); const entityTypeByName = (defs: any[], name: string) => defs @@ -240,28 +225,28 @@ const entityTypeByName = (defs: any[], name: string) => (def.kind === 'ObjectTypeDefinition' && def.directives.find((directive: any) => directive.name.value === 'entity')), ) - .find(def => def.name.value === name) + .find(def => def.name.value === name); -const fieldTargetEntityName = (field: any) => unwrapType(field.type).name.value +const fieldTargetEntityName = (field: any) => unwrapType(field.type).name.value; const fieldTargetEntity = (defs: any[], field: any) => - entityTypeByName(defs, fieldTargetEntityName(field)) + entityTypeByName(defs, fieldTargetEntityName(field)); const validateInnerFieldType = (defs: any[], def: any, field: any) => { - let innerType = unwrapType(field.type) + const innerType = unwrapType(field.type); // Get the name of the type - let typeName = innerType.name.value + const typeName = innerType.name.value; // Look up a possible suggestion for the type to catch common mistakes - let suggestion = typeSuggestion(typeName) + const suggestion = typeSuggestion(typeName); // Collect all types that we can use here: built-ins + entities + enums + interfaces - let availableTypes = List.of( + const availableTypes = List.of( ...BUILTIN_SCALAR_TYPES, ...gatherLocalTypes(defs), ...gatherImportedTypes(defs), - ) + ); // Check whether the type name is available, otherwise return an error return availableTypes.includes(typeName) @@ -272,18 +257,13 @@ const validateInnerFieldType = (defs: any[], def: any, field: any) => { entity: def.name.value, message: `\ Field '${field.name.value}': \ -Unknown type '${typeName}'.${ - suggestion !== undefined ? ` Did you mean '${suggestion}'?` : '' - }`, +Unknown type '${typeName}'.${suggestion !== undefined ? ` Did you mean '${suggestion}'?` : ''}`, }, - ]) -} + ]); +}; const validateEntityFieldType = (defs: any[], def: any, field: any) => - List.of( - ...validateListFieldType(def, field), - ...validateInnerFieldType(defs, def, field), - ) + List.of(...validateListFieldType(def, field), ...validateInnerFieldType(defs, def, field)); const validateEntityFieldArguments = (_defs: any[], def: any, field: any) => field.arguments.length > 0 @@ -296,14 +276,9 @@ Field '${field.name.value}': \ Field arguments are not supported.`, }, ]) - : List() + : List(); -const validateDerivedFromDirective = ( - defs: any[], - def: any, - field: any, - directive: any, -) => { +const validateDerivedFromDirective = (defs: any[], def: any, field: any, directive: any) => { // Validate that there is a `field` argument and nothing else if (directive.arguments.length !== 1 || directive.arguments[0].name.value !== 'field') { return immutable.fromJS([ @@ -314,7 +289,7 @@ const validateDerivedFromDirective = ( Field '${field.name.value}': \ @derivedFrom directive must have a 'field' argument`, }, - ]) + ]); } // Validate that the "field" argument value is a string @@ -327,20 +302,20 @@ Field '${field.name.value}': \ Field '${field.name.value}': \ Value of the @derivedFrom 'field' argument must be a string`, }, - ]) + ]); } - let targetEntity = fieldTargetEntity(defs, field) + const targetEntity = fieldTargetEntity(defs, field); if (targetEntity === undefined) { // This is handled in `validateInnerFieldType` but if we don't catch // the undefined case here, the code below will throw, as it assumes // the target entity exists - return immutable.fromJS([]) + return immutable.fromJS([]); } - let derivedFromField = targetEntity.fields.find( + const derivedFromField = targetEntity.fields.find( (field: any) => field.name.value === directive.arguments[0].value.value, - ) + ); if (derivedFromField === undefined) { return immutable.fromJS([ @@ -352,11 +327,11 @@ Field '${field.name.value}': \ @derivedFrom field '${directive.arguments[0].value.value}' \ does not exist on type '${targetEntity.name.value}'`, }, - ]) + ]); } - let backrefTypeName = unwrapType(derivedFromField.type) - let backRefEntity = entityTypeByName(defs, backrefTypeName.name.value) + const backrefTypeName = unwrapType(derivedFromField.type); + const backRefEntity = entityTypeByName(defs, backrefTypeName.name.value); // The field we are deriving from must either have type 'def' or one of the // interface types that 'def' is implementing @@ -376,28 +351,23 @@ on type '${targetEntity.name.value}' must have the type \ '${def.name.value}', '${def.name.value}!', '[${def.name.value}!]!', \ or one of the interface types that '${def.name.value}' implements`, }, - ]) + ]); } - return List() -} + return List(); +}; -const validateEntityFieldDirective = ( - defs: any[], - def: any, - field: any, - directive: any, -) => +const validateEntityFieldDirective = (defs: any[], def: any, field: any, directive: any) => directive.name.value === 'derivedFrom' ? validateDerivedFromDirective(defs, def, field, directive) - : List() + : List(); const validateEntityFieldDirectives = (defs: any[], def: any, field: any) => field.directives.reduce( (errors: any[], directive: any) => errors.concat(validateEntityFieldDirective(defs, def, field, directive)), List(), - ) + ); const validateEntityFields = (defs: any, def: any) => def.fields.reduce( @@ -407,7 +377,7 @@ const validateEntityFields = (defs: any, def: any) => .concat(validateEntityFieldArguments(defs, def, field)) .concat(validateEntityFieldDirectives(defs, def, field)), List(), - ) + ); const validateNoImportDirective = (def: any) => def.directives.find((directive: any) => directive.name.value == 'import') @@ -418,7 +388,7 @@ const validateNoImportDirective = (def: any) => message: `@import directive only allowed on '${RESERVED_TYPE}' type`, }), ]) - : List() + : List(); const validateNoFulltext = (def: any) => def.directives.find((directive: any) => directive.name.value == 'fulltext') @@ -429,7 +399,7 @@ const validateNoFulltext = (def: any) => message: `@fulltext directive only allowed on '${RESERVED_TYPE}' type`, }), ]) - : List() + : List(); const validateFulltextFields = (def: any, directive: any) => { return directive.arguments.reduce((errors: any[], argument: any) => { @@ -444,12 +414,12 @@ const validateFulltextFields = (def: any, directive: any) => { message: `found invalid argument: '${argument.name.value}', @fulltext directives only allow 'name', 'language', 'algorithm', and 'includes' arguments`, }), ]), - ) - }, List([])) -} + ); + }, List([])); +}; const validateFulltextName = (def: any, directive: any) => { - let name = directive.arguments.find((argument: any) => argument.name.value == 'name') + const name = directive.arguments.find((argument: any) => argument.name.value == 'name'); return name ? validateFulltextArgumentName(def, directive, name) : List([ @@ -459,8 +429,8 @@ const validateFulltextName = (def: any, directive: any) => { directive: fulltextDirectiveName(directive), message: `@fulltext argument 'name' must be specified`, }), - ]) -} + ]); +}; const validateFulltextArgumentName = (def: any, directive: any, argument: any) => { return argument.value.kind != 'StringValue' @@ -472,18 +442,16 @@ const validateFulltextArgumentName = (def: any, directive: any, argument: any) = message: `@fulltext argument 'name' must be a string`, }), ]) - : List([]) -} + : List([]); +}; const fulltextDirectiveName = (directive: any) => { - let arg = directive.arguments.find((argument: any) => argument.name.value == 'name') - return arg ? arg.value.value : 'Other' -} + const arg = directive.arguments.find((argument: any) => argument.name.value == 'name'); + return arg ? arg.value.value : 'Other'; +}; const validateFulltextLanguage = (def: any, directive: any) => { - let language = directive.arguments.find( - (argument: any) => argument.name.value == 'language', - ) + const language = directive.arguments.find((argument: any) => argument.name.value == 'language'); return language ? validateFulltextArgumentLanguage(def, directive, language) : List([ @@ -493,11 +461,11 @@ const validateFulltextLanguage = (def: any, directive: any) => { directive: fulltextDirectiveName(directive), message: `@fulltext argument 'language' must be specified`, }), - ]) -} + ]); +}; const validateFulltextArgumentLanguage = (def: any, directive: any, argument: any) => { - let languages = [ + const languages = [ 'simple', 'da', 'nl', @@ -514,7 +482,7 @@ const validateFulltextArgumentLanguage = (def: any, directive: any, argument: an 'es', 'sv', 'tr', - ] + ]; if (argument.value.kind != 'EnumValue') { return List([ immutable.fromJS({ @@ -523,27 +491,23 @@ const validateFulltextArgumentLanguage = (def: any, directive: any, argument: an directive: fulltextDirectiveName(directive), message: `@fulltext 'language' value must be one of: ${languages.join(', ')}`, }), - ]) - } else if (!languages.includes(argument.value.value)) { + ]); + } + if (!languages.includes(argument.value.value)) { return List([ immutable.fromJS({ loc: directive.name.loc, entity: def.name.value, directive: fulltextDirectiveName(directive), - message: `@fulltext directive 'language' value must be one of: ${languages.join( - ', ', - )}`, + message: `@fulltext directive 'language' value must be one of: ${languages.join(', ')}`, }), - ]) - } else { - return List([]) + ]); } -} + return List([]); +}; const validateFulltextAlgorithm = (def: any, directive: any) => { - let algorithm = directive.arguments.find( - (argument: any) => argument.name.value == 'algorithm', - ) + const algorithm = directive.arguments.find((argument: any) => argument.name.value == 'algorithm'); return algorithm ? validateFulltextArgumentAlgorithm(def, directive, algorithm) : List([ @@ -553,8 +517,8 @@ const validateFulltextAlgorithm = (def: any, directive: any) => { directive: fulltextDirectiveName(directive), message: `@fulltext argument 'algorithm' must be specified`, }), - ]) -} + ]); +}; const validateFulltextArgumentAlgorithm = (def: any, directive: any, argument: any) => { if (argument.value.kind != 'EnumValue') { @@ -565,8 +529,9 @@ const validateFulltextArgumentAlgorithm = (def: any, directive: any, argument: a directive: fulltextDirectiveName(directive), message: `@fulltext argument 'algorithm' must be one of: rank, proximityRank`, }), - ]) - } else if (!['rank', 'proximityRank'].includes(argument.value.value)) { + ]); + } + if (!['rank', 'proximityRank'].includes(argument.value.value)) { return List([ immutable.fromJS({ loc: directive.name.loc, @@ -574,16 +539,13 @@ const validateFulltextArgumentAlgorithm = (def: any, directive: any, argument: a directive: fulltextDirectiveName(directive), message: `@fulltext 'algorithm' value, '${argument.value.value}', must be one of: rank, proximityRank`, }), - ]) - } else { - return List([]) + ]); } -} + return List([]); +}; const validateFulltextInclude = (def: any, directive: any) => { - let include = directive.arguments.find( - (argument: any) => argument.name.value == 'include', - ) + const include = directive.arguments.find((argument: any) => argument.name.value == 'include'); if (include) { if (include.value.kind != 'ListValue') { return List([ @@ -593,24 +555,23 @@ const validateFulltextInclude = (def: any, directive: any) => { directive: fulltextDirectiveName(directive), message: `@fulltext argument 'include' must be a list`, }), - ]) + ]); } return include.value.values.reduce( (errors: any, type: any) => errors.concat(validateFulltextArgumentInclude(def, directive, type)), List(), - ) - } else { - return List([ - immutable.fromJS({ - loc: directive.name.loc, - entity: def.name.value, - directive: fulltextDirectiveName(directive), - message: `@fulltext argument 'include' must be specified`, - }), - ]) + ); } -} + return List([ + immutable.fromJS({ + loc: directive.name.loc, + entity: def.name.value, + directive: fulltextDirectiveName(directive), + message: `@fulltext argument 'include' must be specified`, + }), + ]); +}; const validateFulltextArgumentInclude = (def: any, directive: any, argument: any) => { if (argument.kind != 'ObjectValue') { @@ -621,7 +582,7 @@ const validateFulltextArgumentInclude = (def: any, directive: any, argument: any directive: fulltextDirectiveName(directive), message: `@fulltext argument 'include' must have the form '[{entity: "entityName", fields: [{name: "fieldName"}, ...]} ...]`, }), - ]) + ]); } if (argument.fields.length != 2) { return List([ @@ -631,14 +592,14 @@ const validateFulltextArgumentInclude = (def: any, directive: any, argument: any directive: fulltextDirectiveName(directive), message: `@fulltext argument include must have two fields, 'entity' and 'fields'`, }), - ]) + ]); } return argument.fields.reduce( (errors: any[], field: any) => errors.concat(validateFulltextArgumentIncludeFields(def, directive, field)), List([]), - ) -} + ); +}; const validateFulltextArgumentIncludeFields = (def: any, directive: any, field: any) => { if (!['entity', 'fields'].includes(field.name.value)) { @@ -649,7 +610,7 @@ const validateFulltextArgumentIncludeFields = (def: any, directive: any, field: directive: fulltextDirectiveName(directive), message: `@fulltext argument 'include > ${field.name.value}' must be be one of: entity, fields`, }), - ]) + ]); } if (field.name.value == 'entity' && field.value.kind != 'StringValue') { return List([ @@ -659,8 +620,9 @@ const validateFulltextArgumentIncludeFields = (def: any, directive: any, field: directive: fulltextDirectiveName(directive), message: `@fulltext argument 'include > entity' must be the name of an entity in the schema enclosed in double quotes`, }), - ]) - } else if (field.name.value == 'fields' && field.value.kind != 'ListValue') { + ]); + } + if (field.name.value == 'fields' && field.value.kind != 'ListValue') { return List([ immutable.fromJS({ loc: directive.name.loc, @@ -668,25 +630,19 @@ const validateFulltextArgumentIncludeFields = (def: any, directive: any, field: directive: fulltextDirectiveName(directive), message: `@fulltext argument 'include > fields' must be a list`, }), - ]) - } else if (field.name.value == 'fields' && field.value.kind == 'ListValue') { + ]); + } + if (field.name.value == 'fields' && field.value.kind == 'ListValue') { return field.value.values.reduce( (errors: any[], field: any) => - errors.concat( - validateFulltextArgumentIncludeFieldsObjects(def, directive, field), - ), + errors.concat(validateFulltextArgumentIncludeFieldsObjects(def, directive, field)), List([]), - ) - } else { - return List([]) + ); } -} + return List([]); +}; -const validateFulltextArgumentIncludeFieldsObjects = ( - def: any, - directive: any, - argument: any, -) => { +const validateFulltextArgumentIncludeFieldsObjects = (def: any, directive: any, argument: any) => { if (argument.kind != 'ObjectValue') { return List([ immutable.fromJS({ @@ -695,17 +651,14 @@ const validateFulltextArgumentIncludeFieldsObjects = ( directive: fulltextDirectiveName(directive), message: `@fulltext argument 'include > fields' must have the form '[{ name: "fieldName" }, ...]`, }), - ]) - } else { - return argument.fields.reduce( - (errors: any[], field: any) => - errors.concat( - validateFulltextArgumentIncludeArgumentFieldsObject(def, directive, field), - ), - List(), - ) + ]); } -} + return argument.fields.reduce( + (errors: any[], field: any) => + errors.concat(validateFulltextArgumentIncludeArgumentFieldsObject(def, directive, field)), + List(), + ); +}; const validateFulltextArgumentIncludeArgumentFieldsObject = ( def: any, @@ -720,8 +673,9 @@ const validateFulltextArgumentIncludeArgumentFieldsObject = ( directive: fulltextDirectiveName(directive), message: `@fulltext argument 'include > fields' has invalid member '${field.name.value}', must be one of: name`, }), - ]) - } else if (field.name.value == 'name' && field.value.kind != 'StringValue') { + ]); + } + if (field.name.value == 'name' && field.value.kind != 'StringValue') { return List([ immutable.fromJS({ loc: directive.name.loc, @@ -729,16 +683,15 @@ const validateFulltextArgumentIncludeArgumentFieldsObject = ( directive: fulltextDirectiveName(directive), message: `@fulltext argument 'include > fields > name' must be the name of an entity field enclosed in double quotes`, }), - ]) - } else { - return List([]) + ]); } -} + return List([]); +}; const importDirectiveTypeValidators = { StringValue: (_def: any, _directive: any, _type: any) => List(), ObjectValue: (def: any, directive: any, type: any) => { - let errors = List() + const errors = List(); if (type.fields.length != 2) { return errors.push( immutable.fromJS({ @@ -746,7 +699,7 @@ const importDirectiveTypeValidators = { entity: def.name.value, message: `Import must be one of "Name" or { name: "Name", as: "Alias" }`, }), - ) + ); } return type.fields.reduce((errors: any[], field: any) => { if (!['name', 'as'].includes(field.name.value)) { @@ -756,7 +709,7 @@ const importDirectiveTypeValidators = { entity: def.name.value, message: `@import field '${field.name.value}' invalid, may only be one of: name, as`, }), - ) + ); } if (field.value.kind != 'StringValue') { return errors.push( @@ -765,12 +718,12 @@ const importDirectiveTypeValidators = { entity: def.name.value, message: `@import fields [name, as] must be strings`, }), - ) + ); } - return errors - }, errors) + return errors; + }, errors); }, -} +}; const validateImportDirectiveType = ( def: any, @@ -785,14 +738,10 @@ const validateImportDirectiveType = ( entity: def.name.value, message: `Import must be one of "Name" or { name: "Name", as: "Alias" }`, }), - ]) -} + ]); +}; -const validateImportDirectiveArgumentTypes = ( - def: any, - directive: any, - argument: any, -) => { +const validateImportDirectiveArgumentTypes = (def: any, directive: any, argument: any) => { if (argument.value.kind != 'ListValue') { return List([ immutable.fromJS({ @@ -800,15 +749,14 @@ const validateImportDirectiveArgumentTypes = ( entity: def.name.value, message: `@import argument 'types' must be an list`, }), - ]) + ]); } return argument.value.values.reduce( - (errors: any[], type: any) => - errors.concat(validateImportDirectiveType(def, directive, type)), + (errors: any[], type: any) => errors.concat(validateImportDirectiveType(def, directive, type)), List(), - ) -} + ); +}; const validateImportDirectiveArgumentFrom = (def: any, directive: any, argument: any) => { if (argument.value.kind != 'ObjectValue') { @@ -818,7 +766,7 @@ const validateImportDirectiveArgumentFrom = (def: any, directive: any, argument: entity: def.name.value, message: `@import argument 'from' must be an object`, }), - ]) + ]); } if (argument.value.fields.length != 1) { @@ -828,7 +776,7 @@ const validateImportDirectiveArgumentFrom = (def: any, directive: any, argument: entity: def.name.value, message: `@import argument 'from' must have an 'id' or 'name' field`, }), - ]) + ]); } return argument.value.fields.reduce((errors: any[], field: any) => { @@ -839,7 +787,7 @@ const validateImportDirectiveArgumentFrom = (def: any, directive: any, argument: entity: def.name.value, message: `@import argument 'from' must be one of { name: "Name" } or { id: "ID" }`, }), - ) + ); } if (field.value.kind != 'StringValue') { return errors.push( @@ -848,11 +796,11 @@ const validateImportDirectiveArgumentFrom = (def: any, directive: any, argument: entity: def.name.value, message: `@import argument 'from' must be one of { name: "Name" } or { id: "ID" } with string values`, }), - ) + ); } - return errors - }, List()) -} + return errors; + }, List()); +}; const validateImportDirectiveFields = (def: any, directive: any) => { return directive.arguments.reduce((errors: any[], argument: any) => { @@ -866,12 +814,12 @@ const validateImportDirectiveFields = (def: any, directive: any) => { message: `found invalid argument: '${argument.name.value}', @import directives only allow 'types' and 'from' arguments`, }), ]), - ) - }, List([])) -} + ); + }, List([])); +}; const validateImportDirectiveTypes = (def: any, directive: any) => { - let types = directive.arguments.find((argument: any) => argument.name.value == 'types') + const types = directive.arguments.find((argument: any) => argument.name.value == 'types'); return types ? validateImportDirectiveArgumentTypes(def, directive, types) : List([ @@ -880,11 +828,11 @@ const validateImportDirectiveTypes = (def: any, directive: any) => { entity: def.name.value, message: `@import argument 'types' must be specified`, }), - ]) -} + ]); +}; const validateImportDirectiveFrom = (def: any, directive: any) => { - let from = directive.arguments.find((argument: any) => argument.name.value == 'from') + const from = directive.arguments.find((argument: any) => argument.name.value == 'from'); return from ? validateImportDirectiveArgumentFrom(def, directive, from) : List([ @@ -893,15 +841,15 @@ const validateImportDirectiveFrom = (def: any, directive: any) => { entity: def.name.value, message: `@import argument 'from' must be specified`, }), - ]) -} + ]); +}; const validateImportDirective = (def: any, directive: any) => List.of( ...validateImportDirectiveFields(def, directive), ...validateImportDirectiveTypes(def, directive), ...validateImportDirectiveFrom(def, directive), - ) + ); const validateFulltext = (def: any, directive: any) => List.of( @@ -910,30 +858,30 @@ const validateFulltext = (def: any, directive: any) => ...validateFulltextLanguage(def, directive), ...validateFulltextAlgorithm(def, directive), ...validateFulltextInclude(def, directive), - ) + ); const validateSubgraphSchemaDirective = (def: any, directive: any) => { if (directive.name.value == 'import') { - return validateImportDirective(def, directive) - } else if (directive.name.value == 'fulltext') { - return validateFulltext(def, directive) - } else { - return List([ - immutable.fromJS({ - loc: directive.name.loc, - entity: def.name.value, - message: `${RESERVED_TYPE} type only allows @import and @fulltext directives`, - }), - ]) + return validateImportDirective(def, directive); + } + if (directive.name.value == 'fulltext') { + return validateFulltext(def, directive); } -} + return List([ + immutable.fromJS({ + loc: directive.name.loc, + entity: def.name.value, + message: `${RESERVED_TYPE} type only allows @import and @fulltext directives`, + }), + ]); +}; const validateSubgraphSchemaDirectives = (def: any) => def.directives.reduce( (errors: any[], directive: any) => errors.concat(validateSubgraphSchemaDirective(def, directive)), List(), - ) + ); const validateTypeHasNoFields = (def: any) => def.fields.length @@ -944,9 +892,9 @@ const validateTypeHasNoFields = (def: any) => message: `${def.name.value} type is not allowed any fields by convention`, }), ]) - : List() + : List(); -const validateAtLeastOneExtensionField = (_def: any) => List() +const validateAtLeastOneExtensionField = (_def: any) => List(); const typeDefinitionValidators = { ObjectTypeDefinition: (defs: any[], def: any) => @@ -960,25 +908,22 @@ const typeDefinitionValidators = { ...validateNoFulltext(def), ), ObjectTypeExtension: (_defs: any[], def: any) => validateAtLeastOneExtensionField(def), -} +}; -const validateTypeDefinition = ( - defs: any, - def: { kind: keyof typeof typeDefinitionValidators }, -) => +const validateTypeDefinition = (defs: any, def: { kind: keyof typeof typeDefinitionValidators }) => typeDefinitionValidators[def.kind] !== undefined ? typeDefinitionValidators[def.kind](defs, def) - : List() + : List(); const validateTypeDefinitions = (defs: any) => defs.reduce( (errors: any[], def: any) => errors.concat(validateTypeDefinition(defs, def)), List(), - ) + ); const validateNamingCollisionsInTypes = (types: any) => { - let seen = Set() - let conflicting = Set() + let seen = Set(); + let conflicting = Set(); return types.reduce((errors: immutable.List, type: any) => { if (seen.has(type) && !conflicting.has(type)) { errors = errors.push( @@ -987,26 +932,26 @@ const validateNamingCollisionsInTypes = (types: any) => { entity: type, message: `Type '${type}' is defined more than once`, }), - ) - conflicting = conflicting.add(type) + ); + conflicting = conflicting.add(type); } else { - seen = seen.add(type) + seen = seen.add(type); } - return errors - }, List()) -} + return errors; + }, List()); +}; const validateNamingCollisions = (local: any[], imported: any) => - validateNamingCollisionsInTypes(local.concat(imported)) + validateNamingCollisionsInTypes(local.concat(imported)); export const validateSchema = (filename: string) => { - let doc = loadSchema(filename) - let schema = parseSchema(doc) + const doc = loadSchema(filename); + const schema = parseSchema(doc); return List.of( ...validateTypeDefinitions(schema.definitions), ...validateNamingCollisions( gatherLocalTypes(schema.definitions), gatherImportedTypes(schema.definitions), ), - ) -} + ); +}; diff --git a/packages/cli/src/watcher.ts b/packages/cli/src/watcher.ts index d02f9490..470b267a 100644 --- a/packages/cli/src/watcher.ts +++ b/packages/cli/src/watcher.ts @@ -1,96 +1,96 @@ -import chokidar from 'chokidar' -import path from 'path' +import path from 'path'; +import chokidar from 'chokidar'; export default class Watcher { - private onReady: () => void - private onTrigger: (arg: any) => void - private onCollectFiles: () => Promise - private onError: (error: Error) => void - private watcher: chokidar.FSWatcher | undefined + private onReady: () => void; + private onTrigger: (arg: any) => void; + private onCollectFiles: () => Promise; + private onError: (error: Error) => void; + private watcher: chokidar.FSWatcher | undefined; constructor(options: { - onReady: () => void - onTrigger: (arg: any) => void - onCollectFiles: () => Promise - onError: (error: Error) => void + onReady: () => void; + onTrigger: (arg: any) => void; + onCollectFiles: () => Promise; + onError: (error: Error) => void; }) { - const { onReady, onTrigger, onCollectFiles, onError } = options - this.onReady = onReady - this.onTrigger = onTrigger - this.onCollectFiles = onCollectFiles - this.onError = onError + const { onReady, onTrigger, onCollectFiles, onError } = options; + this.onReady = onReady; + this.onTrigger = onTrigger; + this.onCollectFiles = onCollectFiles; + this.onError = onError; } async watch() { // Collect files to watch - let files = await this.onCollectFiles() + const files = await this.onCollectFiles(); // Initialize watcher this.watcher = chokidar.watch(files, { persistent: true, ignoreInitial: true, atomic: 500, - }) + }); // Bind variables locally - let watcher = this.watcher - let onTrigger = this.onTrigger - let onCollectFiles = this.onCollectFiles - let onError = this.onError - let onReady = this.onReady + const watcher = this.watcher; + const onTrigger = this.onTrigger; + const onCollectFiles = this.onCollectFiles; + const onError = this.onError; + const onReady = this.onReady; watcher.on('ready', async () => { // Notify listeners that we're watching - onReady() + onReady(); // Trigger once when ready - await onTrigger(undefined) - }) + await onTrigger(undefined); + }); watcher.on('error', (error: any) => { - onError(error) - }) + onError(error); + }); watcher.on('all', async (_: any, file: any) => { try { // Collect watch all new files to watch - let newFiles = await onCollectFiles() + const newFiles = await onCollectFiles(); // Collect watched files, if there are any - let watchedFiles = [] + let watchedFiles = []; - let watched = watcher.getWatched() + const watched = watcher.getWatched(); watchedFiles = Object.keys(watched).reduce( (files: string[], dirname: string) => watched[dirname].reduce((files: string[], filename: string) => { - files.push(path.resolve(path.join(dirname, filename))) - return files + files.push(path.resolve(path.join(dirname, filename))); + return files; }, files), [], - ) + ); - let diff = (xs: any[], ys: any[]) => ({ - added: ys.filter((y: any) => xs.indexOf(y) < 0), - removed: xs.filter((x: any) => ys.indexOf(x) < 0), - }) + const diff = (xs: any[], ys: any[]) => ({ + added: ys.filter((y: any) => !xs.includes(y)), + removed: xs.filter((x: any) => !ys.includes(x)), + }); // Diff previously watched files and new files; then remove and // add files from/to the watcher accordingly - let filesDiff = diff(watchedFiles, newFiles) - watcher.unwatch(filesDiff.removed) - watcher.add(filesDiff.added) + const filesDiff = diff(watchedFiles, newFiles); + watcher.unwatch(filesDiff.removed); + watcher.add(filesDiff.added); // Run the trigger callback - await onTrigger(file) + await onTrigger(file); } catch (e) { - onError(e) + onError(e); } - }) + }); } close() { if (this.watcher !== undefined) { - this.watcher.close() + this.watcher.close(); } } } diff --git a/packages/cli/tests/cli/globalSetup.ts b/packages/cli/tests/cli/globalSetup.ts index 3123f0ea..20d5a7e3 100644 --- a/packages/cli/tests/cli/globalSetup.ts +++ b/packages/cli/tests/cli/globalSetup.ts @@ -1,6 +1,8 @@ -import { npmLinkCli } from './util' +/* eslint-disable */ + +import { npmLinkCli } from './util'; export default async () => { - process.env.GRAPH_CLI_TESTS = '1' - await npmLinkCli() -} + process.env.GRAPH_CLI_TESTS = '1'; + await npmLinkCli(); +}; diff --git a/packages/cli/tests/cli/globalTeardown.ts b/packages/cli/tests/cli/globalTeardown.ts index 143e6fc6..d1ffec36 100644 --- a/packages/cli/tests/cli/globalTeardown.ts +++ b/packages/cli/tests/cli/globalTeardown.ts @@ -1,6 +1,8 @@ -import { npmUnlinkCli } from './util' +/* eslint-disable */ + +import { npmUnlinkCli } from './util'; export default async () => { - delete process.env.GRAPH_CLI_TESTS - await npmUnlinkCli() -} + delete process.env.GRAPH_CLI_TESTS; + await npmUnlinkCli(); +}; diff --git a/packages/cli/tests/cli/init.test.ts b/packages/cli/tests/cli/init.test.ts index e153e3f2..d54de441 100644 --- a/packages/cli/tests/cli/init.test.ts +++ b/packages/cli/tests/cli/init.test.ts @@ -1,11 +1,11 @@ -import path from 'path' -import { cliTest } from './util' +import path from 'path'; +import { cliTest } from './util'; describe('Init', () => { - const baseDir = path.join(__dirname, 'init') + const baseDir = path.join(__dirname, 'init'); describe('Ethereum', () => { - const ethereumBaseDir = path.join(baseDir, 'ethereum') + const ethereumBaseDir = path.join(baseDir, 'ethereum'); cliTest( 'From example', @@ -22,11 +22,11 @@ describe('Init', () => { path.join('init', 'ethereum', 'from-example'), { exitCode: 0, - timeout: 100000, + timeout: 100_000, cwd: ethereumBaseDir, deleteDir: true, }, - ) + ); cliTest( 'From contract', @@ -45,11 +45,11 @@ describe('Init', () => { path.join('init', 'ethereum', 'from-contract'), { exitCode: 0, - timeout: 100000, + timeout: 100_000, cwd: ethereumBaseDir, deleteDir: true, }, - ) + ); cliTest( 'From contract with abi', @@ -70,11 +70,11 @@ describe('Init', () => { path.join('init', 'ethereum', 'from-contract-with-abi'), { exitCode: 0, - timeout: 100000, + timeout: 100_000, cwd: ethereumBaseDir, deleteDir: true, }, - ) + ); cliTest( 'From contract with abi and structs', @@ -95,11 +95,11 @@ describe('Init', () => { path.join('init', 'ethereum', 'from-contract-with-abi-and-structs'), { exitCode: 0, - timeout: 100000, + timeout: 100_000, cwd: ethereumBaseDir, deleteDir: true, }, - ) + ); cliTest( 'From contract with overloaded elements', @@ -120,15 +120,15 @@ describe('Init', () => { path.join('init', 'ethereum', 'from-contract-with-overloaded-elements'), { exitCode: 0, - timeout: 100000, + timeout: 100_000, cwd: ethereumBaseDir, deleteDir: true, }, - ) - }) + ); + }); describe('NEAR', () => { - const nearBaseDir = path.join(baseDir, 'near') + const nearBaseDir = path.join(baseDir, 'near'); cliTest( 'From contract', @@ -148,10 +148,10 @@ describe('Init', () => { path.join('init', 'near', 'from-contract'), { exitCode: 0, - timeout: 100000, + timeout: 100_000, cwd: nearBaseDir, deleteDir: true, }, - ) - }) -}) + ); + }); +}); diff --git a/packages/cli/tests/cli/spawn-command.d.ts b/packages/cli/tests/cli/spawn-command.d.ts index 2588221c..2d2e32b7 100644 --- a/packages/cli/tests/cli/spawn-command.d.ts +++ b/packages/cli/tests/cli/spawn-command.d.ts @@ -1,6 +1,7 @@ declare module 'spawn-command' { - import { spawn, SpawnOptions, ChildProcessByStdio, StdioPipe } from 'child_process' - type SpawnResult = ChildProcessByStdio - export { SpawnOptions, SpawnResult } - export default function spawn(command: string, options: SpawnOptions): SpawnResult + import { spawn, SpawnOptions, ChildProcessByStdio } from 'child_process'; + + type SpawnResult = ChildProcessByStdio; + export { SpawnOptions, SpawnResult }; + export default function spawn(command: string, options: SpawnOptions): SpawnResult; } diff --git a/packages/cli/tests/cli/util.ts b/packages/cli/tests/cli/util.ts index 23a4dba0..23c4c9a1 100644 --- a/packages/cli/tests/cli/util.ts +++ b/packages/cli/tests/cli/util.ts @@ -1,54 +1,58 @@ -import fs from 'fs-extra' -import path from 'path' -import spawn from 'spawn-command' -import stripAnsi from 'strip-ansi' +import path from 'path'; +import fs from 'fs-extra'; +import spawn from 'spawn-command'; +import stripAnsi from 'strip-ansi'; // Deletes folder if: // - flag is true // - folder exists const deleteDir = (dir: string, flag: boolean) => { if (flag && fs.existsSync(dir)) { - fs.removeSync(dir) + fs.removeSync(dir); } -} +}; -const resolvePath = (p: string) => path.join(__dirname, p) +const resolvePath = (p: string) => path.join(__dirname, p); export function cliTest( title: string, args: string[], testPath: string, options: { - cwd?: string - deleteDir?: boolean - exitCode?: number - timeout?: number + cwd?: string; + deleteDir?: boolean; + exitCode?: number; + timeout?: number; } = {}, ) { test( title, async () => { try { - deleteDir(resolvePath(`./${testPath}`), !!options.deleteDir) + deleteDir(resolvePath(`./${testPath}`), !!options.deleteDir); // Use the provided cwd if desired - let cwd = options.cwd ? options.cwd : resolvePath(`./${testPath}`) + const cwd = options.cwd ? options.cwd : resolvePath(`./${testPath}`); - let [exitCode, stdout, stderr] = await runGraphCli(args, cwd) + const [exitCode, stdout, stderr] = await runGraphCli(args, cwd); - let expectedExitCode = undefined + let expectedExitCode = undefined; if (options.exitCode !== undefined) { - expectedExitCode = options.exitCode + expectedExitCode = options.exitCode; } - let expectedStdout = undefined + let expectedStdout = undefined; try { - expectedStdout = fs.readFileSync(resolvePath(`./${testPath}.stdout`), 'utf-8') - } catch (e) {} + expectedStdout = fs.readFileSync(resolvePath(`./${testPath}.stdout`), 'utf-8'); + } catch (e) { + // noop + } - let expectedStderr = undefined + let expectedStderr = undefined; try { - expectedStderr = fs.readFileSync(resolvePath(`./${testPath}.stderr`), 'utf-8') - } catch (e) {} + expectedStderr = fs.readFileSync(resolvePath(`./${testPath}.stderr`), 'utf-8'); + } catch (e) { + // noop + } if (expectedStderr !== undefined) { // For some reason the error sometimes comes in stdout, then @@ -61,22 +65,22 @@ export function cliTest( // be using console.error or print.error for example) so this // check can be removed. if (stderr.length === 0 && stdout.length !== 0) { - throw new Error(stdout) + throw new Error(stdout); } - expect(stripAnsi(stderr)).toBe(expectedStderr) + expect(stripAnsi(stderr)).toBe(expectedStderr); } if (expectedExitCode !== undefined) { - expect(exitCode).toBe(expectedExitCode) + expect(exitCode).toBe(expectedExitCode); } if (expectedStdout !== undefined) { - expect(stripAnsi(stdout)).toBe(expectedStdout) + expect(stripAnsi(stdout)).toBe(expectedStdout); } } finally { - deleteDir(resolvePath(`./${testPath}`), !!options.deleteDir) + deleteDir(resolvePath(`./${testPath}`), !!options.deleteDir); } }, options.timeout || undefined, - ) + ); } function runCommand( @@ -91,38 +95,38 @@ function runCommand( ] > { // Make sure to set an absolute working directory - cwd = cwd[0] !== '/' ? path.resolve(__dirname, cwd) : cwd + cwd = cwd[0] !== '/' ? path.resolve(__dirname, cwd) : cwd; return new Promise((resolve, reject) => { - let stdout = '' - let stderr = '' - const child = spawn(`${command} ${args.join(' ')}`, { cwd }) + let stdout = ''; + let stderr = ''; + const child = spawn(`${command} ${args.join(' ')}`, { cwd }); child.on('error', error => { - reject(error) - }) + reject(error); + }); child.stdout.on('data', (data: Buffer) => { - stdout += data.toString() - }) + stdout += data.toString(); + }); child.stderr.on('data', (data: Buffer) => { - stderr += data.toString() - }) + stderr += data.toString(); + }); child.on('exit', exitCode => { - resolve([exitCode, stdout, stderr]) - }) - }) + resolve([exitCode, stdout, stderr]); + }); + }); } export function runGraphCli(args: string[], cwd: string) { // Resolve the path to graph.js - let graphCli = path.join(__dirname, '..', '..', 'dist', 'bin.js') + const graphCli = path.join(__dirname, '..', '..', 'dist', 'bin.js'); - return runCommand(graphCli, args, cwd) + return runCommand(graphCli, args, cwd); } -export const npmLinkCli = () => runCommand('npm', ['link']) +export const npmLinkCli = () => runCommand('npm', ['link']); -export const npmUnlinkCli = () => runCommand('npm', ['unlink']) +export const npmUnlinkCli = () => runCommand('npm', ['unlink']); diff --git a/packages/cli/tests/cli/validation.test.ts b/packages/cli/tests/cli/validation.test.ts index 6456e8fd..7f0f2158 100644 --- a/packages/cli/tests/cli/validation.test.ts +++ b/packages/cli/tests/cli/validation.test.ts @@ -1,4 +1,4 @@ -const cliTest = require('./util').cliTest +import { cliTest } from './util'; describe('Validation', () => { cliTest( @@ -8,7 +8,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Invalid subgraph manifest (cannot infer protocol)', ['codegen', '--skip-migrations'], @@ -16,7 +16,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'ABI not found in data source', ['codegen', '--skip-migrations'], @@ -24,13 +24,10 @@ describe('Validation', () => { { exitCode: 1, }, - ) - cliTest( - 'Invalid ABI files', - ['codegen', '--skip-migrations'], - 'validation/invalid-abis', - { exitCode: 1 }, - ) + ); + cliTest('Invalid ABI files', ['codegen', '--skip-migrations'], 'validation/invalid-abis', { + exitCode: 1, + }); cliTest( 'Event not found in ABI', ['codegen', '--skip-migrations'], @@ -38,7 +35,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Call function not found in the ABI', ['codegen', '--skip-migrations'], @@ -46,7 +43,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Call handler with tuple', ['codegen', '--skip-migrations'], @@ -54,7 +51,7 @@ describe('Validation', () => { { exitCode: 0, }, - ) + ); cliTest( 'Missing entity "id" field', ['codegen', '--skip-migrations'], @@ -62,7 +59,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Invalid entity field types', ['codegen', '--skip-migrations'], @@ -70,12 +67,12 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Invalid contract addresses', ['codegen', '--skip-migrations'], 'validation/invalid-contract-addresses', - ) + ); cliTest( 'Entity field arguments', ['codegen', '--skip-migrations'], @@ -83,13 +80,13 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Example values found in manifest', ['codegen', '--skip-migrations'], 'validation/example-values-found', { exitCode: 0 }, - ) + ); cliTest( 'Source without address is valid', ['codegen', '--skip-migrations'], @@ -97,13 +94,13 @@ describe('Validation', () => { { exitCode: 0, }, - ) + ); cliTest( 'Invalid data source template', ['codegen', '--skip-migrations'], 'validation/invalid-data-source-template', { exitCode: 1 }, - ) + ); cliTest( 'BigDecimal is a valid type', ['codegen', '--skip-migrations'], @@ -111,7 +108,7 @@ describe('Validation', () => { { exitCode: 0, }, - ) + ); cliTest( 'topic0 is valid in an event handler', ['codegen', '--skip-migrations'], @@ -119,7 +116,7 @@ describe('Validation', () => { { exitCode: 0, }, - ) + ); cliTest( 'Ethereum contract data source without handlers', ['codegen', '--skip-migrations'], @@ -127,7 +124,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Missing or invalid @derivedFrom fields', ['codegen', '--skip-migrations'], @@ -135,7 +132,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Deriving from interface-typed fields is allowed', ['codegen', '--skip-migrations'], @@ -143,7 +140,7 @@ describe('Validation', () => { { exitCode: 0, }, - ) + ); cliTest( '@derivedFrom target type missing', ['codegen', '--skip-migrations'], @@ -151,15 +148,10 @@ describe('Validation', () => { { exitCode: 1, }, - ) - cliTest( - 'NEAR is a valid chain', - ['codegen', '--skip-migrations'], - 'validation/near-is-valid', - { - exitCode: 0, - }, - ) + ); + cliTest('NEAR is a valid chain', ['codegen', '--skip-migrations'], 'validation/near-is-valid', { + exitCode: 0, + }); cliTest( 'Deprecated template format gives nice error', ['codegen', '--skip-migrations'], @@ -167,7 +159,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Duplicate data source name', @@ -176,7 +168,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Duplicate template name', @@ -185,7 +177,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'No network names (valid)', @@ -194,7 +186,7 @@ describe('Validation', () => { { exitCode: 0, }, - ) + ); cliTest( 'Conflicting network names', @@ -203,7 +195,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Conflicting protocol names', @@ -212,7 +204,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Invalid @fulltext directive', @@ -221,7 +213,7 @@ describe('Validation', () => { { exitCode: 1, }, - ) + ); cliTest( 'Invalid GraphQL schema', @@ -230,5 +222,5 @@ describe('Validation', () => { { exitCode: 1, }, - ) -}) + ); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd4d17aa..addc0913 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,10 @@ importers: '@babel/preset-typescript': ^7.18.6 '@changesets/changelog-github': ^0.4.7 '@changesets/cli': ^2.25.2 + '@theguild/eslint-config': ^0.6.0 + '@theguild/prettier-config': ^1.0.0 babel-jest: ^29.3.1 + eslint: ^8.31.0 jest: 26.0.0 prettier: ^2.8.2 devDependencies: @@ -18,7 +21,10 @@ importers: '@babel/preset-typescript': 7.18.6_@babel+core@7.20.5 '@changesets/changelog-github': 0.4.7 '@changesets/cli': 2.25.2 + '@theguild/eslint-config': 0.6.0_eslint@8.31.0 + '@theguild/prettier-config': 1.0.0_prettier@2.8.2 babel-jest: 29.3.1_@babel+core@7.20.5 + eslint: 8.31.0 jest: 26.0.0 prettier: 2.8.2 @@ -1291,6 +1297,13 @@ packages: dependencies: regenerator-runtime: 0.13.11 + /@babel/runtime/7.20.7: + resolution: {integrity: sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.13.11 + dev: true + /@babel/template/7.18.10: resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} engines: {node: '>=6.9.0'} @@ -1538,6 +1551,33 @@ packages: minimist: 1.2.7 dev: true + /@eslint-community/eslint-utils/4.1.2_eslint@8.31.0: + resolution: {integrity: sha512-7qELuQWWjVDdVsFQ5+beUl+KPczrEDA7S3zM4QUd/bJl7oXgsmpXaEVqrRTnOBqenOV4rWf2kVZk2Ot085zPWA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.31.0 + eslint-visitor-keys: 3.3.0 + dev: true + + /@eslint/eslintrc/1.4.1: + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.4.1 + globals: 13.19.0 + ignore: 5.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + /@ethersproject/abi/5.0.7: resolution: {integrity: sha512-Cqktk+hSIckwP/W8O47Eef60VwmoSC/L3lY0+dIBhQPCNn9E4V7rwmm2aFrNRRDJfFlGuZ1khkQUOc3oBX+niw==} dependencies: @@ -1713,6 +1753,26 @@ packages: assemblyscript: 0.19.10 dev: true + /@humanwhocodes/config-array/0.11.8: + resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer/1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema/1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + dev: true + /@istanbuljs/load-nyc-config/1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -2037,10 +2097,26 @@ packages: fastq: 1.14.0 dev: true + /@pkgr/utils/2.3.1: + resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dependencies: + cross-spawn: 7.0.3 + is-glob: 4.0.3 + open: 8.4.0 + picocolors: 1.0.0 + tiny-glob: 0.2.9 + tslib: 2.4.1 + dev: true + /@rescript/std/9.0.0: resolution: {integrity: sha512-zGzFsgtZ44mgL4Xef2gOy1hrRVdrs9mcxCOOKZrIPsmbZW14yTkaF591GXxpQvjXiHtgZ/iA9qLyWH6oSReIxQ==} dev: false + /@rushstack/eslint-patch/1.2.0: + resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} + dev: true + /@sinclair/typebox/0.24.51: resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==} dev: true @@ -2057,11 +2133,56 @@ packages: '@sinonjs/commons': 1.8.6 dev: true + /@theguild/eslint-config/0.6.0_eslint@8.31.0: + resolution: {integrity: sha512-KvhPwf1X7Ra775dwdl4ZP2jlqUWpvQPxAm8MSX5QCT5sJu3I/FkW/i1eNgtKiWlu7bqCaqhCMuBmrzDgIFxy7Q==} + peerDependencies: + eslint: ^8.24.0 + dependencies: + '@rushstack/eslint-patch': 1.2.0 + '@typescript-eslint/eslint-plugin': 5.48.1_qdjeohovcytra7xto5vgmxssaq + '@typescript-eslint/parser': 5.48.1_eslint@8.31.0 + eslint: 8.31.0 + eslint-config-prettier: 8.6.0_eslint@8.31.0 + eslint-plugin-import: 2.27.4_qdjeohovcytra7xto5vgmxssaq + eslint-plugin-jsonc: 2.6.0_eslint@8.31.0 + eslint-plugin-jsx-a11y: 6.7.1_eslint@8.31.0 + eslint-plugin-mdx: 2.0.5_eslint@8.31.0 + eslint-plugin-n: 15.6.1_eslint@8.31.0 + eslint-plugin-promise: 6.1.1_eslint@8.31.0 + eslint-plugin-react: 7.32.0_eslint@8.31.0 + eslint-plugin-react-hooks: 4.6.0_eslint@8.31.0 + eslint-plugin-simple-import-sort: 8.0.0_eslint@8.31.0 + eslint-plugin-sonarjs: 0.17.0_eslint@8.31.0 + eslint-plugin-unicorn: 45.0.2_eslint@8.31.0 + eslint-plugin-yml: 1.4.0_eslint@8.31.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + - typescript + dev: true + + /@theguild/prettier-config/1.0.0_prettier@2.8.2: + resolution: {integrity: sha512-EdPbtrXN1Z0QqmFJZXGj4n/xLZTCJtDxb+jeNGmOccrv0cJTB46d+lsvCO8j7SmuUhyt/gv9B6nnVKt66D2X1w==} + peerDependencies: + prettier: ^2 + dependencies: + prettier: 2.8.2 + prettier-plugin-pkg: 0.17.1_prettier@2.8.2 + prettier-plugin-sh: 0.12.8_prettier@2.8.2 + dev: true + /@tootallnate/once/1.1.2: resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} dev: true + /@types/acorn/4.0.6: + resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} + dependencies: + '@types/estree': 1.0.0 + dev: true + /@types/babel__core/7.1.20: resolution: {integrity: sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==} dependencies: @@ -2115,6 +2236,16 @@ packages: '@types/ms': 0.7.31 dev: true + /@types/estree-jsx/1.0.0: + resolution: {integrity: sha512-3qvGd0z8F2ENTGr/GG1yViqfiKmRfrXVx5sJyHGFu3z7m5g5utCQtGp/g29JnjflhtQJBv1WDQukHiT58xPcYQ==} + dependencies: + '@types/estree': 1.0.0 + dev: true + + /@types/estree/1.0.0: + resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==} + dev: true + /@types/express-serve-static-core/4.17.31: resolution: {integrity: sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==} dependencies: @@ -2141,6 +2272,12 @@ packages: '@types/node': 18.11.9 dev: true + /@types/hast/2.3.4: + resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==} + dependencies: + '@types/unist': 2.0.6 + dev: true + /@types/is-ci/3.0.0: resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==} dependencies: @@ -2174,10 +2311,24 @@ packages: resolution: {integrity: sha512-S6+8JAYTE1qdsc9HMVsfY7+SgSuUU/Tp6TYTmITW0PZxiyIMvol3Gy//y69Wkhs0ti4py5qgR3uZH6uz/DNzJQ==} dev: true + /@types/json-schema/7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + dev: true + + /@types/json5/0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true + /@types/lodash/4.14.190: resolution: {integrity: sha512-5iJ3FBJBvQHQ8sFhEhJfjUP+G+LalhavTkYyrAYqz5MEJG+erSv0k9KJLb6q7++17Lafk1scaTIFXcMJlwK8Mw==} dev: false + /@types/mdast/3.0.10: + resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==} + dependencies: + '@types/unist': 2.0.6 + dev: true + /@types/minimist/1.2.2: resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} dev: true @@ -2213,7 +2364,6 @@ packages: /@types/parse-json/4.0.0: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} - dev: false /@types/pbkdf2/3.1.0: resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==} @@ -2251,6 +2401,10 @@ packages: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true + /@types/unist/2.0.6: + resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} + dev: true + /@types/which/2.0.1: resolution: {integrity: sha512-Jjakcv8Roqtio6w1gr0D7y6twbhx6gGgFGF5BLwajPpnOIOxFkakFhCq+LmyyeAz7BX6ULrjBOxdKaCDy+4+dQ==} dev: true @@ -2277,6 +2431,131 @@ packages: '@types/yargs-parser': 21.0.0 dev: true + /@typescript-eslint/eslint-plugin/5.48.1_qdjeohovcytra7xto5vgmxssaq: + resolution: {integrity: sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/parser': 5.48.1_eslint@8.31.0 + '@typescript-eslint/scope-manager': 5.48.1 + '@typescript-eslint/type-utils': 5.48.1_eslint@8.31.0 + '@typescript-eslint/utils': 5.48.1_eslint@8.31.0 + debug: 4.3.4 + eslint: 8.31.0 + ignore: 5.2.1 + natural-compare-lite: 1.4.0 + regexpp: 3.2.0 + semver: 7.3.8 + tsutils: 3.21.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser/5.48.1_eslint@8.31.0: + resolution: {integrity: sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.48.1 + '@typescript-eslint/types': 5.48.1 + '@typescript-eslint/typescript-estree': 5.48.1 + debug: 4.3.4 + eslint: 8.31.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager/5.48.1: + resolution: {integrity: sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.48.1 + '@typescript-eslint/visitor-keys': 5.48.1 + dev: true + + /@typescript-eslint/type-utils/5.48.1_eslint@8.31.0: + resolution: {integrity: sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.48.1 + '@typescript-eslint/utils': 5.48.1_eslint@8.31.0 + debug: 4.3.4 + eslint: 8.31.0 + tsutils: 3.21.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types/5.48.1: + resolution: {integrity: sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/typescript-estree/5.48.1: + resolution: {integrity: sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.48.1 + '@typescript-eslint/visitor-keys': 5.48.1 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.8 + tsutils: 3.21.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils/5.48.1_eslint@8.31.0: + resolution: {integrity: sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@types/json-schema': 7.0.11 + '@types/semver': 7.3.13 + '@typescript-eslint/scope-manager': 5.48.1 + '@typescript-eslint/types': 5.48.1 + '@typescript-eslint/typescript-estree': 5.48.1 + eslint: 8.31.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.31.0 + semver: 7.3.8 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys/5.48.1: + resolution: {integrity: sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.48.1 + eslint-visitor-keys: 3.3.0 + dev: true + /JSONStream/1.3.2: resolution: {integrity: sha512-mn0KSip7N4e0UDPZHnqDsHECo5uGQrixQKnAskOM1BIB8hd7QKbd6il8IPRPudPHOeHiECoCFqhyMaRO9+nWyA==} hasBin: true @@ -2311,6 +2590,14 @@ packages: acorn-walk: 7.2.0 dev: true + /acorn-jsx/5.3.2_acorn@8.8.1: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.8.1 + dev: true + /acorn-loose/6.1.0: resolution: {integrity: sha512-FHhXoiF0Uch3IqsrnPpWwCtiv5PYvipTpT1k9lDMgQVVYc9iDuSl5zdJV358aI8twfHCYMFBRVYvAVki9wC/ng==} engines: {node: '>=0.4.0'} @@ -2362,7 +2649,6 @@ packages: fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - dev: false /ansi-colors/3.2.4: resolution: {integrity: sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==} @@ -2457,7 +2743,12 @@ packages: /argparse/2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: false + + /aria-query/5.1.3: + resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + dependencies: + deep-equal: 2.2.0 + dev: true /arr-diff/4.0.0: resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} @@ -2474,6 +2765,17 @@ packages: engines: {node: '>=0.10.0'} dev: true + /array-includes/3.1.6: + resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + get-intrinsic: 1.1.3 + is-string: 1.0.7 + dev: true + /array-union/2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -2494,6 +2796,26 @@ packages: es-shim-unscopables: 1.0.0 dev: true + /array.prototype.flatmap/1.3.1: + resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + es-shim-unscopables: 1.0.0 + dev: true + + /array.prototype.tosorted/1.1.1: + resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + es-shim-unscopables: 1.0.0 + get-intrinsic: 1.1.3 + dev: true + /arrify/1.0.1: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} @@ -2549,6 +2871,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /ast-types-flow/0.0.7: + resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} + dev: true + /async/2.6.4: resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} dependencies: @@ -2569,6 +2895,11 @@ packages: hasBin: true dev: true + /available-typed-arrays/1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + /aws-sign2/0.7.0: resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} dev: false @@ -2577,6 +2908,11 @@ packages: resolution: {integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==} dev: false + /axe-core/4.6.2: + resolution: {integrity: sha512-b1WlTV8+XKLj9gZy2DZXgQiyDp9xkkoe2a6U6UbYccScq2wgH/YwCeI2/Jq2mgo0HzQxqJOjWZBLeA/mqsk5Mg==} + engines: {node: '>=4'} + dev: true + /axios/0.21.4_debug@4.3.1: resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} dependencies: @@ -2585,6 +2921,12 @@ packages: - debug dev: false + /axobject-query/3.1.1: + resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==} + dependencies: + deep-equal: 2.2.0 + dev: true + /babel-code-frame/6.26.0: resolution: {integrity: sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==} dependencies: @@ -2866,6 +3208,10 @@ packages: hasBin: true dev: false + /bail/2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + dev: true + /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -3131,10 +3477,21 @@ packages: node-gyp-build: 4.5.0 dev: false + /builtin-modules/3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + dev: true + /builtin-status-codes/3.0.0: resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} dev: false + /builtins/5.0.1: + resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} + dependencies: + semver: 7.3.8 + dev: true + /cache-base/1.0.1: resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} engines: {node: '>=0.10.0'} @@ -3198,6 +3555,10 @@ packages: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} dev: false + /ccount/2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + dev: true + /chalk/1.1.3: resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} engines: {node: '>=0.10.0'} @@ -3238,6 +3599,34 @@ packages: engines: {node: '>=10'} dev: true + /character-entities-html4/2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + dev: true + + /character-entities-legacy/1.1.4: + resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} + dev: true + + /character-entities-legacy/3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + dev: true + + /character-entities/1.2.4: + resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} + dev: true + + /character-entities/2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + dev: true + + /character-reference-invalid/1.1.4: + resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} + dev: true + + /character-reference-invalid/2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + dev: true + /chardet/0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} dev: true @@ -3324,6 +3713,13 @@ packages: static-extend: 0.1.2 dev: true + /clean-regexp/1.0.0: + resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} + engines: {node: '>=4'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + /cli-cursor/3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -3513,6 +3909,17 @@ packages: yaml: 1.9.2 dev: false + /cosmiconfig/7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.0 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: true + /create-hash/1.2.0: resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} dependencies: @@ -3611,6 +4018,10 @@ packages: type: 1.2.0 dev: false + /damerau-levenshtein/1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + dev: true + /dashdash/1.14.1: resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} engines: {node: '>=0.10'} @@ -3662,7 +4073,6 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: false /debug/4.3.1: resolution: {integrity: sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==} @@ -3703,11 +4113,39 @@ packages: resolution: {integrity: sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==} dev: true + /decode-named-character-reference/1.0.2: + resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + dependencies: + character-entities: 2.0.2 + dev: true + /decode-uri-component/0.2.0: resolution: {integrity: sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==} engines: {node: '>=0.10'} dev: true + /deep-equal/2.2.0: + resolution: {integrity: sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==} + dependencies: + call-bind: 1.0.2 + es-get-iterator: 1.1.3 + get-intrinsic: 1.1.3 + is-arguments: 1.1.1 + is-array-buffer: 3.0.1 + is-date-object: 1.0.5 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + isarray: 2.0.5 + object-is: 1.1.5 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.4.3 + side-channel: 1.0.4 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.1 + which-typed-array: 1.1.9 + dev: true + /deep-is/0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true @@ -3722,6 +4160,11 @@ packages: dependencies: clone: 1.0.4 + /define-lazy-prop/2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + dev: true + /define-properties/1.1.4: resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} engines: {node: '>= 0.4'} @@ -3765,6 +4208,11 @@ packages: resolution: {integrity: sha512-a02fiQ7poS5CnjiJBAsjGLPp5EwVoGHNeu9sziBd9huppRfsAFIpv5zNLv0V1gbop53ilngAf5Kf331AwcoRBQ==} dev: false + /dequal/2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + dev: true + /detect-indent/4.0.0: resolution: {integrity: sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==} engines: {node: '>=0.10.0'} @@ -3796,6 +4244,11 @@ packages: engines: {node: '>=0.3.1'} dev: false + /diff/5.1.0: + resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} + engines: {node: '>=0.3.1'} + dev: true + /dir-glob/3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -3831,6 +4284,20 @@ packages: - supports-color dev: false + /doctrine/2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /doctrine/3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + /domexception/2.0.1: resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==} engines: {node: '>=8'} @@ -3890,6 +4357,10 @@ packages: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /emoji-regex/9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + /encoding/0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} dependencies: @@ -3967,11 +4438,25 @@ packages: unbox-primitive: 1.0.2 dev: true - /es-shim-unscopables/1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + /es-get-iterator/1.1.3: + resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} dependencies: - has: 1.0.3 - dev: true + call-bind: 1.0.2 + get-intrinsic: 1.1.3 + has-symbols: 1.0.3 + is-arguments: 1.1.1 + is-map: 2.0.2 + is-set: 2.0.2 + is-string: 1.0.7 + isarray: 2.0.5 + stop-iteration-iterator: 1.0.0 + dev: true + + /es-shim-unscopables/1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + dependencies: + has: 1.0.3 + dev: true /es-to-primitive/1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} @@ -4031,6 +4516,11 @@ packages: engines: {node: '>=8'} dev: true + /escape-string-regexp/4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + /escodegen/2.0.0: resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==} engines: {node: '>=6.0'} @@ -4044,16 +4534,452 @@ packages: source-map: 0.6.1 dev: true + /eslint-config-prettier/8.6.0_eslint@8.31.0: + resolution: {integrity: sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.31.0 + dev: true + + /eslint-import-resolver-node/0.3.7: + resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} + dependencies: + debug: 3.2.7 + is-core-module: 2.11.0 + resolve: 1.22.1 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-mdx/2.0.5_eslint@8.31.0: + resolution: {integrity: sha512-1ZzcJwJNfladtuK+uuG/MdC0idc1e3d1vCI2STOq/pLcJBGuao2biWh90vEh2M93zDiNoHJGUIU7UAxupiiHFw==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '>=8.0.0' + dependencies: + acorn: 8.8.1 + acorn-jsx: 5.3.2_acorn@8.8.1 + cosmiconfig: 7.1.0 + eslint: 8.31.0 + espree: 9.4.1 + estree-util-visit: 1.2.0 + remark-mdx: 2.2.1 + remark-parse: 10.0.1 + remark-stringify: 10.0.2 + synckit: 0.8.4 + tslib: 2.4.1 + unified: 10.1.2 + unist-util-visit: 4.1.1 + uvu: 0.5.6 + vfile: 5.3.6 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils/2.7.4_sqt5xxn4ciiurbqrzlaarm6ama: + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.48.1_eslint@8.31.0 + debug: 3.2.7 + eslint: 8.31.0 + eslint-import-resolver-node: 0.3.7 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-es/4.1.0_eslint@8.31.0: + resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} + engines: {node: '>=8.10.0'} + peerDependencies: + eslint: '>=4.19.1' + dependencies: + eslint: 8.31.0 + eslint-utils: 2.1.0 + regexpp: 3.2.0 + dev: true + + /eslint-plugin-import/2.27.4_qdjeohovcytra7xto5vgmxssaq: + resolution: {integrity: sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 5.48.1_eslint@8.31.0 + array-includes: 3.1.6 + array.prototype.flat: 1.3.1 + array.prototype.flatmap: 1.3.1 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.31.0 + eslint-import-resolver-node: 0.3.7 + eslint-module-utils: 2.7.4_sqt5xxn4ciiurbqrzlaarm6ama + has: 1.0.3 + is-core-module: 2.11.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.values: 1.1.6 + resolve: 1.22.1 + semver: 6.3.0 + tsconfig-paths: 3.14.1 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-jsonc/2.6.0_eslint@8.31.0: + resolution: {integrity: sha512-4bA9YTx58QaWalua1Q1b82zt7eZMB7i+ed8q8cKkbKP75ofOA2SXbtFyCSok7RY6jIXeCqQnKjN9If8zCgv6PA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + eslint: 8.31.0 + eslint-utils: 3.0.0_eslint@8.31.0 + jsonc-eslint-parser: 2.1.0 + natural-compare: 1.4.0 + dev: true + + /eslint-plugin-jsx-a11y/6.7.1_eslint@8.31.0: + resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + '@babel/runtime': 7.20.7 + aria-query: 5.1.3 + array-includes: 3.1.6 + array.prototype.flatmap: 1.3.1 + ast-types-flow: 0.0.7 + axe-core: 4.6.2 + axobject-query: 3.1.1 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 8.31.0 + has: 1.0.3 + jsx-ast-utils: 3.3.3 + language-tags: 1.0.5 + minimatch: 3.1.2 + object.entries: 1.1.6 + object.fromentries: 2.0.6 + semver: 6.3.0 + dev: true + + /eslint-plugin-markdown/3.0.0_eslint@8.31.0: + resolution: {integrity: sha512-hRs5RUJGbeHDLfS7ELanT0e29Ocyssf/7kBM+p7KluY5AwngGkDf8Oyu4658/NZSGTTq05FZeWbkxXtbVyHPwg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.31.0 + mdast-util-from-markdown: 0.8.5 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-mdx/2.0.5_eslint@8.31.0: + resolution: {integrity: sha512-j2xN97jSlc5IoH94rJTHqYMztl46+hHzyC8Zqjx+OI1Rvv33isyf8xSSBHN6f0z8IJmgPgGsb/fH90JbvKplXg==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '>=8.0.0' + dependencies: + eslint: 8.31.0 + eslint-mdx: 2.0.5_eslint@8.31.0 + eslint-plugin-markdown: 3.0.0_eslint@8.31.0 + remark-mdx: 2.2.1 + remark-parse: 10.0.1 + remark-stringify: 10.0.2 + tslib: 2.4.1 + unified: 10.1.2 + vfile: 5.3.6 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-n/15.6.1_eslint@8.31.0: + resolution: {integrity: sha512-R9xw9OtCRxxaxaszTQmQAlPgM+RdGjaL1akWuY/Fv9fRAi8Wj4CUKc6iYVG8QNRjRuo8/BqVYIpfqberJUEacA==} + engines: {node: '>=12.22.0'} + peerDependencies: + eslint: '>=7.0.0' + dependencies: + builtins: 5.0.1 + eslint: 8.31.0 + eslint-plugin-es: 4.1.0_eslint@8.31.0 + eslint-utils: 3.0.0_eslint@8.31.0 + ignore: 5.2.1 + is-core-module: 2.11.0 + minimatch: 3.1.2 + resolve: 1.22.1 + semver: 7.3.8 + dev: true + + /eslint-plugin-promise/6.1.1_eslint@8.31.0: + resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.31.0 + dev: true + + /eslint-plugin-react-hooks/4.6.0_eslint@8.31.0: + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 8.31.0 + dev: true + + /eslint-plugin-react/7.32.0_eslint@8.31.0: + resolution: {integrity: sha512-vSBi1+SrPiLZCGvxpiZIa28fMEUaMjXtCplrvxcIxGzmFiYdsXQDwInEjuv5/i/2CTTxbkS87tE8lsQ0Qxinbw==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: 3.1.6 + array.prototype.flatmap: 1.3.1 + array.prototype.tosorted: 1.1.1 + doctrine: 2.1.0 + eslint: 8.31.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.3 + minimatch: 3.1.2 + object.entries: 1.1.6 + object.fromentries: 2.0.6 + object.hasown: 1.1.2 + object.values: 1.1.6 + prop-types: 15.8.1 + resolve: 2.0.0-next.4 + semver: 6.3.0 + string.prototype.matchall: 4.0.8 + dev: true + + /eslint-plugin-simple-import-sort/8.0.0_eslint@8.31.0: + resolution: {integrity: sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==} + peerDependencies: + eslint: '>=5.0.0' + dependencies: + eslint: 8.31.0 + dev: true + + /eslint-plugin-sonarjs/0.17.0_eslint@8.31.0: + resolution: {integrity: sha512-jtGtxI49UbJJeJj7CVRLI3+LLH+y+hkR3GOOwM7vBbci9DEFIRGCWvEd2BJScrzltZ6D6iubukTAfc9cyG7sdw==} + engines: {node: '>=14'} + peerDependencies: + eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + eslint: 8.31.0 + dev: true + + /eslint-plugin-unicorn/45.0.2_eslint@8.31.0: + resolution: {integrity: sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==} + engines: {node: '>=14.18'} + peerDependencies: + eslint: '>=8.28.0' + dependencies: + '@babel/helper-validator-identifier': 7.19.1 + '@eslint-community/eslint-utils': 4.1.2_eslint@8.31.0 + ci-info: 3.7.0 + clean-regexp: 1.0.0 + eslint: 8.31.0 + esquery: 1.4.0 + indent-string: 4.0.0 + is-builtin-module: 3.2.0 + jsesc: 3.0.2 + lodash: 4.17.21 + pluralize: 8.0.0 + read-pkg-up: 7.0.1 + regexp-tree: 0.1.24 + regjsparser: 0.9.1 + safe-regex: 2.1.1 + semver: 7.3.8 + strip-indent: 3.0.0 + dev: true + + /eslint-plugin-yml/1.4.0_eslint@8.31.0: + resolution: {integrity: sha512-vzggXNfPKa+arIaNUGoC3DPRZCxNty+xD/v9xOcE5D3Bj9SbgIrEobqVB35I8QxHd2YjL/dOS0xIIFmjAalwbw==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + dependencies: + debug: 4.3.4 + eslint: 8.31.0 + lodash: 4.17.21 + natural-compare: 1.4.0 + yaml-eslint-parser: 1.1.0 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-scope/5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /eslint-scope/7.1.1: + resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-utils/2.1.0: + resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} + engines: {node: '>=6'} + dependencies: + eslint-visitor-keys: 1.3.0 + dev: true + + /eslint-utils/3.0.0_eslint@8.31.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.31.0 + eslint-visitor-keys: 2.1.0 + dev: true + + /eslint-visitor-keys/1.3.0: + resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} + engines: {node: '>=4'} + dev: true + + /eslint-visitor-keys/2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + dev: true + + /eslint-visitor-keys/3.3.0: + resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint/8.31.0: + resolution: {integrity: sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.4.1 + '@humanwhocodes/config-array': 0.11.8 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.1.1 + eslint-utils: 3.0.0_eslint@8.31.0 + eslint-visitor-keys: 3.3.0 + espree: 9.4.1 + esquery: 1.4.0 + esutils: 2.0.3 + 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 + grapheme-splitter: 1.0.4 + ignore: 5.2.1 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-sdsl: 4.2.0 + 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.1 + regexpp: 3.2.0 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree/9.4.1: + resolution: {integrity: sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.8.1 + acorn-jsx: 5.3.2_acorn@8.8.1 + eslint-visitor-keys: 3.3.0 + dev: true + /esprima/4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true + /esquery/1.4.0: + resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse/4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse/4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + /estraverse/5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} dev: true + /estree-util-is-identifier-name/2.0.1: + resolution: {integrity: sha512-rxZj1GkQhY4x1j/CSnybK9cGuMFQYFPLq0iNyopqf14aOVLFtMv7Esika+ObJWPWiOHuMOAHz3YkWoLYYRnzWQ==} + dev: true + + /estree-util-visit/1.2.0: + resolution: {integrity: sha512-wdsoqhWueuJKsh5hqLw3j8lwFqNStm92VcwtAOAny8g/KS/l5Y8RISjR4k5W6skCj3Nirag/WUCMS0Nfy3sgsg==} + dependencies: + '@types/estree-jsx': 1.0.0 + '@types/unist': 2.0.6 + dev: true + /esutils/2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -4221,7 +5147,6 @@ packages: /extend/3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - dev: false /extendable-error/0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -4264,7 +5189,6 @@ packages: /fast-deep-equal/3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: false /fast-glob/3.2.12: resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} @@ -4296,6 +5220,13 @@ packages: bser: 2.1.1 dev: true + /file-entry-cache/6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.0.4 + dev: true + /file-uri-to-path/1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} dev: false @@ -4346,10 +5277,22 @@ packages: pkg-dir: 4.2.0 dev: true + /flat-cache/3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.7 + rimraf: 3.0.2 + dev: true + /flatmap/0.0.3: resolution: {integrity: sha512-OuR+o7kHVe+x9RtIujPay7Uw3bvDZBZFSBXClEphZuSDLmZTqMdclasf4vFSsogC8baDz0eaC2NdO/2dlXHBKQ==} dev: false + /flatted/3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + dev: true + /follow-redirects/1.15.2_debug@4.3.1: resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} engines: {node: '>=4.0'} @@ -4362,6 +5305,12 @@ packages: debug: 4.3.1 dev: false + /for-each/0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: true + /for-in/1.0.2: resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} engines: {node: '>=0.10.0'} @@ -4548,6 +5497,13 @@ packages: dependencies: is-glob: 4.0.3 + /glob-parent/6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + /glob/7.1.2: resolution: {integrity: sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==} dependencies: @@ -4585,11 +5541,22 @@ packages: engines: {node: '>=4'} dev: true + /globals/13.19.0: + resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + /globals/9.18.0: resolution: {integrity: sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==} engines: {node: '>=0.10.0'} dev: false + /globalyzer/0.1.0: + resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} + dev: true + /globby/11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -4602,6 +5569,16 @@ packages: slash: 3.0.0 dev: true + /globrex/0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + dev: true + + /gopd/1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.1.3 + dev: true + /graceful-fs/4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} @@ -4877,7 +5854,6 @@ packages: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: false /import-local/3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} @@ -4916,6 +5892,15 @@ packages: side-channel: 1.0.4 dev: true + /internal-slot/1.0.4: + resolution: {integrity: sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.1.3 + has: 1.0.3 + side-channel: 1.0.4 + dev: true + /invariant/2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} dependencies: @@ -5069,6 +6054,44 @@ packages: kind-of: 6.0.3 dev: true + /is-alphabetical/1.0.4: + resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} + dev: true + + /is-alphabetical/2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + dev: true + + /is-alphanumerical/1.0.4: + resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} + dependencies: + is-alphabetical: 1.0.4 + is-decimal: 1.0.4 + dev: true + + /is-alphanumerical/2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + dev: true + + /is-arguments/1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + dev: true + + /is-array-buffer/3.0.1: + resolution: {integrity: sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.1.3 + is-typed-array: 1.1.10 + dev: true + /is-arrayish/0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -5100,7 +6123,13 @@ packages: /is-buffer/2.0.5: resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} engines: {node: '>=4'} - dev: false + + /is-builtin-module/3.2.0: + resolution: {integrity: sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==} + engines: {node: '>=6'} + dependencies: + builtin-modules: 3.3.0 + dev: true /is-callable/1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} @@ -5152,6 +6181,14 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-decimal/1.0.4: + resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} + dev: true + + /is-decimal/2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + dev: true + /is-descriptor/0.1.6: resolution: {integrity: sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==} engines: {node: '>=0.10.0'} @@ -5175,7 +6212,6 @@ packages: engines: {node: '>=8'} hasBin: true dev: true - optional: true /is-electron/2.2.1: resolution: {integrity: sha512-r8EEQQsqT+Gn0aXFx7lTFygYQhILLCB+wn0WCDL5LZRINeLH/Rvw1j2oKodELLXYNImQ3CRlVsY8wW4cGOsyuw==} @@ -5235,6 +6271,14 @@ packages: engines: {node: '>=6.5.0', npm: '>=3'} dev: false + /is-hexadecimal/1.0.4: + resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + dev: true + + /is-hexadecimal/2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + dev: true + /is-interactive/1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} @@ -5265,6 +6309,10 @@ packages: multihashes: 0.4.21 dev: false + /is-map/2.0.2: + resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + dev: true + /is-negative-zero/2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -5288,11 +6336,21 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + /is-path-inside/3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + /is-plain-obj/1.1.0: resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} engines: {node: '>=0.10.0'} dev: true + /is-plain-obj/4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + dev: true + /is-plain-object/2.0.4: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} @@ -5320,6 +6378,10 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-set/2.0.2: + resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + dev: true + /is-shared-array-buffer/1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: @@ -5355,15 +6417,37 @@ packages: has-symbols: 1.0.3 dev: true + /is-typed-array/1.1.10: + resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + dev: true + /is-typedarray/1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + /is-weakmap/2.0.1: + resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + dev: true + /is-weakref/1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.2 dev: true + /is-weakset/2.0.2: + resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.1.3 + dev: true + /is-windows/1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} @@ -5375,7 +6459,6 @@ packages: dependencies: is-docker: 2.2.1 dev: true - optional: true /isarray/0.0.1: resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} @@ -5383,6 +6466,10 @@ packages: /isarray/1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + /isarray/2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + /isexe/2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -6000,6 +7087,10 @@ packages: - utf-8-validate dev: true + /js-sdsl/4.2.0: + resolution: {integrity: sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==} + dev: true + /js-sha3/0.8.0: resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} dev: false @@ -6032,7 +7123,6 @@ packages: hasBin: true dependencies: argparse: 2.0.1 - dev: false /jsbn/0.1.1: resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} @@ -6096,17 +7186,26 @@ packages: hasBin: true dev: true + /jsesc/3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + dev: true + /json-parse-even-better-errors/2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} /json-schema-traverse/0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: false /json-schema/0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} dev: false + /json-stable-stringify-without-jsonify/1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + /json-stringify-safe/5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} dev: false @@ -6122,12 +7221,29 @@ packages: hasBin: true dev: false + /json5/1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + dependencies: + minimist: 1.2.7 + dev: true + /json5/2.2.1: resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} engines: {node: '>=6'} hasBin: true dev: true + /jsonc-eslint-parser/2.1.0: + resolution: {integrity: sha512-qCRJWlbP2v6HbmKW7R3lFbeiVWHo+oMJ0j+MizwvauqnCV/EvtAeEeuCgoc/ErtsuoKgYB8U4Ih8AxJbXoE6/g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.8.1 + eslint-visitor-keys: 3.3.0 + espree: 9.4.1 + semver: 7.3.8 + dev: true + /jsonfile/2.4.0: resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==} optionalDependencies: @@ -6163,6 +7279,14 @@ packages: verror: 1.10.0 dev: false + /jsx-ast-utils/3.3.3: + resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} + engines: {node: '>=4.0'} + dependencies: + array-includes: 3.1.6 + object.assign: 4.1.4 + dev: true + /just-kebab-case/1.1.0: resolution: {integrity: sha512-QkuwuBMQ9BQHMUEkAtIA4INLrkmnnveqlFB1oFi09gbU0wBdZo6tTnyxNWMR84zHxBuwK7GLAwqN8nrvVxOLTA==} dev: false @@ -6251,6 +7375,16 @@ packages: engines: {node: '>=8'} dev: false + /language-subtag-registry/0.3.22: + resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} + dev: true + + /language-tags/1.0.5: + resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==} + dependencies: + language-subtag-registry: 0.3.22 + dev: true + /lcid/2.0.0: resolution: {integrity: sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==} engines: {node: '>=6'} @@ -6271,6 +7405,14 @@ packages: type-check: 0.3.2 dev: true + /levn/0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + /libp2p-crypto-secp256k1/0.3.1: resolution: {integrity: sha512-evrfK/CeUSd/lcELUdDruyPBvxDmLairth75S32OLl3H+++2m2fV24JEtxzdFS9JH3xEFw0h6JFO8DBa1bP9dA==} engines: {node: '>=6.0.0', npm: '>=3.0.0'} @@ -6361,6 +7503,10 @@ packages: resolution: {integrity: sha512-UUKX7VhP1/JL54NXg2aq/E1Sfnjjes8fNYTNkPU8ZmsaVeBvPHKdbNaN79Re5XRL01u6wbq3j0cbYZj71Fcu5w==} dev: false + /lodash.merge/4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + /lodash.pad/4.5.1: resolution: {integrity: sha512-mvUHifnLqM+03YNzeTBS1/Gr6JRFjd3rRx88FHWUvamVaT9k2O/kXha3yBSOwB9/DTQrSTLJNHvLBBt2FdX7Mg==} dev: false @@ -6422,6 +7568,10 @@ packages: resolution: {integrity: sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==} dev: false + /longest-streak/3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + dev: true + /looper/3.0.0: resolution: {integrity: sha512-LJ9wplN/uSn72oJRsXTx+snxPet5c8XiZmOKCm906NVYu+ag6SB6vUcnJcWxgnl2NfbIyeobAn7Bwv6xRj2XJg==} dev: false @@ -6431,7 +7581,6 @@ packages: hasBin: true dependencies: js-tokens: 4.0.0 - dev: false /lru-cache/4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} @@ -6514,6 +7663,114 @@ packages: safe-buffer: 5.2.1 dev: false + /mdast-util-from-markdown/0.8.5: + resolution: {integrity: sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-to-string: 2.0.0 + micromark: 2.11.4 + parse-entities: 2.0.0 + unist-util-stringify-position: 2.0.3 + transitivePeerDependencies: + - supports-color + dev: true + + /mdast-util-from-markdown/1.2.0: + resolution: {integrity: sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q==} + dependencies: + '@types/mdast': 3.0.10 + '@types/unist': 2.0.6 + decode-named-character-reference: 1.0.2 + mdast-util-to-string: 3.1.0 + micromark: 3.1.0 + micromark-util-decode-numeric-character-reference: 1.0.0 + micromark-util-decode-string: 1.0.2 + micromark-util-normalize-identifier: 1.0.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + unist-util-stringify-position: 3.0.2 + uvu: 0.5.6 + transitivePeerDependencies: + - supports-color + dev: true + + /mdast-util-mdx-expression/1.3.1: + resolution: {integrity: sha512-TTb6cKyTA1RD+1su1iStZ5PAv3rFfOUKcoU5EstUpv/IZo63uDX03R8+jXjMEhcobXnNOiG6/ccekvVl4eV1zQ==} + dependencies: + '@types/estree-jsx': 1.0.0 + '@types/hast': 2.3.4 + '@types/mdast': 3.0.10 + mdast-util-from-markdown: 1.2.0 + mdast-util-to-markdown: 1.5.0 + transitivePeerDependencies: + - supports-color + dev: true + + /mdast-util-mdx-jsx/2.1.0: + resolution: {integrity: sha512-KzgzfWMhdteDkrY4mQtyvTU5bc/W4ppxhe9SzelO6QUUiwLAM+Et2Dnjjprik74a336kHdo0zKm7Tp+n6FFeRg==} + dependencies: + '@types/estree-jsx': 1.0.0 + '@types/hast': 2.3.4 + '@types/mdast': 3.0.10 + ccount: 2.0.1 + mdast-util-to-markdown: 1.5.0 + parse-entities: 4.0.0 + stringify-entities: 4.0.3 + unist-util-remove-position: 4.0.1 + unist-util-stringify-position: 3.0.2 + vfile-message: 3.1.3 + dev: true + + /mdast-util-mdx/2.0.0: + resolution: {integrity: sha512-M09lW0CcBT1VrJUaF/PYxemxxHa7SLDHdSn94Q9FhxjCQfuW7nMAWKWimTmA3OyDMSTH981NN1csW1X+HPSluw==} + dependencies: + mdast-util-mdx-expression: 1.3.1 + mdast-util-mdx-jsx: 2.1.0 + mdast-util-mdxjs-esm: 1.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /mdast-util-mdxjs-esm/1.3.0: + resolution: {integrity: sha512-7N5ihsOkAEGjFotIX9p/YPdl4TqUoMxL4ajNz7PbT89BqsdWJuBC9rvgt6wpbwTZqWWR0jKWqQbwsOWDBUZv4g==} + dependencies: + '@types/estree-jsx': 1.0.0 + '@types/hast': 2.3.4 + '@types/mdast': 3.0.10 + mdast-util-from-markdown: 1.2.0 + mdast-util-to-markdown: 1.5.0 + transitivePeerDependencies: + - supports-color + dev: true + + /mdast-util-phrasing/3.0.0: + resolution: {integrity: sha512-S+QYsDRLkGi8U7o5JF1agKa/sdP+CNGXXLqC17pdTVL8FHHgQEiwFGa9yE5aYtUxNiFGYoaDy9V1kC85Sz86Gg==} + dependencies: + '@types/mdast': 3.0.10 + unist-util-is: 5.1.1 + dev: true + + /mdast-util-to-markdown/1.5.0: + resolution: {integrity: sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==} + dependencies: + '@types/mdast': 3.0.10 + '@types/unist': 2.0.6 + longest-streak: 3.1.0 + mdast-util-phrasing: 3.0.0 + mdast-util-to-string: 3.1.0 + micromark-util-decode-string: 1.0.2 + unist-util-visit: 4.1.1 + zwitch: 2.0.4 + dev: true + + /mdast-util-to-string/2.0.0: + resolution: {integrity: sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==} + dev: true + + /mdast-util-to-string/3.1.0: + resolution: {integrity: sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA==} + dev: true + /mem/4.3.0: resolution: {integrity: sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==} engines: {node: '>=6'} @@ -6552,12 +7809,280 @@ packages: yargs-parser: 18.1.3 dev: true - /merge-stream/2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + /merge-stream/2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + /merge2/1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromark-core-commonmark/1.0.6: + resolution: {integrity: sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==} + dependencies: + decode-named-character-reference: 1.0.2 + micromark-factory-destination: 1.0.0 + micromark-factory-label: 1.0.2 + micromark-factory-space: 1.0.0 + micromark-factory-title: 1.0.2 + micromark-factory-whitespace: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-chunked: 1.0.0 + micromark-util-classify-character: 1.0.0 + micromark-util-html-tag-name: 1.1.0 + micromark-util-normalize-identifier: 1.0.0 + micromark-util-resolve-all: 1.0.0 + micromark-util-subtokenize: 1.0.2 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: true + + /micromark-extension-mdx-expression/1.0.3: + resolution: {integrity: sha512-TjYtjEMszWze51NJCZmhv7MEBcgYRgb3tJeMAJ+HQCAaZHHRBaDCccqQzGizR/H4ODefP44wRTgOn2vE5I6nZA==} + dependencies: + micromark-factory-mdx-expression: 1.0.6 + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-events-to-acorn: 1.2.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: true + + /micromark-extension-mdx-jsx/1.0.3: + resolution: {integrity: sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA==} + dependencies: + '@types/acorn': 4.0.6 + estree-util-is-identifier-name: 2.0.1 + micromark-factory-mdx-expression: 1.0.6 + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + vfile-message: 3.1.3 + dev: true + + /micromark-extension-mdx-md/1.0.0: + resolution: {integrity: sha512-xaRAMoSkKdqZXDAoSgp20Azm0aRQKGOl0RrS81yGu8Hr/JhMsBmfs4wR7m9kgVUIO36cMUQjNyiyDKPrsv8gOw==} + dependencies: + micromark-util-types: 1.0.2 + dev: true + + /micromark-extension-mdxjs-esm/1.0.3: + resolution: {integrity: sha512-2N13ol4KMoxb85rdDwTAC6uzs8lMX0zeqpcyx7FhS7PxXomOnLactu8WI8iBNXW8AVyea3KIJd/1CKnUmwrK9A==} + dependencies: + micromark-core-commonmark: 1.0.6 + micromark-util-character: 1.1.0 + micromark-util-events-to-acorn: 1.2.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + unist-util-position-from-estree: 1.1.1 + uvu: 0.5.6 + vfile-message: 3.1.3 + dev: true + + /micromark-extension-mdxjs/1.0.0: + resolution: {integrity: sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ==} + dependencies: + acorn: 8.8.1 + acorn-jsx: 5.3.2_acorn@8.8.1 + micromark-extension-mdx-expression: 1.0.3 + micromark-extension-mdx-jsx: 1.0.3 + micromark-extension-mdx-md: 1.0.0 + micromark-extension-mdxjs-esm: 1.0.3 + micromark-util-combine-extensions: 1.0.0 + micromark-util-types: 1.0.2 + dev: true + + /micromark-factory-destination/1.0.0: + resolution: {integrity: sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + dev: true + + /micromark-factory-label/1.0.2: + resolution: {integrity: sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: true + + /micromark-factory-mdx-expression/1.0.6: + resolution: {integrity: sha512-WRQIc78FV7KrCfjsEf/sETopbYjElh3xAmNpLkd1ODPqxEngP42eVRGbiPEQWpRV27LzqW+XVTvQAMIIRLPnNA==} + dependencies: + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-events-to-acorn: 1.2.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + unist-util-position-from-estree: 1.1.1 + uvu: 0.5.6 + vfile-message: 3.1.3 + dev: true + + /micromark-factory-space/1.0.0: + resolution: {integrity: sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-types: 1.0.2 + dev: true + + /micromark-factory-title/1.0.2: + resolution: {integrity: sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A==} + dependencies: + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: true + + /micromark-factory-whitespace/1.0.0: + resolution: {integrity: sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A==} + dependencies: + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + dev: true + + /micromark-util-character/1.1.0: + resolution: {integrity: sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg==} + dependencies: + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + dev: true + + /micromark-util-chunked/1.0.0: + resolution: {integrity: sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==} + dependencies: + micromark-util-symbol: 1.0.1 + dev: true + + /micromark-util-classify-character/1.0.0: + resolution: {integrity: sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + dev: true + + /micromark-util-combine-extensions/1.0.0: + resolution: {integrity: sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA==} + dependencies: + micromark-util-chunked: 1.0.0 + micromark-util-types: 1.0.2 + dev: true + + /micromark-util-decode-numeric-character-reference/1.0.0: + resolution: {integrity: sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==} + dependencies: + micromark-util-symbol: 1.0.1 + dev: true + + /micromark-util-decode-string/1.0.2: + resolution: {integrity: sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q==} + dependencies: + decode-named-character-reference: 1.0.2 + micromark-util-character: 1.1.0 + micromark-util-decode-numeric-character-reference: 1.0.0 + micromark-util-symbol: 1.0.1 + dev: true + + /micromark-util-encode/1.0.1: + resolution: {integrity: sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==} + dev: true + + /micromark-util-events-to-acorn/1.2.0: + resolution: {integrity: sha512-WWp3bf7xT9MppNuw3yPjpnOxa8cj5ACivEzXJKu0WwnjBYfzaBvIAT9KfeyI0Qkll+bfQtfftSwdgTH6QhTOKw==} + dependencies: + '@types/acorn': 4.0.6 + '@types/estree': 1.0.0 + estree-util-visit: 1.2.0 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + vfile-location: 4.0.1 + vfile-message: 3.1.3 + dev: true + + /micromark-util-html-tag-name/1.1.0: + resolution: {integrity: sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==} + dev: true + + /micromark-util-normalize-identifier/1.0.0: + resolution: {integrity: sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==} + dependencies: + micromark-util-symbol: 1.0.1 + dev: true + + /micromark-util-resolve-all/1.0.0: + resolution: {integrity: sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==} + dependencies: + micromark-util-types: 1.0.2 + dev: true + + /micromark-util-sanitize-uri/1.1.0: + resolution: {integrity: sha512-RoxtuSCX6sUNtxhbmsEFQfWzs8VN7cTctmBPvYivo98xb/kDEoTCtJQX5wyzIYEmk/lvNFTat4hL8oW0KndFpg==} + dependencies: + micromark-util-character: 1.1.0 + micromark-util-encode: 1.0.1 + micromark-util-symbol: 1.0.1 + dev: true - /merge2/1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} + /micromark-util-subtokenize/1.0.2: + resolution: {integrity: sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA==} + dependencies: + micromark-util-chunked: 1.0.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + dev: true + + /micromark-util-symbol/1.0.1: + resolution: {integrity: sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==} + dev: true + + /micromark-util-types/1.0.2: + resolution: {integrity: sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==} + dev: true + + /micromark/2.11.4: + resolution: {integrity: sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==} + dependencies: + debug: 4.3.4 + parse-entities: 2.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /micromark/3.1.0: + resolution: {integrity: sha512-6Mj0yHLdUZjHnOPgr5xfWIMqMWS12zDN6iws9SLuSz76W8jTtAv24MN4/CL7gJrl5vtxGInkkqDv/JIoRsQOvA==} + dependencies: + '@types/debug': 4.1.7 + debug: 4.3.4 + decode-named-character-reference: 1.0.2 + micromark-core-commonmark: 1.0.6 + micromark-factory-space: 1.0.0 + micromark-util-character: 1.1.0 + micromark-util-chunked: 1.0.0 + micromark-util-combine-extensions: 1.0.0 + micromark-util-decode-numeric-character-reference: 1.0.0 + micromark-util-encode: 1.0.1 + micromark-util-normalize-identifier: 1.0.0 + micromark-util-resolve-all: 1.0.0 + micromark-util-sanitize-uri: 1.1.0 + micromark-util-subtokenize: 1.0.2 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + uvu: 0.5.6 + transitivePeerDependencies: + - supports-color dev: true /micromatch/3.1.10: @@ -6702,6 +8227,11 @@ packages: supports-color: 4.4.0 dev: false + /mri/1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + dev: true + /ms/2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -6853,6 +8383,10 @@ packages: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} dev: false + /mvdan-sh/0.10.1: + resolution: {integrity: sha512-kMbrH0EObaKmK3nVRKUIIya1dpASHIEusM13S4V1ViHFuxuNxCo+arxoa6j/dbV22YBGjl7UKJm9QQKJ2Crzhg==} + dev: true + /nan/2.17.0: resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==} dev: false @@ -6876,6 +8410,10 @@ packages: - supports-color dev: true + /natural-compare-lite/1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + dev: true + /natural-compare/1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true @@ -7021,6 +8559,14 @@ packages: /object-inspect/1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} + /object-is/1.1.5: + resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + dev: true + /object-keys/1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -7043,6 +8589,31 @@ packages: object-keys: 1.1.1 dev: true + /object.entries/1.1.6: + resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + dev: true + + /object.fromentries/2.0.6: + resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + dev: true + + /object.hasown/1.1.2: + resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} + dependencies: + define-properties: 1.1.4 + es-abstract: 1.20.4 + dev: true + /object.pick/1.3.0: resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} engines: {node: '>=0.10.0'} @@ -7050,6 +8621,15 @@ packages: isobject: 3.0.1 dev: true + /object.values/1.1.6: + resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + dev: true + /once/1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -7061,6 +8641,15 @@ packages: dependencies: mimic-fn: 2.1.0 + /open/8.4.0: + resolution: {integrity: sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==} + engines: {node: '>=12'} + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + dev: true + /optimist/0.3.7: resolution: {integrity: sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==} dependencies: @@ -7079,6 +8668,18 @@ packages: word-wrap: 1.2.3 dev: true + /optionator/0.9.1: + resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.3 + dev: true + /ora/4.1.1: resolution: {integrity: sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A==} engines: {node: '>=8'} @@ -7212,12 +8813,35 @@ packages: engines: {node: '>=6'} dependencies: callsites: 3.1.0 - dev: false /parse-cache-control/1.0.1: resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} dev: false + /parse-entities/2.0.0: + resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + dependencies: + character-entities: 1.2.4 + character-entities-legacy: 1.1.4 + character-reference-invalid: 1.1.4 + is-alphanumerical: 1.0.4 + is-decimal: 1.0.4 + is-hexadecimal: 1.0.4 + dev: true + + /parse-entities/4.0.0: + resolution: {integrity: sha512-5nk9Fn03x3rEhGaX1FU6IDwG/k+GxLXlFAkgrbM1asuAFl3BhdQWvASaIsmwWypRNcZKHPYnIuOSfIWEyEQnPQ==} + dependencies: + '@types/unist': 2.0.6 + character-entities: 2.0.2 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.0.2 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + dev: true + /parse-json/5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -7344,7 +8968,6 @@ packages: /pluralize/8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} - dev: false /posix-character-classes/0.1.1: resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} @@ -7366,6 +8989,32 @@ packages: engines: {node: '>= 0.8.0'} dev: true + /prelude-ls/1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prettier-plugin-pkg/0.17.1_prettier@2.8.2: + resolution: {integrity: sha512-XPRRMQR5oseJXdfK8kQDj2LCV1UjmTuDlPbbJ8C2WLaATNhdvZLhQO0+NtWnRrQTP+erLR5cVxfcwyqF+3R8SA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + peerDependencies: + prettier: ^2.0.0 + dependencies: + prettier: 2.8.2 + dev: true + + /prettier-plugin-sh/0.12.8_prettier@2.8.2: + resolution: {integrity: sha512-VOq8h2Gn5UzrCIKm4p/nAScXJbN09HdyFDknAcxt6Qu/tv/juu9bahxSrcnM9XWYA+Spz1F1ANJ4LhfwB7+Q1Q==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + peerDependencies: + prettier: ^2.0.0 + dependencies: + mvdan-sh: 0.10.1 + prettier: 2.8.2 + sh-syntax: 0.3.7 + synckit: 0.8.4 + dev: true + /prettier/1.19.1: resolution: {integrity: sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==} engines: {node: '>=4'} @@ -7427,6 +9076,14 @@ packages: sisteransi: 1.0.5 dev: true + /prop-types/15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + dev: true + /protocol-buffers-schema/3.6.0: resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} dev: false @@ -7529,6 +9186,10 @@ packages: safe-buffer: 5.2.1 dev: false + /react-is/16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: true + /react-is/17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} dev: true @@ -7641,6 +9302,11 @@ packages: safe-regex: 1.1.0 dev: true + /regexp-tree/0.1.24: + resolution: {integrity: sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==} + hasBin: true + dev: true + /regexp.prototype.flags/1.4.3: resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} engines: {node: '>= 0.4'} @@ -7650,6 +9316,11 @@ packages: functions-have-names: 1.2.3 dev: true + /regexpp/3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + dev: true + /regexpu-core/5.2.2: resolution: {integrity: sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==} engines: {node: '>=4'} @@ -7673,6 +9344,33 @@ packages: jsesc: 0.5.0 dev: true + /remark-mdx/2.2.1: + resolution: {integrity: sha512-R9wcN+/THRXTKyRBp6Npo/mcbGA2iT3N4G8qUqLA5pOEg7kBidHv8K2hHidCMYZ6DXmwK18umu0K4cicgA2PPQ==} + dependencies: + mdast-util-mdx: 2.0.0 + micromark-extension-mdxjs: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /remark-parse/10.0.1: + resolution: {integrity: sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-from-markdown: 1.2.0 + unified: 10.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /remark-stringify/10.0.2: + resolution: {integrity: sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-to-markdown: 1.5.0 + unified: 10.1.2 + dev: true + /remove-trailing-separator/1.1.0: resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} dev: true @@ -7757,7 +9455,6 @@ packages: /resolve-from/4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - dev: false /resolve-from/5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} @@ -7778,6 +9475,15 @@ packages: supports-preserve-symlinks-flag: 1.0.0 dev: true + /resolve/2.0.0-next.4: + resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} + hasBin: true + dependencies: + is-core-module: 2.11.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /restore-cursor/3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -7848,6 +9554,13 @@ packages: queue-microtask: 1.2.3 dev: true + /sade/1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + dependencies: + mri: 1.2.0 + dev: true + /safe-buffer/5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -7869,6 +9582,12 @@ packages: ret: 0.1.15 dev: true + /safe-regex/2.1.1: + resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==} + dependencies: + regexp-tree: 0.1.24 + dev: true + /safer-buffer/2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -7968,6 +9687,13 @@ packages: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} dev: false + /sh-syntax/0.3.7: + resolution: {integrity: sha512-xIB/uRniZ9urxAuXp1Ouh/BKSI1VK8RSqfwGj7cV57HvGrFo3vHdJfv8Tdp/cVcxJgXQTkmHr5mG5rqJW8r4wQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dependencies: + tslib: 2.4.1 + dev: true + /sha.js/2.4.11: resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} hasBin: true @@ -8218,6 +9944,13 @@ packages: object-copy: 0.1.0 dev: true + /stop-iteration-iterator/1.0.0: + resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} + engines: {node: '>= 0.4'} + dependencies: + internal-slot: 1.0.4 + dev: true + /stream-to-pull-stream/1.7.3: resolution: {integrity: sha512-6sNyqJpr5dIOQdgNy/xcDWwDuzAsAwVzhzrWlAPAQ7Lkjx/rv0wgvxEyKwTq6FmNd5rjTrELt/CLmaSw7crMGg==} dependencies: @@ -8265,6 +9998,19 @@ packages: strip-ansi: 6.0.1 dev: true + /string.prototype.matchall/4.0.8: + resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + get-intrinsic: 1.1.3 + has-symbols: 1.0.3 + internal-slot: 1.0.3 + regexp.prototype.flags: 1.4.3 + side-channel: 1.0.4 + dev: true + /string.prototype.trimend/1.0.6: resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} dependencies: @@ -8295,6 +10041,13 @@ packages: safe-buffer: 5.2.1 dev: false + /stringify-entities/4.0.3: + resolution: {integrity: sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==} + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + dev: true + /strip-ansi/3.0.1: resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} engines: {node: '>=0.10.0'} @@ -8354,6 +10107,11 @@ packages: min-indent: 1.0.1 dev: true + /strip-json-comments/3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + /supports-color/2.0.0: resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} engines: {node: '>=0.8.0'} @@ -8417,6 +10175,14 @@ packages: get-port: 3.2.0 dev: false + /synckit/0.8.4: + resolution: {integrity: sha512-Dn2ZkzMdSX827QbowGbU/4yjWuvNaCoScLLoMo/yKbu+P4GBR6cRGKZH27k6a9bRzdqcyd1DE96pQtQ6uNkmyw==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/utils': 2.3.1 + tslib: 2.4.1 + dev: true + /tapable/0.2.9: resolution: {integrity: sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==} engines: {node: '>=0.6'} @@ -8502,6 +10268,10 @@ packages: minimatch: 3.1.2 dev: true + /text-table/0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + /then-request/6.0.2: resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==} engines: {node: '>=6.0.0'} @@ -8541,6 +10311,13 @@ packages: readable-stream: 3.6.0 dev: false + /tiny-glob/0.2.9: + resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} + dependencies: + globalyzer: 0.1.0 + globrex: 0.1.2 + dev: true + /tmp-promise/3.0.2: resolution: {integrity: sha512-OyCLAKU1HzBjL6Ev3gxUeraJNlbNingmi8IrHHEsYH8LTmEuhvYfqvhn2F/je+mjf4N58UmZ96OMEy1JanSCpA==} dependencies: @@ -8645,6 +10422,10 @@ packages: engines: {node: '>=0.10.0'} dev: false + /trough/2.1.0: + resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} + dev: true + /truffle-hdwallet-provider/1.0.6: resolution: {integrity: sha512-cYTG0t9XouLLEBLMjkfHe3s2JO9wrFFVeXEgpW5Ay+8S56isf3LkrAUh0ws9bcYCJ0l7jho9xkaNnakeDqq//Q==} deprecated: 'WARNING: This package has been renamed to @truffle/hdwallet-provider.' @@ -8666,6 +10447,32 @@ packages: solc: 0.5.0 dev: false + /tsconfig-paths/3.14.1: + resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.7 + strip-bom: 3.0.0 + dev: true + + /tslib/1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tslib/2.4.1: + resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} + dev: true + + /tsutils/3.21.0: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + dev: true + /tty-table/4.1.6: resolution: {integrity: sha512-kRj5CBzOrakV4VRRY5kUWbNYvo/FpOsz65DzI5op9P+cHov3+IqPbo1JE1ZnQGkHdZgNFDsrEjrfqqy/Ply9fw==} engines: {node: '>=8.0.0'} @@ -8701,6 +10508,13 @@ packages: prelude-ls: 1.1.2 dev: true + /type-check/0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + /type-detect/4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} @@ -8711,6 +10525,11 @@ packages: engines: {node: '>=10'} dev: true + /type-fest/0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + /type-fest/0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} @@ -8781,6 +10600,18 @@ packages: engines: {node: '>=4'} dev: true + /unified/10.1.2: + resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==} + dependencies: + '@types/unist': 2.0.6 + bail: 2.0.2 + extend: 3.0.2 + is-buffer: 2.0.5 + is-plain-obj: 4.1.0 + trough: 2.1.0 + vfile: 5.3.6 + dev: true + /union-value/1.0.1: resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} engines: {node: '>=0.10.0'} @@ -8796,6 +10627,50 @@ packages: engines: {node: '>= 0.10.x'} dev: false + /unist-util-is/5.1.1: + resolution: {integrity: sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ==} + dev: true + + /unist-util-position-from-estree/1.1.1: + resolution: {integrity: sha512-xtoY50b5+7IH8tFbkw64gisG9tMSpxDjhX9TmaJJae/XuxQ9R/Kc8Nv1eOsf43Gt4KV/LkriMy9mptDr7XLcaw==} + dependencies: + '@types/unist': 2.0.6 + dev: true + + /unist-util-remove-position/4.0.1: + resolution: {integrity: sha512-0yDkppiIhDlPrfHELgB+NLQD5mfjup3a8UYclHruTJWmY74je8g+CIFr79x5f6AkmzSwlvKLbs63hC0meOMowQ==} + dependencies: + '@types/unist': 2.0.6 + unist-util-visit: 4.1.1 + dev: true + + /unist-util-stringify-position/2.0.3: + resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} + dependencies: + '@types/unist': 2.0.6 + dev: true + + /unist-util-stringify-position/3.0.2: + resolution: {integrity: sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg==} + dependencies: + '@types/unist': 2.0.6 + dev: true + + /unist-util-visit-parents/5.1.1: + resolution: {integrity: sha512-gks4baapT/kNRaWxuGkl5BIhoanZo7sC/cUT/JToSRNL1dYoXRFl75d++NkjYk4TAu2uv2Px+l8guMajogeuiw==} + dependencies: + '@types/unist': 2.0.6 + unist-util-is: 5.1.1 + dev: true + + /unist-util-visit/4.1.1: + resolution: {integrity: sha512-n9KN3WV9k4h1DxYR1LoajgN93wpEi/7ZplVe02IoB4gH5ctI1AaF2670BLHQYbwj+pY83gFtyeySFiyMHJklrg==} + dependencies: + '@types/unist': 2.0.6 + unist-util-is: 5.1.1 + unist-util-visit-parents: 5.1.1 + dev: true + /universalify/0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -8844,7 +10719,6 @@ packages: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.1.1 - dev: false /urix/0.1.0: resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} @@ -8897,6 +10771,17 @@ packages: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true + /uvu/0.5.6: + resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} + engines: {node: '>=8'} + hasBin: true + dependencies: + dequal: 2.0.3 + diff: 5.1.0 + kleur: 4.1.5 + sade: 1.8.1 + dev: true + /v8-to-istanbul/7.1.2: resolution: {integrity: sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==} engines: {node: '>=10.10.0'} @@ -8926,6 +10811,29 @@ packages: extsprintf: 1.3.0 dev: false + /vfile-location/4.0.1: + resolution: {integrity: sha512-JDxPlTbZrZCQXogGheBHjbRWjESSPEak770XwWPfw5mTc1v1nWGLB/apzZxsx8a0SJVfF8HK8ql8RD308vXRUw==} + dependencies: + '@types/unist': 2.0.6 + vfile: 5.3.6 + dev: true + + /vfile-message/3.1.3: + resolution: {integrity: sha512-0yaU+rj2gKAyEk12ffdSbBfjnnj+b1zqTBv3OQCTn8yEB02bsPizwdBPrLJjHnK+cU9EMMcUnNv938XcZIkmdA==} + dependencies: + '@types/unist': 2.0.6 + unist-util-stringify-position: 3.0.2 + dev: true + + /vfile/5.3.6: + resolution: {integrity: sha512-ADBsmerdGBs2WYckrLBEmuETSPyTD4TuLxTrw0DvjirxW1ra4ZwkbzG8ndsv3Q57smvHxo677MHaQrY9yxH8cA==} + dependencies: + '@types/unist': 2.0.6 + is-buffer: 2.0.5 + unist-util-stringify-position: 3.0.2 + vfile-message: 3.1.3 + dev: true + /w3c-hr-time/1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} deprecated: Use your platform's native performance.now() and performance.timeOrigin. @@ -9029,6 +10937,15 @@ packages: is-symbol: 1.0.4 dev: true + /which-collection/1.0.1: + resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + dependencies: + is-map: 2.0.2 + is-set: 2.0.2 + is-weakmap: 2.0.1 + is-weakset: 2.0.2 + dev: true + /which-module/2.0.0: resolution: {integrity: sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==} @@ -9040,6 +10957,18 @@ packages: path-exists: 4.0.0 dev: true + /which-typed-array/1.1.9: + resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.0 + is-typed-array: 1.1.10 + dev: true + /which/1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -9162,6 +11091,20 @@ packages: /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + /yaml-eslint-parser/1.1.0: + resolution: {integrity: sha512-b464Q1fYiX1oYx2kE8k4mEp6S9Prk+tfDsY/IPxQ0FCjEuj3AKko5Skf3/yQJeYTTDyjDE+aWIJemnv29HvEWQ==} + engines: {node: ^14.17.0 || >=16.0.0} + dependencies: + eslint-visitor-keys: 3.3.0 + lodash: 4.17.21 + yaml: 2.2.1 + dev: true + + /yaml/1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: true + /yaml/1.9.2: resolution: {integrity: sha512-HPT7cGGI0DuRcsO51qC1j9O16Dh1mZ2bnXwsi0jrSpsLz0WxOLSLXfkABVl6bZO629py3CU+OMJtpNHDLB97kg==} engines: {node: '>= 6'} @@ -9169,6 +11112,11 @@ packages: '@babel/runtime': 7.20.6 dev: false + /yaml/2.2.1: + resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==} + engines: {node: '>= 14'} + dev: true + /yargs-parser/16.1.0: resolution: {integrity: sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==} dependencies: @@ -9265,6 +11213,10 @@ packages: engines: {node: '>=10'} dev: true + /zwitch/2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + dev: true + github.com/edgeandnode/gluegun/b34b9003d7bf556836da41b57ef36eb21570620a_debug@4.3.1: resolution: {tarball: https://codeload.github.com/edgeandnode/gluegun/tar.gz/b34b9003d7bf556836da41b57ef36eb21570620a} id: github.com/edgeandnode/gluegun/b34b9003d7bf556836da41b57ef36eb21570620a