diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 4666829b8613..9af6ec7a45e7 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -10,6 +10,7 @@ module.exports = { }, { files: ['*.{ts,tsx}'], + excludedFiles: ['**/*.{md,mdx}/*.{ts,tsx}'], parserOptions: { project: 'tsconfig.json', }, @@ -23,6 +24,32 @@ module.exports = { rules: { 'mdx/remark': 'error', }, + settings: { + 'mdx/code-blocks': true, + }, + }, + { + files: ['**/*.{md,mdx}/*.{ts,tsx}'], + rules: { + // Disables rules that requires type information + '@typescript-eslint/await-thenable': 'off', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-implied-eval': 'off', + '@typescript-eslint/no-misused-promises': 'off', + '@typescript-eslint/no-unnecessary-type-assertion': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/prefer-regexp-exec': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'off', + '@typescript-eslint/no-unnecessary-condition': 'off', + '@typescript-eslint/no-unnecessary-type-arguments': 'off', + '@typescript-eslint/non-nullable-type-assertion-style': 'off', + '@typescript-eslint/prefer-includes': 'off', + '@typescript-eslint/prefer-return-this-type': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + // Disable rules for code-blocks + 'no-restricted-globals': 'off', + }, }, ], } diff --git a/website/pages/en/cookbook/near.mdx b/website/pages/en/cookbook/near.mdx index 33ef5e56c213..eb7a9641f6aa 100644 --- a/website/pages/en/cookbook/near.mdx +++ b/website/pages/en/cookbook/near.mdx @@ -102,64 +102,63 @@ The handlers for processing events are written in [AssemblyScript](https://www.a NEAR indexing introduces NEAR-specific data types to the [AssemblyScript API](/developing/assemblyscript-api). -```typescript - +```ts class ExecutionOutcome { - gasBurnt: u64, - blockHash: Bytes, - id: Bytes, - logs: Array, - receiptIds: Array, - tokensBurnt: BigInt, - executorId: string, - } + gasBurnt: u64 + blockHash: Bytes + id: Bytes + logs: string[] + receiptIds: Bytes[] + tokensBurnt: bigint + executorId: string +} class ActionReceipt { - predecessorId: string, - receiverId: string, - id: CryptoHash, - signerId: string, - gasPrice: BigInt, - outputDataReceivers: Array, - inputDataIds: Array, - actions: Array, - } + predecessorId: string + receiverId: string + id: CryptoHash + signerId: string + gasPrice: bigint + outputDataReceivers: DataReceiver[] + inputDataIds: CryptoHash[] + actions: ActionValue[] +} class BlockHeader { - height: u64, - prevHeight: u64,// Always zero when version < V3 - epochId: Bytes, - nextEpochId: Bytes, - chunksIncluded: u64, - hash: Bytes, - prevHash: Bytes, - timestampNanosec: u64, - randomValue: Bytes, - gasPrice: BigInt, - totalSupply: BigInt, - latestProtocolVersion: u32, - } + height: u64 + prevHeight: u64 // Always zero when version < V3 + epochId: Bytes + nextEpochId: Bytes + chunksIncluded: u64 + hash: Bytes + prevHash: Bytes + timestampNanosec: u64 + randomValue: Bytes + gasPrice: bigint + totalSupply: bigint + latestProtocolVersion: u32 +} class ChunkHeader { - gasUsed: u64, - gasLimit: u64, - shardId: u64, - chunkHash: Bytes, - prevBlockHash: Bytes, - balanceBurnt: BigInt, - } + gasUsed: u64 + gasLimit: u64 + shardId: u64 + chunkHash: Bytes + prevBlockHash: Bytes + balanceBurnt: bigint +} class Block { - author: string, - header: BlockHeader, - chunks: Array, - } + author: string + header: BlockHeader + chunks: ChunkHeader[] +} class ReceiptWithOutcome { - outcome: ExecutionOutcome, - receipt: ActionReceipt, - block: Block, - } + outcome: ExecutionOutcome + receipt: ActionReceipt + block: Block +} ``` These types are passed to block & receipt handlers: diff --git a/website/pages/en/cookbook/subgraph-debug-forking.mdx b/website/pages/en/cookbook/subgraph-debug-forking.mdx index 5f214139646a..042fd9dea26a 100644 --- a/website/pages/en/cookbook/subgraph-debug-forking.mdx +++ b/website/pages/en/cookbook/subgraph-debug-forking.mdx @@ -22,9 +22,9 @@ To stay focused on subgraph debugging, let's keep things simple and run along wi Here are the handlers defined for indexing `Gravatar`s, with no bugs whatsoever: -```tsx +```ts export function handleNewGravatar(event: NewGravatar): void { - let gravatar = new Gravatar(event.params.id.toHex().toString()) + const gravatar = new Gravatar(event.params.id.toHex().toString()) gravatar.owner = event.params.owner gravatar.displayName = event.params.displayName gravatar.imageUrl = event.params.imageUrl @@ -32,7 +32,7 @@ export function handleNewGravatar(event: NewGravatar): void { } export function handleUpdatedGravatar(event: UpdatedGravatar): void { - let gravatar = Gravatar.load(event.params.id.toI32().toString()) + const gravatar = Gravatar.load(event.params.id.toI32().toString()) if (gravatar == null) { log.critical('Gravatar not found!', []) return diff --git a/website/pages/en/developing/assemblyscript-api.mdx b/website/pages/en/developing/assemblyscript-api.mdx index 787a1350f676..d48077ab8a84 100644 --- a/website/pages/en/developing/assemblyscript-api.mdx +++ b/website/pages/en/developing/assemblyscript-api.mdx @@ -238,15 +238,14 @@ The following is a common pattern for creating entities from Ethereum events. ```typescript // Import the Transfer event class generated from the ERC20 ABI import { Transfer as TransferEvent } from '../generated/ERC20/ERC20' - // Import the Transfer entity type generated from the GraphQL schema import { Transfer } from '../generated/schema' // Transfer event handler export function handleTransfer(event: TransferEvent): void { // Create a Transfer entity, using the transaction hash as the entity ID - let id = event.transaction.hash - let transfer = new Transfer(id) + const id = event.transaction.hash + const transfer = new Transfer(id) // Set properties on the entity, using the event parameters transfer.from = event.params.from @@ -267,7 +266,7 @@ Each entity must have a unique ID to avoid collisions with other entities. It is If an entity already exists, it can be loaded from the store with the following: ```typescript -let id = event.transaction.hash // or however the ID is constructed +const id = event.transaction.hash // or however the ID is constructed let transfer = Transfer.load(id) if (transfer == null) { transfer = new Transfer(id) @@ -290,10 +289,10 @@ There are two ways to update an existing entity: Changing properties is straight forward in most cases, thanks to the generated property setters: ```typescript -let transfer = new Transfer(id) -transfer.from = ... -transfer.to = ... -transfer.amount = ... +const transfer = new Transfer(id) +// transfer.from = ... +// transfer.to = ... +// transfer.amount = ... ``` It is also possible to unset properties with one of the following two instructions: @@ -313,7 +312,7 @@ entity.numbers.push(BigInt.fromI32(1)) entity.save() // This will work -let numbers = entity.numbers +const { numbers } = entity numbers.push(BigInt.fromI32(1)) entity.numbers = numbers entity.save() @@ -325,8 +324,8 @@ There is currently no way to remove an entity via the generated types. Instead, ```typescript import { store } from '@graphprotocol/graph-ts' -... -let id = event.transaction.hash +// ... +const id = event.transaction.hash store.remove('Transfer', id) ``` @@ -354,8 +353,8 @@ type Transfer @entity { and a `Transfer(address,address,uint256)` event signature on Ethereum, the `from`, `to` and `amount` values of type `address`, `address` and `uint256` are converted to `Address` and `BigInt`, allowing them to be passed on to the `Bytes!` and `BigInt!` properties of the `Transfer` entity: ```typescript -let id = event.transaction.hash -let transfer = new Transfer(id) +const id = event.transaction.hash +const transfer = new Transfer(id) transfer.from = event.params.from transfer.to = event.params.to transfer.amount = event.params.amount @@ -369,8 +368,8 @@ Ethereum events passed to event handlers, such as the `Transfer` event in the pr ```typescript class Event { address: Address - logIndex: BigInt - transactionLogIndex: BigInt + logIndex: bigint + transactionLogIndex: bigint logType: string | null block: Block transaction: Transaction @@ -386,38 +385,38 @@ class Block { stateRoot: Bytes transactionsRoot: Bytes receiptsRoot: Bytes - number: BigInt - gasUsed: BigInt - gasLimit: BigInt - timestamp: BigInt - difficulty: BigInt - totalDifficulty: BigInt - size: BigInt | null - baseFeePerGas: BigInt | null + number: bigint + gasUsed: bigint + gasLimit: bigint + timestamp: bigint + difficulty: bigint + totalDifficulty: bigint + size: bigint | null + baseFeePerGas: bigint | null } class Transaction { hash: Bytes - index: BigInt + index: bigint from: Address to: Address | null - value: BigInt - gasLimit: BigInt - gasPrice: BigInt + value: bigint + gasLimit: bigint + gasPrice: bigint input: Bytes - nonce: BigInt + nonce: bigint } class TransactionReceipt { transactionHash: Bytes - transactionIndex: BigInt + transactionIndex: bigint blockHash: Bytes - blockNumber: BigInt - cumulativeGasUsed: BigInt - gasUsed: BigInt + blockNumber: bigint + cumulativeGasUsed: bigint + gasUsed: bigint contractAddress: Address logs: Array - status: BigInt + status: bigint root: Bytes logsBloom: Bytes } @@ -429,9 +428,9 @@ class Log { blockHash: Bytes blockNumber: Bytes transactionHash: Bytes - transactionIndex: BigInt - logIndex: BigInt - transactionLogIndex: BigInt + transactionIndex: bigint + logIndex: bigint + transactionLogIndex: bigint logType: string removed: bool | null } @@ -451,10 +450,10 @@ import { Transfer } from '../generated/schema' export function handleTransfer(event: TransferEvent) { // Bind the contract to the address that emitted the event - let contract = ERC20Contract.bind(event.address) + const contract = ERC20Contract.bind(event.address) // Access state variables and functions by calling them - let erc20Symbol = contract.symbol() + const erc20Symbol = contract.symbol() } ``` @@ -469,12 +468,12 @@ Any other contract that is part of the subgraph can be imported from the generat If the read-only methods of your contract may revert, then you should handle that by calling the generated contract method prefixed with `try_`. For example, the Gravity contract exposes the `gravatarToOwner` method. This code would be able to handle a revert in that method: ```typescript -let gravity = Gravity.bind(event.address) -let callResult = gravity.try_gravatarToOwner(gravatar) +const gravity = Gravity.bind(event.address) +const callResult = gravity.try_gravatarToOwner(gravatar) if (callResult.reverted) { log.info('getGravatar reverted', []) } else { - let owner = callResult.value + const owner = callResult.value } ``` @@ -487,16 +486,16 @@ Data can be encoded and decoded according to Ethereum's ABI encoding format usin ```typescript import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts' -let tupleArray: Array = [ +const tupleArray: Array = [ ethereum.Value.fromAddress(Address.fromString('0x0000000000000000000000000000000000000420')), ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(62)), ] -let tuple = tupleArray as ethereum.Tuple +const tuple = tupleArray as ethereum.Tuple -let encoded = ethereum.encode(ethereum.Value.fromTuple(tuple))! +const encoded = ethereum.encode(ethereum.Value.fromTuple(tuple))! -let decoded = ethereum.decode('(address,uint256)', encoded) +const decoded = ethereum.decode('(address,uint256)', encoded) ``` For more information: @@ -534,7 +533,7 @@ log.info('Message to be displayed: {}, {}, {}', [value.toString(), anotherValue. In the example below, the string value "A" is passed into an array to become`['A']` before being logged: ```typescript -let myValue = 'A' +const myValue = 'A' export function handleSomeEvent(event: SomeEvent): void { // Displays : "My value is: A" @@ -547,7 +546,7 @@ export function handleSomeEvent(event: SomeEvent): void { In the example below, only the first value of the argument array is logged, despite the array containing three values. ```typescript -let myArray = ['A', 'B', 'C'] +const myArray = ['A', 'B', 'C'] export function handleSomeEvent(event: SomeEvent): void { // Displays : "My value is: A" (Even though three values are passed to `log.info`) @@ -560,7 +559,7 @@ export function handleSomeEvent(event: SomeEvent): void { Each entry in the arguments array requires its own placeholder `{}` in the log message string. The below example contains three placeholders `{}` in the log message. Because of this, all three values in `myArray` are logged. ```typescript -let myArray = ['A', 'B', 'C'] +const myArray = ['A', 'B', 'C'] export function handleSomeEvent(event: SomeEvent): void { // Displays : "My first value is: A, second value is: B, third value is: C" @@ -607,12 +606,12 @@ Given an IPFS hash or path, reading a file from IPFS is done as follows: ```typescript // Put this inside an event handler in the mapping -let hash = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D' +const hash = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D' let data = ipfs.cat(hash) // Paths like `QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile` // that include files in directories are also supported -let path = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile' +const path = 'QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile' let data = ipfs.cat(path) ``` @@ -626,16 +625,16 @@ import { JSONValue, Value } from '@graphprotocol/graph-ts' export function processItem(value: JSONValue, userData: Value): void { // See the JSONValue documentation for details on dealing // with JSON values - let obj = value.toObject() - let id = obj.get('id') - let title = obj.get('title') + const obj = value.toObject() + const id = obj.get('id') + const title = obj.get('title') if (!id || !title) { return } // Callbacks can also created entities - let newItem = new Item(id) + const newItem = new Item(id) newItem.title = title.toString() newitem.parent = userData.toString() // Set parent to "parentId" newitem.save() @@ -678,9 +677,9 @@ JSON data can be parsed using the `json` API: The `JSONValue` class provides a way to pull values out of an arbitrary JSON document. Since JSON values can be booleans, numbers, arrays and more, `JSONValue` comes with a `kind` property to check the type of a value: ```typescript -let value = json.fromBytes(...) -if (value.kind == JSONValueKind.BOOL) { - ... +const value = json.fromBytes(/* ... */) +if (value.kind === JSONValueKind.BOOL) { + // ... } ``` diff --git a/website/pages/en/developing/creating-a-subgraph.mdx b/website/pages/en/developing/creating-a-subgraph.mdx index 683b7dbaa086..4350cc374a34 100644 --- a/website/pages/en/developing/creating-a-subgraph.mdx +++ b/website/pages/en/developing/creating-a-subgraph.mdx @@ -481,12 +481,12 @@ For each event handler that is defined in `subgraph.yaml` under `mapping.eventHa In the example subgraph, `src/mapping.ts` contains handlers for the `NewGravatar` and `UpdatedGravatar` events: -```javascript +```ts import { NewGravatar, UpdatedGravatar } from '../generated/Gravity/Gravity' import { Gravatar } from '../generated/schema' export function handleNewGravatar(event: NewGravatar): void { - let gravatar = new Gravatar(event.params.id) + const gravatar = new Gravatar(event.params.id) gravatar.owner = event.params.owner gravatar.displayName = event.params.displayName gravatar.imageUrl = event.params.imageUrl @@ -494,7 +494,7 @@ export function handleNewGravatar(event: NewGravatar): void { } export function handleUpdatedGravatar(event: UpdatedGravatar): void { - let id = event.params.id + const { id } = event.params let gravatar = Gravatar.load(id) if (gravatar == null) { gravatar = new Gravatar(id) @@ -657,7 +657,7 @@ Data source contexts allow passing extra configuration when instantiating a temp import { Exchange } from '../generated/templates' export function handleNewExchange(event: NewExchange): void { - let context = new DataSourceContext() + const context = new DataSourceContext() context.setString('tradingPair', event.params.tradingPair) Exchange.createWithContext(event.params.exchange, context) } @@ -668,8 +668,8 @@ Inside a mapping of the `Exchange` template, the context can then be accessed: ```typescript import { dataSource } from '@graphprotocol/graph-ts' -let context = dataSource.context() -let tradingPair = context.getString('tradingPair') +const context = dataSource.context() +const tradingPair = context.getString('tradingPair') ``` There are setters and getters like `setString` and `getString` for all value types. @@ -754,8 +754,8 @@ import { CreateGravatarCall } from '../generated/Gravity/Gravity' import { Transaction } from '../generated/schema' export function handleCreateGravatar(call: CreateGravatarCall): void { - let id = call.transaction.hash - let transaction = new Transaction(id) + const id = call.transaction.hash + const transaction = new Transaction(id) transaction.displayName = call.inputs._displayName transaction.imageUrl = call.inputs._imageUrl transaction.save() @@ -814,8 +814,8 @@ The mapping function will receive an `ethereum.Block` as its only argument. Like import { ethereum } from '@graphprotocol/graph-ts' export function handleBlock(block: ethereum.Block): void { - let id = block.hash - let entity = new Block(id) + const id = block.hash + const entity = new Block(id) entity.save() } ``` @@ -914,22 +914,16 @@ _meta { If the subgraph encounters an error, that query will return both the data and a graphql error with the message `"indexing_error"`, as in this example response: -```graphql -"data": { - "foos": [ - { - "id": "0xdead" - } - ], +```json +{ + "data": { + "foos": [{ "id": "0xdead" }], "_meta": { - "hasIndexingErrors": true - } -}, -"errors": [ - { - "message": "indexing_error" + "hasIndexingErrors": true } -] + }, + "errors": [{ "message": "indexing_error" }] +} ``` ### Grafting onto Existing Subgraphs @@ -1067,11 +1061,12 @@ const cid = dataSource.stringParam() Example handler: ```typescript -import { json, Bytes, dataSource } from '@graphprotocol/graph-ts' +import { Bytes, dataSource, json } from '@graphprotocol/graph-ts' + import { TokenMetadata } from '../generated/schema' export function handleMetadata(content: Bytes): void { - let tokenMetadata = new TokenMetadata(dataSource.stringParam()) + const tokenMetadata = new TokenMetadata(dataSource.stringParam()) const value = json.fromBytes(content).toObject() if (value) { const image = value.get('image') diff --git a/website/pages/en/developing/unit-testing-framework.mdx b/website/pages/en/developing/unit-testing-framework.mdx index 86b29635afb1..9b98eaa54d92 100644 --- a/website/pages/en/developing/unit-testing-framework.mdx +++ b/website/pages/en/developing/unit-testing-framework.mdx @@ -54,19 +54,19 @@ or Please make sure you're on a newer version of Node.js graph-cli doesn't support **v10.19.0** anymore, and that is still the default version for new Ubuntu images on WSL. For instance Matchstick is confirmed to be working on WSL with **v18.1.0**, you can switch to it either via **nvm** or if you update your global Node.js. Don't forget to delete `node_modules` and to run `npm install` again after updating you nodejs! Then, make sure you have **libpq** installed, you can do that by running -``` +```sh sudo apt-get install libpq-dev ``` And finally, do not use `graph test` (which uses your global installation of graph-cli and for some reason that looks like it's broken on WSL currently), instead use `yarn test` or `npm run test` (that will use the local, project-level instance of graph-cli, which works like a charm). For that you would of course need to have a `"test"` script in your `package.json` file which can be something as simple as -```json +```jsonc { "name": "demo-subgraph", "version": "0.1.0", "scripts": { - "test": "graph test", - ... + "test": "graph test" + //... }, "dependencies": { "@graphprotocol/graph-cli": "^0.30.0", @@ -157,12 +157,13 @@ _**IMPORTANT: Requires matchstick-as >=0.5.0**_ Example: ```typescript -import { describe, test } from "matchstick-as/assembly/index" -import { handleNewGravatar } from "../../src/gravity" +import { describe, test } from 'matchstick-as/assembly/index' -describe("handleNewGravatar()", () => { - test("Should create a new Gravatar entity", () => { - ... +import { handleNewGravatar } from '../../src/gravity' + +describe('handleNewGravatar()', () => { + test('Should create a new Gravatar entity', () => { + // ... }) }) ``` @@ -170,19 +171,20 @@ describe("handleNewGravatar()", () => { Nested `describe()` example: ```typescript -import { describe, test } from "matchstick-as/assembly/index" -import { handleUpdatedGravatar } from "../../src/gravity" +import { describe, test } from 'matchstick-as/assembly/index' + +import { handleUpdatedGravatar } from '../../src/gravity' -describe("handleUpdatedGravatar()", () => { - describe("When entity exists", () => { - test("updates the entity", () => { - ... +describe('handleUpdatedGravatar()', () => { + describe('When entity exists', () => { + test('updates the entity', () => { + // ... }) }) - describe("When entity does not exists", () => { - test("it creates a new entity", () => { - ... + describe('When entity does not exists', () => { + test('it creates a new entity', () => { + // ... }) }) }) @@ -197,12 +199,13 @@ describe("handleUpdatedGravatar()", () => { Example: ```typescript -import { describe, test } from "matchstick-as/assembly/index" -import { handleNewGravatar } from "../../src/gravity" +import { describe, test } from 'matchstick-as/assembly/index' -describe("handleNewGravatar()", () => { - test("Should create a new Entity", () => { - ... +import { handleNewGravatar } from '../../src/gravity' + +describe('handleNewGravatar()', () => { + test('Should create a new Entity', () => { + // ... }) }) ``` @@ -210,11 +213,9 @@ describe("handleNewGravatar()", () => { or ```typescript -test("handleNewGravatar() should create a new entity", () => { - ... +test('handleNewGravatar() should create a new entity', () => { + // ... }) - - ``` --- @@ -228,26 +229,27 @@ Examples: Code inside `beforeAll` will execute once before _all_ tests in the file. ```typescript -import { describe, test, beforeAll } from "matchstick-as/assembly/index" -import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity" -import { Gravatar } from "../../generated/schema" +import { beforeAll, describe, test } from 'matchstick-as/assembly/index' + +import { Gravatar } from '../../generated/schema' +import { handleNewGravatar, handleUpdatedGravatar } from '../../src/gravity' beforeAll(() => { - let gravatar = new Gravatar("0x0") - gravatar.displayName = “First Gravatar” + const gravatar = new Gravatar('0x0') + gravatar.displayName = 'First Gravatar' gravatar.save() - ... + // ... }) -describe("When the entity does not exist", () => { - test("it should create a new Gravatar with id 0x1", () => { - ... +describe('When the entity does not exist', () => { + test('it should create a new Gravatar with id 0x1', () => { + // ... }) }) -describe("When entity already exists", () => { - test("it should update the Gravatar with id 0x0", () => { - ... +describe('When entity already exists', () => { + test('it should update the Gravatar with id 0x0', () => { + // ... }) }) ``` @@ -255,24 +257,25 @@ describe("When entity already exists", () => { Code inside `beforeAll` will execute once before all tests in the first describe block ```typescript -import { describe, test, beforeAll } from "matchstick-as/assembly/index" -import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity" -import { Gravatar } from "../../generated/schema" +import { beforeAll, describe, test } from 'matchstick-as/assembly/index' + +import { Gravatar } from '../../generated/schema' +import { handleNewGravatar, handleUpdatedGravatar } from '../../src/gravity' -describe("handleUpdatedGravatar()", () => { +describe('handleUpdatedGravatar()', () => { beforeAll(() => { - let gravatar = new Gravatar("0x0") - gravatar.displayName = “First Gravatar” + const gravatar = new Gravatar('0x0') + gravatar.displayName = 'First Gravatar' gravatar.save() - ... + // ... }) - test("updates Gravatar with id 0x0", () => { - ... + test('updates Gravatar with id 0x0', () => { + // ... }) - test("creates new Gravatar with id 0x1", () => { - ... + test('creates new Gravatar with id 0x1', () => { + // ... }) }) ``` @@ -288,24 +291,25 @@ Example: Code inside `afterAll` will execute once after _all_ tests in the file. ```typescript -import { describe, test, afterAll } from "matchstick-as/assembly/index" -import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity" -import { store } from "@graphprotocol/graph-ts" +import { store } from '@graphprotocol/graph-ts' +import { afterAll, describe, test } from 'matchstick-as/assembly/index' + +import { handleNewGravatar, handleUpdatedGravatar } from '../../src/gravity' afterAll(() => { - store.remove("Gravatar", "0x0") - ... + store.remove('Gravatar', '0x0') + // ... }) -describe("handleNewGravatar, () => { - test("creates Gravatar with id 0x0", () => { - ... +describe('handleNewGravatar', () => { + test('creates Gravatar with id 0x0', () => { + // ... }) }) -describe("handleUpdatedGravatar", () => { - test("updates Gravatar with id 0x0", () => { - ... +describe('handleUpdatedGravatar', () => { + test('updates Gravatar with id 0x0', () => { + // ... }) }) ``` @@ -313,27 +317,28 @@ describe("handleUpdatedGravatar", () => { Code inside `afterAll` will execute once after all tests in the first describe block ```typescript -import { describe, test, afterAll, clearStore } from "matchstick-as/assembly/index" -import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity" +import { afterAll, clearStore, describe, test } from 'matchstick-as/assembly/index' -describe("handleNewGravatar", () => { - afterAll(() => { - store.remove("Gravatar", "0x1") - ... - }) +import { handleNewGravatar, handleUpdatedGravatar } from '../../src/gravity' - test("It creates a new entity with Id 0x0", () => { - ... +describe('handleNewGravatar', () => { + afterAll(() => { + store.remove('Gravatar', '0x1') + // ... }) - test("It creates a new entity with Id 0x1", () => { - ... + test('It creates a new entity with Id 0x0', () => { + // ... + }) + + test('It creates a new entity with Id 0x1', () => { + // ... }) }) -describe("handleUpdatedGravatar", () => { - test("updates Gravatar with id 0x0", () => { - ... +describe('handleUpdatedGravatar', () => { + test('updates Gravatar with id 0x0', () => { + // ... }) }) ``` @@ -347,35 +352,35 @@ Runs a code block before every test. If `beforeEach` is declared inside of a `de Examples: Code inside `beforeEach` will execute before each tests. ```typescript -import { describe, test, beforeEach, clearStore } from "matchstick-as/assembly/index" -import { handleNewGravatars } from "./utils" +import { beforeEach, clearStore, describe, test } from 'matchstick-as/assembly/index' + +import { handleNewGravatars } from './utils' beforeEach(() => { clearStore() // <-- clear the store before each test in the file }) -describe("handleNewGravatars, () => { - test("A test that requires a clean store", () => { - ... +describe('handleNewGravatars', () => { + test('A test that requires a clean store', () => { + // ... }) - test("Second that requires a clean store", () => { - ... + test('Second that requires a clean store', () => { + // ... }) }) - - ... ``` Code inside `beforeEach` will execute only before each test in the that describe ```typescript -import { describe, test, beforeEach } from 'matchstick-as/assembly/index' -import { handleUpdatedGravatar, handleNewGravatar } from '../../src/gravity' +import { beforeEach, describe, test } from 'matchstick-as/assembly/index' + +import { handleNewGravatar, handleUpdatedGravatar } from '../../src/gravity' describe('handleUpdatedGravatars', () => { beforeEach(() => { - let gravatar = new Gravatar('0x0') + const gravatar = new Gravatar('0x0') gravatar.displayName = 'First Gravatar' gravatar.imageUrl = '' gravatar.save() @@ -412,38 +417,39 @@ Examples: Code inside `afterEach` will execute after every test. ```typescript -import { describe, test, beforeEach, afterEach } from "matchstick-as/assembly/index" -import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity" +import { afterEach, beforeEach, describe, test } from 'matchstick-as/assembly/index' + +import { handleNewGravatar, handleUpdatedGravatar } from '../../src/gravity' beforeEach(() => { - let gravatar = new Gravatar("0x0") - gravatar.displayName = “First Gravatar” + const gravatar = new Gravatar('0x0') + gravatar.displayName = 'First Gravatar' gravatar.save() }) afterEach(() => { - store.remove("Gravatar", "0x0") + store.remove('Gravatar', '0x0') }) -describe("handleNewGravatar", () => { - ... +describe('handleNewGravatar', () => { + // ... }) -describe("handleUpdatedGravatar", () => { - test("Upates the displayName", () => { - assert.fieldEquals("Gravatar", "0x0", "displayName", "First Gravatar") +describe('handleUpdatedGravatar', () => { + test('Upates the displayName', () => { + assert.fieldEquals('Gravatar', '0x0', 'displayName', 'First Gravatar') // code that should update the displayName to 1st Gravatar - assert.fieldEquals("Gravatar", "0x0", "displayName", "1st Gravatar") + assert.fieldEquals('Gravatar', '0x0', 'displayName', '1st Gravatar') }) - test("Updates the imageUrl", () => { - assert.fieldEquals("Gravatar", "0x0", "imageUrl", "") + test('Updates the imageUrl', () => { + assert.fieldEquals('Gravatar', '0x0', 'imageUrl', '') // code that should changes the imageUrl to https://www.gravatar.com/avatar/0x0 - assert.fieldEquals("Gravatar", "0x0", "imageUrl", "https://www.gravatar.com/avatar/0x0") + assert.fieldEquals('Gravatar', '0x0', 'imageUrl', 'https://www.gravatar.com/avatar/0x0') }) }) ``` @@ -451,46 +457,47 @@ describe("handleUpdatedGravatar", () => { Code inside `afterEach` will execute after each test in that describe ```typescript -import { describe, test, beforeEach, afterEach } from "matchstick-as/assembly/index" -import { handleUpdatedGravatar, handleNewGravatar } from "../../src/gravity" +import { afterEach, beforeEach, describe, test } from 'matchstick-as/assembly/index' -describe("handleNewGravatar", () => { - ... +import { handleNewGravatar, handleUpdatedGravatar } from '../../src/gravity' + +describe('handleNewGravatar', () => { + // ... }) -describe("handleUpdatedGravatar", () => { +describe('handleUpdatedGravatar', () => { beforeEach(() => { - let gravatar = new Gravatar("0x0") - gravatar.displayName = "First Gravatar" - gravatar.imageUrl = "" + const gravatar = new Gravatar('0x0') + gravatar.displayName = 'First Gravatar' + gravatar.imageUrl = '' gravatar.save() }) afterEach(() => { - store.remove("Gravatar", "0x0") + store.remove('Gravatar', '0x0') }) - test("Upates the displayName", () => { - assert.fieldEquals("Gravatar", "0x0", "displayName", "First Gravatar") + test('Upates the displayName', () => { + assert.fieldEquals('Gravatar', '0x0', 'displayName', 'First Gravatar') // code that should update the displayName to 1st Gravatar - assert.fieldEquals("Gravatar", "0x0", "displayName", "1st Gravatar") + assert.fieldEquals('Gravatar', '0x0', 'displayName', '1st Gravatar') }) - test("Updates the imageUrl", () => { - assert.fieldEquals("Gravatar", "0x0", "imageUrl", "") + test('Updates the imageUrl', () => { + assert.fieldEquals('Gravatar', '0x0', 'imageUrl', '') // code that should changes the imageUrl to https://www.gravatar.com/avatar/0x0 - assert.fieldEquals("Gravatar", "0x0", "imageUrl", "https://www.gravatar.com/avatar/0x0") + assert.fieldEquals('Gravatar', '0x0', 'imageUrl', 'https://www.gravatar.com/avatar/0x0') }) }) ``` ## Asserts -```typescript +```text fieldEquals(entityType: string, id: string, fieldName: string, expectedVal: string) equals(expected: ethereum.Value, actual: ethereum.Value) @@ -503,7 +510,7 @@ bytesEquals(bytes1: Bytes, bytes2: Bytes) i32Equals(number1: i32, number2: i32) -bigIntEquals(bigInt1: BigInt, bigInt2: BigInt) +bigIntEquals(bigInt1: bigint, bigInt2: bigint) booleanEquals(bool1: boolean, bool2: boolean) @@ -530,7 +537,7 @@ Assuming we have the following handler function (along with two helper functions ```typescript export function handleNewGravatar(event: NewGravatar): void { - let gravatar = new Gravatar(event.params.id.toHex()) + const gravatar = new Gravatar(event.params.id.toHex()) gravatar.owner = event.params.owner gravatar.displayName = event.params.displayName gravatar.imageUrl = event.params.imageUrl @@ -549,8 +556,8 @@ export function createNewGravatarEvent( displayName: string, imageUrl: string ): NewGravatar { - let mockEvent = newMockEvent() - let newGravatarEvent = new NewGravatar( + const mockEvent = newMockEvent() + const newGravatarEvent = new NewGravatar( mockEvent.address, mockEvent.logIndex, mockEvent.transactionLogIndex, @@ -559,14 +566,14 @@ export function createNewGravatarEvent( mockEvent.transaction, mockEvent.parameters ) - newGravatarEvent.parameters = new Array() - let idParam = new ethereum.EventParam('id', ethereum.Value.fromI32(id)) - let addressParam = new ethereum.EventParam( + newGravatarEvent.parameters = [] + const idParam = new ethereum.EventParam('id', ethereum.Value.fromI32(id)) + const addressParam = new ethereum.EventParam( 'ownderAddress', ethereum.Value.fromAddress(Address.fromString(ownerAddress)) ) - let displayNameParam = new ethereum.EventParam('displayName', ethereum.Value.fromString(displayName)) - let imageUrlParam = new ethereum.EventParam('imageUrl', ethereum.Value.fromString(imageUrl)) + const displayNameParam = new ethereum.EventParam('displayName', ethereum.Value.fromString(displayName)) + const imageUrlParam = new ethereum.EventParam('imageUrl', ethereum.Value.fromString(imageUrl)) newGravatarEvent.parameters.push(idParam) newGravatarEvent.parameters.push(addressParam) @@ -580,19 +587,20 @@ export function createNewGravatarEvent( We first have to create a test file in our project. This is an example of how that might look like: ```typescript -import { clearStore, test, assert } from 'matchstick-as/assembly/index' -import { Gravatar } from '../../generated/schema' +import { assert, clearStore, test } from 'matchstick-as/assembly/index' + import { NewGravatar } from '../../generated/Gravity/Gravity' +import { Gravatar } from '../../generated/schema' import { createNewGravatarEvent, handleNewGravatars } from '../mappings/gravity' test('Can call mappings with custom events', () => { // Create a test entity and save it in the store as initial state (optional) - let gravatar = new Gravatar('gravatarId0') + const gravatar = new Gravatar('gravatarId0') gravatar.save() // Create mock events - let newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac') - let anotherGravatarEvent = createNewGravatarEvent(3546, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac') + const newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac') + const anotherGravatarEvent = createNewGravatarEvent(3546, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac') // Call mapping functions passing the events we just created handleNewGravatars([newGravatarEvent, anotherGravatarEvent]) @@ -607,7 +615,7 @@ test('Can call mappings with custom events', () => { }) test('Next test', () => { - //... + // ... }) ``` @@ -636,7 +644,7 @@ And if all goes well you should be greeted with the following: Users are able to hydrate the store with a known set of entities. Here's an example to initialise the store with a Gravatar entity: ```typescript -let gravatar = new Gravatar('entryId') +const gravatar = new Gravatar('entryId') gravatar.save() ``` @@ -646,10 +654,12 @@ A user can create a custom event and pass it to a mapping function that is bound ```typescript import { store } from 'matchstick-as/assembly/store' + import { NewGravatar } from '../../generated/Gravity/Gravity' -import { handleNewGravatars, createNewGravatarEvent } from './mapping' -let newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac') +import { createNewGravatarEvent, handleNewGravatars } from './mapping' + +const newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac') handleNewGravatar(newGravatarEvent) ``` @@ -659,22 +669,24 @@ handleNewGravatar(newGravatarEvent) Users can call the mappings with test fixtures. ```typescript -import { NewGravatar } from '../../generated/Gravity/Gravity' import { store } from 'matchstick-as/assembly/store' -import { handleNewGravatars, createNewGravatarEvent } from './mapping' -let newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac') +import { NewGravatar } from '../../generated/Gravity/Gravity' + +import { createNewGravatarEvent, handleNewGravatars } from './mapping' -let anotherGravatarEvent = createNewGravatarEvent(3546, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac') +const newGravatarEvent = createNewGravatarEvent(12345, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac') + +const anotherGravatarEvent = createNewGravatarEvent(3546, '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7', 'cap', 'pac') handleNewGravatars([newGravatarEvent, anotherGravatarEvent]) ``` -``` +```ts export function handleNewGravatars(events: NewGravatar[]): void { - events.forEach(event => { - handleNewGravatar(event); - }); + events.forEach((event) => { + handleNewGravatar(event) + }) } ``` @@ -683,19 +695,20 @@ export function handleNewGravatars(events: NewGravatar[]): void { Users can mock contract calls: ```typescript -import { addMetadata, assert, createMockedFunction, clearStore, test } from 'matchstick-as/assembly/index' -import { Gravity } from '../../generated/Gravity/Gravity' import { Address, BigInt, ethereum } from '@graphprotocol/graph-ts' +import { addMetadata, assert, clearStore, createMockedFunction, test } from 'matchstick-as/assembly/index' -let contractAddress = Address.fromString('0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7') -let expectedResult = Address.fromString('0x90cBa2Bbb19ecc291A12066Fd8329D65FA1f1947') -let bigIntParam = BigInt.fromString('1234') +import { Gravity } from '../../generated/Gravity/Gravity' + +const contractAddress = Address.fromString('0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7') +const expectedResult = Address.fromString('0x90cBa2Bbb19ecc291A12066Fd8329D65FA1f1947') +const bigIntParam = BigInt.fromString('1234') createMockedFunction(contractAddress, 'gravatarToOwner', 'gravatarToOwner(uint256):(address)') .withArgs([ethereum.Value.fromSignedBigInt(bigIntParam)]) .returns([ethereum.Value.fromAddress(Address.fromString('0x90cBa2Bbb19ecc291A12066Fd8329D65FA1f1947'))]) -let gravity = Gravity.bind(contractAddress) -let result = gravity.gravatarToOwner(bigIntParam) +const gravity = Gravity.bind(contractAddress) +const result = gravity.gravatarToOwner(bigIntParam) assert.equals(ethereum.Value.fromAddress(expectedResult), ethereum.Value.fromAddress(result)) ``` @@ -705,7 +718,7 @@ As demonstrated, in order to mock a contract call and hardcore a return value, t Users can also mock function reverts: ```typescript -let contractAddress = Address.fromString('0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7') +const contractAddress = Address.fromString('0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7') createMockedFunction(contractAddress, 'getGravatar', 'getGravatar(address):(string,string)') .withArgs([ethereum.Value.fromAddress(contractAddress)]) .reverts() @@ -720,8 +733,9 @@ NOTE: When testing `ipfs.map/ipfs.mapJSON`, the callback function must be export `.test.ts` file: ```typescript -import { assert, test, mockIpfsFile } from 'matchstick-as/assembly/index' import { ipfs } from '@graphprotocol/graph-ts' +import { assert, mockIpfsFile, test } from 'matchstick-as/assembly/index' + import { gravatarFromIpfs } from './utils' // Export ipfs.map() callback in order for matchstck to detect it @@ -757,46 +771,47 @@ test('ipfs.map', () => { `utils.ts` file: ```typescript -import { Address, ethereum, JSONValue, Value, ipfs, json, Bytes } from "@graphprotocol/graph-ts" -import { Gravatar } from "../../generated/schema" +import { Address, Bytes, ethereum, ipfs, json, JSONValue, Value } from '@graphprotocol/graph-ts' + +import { Gravatar } from '../../generated/schema' -... +// ... // ipfs.map callback export function processGravatar(value: JSONValue, userData: Value): void { // See the JSONValue documentation for details on dealing // with JSON values - let obj = value.toObject() - let id = obj.get('id') + const obj = value.toObject() + const id = obj.get('id') if (!id) { return } // Callbacks can also created entities - let gravatar = new Gravatar(id.toString()) + const gravatar = new Gravatar(id.toString()) gravatar.displayName = userData.toString() + id.toString() gravatar.save() } // function that calls ipfs.cat export function gravatarFromIpfs(): void { - let rawData = ipfs.cat("ipfsCatfileHash") + const rawData = ipfs.cat('ipfsCatfileHash') if (!rawData) { return } - let jsonData = json.fromBytes(rawData as Bytes).toObject() + const jsonData = json.fromBytes(rawData as Bytes).toObject() - let id = jsonData.get('id') - let url = jsonData.get("imageUrl") + const id = jsonData.get('id') + const url = jsonData.get('imageUrl') if (!id || !url) { return } - let gravatar = new Gravatar(id.toString()) + const gravatar = new Gravatar(id.toString()) gravatar.imageUrl = url.toString() gravatar.save() } @@ -808,9 +823,10 @@ Users are able to assert the final (or midway) state of the store through assert ```typescript import { assert } from 'matchstick-as/assembly/index' + import { Gravatar } from '../generated/schema' -let gravatar = new Gravatar('gravatarId0') +const gravatar = new Gravatar('gravatarId0') gravatar.save() assert.fieldEquals('Gravatar', 'gravatarId0', 'id', 'gravatarId0') @@ -824,17 +840,17 @@ Users can use default transaction metadata, which could be returned as an ethere ```typescript // Read -let logType = newGravatarEvent.logType +const logType = newGravatarEvent.logType // Write -let UPDATED_ADDRESS = '0xB16081F360e3847006dB660bae1c6d1b2e17eC2A' +const UPDATED_ADDRESS = '0xB16081F360e3847006dB660bae1c6d1b2e17eC2A' newGravatarEvent.address = Address.fromString(UPDATED_ADDRESS) ``` ### Asserting variable equality ```typescript -assert.equals(ethereum.Value.fromString("hello"); ethereum.Value.fromString("hello")); +assert.equals(ethereum.Value.fromString('hello'), ethereum.Value.fromString('hello')) ``` ### Asserting that an Entity is **not** in the store @@ -876,24 +892,24 @@ If the test is marked with shouldFail = true but DOES NOT fail, that will show u Having custom logs in the unit tests is exactly the same as logging in the mappings. The difference is that the log object needs to be imported from matchstick-as rather than graph-ts. Here's a simple example with all non-critical log types: ```typescript -import { test } from "matchstick-as/assembly/index"; -import { log } from "matchstick-as/assembly/log"; - -test("Success", () => { - log.success("Success!". []); -}); -test("Error", () => { - log.error("Error :( ", []); -}); -test("Debug", () => { - log.debug("Debugging...", []); -}); -test("Info", () => { - log.info("Info!", []); -}); -test("Warning", () => { - log.warning("Warning!", []); -}); +import { test } from 'matchstick-as/assembly/index' +import { log } from 'matchstick-as/assembly/log' + +test('Success', () => { + log.success('Success!', []) +}) +test('Error', () => { + log.error('Error :( ', []) +}) +test('Debug', () => { + log.debug('Debugging...', []) +}) +test('Info', () => { + log.info('Info!', []) +}) +test('Warning', () => { + log.warning('Warning!', []) +}) ``` Users can also simulate a critical failure, like so: @@ -914,10 +930,10 @@ Testing derived fields is a feature which (as the example below shows) allows th test('Derived fields example test', () => { let mainAccount = new GraphAccount('12') mainAccount.save() - let operatedAccount = new GraphAccount('1') + const operatedAccount = new GraphAccount('1') operatedAccount.operators = ['12'] operatedAccount.save() - let nst = new NameSignalTransaction('1234') + const nst = new NameSignalTransaction('1234') nst.signer = '12' nst.save() @@ -941,11 +957,11 @@ First we have the following event handler (which has been intentionally repurpos ```typescript export function handleApproveTokenDestinations(event: ApproveTokenDestinations): void { - let tokenLockWallet = TokenLockWallet.load(dataSource.address().toHexString())! - if (dataSource.network() == 'rinkeby') { + const tokenLockWallet = TokenLockWallet.load(dataSource.address().toHexString())! + if (dataSource.network() === 'rinkeby') { tokenLockWallet.tokenDestinationsApproved = true } - let context = dataSource.context() + const context = dataSource.context() if (context.get('contextVal')!.toI32() > 0) { tokenLockWallet.setBigInt('tokensReleased', BigInt.fromI32(context.get('contextVal')!.toI32())) } @@ -956,23 +972,23 @@ export function handleApproveTokenDestinations(event: ApproveTokenDestinations): And then we have the test using one of the methods in the dataSourceMock namespace to set a new return value for all of the dataSource functions: ```typescript -import { assert, test, newMockEvent, dataSourceMock } from 'matchstick-as/assembly/index' import { BigInt, DataSourceContext, Value } from '@graphprotocol/graph-ts' +import { assert, dataSourceMock, newMockEvent, test } from 'matchstick-as/assembly/index' -import { handleApproveTokenDestinations } from '../../src/token-lock-wallet' -import { ApproveTokenDestinations } from '../../generated/templates/GraphTokenLockWallet/GraphTokenLockWallet' import { TokenLockWallet } from '../../generated/schema' +import { ApproveTokenDestinations } from '../../generated/templates/GraphTokenLockWallet/GraphTokenLockWallet' +import { handleApproveTokenDestinations } from '../../src/token-lock-wallet' test('Data source simple mocking example', () => { - let addressString = '0xA16081F360e3847006dB660bae1c6d1b2e17eC2A' - let address = Address.fromString(addressString) + const addressString = '0xA16081F360e3847006dB660bae1c6d1b2e17eC2A' + const address = Address.fromString(addressString) let wallet = new TokenLockWallet(address.toHexString()) wallet.save() - let context = new DataSourceContext() + const context = new DataSourceContext() context.set('contextVal', Value.fromI32(325)) dataSourceMock.setReturnValues(addressString, 'rinkeby', context) - let event = changetype(newMockEvent()) + const event = changetype(newMockEvent()) assert.assertTrue(!wallet.tokenDestinationsApproved) @@ -1009,6 +1025,8 @@ import { handleNewGravatar } from '../../src/gravity' In order for that function to be visible (for it to be included in the `wat` file **by name**) we need to also export it, like this: ```typescript +import { handleNewGravatar } from '../../src/gravity' + export { handleNewGravatar } ``` @@ -1022,11 +1040,13 @@ graph test -- -c You could also add a custom `coverage` command to your `package.json` file, like so: -```typescript - "scripts": { - /.../ +```jsonc +{ + "scripts": { + // ... "coverage": "graph test -- -c" - }, + } +} ``` Hopefully that should execute the coverage tool without any issues. You should see something like this in the terminal: diff --git a/website/pages/en/querying/distributed-systems.mdx b/website/pages/en/querying/distributed-systems.mdx index 85337206bfd3..1a248bbe0e04 100644 --- a/website/pages/en/querying/distributed-systems.mdx +++ b/website/pages/en/querying/distributed-systems.mdx @@ -49,17 +49,18 @@ async function updateProtocolPaused() { setTimeout(f, 14000) }) - const query = ` - query GetProtocol($minBlock: Int!) { - protocol(block: { number_gte: $minBlock } id: "0") { - paused - } - _meta { - block { - number - } - } - }` + const query = /* GraphQL */ ` + query GetProtocol($minBlock: Int!) { + protocol(block: { number_gte: $minBlock }, id: "0") { + paused + } + _meta { + block { + number + } + } + } + ` const variables = { minBlock } const response = await graphql(query, variables) @@ -89,36 +90,38 @@ async function getDomainNames() { // The first query will get the first page of results and also get the block // hash so that the remainder of the queries are consistent with the first. - const listDomainsQuery = ` + const listDomainsQuery = /* GraphQL */ ` query ListDomains($perPage: Int!) { - domains(first: $perPage) { - name - id + domains(first: $perPage) { + name + id + } + _meta { + block { + hash } - _meta { - block { - hash - } - } - }` + } + } + ` let data = await graphql(listDomainsQuery, { perPage }) - let result = data.domains.map((d) => d.name) - let blockHash = data._meta.block.hash + const result = data.domains.map((d) => d.name) + const blockHash = data._meta.block.hash let query // Continue fetching additional pages until either we run into the limit of // 5 pages total (specified above) or we know we have reached the last page // because the page has fewer entities than a full page. - while (data.domains.length == perPage && --pages) { - let lastID = data.domains[data.domains.length - 1].id - query = ` - query ListDomains($perPage: Int!, $lastID: ID!, $blockHash: Bytes!) { - domains(first: $perPage, where: { id_gt: $lastID }, block: { hash: $blockHash }) { - name - id - } - }` + while (data.domains.length === perPage && --pages) { + const lastID = data.domains[data.domains.length - 1].id + query = /* GraphQL */ ` + query ListDomains($perPage: Int!, $lastID: ID!, $blockHash: Bytes!) { + domains(first: $perPage, where: { id_gt: $lastID }, block: { hash: $blockHash }) { + name + id + } + } + ` data = await graphql(query, { perPage, lastID, blockHash }) diff --git a/website/pages/en/querying/querying-from-an-application.mdx b/website/pages/en/querying/querying-from-an-application.mdx index 44a8f9cebef4..cc6805bc3252 100644 --- a/website/pages/en/querying/querying-from-an-application.mdx +++ b/website/pages/en/querying/querying-from-an-application.mdx @@ -104,6 +104,7 @@ Finally, update your `.ts` file to use the generated typed GraphQL documents: ```tsx import React, { useEffect } from 'react' + // ... // we import types and typed-graphql document from the generated code (`..graphclient/`) import { ExampleQueryDocument, ExampleQueryQuery, execute } from '../.graphclient' @@ -173,7 +174,7 @@ npm install @apollo/client graphql Then you can query the API with the following code: ```javascript -import { ApolloClient, InMemoryCache, gql } from '@apollo/client' +import { ApolloClient, gql, InMemoryCache } from '@apollo/client' const APIURL = 'https://api.studio.thegraph.com/query///' diff --git a/website/pages/en/release-notes/assemblyscript-migration-guide.mdx b/website/pages/en/release-notes/assemblyscript-migration-guide.mdx index 85f6903a6c69..4ec53a44fa48 100644 --- a/website/pages/en/release-notes/assemblyscript-migration-guide.mdx +++ b/website/pages/en/release-notes/assemblyscript-migration-guide.mdx @@ -82,16 +82,18 @@ npm install --save @graphprotocol/graph-ts@latest On the older version of AssemblyScript, you could create code like this: ```typescript -function load(): Value | null { ... } +function load(): Value | null { + // ... +} -let maybeValue = load(); -maybeValue.aMethod(); +const maybeValue = load() +maybeValue.aMethod() ``` However on the newer version, because the value is nullable, it requires you to check, like this: ```typescript -let maybeValue = load() +const maybeValue = load() if (maybeValue) { maybeValue.aMethod() // `maybeValue` is not null anymore @@ -101,7 +103,7 @@ if (maybeValue) { Or force it like this: ```typescript -let maybeValue = load()! // breaks in runtime if value is null +const maybeValue = load()! // breaks in runtime if value is null maybeValue.aMethod() ``` @@ -114,13 +116,13 @@ Before you could do [variable shadowing](https://en.wikipedia.org/wiki/Variable_ ```typescript let a = 10 -let b = 20 +const b = 20 let a = a + b ``` However now this isn't possible anymore, and the compiler returns this error: -```typescript +```text ERROR TS2451: Cannot redeclare block-scoped variable 'a' let a = a + b; @@ -134,7 +136,7 @@ You'll need to rename your duplicate variables if you had variable shadowing. By doing the upgrade on your subgraph, sometimes you might get errors like these: -```typescript +```text ERROR TS2322: Type '~lib/@graphprotocol/graph-ts/common/numbers/BigInt | null' is not assignable to type '~lib/@graphprotocol/graph-ts/common/numbers/BigInt'. if (decimals == null) { ~~~~ @@ -144,11 +146,13 @@ ERROR TS2322: Type '~lib/@graphprotocol/graph-ts/common/numbers/BigInt | null' i To solve you can simply change the `if` statement to something like this: ```typescript - if (!decimals) { +if (!decimals) { +} - // or +// or - if (decimals === null) { +if (decimals === null) { +} ``` The same applies if you're doing != instead of ==. @@ -158,8 +162,8 @@ The same applies if you're doing != instead of ==. The common way to do casting before was to just use the `as` keyword, like this: ```typescript -let byteArray = new ByteArray(10) -let uint8Array = byteArray as Uint8Array // equivalent to: byteArray +const byteArray = new ByteArray(10) +const uint8Array = byteArray as Uint8Array // equivalent to: byteArray ``` However this only works in two scenarios: @@ -171,16 +175,16 @@ Examples: ```typescript // primitive casting -let a: usize = 10 -let b: isize = 5 -let c: usize = a + (b as usize) +const a: usize = 10 +const b: isize = 5 +const c: usize = a + (b as usize) ``` ```typescript // upcasting on class inheritance class Bytes extends Uint8Array {} -let bytes = new Bytes(2) +const bytes = new Bytes(2) // bytes // same as: bytes as Uint8Array ``` @@ -193,7 +197,7 @@ There are two scenarios where you may want to cast, but using `as`/`var` **is // downcasting on class inheritance class Bytes extends Uint8Array {} -let uint8Array = new Uint8Array(2) +const uint8Array = new Uint8Array(2) // uint8Array // breaks in runtime :( ``` @@ -202,7 +206,7 @@ let uint8Array = new Uint8Array(2) class Bytes extends Uint8Array {} class ByteArray extends Uint8Array {} -let bytes = new Bytes(2) +const bytes = new Bytes(2) // bytes // breaks in runtime :( ``` @@ -212,7 +216,7 @@ For those cases, you can use the `changetype` function: // downcasting on class inheritance class Bytes extends Uint8Array {} -let uint8Array = new Uint8Array(2) +const uint8Array = new Uint8Array(2) changetype(uint8Array) // works :) ``` @@ -221,7 +225,7 @@ changetype(uint8Array) // works :) class Bytes extends Uint8Array {} class ByteArray extends Uint8Array {} -let bytes = new Bytes(2) +const bytes = new Bytes(2) changetype(bytes) // works :) ``` @@ -229,13 +233,13 @@ If you just want to remove nullability, you can keep using the `as` operator (or ```typescript // remove nullability -let previousBalance = AccountBalance.load(balanceId) // AccountBalance | null +const previousBalance = AccountBalance.load(balanceId) // AccountBalance | null if (previousBalance != null) { return previousBalance as AccountBalance // safe remove null } -let newBalance = new AccountBalance(balanceId) +const newBalance = new AccountBalance(balanceId) ``` For the nullability case we recommend taking a look at the [nullability check feature](https://www.assemblyscript.org/basics.html#nullability-checks), it will make your code cleaner 🙂 @@ -252,7 +256,7 @@ Also we've added a few more static methods in some types to ease casting, they a To use the [nullability check feature](https://www.assemblyscript.org/basics.html#nullability-checks) you can use either `if` statements or the ternary operator (`?` and `:`) like this: ```typescript -let something: string | null = 'data' +const something: string | null = 'data' let somethingOrElse = something ? something : 'else' @@ -274,15 +278,15 @@ class Container { data: string | null } -let container = new Container() +const container = new Container() container.data = 'data' -let somethingOrElse: string = container.data ? container.data : 'else' // doesn't compile +const somethingOrElse: string = container.data ? container.data : 'else' // doesn't compile ``` Which outputs this error: -```typescript +```text ERROR TS2322: Type '~lib/string/String | null' is not assignable to type '~lib/string/String'. let somethingOrElse: string = container.data ? container.data : "else"; @@ -296,12 +300,12 @@ class Container { data: string | null } -let container = new Container() +const container = new Container() container.data = 'data' -let data = container.data +const data = container.data -let somethingOrElse: string = data ? data : 'else' // compiles just fine :) +const somethingOrElse: string = data ? data : 'else' // compiles just fine :) ``` ### Operator overloading with property access @@ -311,21 +315,21 @@ If you try to sum (for example) a nullable type (from a property access) with a ```typescript class BigInt extends Uint8Array { @operator('+') - plus(other: BigInt): BigInt { + plus(other: bigint): bigint { // ... } } class Wrapper { - public constructor(public n: BigInt | null) {} + public constructor(public n: bigint | null) {} } -let x = BigInt.fromI32(2) -let y: BigInt | null = null +const x = BigInt.fromI32(2) +const y: bigint | null = null -x + y // give compile time error about nullability +console.log(x + y) // give compile time error about nullability -let wrapper = new Wrapper(y) +const wrapper = new Wrapper(y) wrapper.n = wrapper.n + x // doesn't give compile time errors as it should ``` @@ -333,7 +337,7 @@ wrapper.n = wrapper.n + x // doesn't give compile time errors as it should We've opened a issue on the AssemblyScript compiler for this, but for now if you do these kind of operations in your subgraph mappings, you should change them to do a null check before it. ```typescript -let wrapper = new Wrapper(y) +const wrapper = new Wrapper(y) if (!wrapper.n) { wrapper.n = BigInt.fromI32(0) @@ -347,7 +351,7 @@ wrapper.n = wrapper.n + x // now `n` is guaranteed to be a BigInt If you have any code like this: ```typescript -var value: Type // null +let value: Type // null value.x = 10 value.y = 'content' ``` @@ -355,7 +359,7 @@ value.y = 'content' It will compile but break at runtime, that happens because the value hasn't been initialized, so make sure your subgraph has initialized their values, like this: ```typescript -var value = new Type() // initialized +const value = new Type() // initialized value.x = 10 value.y = 'content' ``` @@ -454,7 +458,7 @@ export class Something { The `Array` class still accepts a number to initialize the length of the list, however you should take care because operations like `.push` will actually increase the size instead of adding to the beginning, for example: ```typescript -let arr = new Array(5) // ["", "", "", "", ""] +const arr = new Array(5) // ["", "", "", "", ""] arr.push('something') // ["", "", "", "", "", "something"] // size 6 :( ``` @@ -468,7 +472,7 @@ ERRO Handler skipped due to execution failure, error: Mapping aborted at ~lib/ar To actually push at the beginning you should either, initialize the `Array` with size zero, like this: ```typescript -let arr = new Array(0) // [] +const arr = new Array(0) // [] arr.push('something') // ["something"] ``` @@ -476,7 +480,7 @@ arr.push('something') // ["something"] Or you should mutate it via index: ```typescript -let arr = new Array(5) // ["", "", "", "", ""] +const arr = new Array(5) // ["", "", "", "", ""] arr[0] = 'something' // ["something", "", "", "", ""] ```