diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 4666829b8613..9b9b93b54c74 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -2,14 +2,18 @@ module.exports = { root: true, overrides: [ { - files: ['*.{ts,tsx,js,jsx,mjs,cjs}'], + files: ['**/*.{ts,tsx,js,jsx,mjs,cjs}'], + // to lint graphql documents marked with /* GraphQL */ comments inside js/ts codeblocks in markdown + processor: '@graphql-eslint/graphql', + plugins: ['@graphql-eslint'], extends: ['@edgeandnode/eslint-config', '@edgeandnode/eslint-config/next'], settings: { next: { rootDir: 'website' }, }, }, { - files: ['*.{ts,tsx}'], + files: ['**/*.{ts,tsx}'], + excludedFiles: ['**/*.{md,mdx}/*.{ts,tsx}'], parserOptions: { project: 'tsconfig.json', }, @@ -23,6 +27,36 @@ 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', + }, + }, + { + files: ['**/*.graphql'], + parser: '@graphql-eslint/eslint-plugin', }, ], } diff --git a/package.json b/package.json index 27591a3c67bc..b43490ed9c89 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ }, "devDependencies": { "@edgeandnode/eslint-config": "^1.3.1", + "@graphql-eslint/eslint-plugin": "^3.18.0", "eslint": "^8.39.0", "eslint-plugin-mdx": "^2.0.5", "husky": "^8.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5bec991da53c..221c0c384345 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,9 @@ importers: '@edgeandnode/eslint-config': specifier: ^1.3.1 version: 1.3.1(eslint@8.39.0)(typescript@5.0.4) + '@graphql-eslint/eslint-plugin': + specifier: ^3.18.0 + version: 3.18.0 eslint: specifier: ^8.39.0 version: 8.39.0 @@ -295,6 +298,15 @@ packages: '@jridgewell/trace-mapping': 0.3.18 dev: true + /@ardatan/sync-fetch@0.0.1: + resolution: {integrity: sha512-xhlTqH0m31mnsG0tIP4ETgfSB6gXDaYYsUWTrlUV93fFQPI9dd8hE0Ot6MHLCtqgB32hwJAC3YZMWlXZw7AleA==} + engines: {node: '>=14'} + dependencies: + node-fetch: 2.6.9 + transitivePeerDependencies: + - encoding + dev: true + /@babel/code-frame@7.21.4: resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} engines: {node: '>=6.9.0'} @@ -852,6 +864,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-import-assertions@7.20.0: + resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-import-assertions@7.20.0(@babel/core@7.21.4): resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==} engines: {node: '>=6.9.0'} @@ -2362,6 +2383,265 @@ packages: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + /@graphql-eslint/eslint-plugin@3.18.0: + resolution: {integrity: sha512-riEEfRycc0+pWxcEWqHi8woRxzg1xZqAfh9DRACJUR7bTN8dmc1N04i7+pvW4sevClUFYC2wuL1Vtr+DwzXLUg==} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + dependencies: + '@babel/code-frame': 7.21.4 + '@graphql-tools/code-file-loader': 7.3.23 + '@graphql-tools/graphql-tag-pluck': 7.5.2 + '@graphql-tools/utils': 9.2.1 + chalk: 4.1.2 + debug: 4.3.4 + fast-glob: 3.2.12 + graphql-config: 4.5.0 + graphql-depth-limit: 1.1.0 + lodash.lowercase: 4.3.0 + tslib: 2.5.0 + transitivePeerDependencies: + - '@babel/core' + - '@types/node' + - bufferutil + - cosmiconfig-toml-loader + - encoding + - supports-color + - utf-8-validate + dev: true + + /@graphql-tools/batch-execute@8.5.21: + resolution: {integrity: sha512-DDyCPUSUjc0he/I9byguxohW/owQyVEO/gJcXLFAbHtTjORci3gRaRwLw24j0WaP+ZAlxYTMQs1HSlyJFaUArA==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/utils': 9.2.1 + dataloader: 2.2.2 + tslib: 2.5.0 + value-or-promise: 1.0.12 + dev: true + + /@graphql-tools/code-file-loader@7.3.23: + resolution: {integrity: sha512-8Wt1rTtyTEs0p47uzsPJ1vAtfAx0jmxPifiNdmo9EOCuUPyQGEbMaik/YkqZ7QUFIEYEQu+Vgfo8tElwOPtx5Q==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/graphql-tag-pluck': 7.5.2 + '@graphql-tools/utils': 9.2.1 + globby: 11.1.0 + tslib: 2.5.0 + unixify: 1.0.0 + transitivePeerDependencies: + - '@babel/core' + - supports-color + dev: true + + /@graphql-tools/delegate@9.0.34: + resolution: {integrity: sha512-qVTeq+0nxiDo54f28r0tOoXE6nipzGyDp5uuNMJJRvmIWjFGiyOBI8IsynPvLb2nCwhcpaTVJ2Bqswk/3DNO4w==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/batch-execute': 8.5.21 + '@graphql-tools/executor': 0.0.19 + '@graphql-tools/schema': 9.0.19 + '@graphql-tools/utils': 9.2.1 + dataloader: 2.2.2 + tslib: 2.5.0 + value-or-promise: 1.0.12 + dev: true + + /@graphql-tools/executor-graphql-ws@0.0.14: + resolution: {integrity: sha512-P2nlkAsPZKLIXImFhj0YTtny5NQVGSsKnhi7PzXiaHSXc6KkzqbWZHKvikD4PObanqg+7IO58rKFpGXP7eeO+w==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/utils': 9.2.1 + '@repeaterjs/repeater': 3.0.4 + '@types/ws': 8.5.4 + graphql-ws: 5.12.1 + isomorphic-ws: 5.0.0(ws@8.13.0) + tslib: 2.5.0 + ws: 8.13.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: true + + /@graphql-tools/executor-http@0.1.9: + resolution: {integrity: sha512-tNzMt5qc1ptlHKfpSv9wVBVKCZ7gks6Yb/JcYJluxZIT4qRV+TtOFjpptfBU63usgrGVOVcGjzWc/mt7KhmmpQ==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/utils': 9.2.1 + '@repeaterjs/repeater': 3.0.4 + '@whatwg-node/fetch': 0.8.8 + dset: 3.1.2 + extract-files: 11.0.0 + meros: 1.2.1 + tslib: 2.5.0 + value-or-promise: 1.0.12 + transitivePeerDependencies: + - '@types/node' + dev: true + + /@graphql-tools/executor-legacy-ws@0.0.11: + resolution: {integrity: sha512-4ai+NnxlNfvIQ4c70hWFvOZlSUN8lt7yc+ZsrwtNFbFPH/EroIzFMapAxM9zwyv9bH38AdO3TQxZ5zNxgBdvUw==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/utils': 9.2.1 + '@types/ws': 8.5.4 + isomorphic-ws: 5.0.0(ws@8.13.0) + tslib: 2.5.0 + ws: 8.13.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: true + + /@graphql-tools/executor@0.0.19: + resolution: {integrity: sha512-JYxuxseH7GGQ9olamrK73xUA05q/bKZ1efnYglSD6/05pb+Gz+VXDK8Y3pWha10aM6c529t//6hzJ5T/99Be5Q==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/utils': 9.2.1 + '@graphql-typed-document-node/core': 3.2.0 + '@repeaterjs/repeater': 3.0.4 + tslib: 2.5.0 + value-or-promise: 1.0.12 + dev: true + + /@graphql-tools/graphql-file-loader@7.5.17: + resolution: {integrity: sha512-hVwwxPf41zOYgm4gdaZILCYnKB9Zap7Ys9OhY1hbwuAuC4MMNY9GpUjoTU3CQc3zUiPoYStyRtUGkHSJZ3HxBw==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/import': 6.7.18 + '@graphql-tools/utils': 9.2.1 + globby: 11.1.0 + tslib: 2.5.0 + unixify: 1.0.0 + dev: true + + /@graphql-tools/graphql-tag-pluck@7.5.2: + resolution: {integrity: sha512-RW+H8FqOOLQw0BPXaahYepVSRjuOHw+7IL8Opaa5G5uYGOBxoXR7DceyQ7BcpMgktAOOmpDNQ2WtcboChOJSRA==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@babel/parser': 7.21.4 + '@babel/plugin-syntax-import-assertions': 7.20.0 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 + '@graphql-tools/utils': 9.2.1 + tslib: 2.5.0 + transitivePeerDependencies: + - '@babel/core' + - supports-color + dev: true + + /@graphql-tools/import@6.7.18: + resolution: {integrity: sha512-XQDdyZTp+FYmT7as3xRWH/x8dx0QZA2WZqfMF5EWb36a0PiH7WwlRQYIdyYXj8YCLpiWkeBXgBRHmMnwEYR8iQ==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/utils': 9.2.1 + resolve-from: 5.0.0 + tslib: 2.5.0 + dev: true + + /@graphql-tools/json-file-loader@7.4.18: + resolution: {integrity: sha512-AJ1b6Y1wiVgkwsxT5dELXhIVUPs/u3VZ8/0/oOtpcoyO/vAeM5rOvvWegzicOOnQw8G45fgBRMkkRfeuwVt6+w==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/utils': 9.2.1 + globby: 11.1.0 + tslib: 2.5.0 + unixify: 1.0.0 + dev: true + + /@graphql-tools/load@7.8.14: + resolution: {integrity: sha512-ASQvP+snHMYm+FhIaLxxFgVdRaM0vrN9wW2BKInQpktwWTXVyk+yP5nQUCEGmn0RTdlPKrffBaigxepkEAJPrg==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/schema': 9.0.19 + '@graphql-tools/utils': 9.2.1 + p-limit: 3.1.0 + tslib: 2.5.0 + dev: true + + /@graphql-tools/merge@8.4.1: + resolution: {integrity: sha512-hssnPpZ818mxgl5+GfyOOSnnflAxiaTn1A1AojZcIbh4J52sS1Q0gSuBR5VrnUDjuxiqoCotpXdAQl+K+U6KLQ==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/utils': 9.2.1 + tslib: 2.5.0 + dev: true + + /@graphql-tools/schema@9.0.19: + resolution: {integrity: sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/merge': 8.4.1 + '@graphql-tools/utils': 9.2.1 + tslib: 2.5.0 + value-or-promise: 1.0.12 + dev: true + + /@graphql-tools/url-loader@7.17.18: + resolution: {integrity: sha512-ear0CiyTj04jCVAxi7TvgbnGDIN2HgqzXzwsfcqiVg9cvjT40NcMlZ2P1lZDgqMkZ9oyLTV8Bw6j+SyG6A+xPw==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@ardatan/sync-fetch': 0.0.1 + '@graphql-tools/delegate': 9.0.34 + '@graphql-tools/executor-graphql-ws': 0.0.14 + '@graphql-tools/executor-http': 0.1.9 + '@graphql-tools/executor-legacy-ws': 0.0.11 + '@graphql-tools/utils': 9.2.1 + '@graphql-tools/wrap': 9.4.2 + '@types/ws': 8.5.4 + '@whatwg-node/fetch': 0.8.8 + isomorphic-ws: 5.0.0(ws@8.13.0) + tslib: 2.5.0 + value-or-promise: 1.0.12 + ws: 8.13.0 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - encoding + - utf-8-validate + dev: true + + /@graphql-tools/utils@9.2.1: + resolution: {integrity: sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-typed-document-node/core': 3.2.0 + tslib: 2.5.0 + dev: true + + /@graphql-tools/wrap@9.4.2: + resolution: {integrity: sha512-DFcd9r51lmcEKn0JW43CWkkI2D6T9XI1juW/Yo86i04v43O9w2/k4/nx2XTJv4Yv+iXwUw7Ok81PGltwGJSDSA==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dependencies: + '@graphql-tools/delegate': 9.0.34 + '@graphql-tools/schema': 9.0.19 + '@graphql-tools/utils': 9.2.1 + tslib: 2.5.0 + value-or-promise: 1.0.12 + dev: true + + /@graphql-typed-document-node/core@3.2.0: + resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + dev: true + /@humanwhocodes/config-array@0.11.8: resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} engines: {node: '>=10.10.0'} @@ -2660,6 +2940,32 @@ packages: /@openzeppelin/contracts@3.4.2-solc-0.7: resolution: {integrity: sha512-W6QmqgkADuFcTLzHL8vVoNBtkwjvQRpYIAom7KiUNoLKghyx3FgH0GBjt8NRvigV1ZmMOBllvE1By1C+bi8WpA==} + /@peculiar/asn1-schema@2.3.6: + resolution: {integrity: sha512-izNRxPoaeJeg/AyH8hER6s+H7p4itk+03QCa4sbxI3lNdseQYCuxzgsuNK8bTXChtLTjpJz6NmXKA73qLa3rCA==} + dependencies: + asn1js: 3.0.5 + pvtsutils: 1.3.2 + tslib: 2.5.0 + dev: true + + /@peculiar/json-schema@1.1.12: + resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==} + engines: {node: '>=8.0.0'} + dependencies: + tslib: 2.5.0 + dev: true + + /@peculiar/webcrypto@1.4.3: + resolution: {integrity: sha512-VtaY4spKTdN5LjJ04im/d/joXuvLbQdgy5Z4DXF4MFZhQ+MTrejbNMkfZBp1Bs3O5+bFqnJgyGdPuZQflvIa5A==} + engines: {node: '>=10.12.0'} + dependencies: + '@peculiar/asn1-schema': 2.3.6 + '@peculiar/json-schema': 1.1.12 + pvtsutils: 1.3.2 + tslib: 2.5.0 + webcrypto-core: 1.7.7 + 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} @@ -3188,6 +3494,10 @@ packages: dependencies: '@babel/runtime': 7.21.0 + /@repeaterjs/repeater@3.0.4: + resolution: {integrity: sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA==} + dev: true + /@rushstack/eslint-patch@1.2.0: resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} dev: true @@ -3644,6 +3954,12 @@ packages: /@types/unist@2.0.6: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} + /@types/ws@8.5.4: + resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} + dependencies: + '@types/node': 18.15.12 + dev: true + /@typescript-eslint/eslint-plugin@5.59.0(@typescript-eslint/parser@5.59.0)(eslint@8.39.0)(typescript@5.0.4): resolution: {integrity: sha512-p0QgrEyrxAWBecR56gyn3wkG15TJdI//eetInP3zYRewDh0XS+DhB3VUAd3QqvziFsfaQIoIuZMxZRB7vXYaYw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3857,6 +4173,30 @@ packages: '@uniswap/v3-core': 1.0.0 '@uniswap/v3-periphery': 1.4.3 + /@whatwg-node/events@0.0.3: + resolution: {integrity: sha512-IqnKIDWfXBJkvy/k6tzskWTc2NK3LcqHlb+KHGCrjOCH4jfQckRX0NAiIcC/vIqQkzLYw2r2CTSwAxcrtcD6lA==} + dev: true + + /@whatwg-node/fetch@0.8.8: + resolution: {integrity: sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==} + dependencies: + '@peculiar/webcrypto': 1.4.3 + '@whatwg-node/node-fetch': 0.3.6 + busboy: 1.6.0 + urlpattern-polyfill: 8.0.2 + web-streams-polyfill: 3.2.1 + dev: true + + /@whatwg-node/node-fetch@0.3.6: + resolution: {integrity: sha512-w9wKgDO4C95qnXZRwZTfCmLWqyRnooGjcIwG0wADWjw9/HN0p7dtvtgSvItZtUyNteEvgTrd8QojNEqV6DAGTA==} + dependencies: + '@whatwg-node/events': 0.0.3 + busboy: 1.6.0 + fast-querystring: 1.1.1 + fast-url-parser: 1.1.3 + tslib: 2.5.0 + dev: true + /@xobotyi/scrollbar-width@1.9.5: resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==} dev: false @@ -4059,6 +4399,20 @@ packages: get-intrinsic: 1.2.0 dev: true + /arrify@1.0.1: + resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} + engines: {node: '>=0.10.0'} + dev: true + + /asn1js@3.0.5: + resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==} + engines: {node: '>=12.0.0'} + dependencies: + pvtsutils: 1.3.2 + pvutils: 1.1.3 + tslib: 2.5.0 + dev: true + /ast-types-flow@0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} dev: true @@ -4436,6 +4790,16 @@ packages: path-type: 4.0.0 yaml: 1.10.2 + /cosmiconfig@8.0.0: + resolution: {integrity: sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==} + engines: {node: '>=14'} + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + dev: true + /cosmiconfig@8.1.3: resolution: {integrity: sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==} engines: {node: '>=14'} @@ -4746,6 +5110,11 @@ packages: resolution: {integrity: sha512-vwEppIphpFdvaMCaHfCEv9IgwcxMljMw2TnAQBB4VWPvzXQLTb82jwmdOKzlEVUL3gNFT4l4TPKO+Bn+sqcrVQ==} engines: {node: '>=12'} + /dset@3.1.2: + resolution: {integrity: sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==} + engines: {node: '>=4'} + dev: true + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true @@ -5393,6 +5762,15 @@ packages: /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + /extract-files@11.0.0: + resolution: {integrity: sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ==} + engines: {node: ^12.20 || >= 14.13} + dev: true + + /fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + dev: true + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -5422,10 +5800,22 @@ packages: resolution: {integrity: sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==} dev: false + /fast-querystring@1.1.1: + resolution: {integrity: sha512-qR2r+e3HvhEFmpdHMv//U8FnFlnYjaC6QKDuaXALDkw2kvHO8WDjxH+f/rHGR4Me4pnk8p9JAkRNTjYHAKRn2Q==} + dependencies: + fast-decode-uri-component: 1.0.1 + dev: true + /fast-shallow-equal@1.0.0: resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==} dev: false + /fast-url-parser@1.1.3: + resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==} + dependencies: + punycode: 1.4.1 + dev: true + /fast-xml-parser@4.2.2: resolution: {integrity: sha512-DLzIPtQqmvmdq3VUKR7T6omPK/VCRNqgFlGtbESfyhcH2R4I8EzK1/K6E8PkRCK2EabWrUHK32NjYRbEFnnz0Q==} hasBin: true @@ -5683,6 +6073,43 @@ packages: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} dev: true + /graphql-config@4.5.0: + resolution: {integrity: sha512-x6D0/cftpLUJ0Ch1e5sj1TZn6Wcxx4oMfmhaG9shM0DKajA9iR+j1z86GSTQ19fShbGvrSSvbIQsHku6aQ6BBw==} + engines: {node: '>= 10.0.0'} + peerDependencies: + cosmiconfig-toml-loader: ^1.0.0 + graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + peerDependenciesMeta: + cosmiconfig-toml-loader: + optional: true + dependencies: + '@graphql-tools/graphql-file-loader': 7.5.17 + '@graphql-tools/json-file-loader': 7.4.18 + '@graphql-tools/load': 7.8.14 + '@graphql-tools/merge': 8.4.1 + '@graphql-tools/url-loader': 7.17.18 + '@graphql-tools/utils': 9.2.1 + cosmiconfig: 8.0.0 + jiti: 1.17.1 + minimatch: 4.2.3 + string-env-interpolation: 1.0.1 + tslib: 2.5.0 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - encoding + - utf-8-validate + dev: true + + /graphql-depth-limit@1.1.0: + resolution: {integrity: sha512-+3B2BaG8qQ8E18kzk9yiSdAa75i/hnnOwgSeAxVJctGQPvmeiLtqKOYF6HETCyRjiF7Xfsyal0HbLlxCQkgkrw==} + engines: {node: '>=6.0.0'} + peerDependencies: + graphql: '*' + dependencies: + arrify: 1.0.1 + dev: true + /graphql-tag@2.12.6(graphql@16.6.0): resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} engines: {node: '>=10'} @@ -5692,6 +6119,13 @@ packages: graphql: 16.6.0 tslib: 2.5.0 + /graphql-ws@5.12.1: + resolution: {integrity: sha512-umt4f5NnMK46ChM2coO36PTFhHouBrK9stWWBczERguwYrGnPNxJ9dimU6IyOBfOkC6Izhkg4H8+F51W/8CYDg==} + engines: {node: '>=10'} + peerDependencies: + graphql: '>=0.11 <=16' + dev: true + /graphql@16.6.0: resolution: {integrity: sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} @@ -6186,6 +6620,19 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + /isomorphic-ws@5.0.0(ws@8.13.0): + resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} + peerDependencies: + ws: '*' + dependencies: + ws: 8.13.0 + dev: true + + /jiti@1.17.1: + resolution: {integrity: sha512-NZIITw8uZQFuzQimqjUxIrIcEdxYDFIe/0xYfIlVXTkiBjjyBEvgasj5bb0/cHtPRD/NziPbT312sFrkI5ALpw==} + hasBin: true + dev: true + /joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -6374,6 +6821,10 @@ packages: /lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + /lodash.lowercase@4.3.0: + resolution: {integrity: sha512-UcvP1IZYyDKyEL64mmrwoA1AbFu5ahojhTtkOUr1K9dbuxzS9ev8i4TxMMGCqRC9TE8uDaSoufNAXxRPNTseVA==} + dev: true + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -6663,6 +7114,16 @@ packages: engines: {node: '>= 8'} dev: true + /meros@1.2.1: + resolution: {integrity: sha512-R2f/jxYqCAGI19KhAvaxSOxALBMkaXWH2a7rOyqQw+ZmizX5bKkEYWLzdhC+U82ZVVPVp6MCXe3EkVligh+12g==} + engines: {node: '>=13'} + peerDependencies: + '@types/node': '>=13' + peerDependenciesMeta: + '@types/node': + optional: true + dev: true + /micromark-core-commonmark@1.0.6: resolution: {integrity: sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA==} dependencies: @@ -7019,6 +7480,13 @@ packages: brace-expansion: 1.1.11 dev: true + /minimatch@4.2.3: + resolution: {integrity: sha512-lIUdtK5hdofgCTu3aT0sOaHsYR37viUuIc0rwnnDXImbwFRcumyLMeZaM0t0I/fgxS6s6JMfu0rLD1Wz9pv1ng==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 1.1.11 + dev: true + /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -7194,10 +7662,29 @@ packages: transitivePeerDependencies: - supports-color + /node-fetch@2.6.9: + resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true + /node-releases@2.0.10: resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} dev: true + /normalize-path@2.1.1: + resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} + engines: {node: '>=0.10.0'} + dependencies: + remove-trailing-separator: 1.1.0 + dev: true + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -7532,11 +8019,26 @@ packages: /pseudomap@1.0.2: resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + /punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + dev: true + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} dev: true + /pvtsutils@1.3.2: + resolution: {integrity: sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==} + dependencies: + tslib: 2.5.0 + dev: true + + /pvutils@1.1.3: + resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} + engines: {node: '>=6.0.0'} + dev: true + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -7968,6 +8470,10 @@ packages: unified: 10.1.2 dev: true + /remove-trailing-separator@1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + dev: true + /resize-observer-polyfill@1.5.1: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} dev: false @@ -8271,6 +8777,10 @@ packages: engines: {node: '>=0.6.19'} dev: true + /string-env-interpolation@1.0.1: + resolution: {integrity: sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==} + dev: true + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -8571,6 +9081,10 @@ packages: resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} dev: false + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: true + /tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} dependencies: @@ -8823,6 +9337,13 @@ packages: unist-util-is: 5.2.1 unist-util-visit-parents: 5.1.3 + /unixify@1.0.0: + resolution: {integrity: sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==} + engines: {node: '>=0.10.0'} + dependencies: + normalize-path: 2.1.1 + dev: true + /update-browserslist-db@1.0.11(browserslist@4.21.5): resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==} hasBin: true @@ -8840,6 +9361,10 @@ packages: punycode: 2.3.0 dev: true + /urlpattern-polyfill@8.0.2: + resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} + dev: true + /use-callback-ref@1.3.0(@types/react@18.0.37)(react@18.2.0): resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==} engines: {node: '>=10'} @@ -8898,6 +9423,11 @@ packages: kleur: 4.1.5 sade: 1.8.1 + /value-or-promise@1.0.12: + resolution: {integrity: sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==} + engines: {node: '>=12'} + dev: true + /vfile-location@4.1.0: resolution: {integrity: sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw==} dependencies: @@ -8952,10 +9482,36 @@ packages: /web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + /web-streams-polyfill@3.2.1: + resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} + engines: {node: '>= 8'} + dev: true + + /webcrypto-core@1.7.7: + resolution: {integrity: sha512-7FjigXNsBfopEj+5DV2nhNpfic2vumtjjgPmeDKk45z+MJwXKKfhPB7118Pfzrmh4jqOMST6Ch37iPAHoImg5g==} + dependencies: + '@peculiar/asn1-schema': 2.3.6 + '@peculiar/json-schema': 1.1.12 + asn1js: 3.0.5 + pvtsutils: 1.3.2 + tslib: 2.5.0 + dev: true + + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true + /webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} dev: true + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: true + /whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} dependencies: @@ -9048,6 +9604,19 @@ packages: utf-8-validate: optional: true + /ws@8.13.0: + resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + /xstate@4.37.1: resolution: {integrity: sha512-MuB7s01nV5vG2CzaBg2msXLGz7JuS+x/NBkQuZAwgEYCnWA8iQMiRz2VGxD3pcFjZAOih3fOgDD3kDaFInEx+g==} 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..3560a12e10f5 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() } ``` @@ -903,33 +903,29 @@ features: The query must also opt-in to querying data with potential inconsistencies through the `subgraphError` argument. It is also recommended to query `_meta` to check if the subgraph has skipped over errors, as in the example: ```graphql -foos(first: 100, subgraphError: allow) { - id -} +{ + foos(first: 100, subgraphError: allow) { + id + } -_meta { - hasIndexingErrors + _meta { + hasIndexingErrors + } } ``` 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 +1063,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/developer-faqs.mdx b/website/pages/en/developing/developer-faqs.mdx index 726464abe60b..e3723c5a9933 100644 --- a/website/pages/en/developing/developer-faqs.mdx +++ b/website/pages/en/developing/developer-faqs.mdx @@ -117,7 +117,7 @@ Federation is not supported yet, although we do want to support it in the future By default, query responses are limited to 100 items per collection. If you want to receive more, you can go up to 1000 items per collection and beyond that, you can paginate with: -```graphql +```text someCollection(first: 1000, skip: ) { ... } ``` 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/network/indexing.mdx b/website/pages/en/network/indexing.mdx index 90e741a6d052..8fd465c158ba 100644 --- a/website/pages/en/network/indexing.mdx +++ b/website/pages/en/network/indexing.mdx @@ -569,23 +569,23 @@ For example, if the global rule has a `minStake` of **5** (GRT), any subgraph de Data model: -```graphql -type IndexingRule { - identifier: string - identifierType: IdentifierType - decisionBasis: IndexingDecisionBasis! - allocationAmount: number | null - allocationLifetime: number | null - autoRenewal: boolean - parallelAllocations: number | null - maxAllocationPercentage: number | null - minSignal: string | null - maxSignal: string | null - minStake: string | null - minAverageQueryFees: string | null - custom: string | null - requireSupported: boolean | null - } +```text +Type IndexingRule { + identifier: string + identifierType: IdentifierType + decisionBasis: IndexingDecisionBasis! + allocationAmount: number | null + allocationLifetime: number | null + autoRenewal: boolean + parallelAllocations: number | null + maxAllocationPercentage: number | null + minSignal: string | null + maxSignal: string | null + minStake: string | null + minAverageQueryFees: string | null + custom: string | null + requireSupported: boolean | null +} IdentifierType { deployment @@ -628,18 +628,18 @@ The action execution worker will only grab items from the queue to execute if th Data model: -```graphql +```text Type ActionInput { - status: ActionStatus - type: ActionType - deploymentID: string | null - allocationID: string | null - amount: string | null - poi: string | null - force: boolean | null - source: string - reason: string | null - priority: number | null + status: ActionStatus + type: ActionType + deploymentID: string | null + allocationID: string | null + amount: string | null + poi: string | null + force: boolean | null + source: string + reason: string | null + priority: number | null } ActionStatus { 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-best-practices.mdx b/website/pages/en/querying/querying-best-practices.mdx index ce2b7b2114f6..4603cbad70b0 100644 --- a/website/pages/en/querying/querying-best-practices.mdx +++ b/website/pages/en/querying/querying-best-practices.mdx @@ -42,7 +42,7 @@ GraphQL queries use the GraphQL language, which is defined upon [a specification The above `GetToken` query is composed of multiple language parts (replaced below with `[...]` placeholders): -```graphql +```text query [operationName]([variableName]: [variableType]) { [queryName]([argumentName]: [variableName]) { # "{ ... }" express a Selection-Set, we are querying fields from `queryName`. @@ -87,13 +87,13 @@ Here's how to query The Graph with `graph-client`: ```tsx import { execute } from '../.graphclient' -const query = ` -query GetToken($id: ID!) { - token(id: $id) { - id - owner +const query = /* GraphQL */ ` + query GetToken($id: ID!) { + token(id: $id) { + id + owner + } } -} ` const variables = { id: '1' } @@ -147,13 +147,13 @@ For this reason, it is recommended to always write queries as static strings: import { execute } from 'your-favorite-graphql-client' const id = params.id -const query = ` -query GetToken($id: ID!) { - token(id: $id) { - id - owner +const query = /* GraphQL */ ` + query GetToken($id: ID!) { + token(id: $id) { + id + owner + } } -} ` const result = await execute(query, { @@ -180,13 +180,13 @@ For this, we can leverage the `@include(if:...)` directive as follows: import { execute } from 'your-favorite-graphql-client' const id = params.id -const query = ` -query GetToken($id: ID!, $includeOwner: Boolean) { - token(id: $id) { - id - owner @include(if: $includeOwner) +const query = /* GraphQL */ ` + query GetToken($id: ID!, $includeOwner: Boolean) { + token(id: $id) { + id + owner @include(if: $includeOwner) + } } -} ` const result = await execute(query, { @@ -236,55 +236,52 @@ If the application only needs 10 transactions, the query should explicitly set ` Your application might require querying multiple types of data as follows: -```graphql -import { execute } from "your-favorite-graphql-client" +```ts +import { execute } from 'your-favorite-graphql-client' -const tokensQuery = ` -query GetTokens { - tokens(first: 50) { - id - owner +const tokensQuery = /* GraphQL */ ` + query GetTokens { + tokens(first: 50) { + id + owner + } } -} ` -const countersQuery = ` -query GetCounters { - counters { - id - value +const countersQuery = /* GraphQL */ ` + query GetCounters { + counters { + id + value + } } -} ` -const [tokens, counters] = Promise.all( - [ - tokensQuery, - countersQuery, - ].map(execute) -) +const [tokens, counters] = Promise.all([tokensQuery, countersQuery].map(execute)) ``` While this implementation is totally valid, it will require two round trips with the GraphQL API. Fortunately, it is also valid to send multiple queries in the same GraphQL request as follows: -```graphql -import { execute } from "your-favorite-graphql-client" +```ts +import { execute } from 'your-favorite-graphql-client' -const query = ` -query GetTokensandCounters { - tokens(first: 50) { - id - owner - } - counters { - id - value +const query = /* GraphQL */ ` + query GetTokensandCounters { + tokens(first: 50) { + id + owner + } + counters { + id + value + } } -} ` -const { result: { tokens, counters } } = execute(query) +const { + result: { tokens, counters }, +} = execute(query) ``` This approach will **improve the overall performance** by reducing the time spent on the network (saves you a round trip to the API) and will provide a **more concise implementation**. @@ -356,7 +353,7 @@ When using the types generation tool, the above query will generate a proper `De A Fragment cannot be based on a non-applicable type, in short, **on type not having fields**: -```graphql +```text fragment MyFragment on BigInt { # ... } @@ -446,7 +443,7 @@ In order to keep up with the mentioned above best practices and syntactic rules, [Setup the "operations-recommended"](https://github.com/dotansimha/graphql-eslint#available-configs) config will enforce essential rules such as: - `@graphql-eslint/fields-on-correct-type`: is a field used on a proper type? -- `@graphql-eslint/no-unused variables`: should a given variable stay unused? +- `@graphql-eslint/no-unused-variables`: should a given variable stay unused? - and more! This will allow you to **catch errors without even testing queries** on the playground or running them in production! 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", "", "", "", ""] ``` diff --git a/website/pages/en/release-notes/graphql-validations-migration-guide.mdx b/website/pages/en/release-notes/graphql-validations-migration-guide.mdx index f8cf8a3c2ed3..d3fa686cd1c0 100644 --- a/website/pages/en/release-notes/graphql-validations-migration-guide.mdx +++ b/website/pages/en/release-notes/graphql-validations-migration-guide.mdx @@ -118,11 +118,11 @@ query myData { ...MyFields } -fragment MyFields { +fragment MyFields on MyType { metadata } -fragment MyFields { +fragment MyFields on MyType { name } ``` @@ -136,11 +136,13 @@ query myData { ...MyFieldsMetadata } -fragment MyFieldsMetadata { # assign a unique name to fragment +fragment MyFieldsMetadata on MyType { + # assign a unique name to fragment metadata } -fragment MyFieldsName { # assign a unique name to fragment +fragment MyFieldsName on MyType { + # assign a unique name to fragment name } ``` @@ -341,7 +343,8 @@ query something { someData } -fragment AllFields { # unused :( +fragment AllFields on MyType { + # unused :( name age } @@ -368,25 +371,23 @@ Also, a GraphQL field selection is only valid if the following is validated: Here are a few examples of violations of these rules with the following Schema: ```graphql -schema { - type Image { - url: String! - } +type Image { + url: String! +} - type User { - id: ID! - avatar: Image! - } +type User { + id: ID! + avatar: Image! +} - type Query { - user: User! - } +type Query { + user: User! } ``` **Invalid Selection-Set** -```graphql +```text query { user { id { # Invalid, because "id" is of type ID and does not have sub-fields @@ -474,10 +475,10 @@ A Fragment cannot be spread on a non-applicable type. Example, we cannot apply a `Cat` fragment to the `Dog` type: -```graphql +```text query { - dog { - ...CatSimple + dog { + ...CatSimple } } @@ -517,13 +518,13 @@ Here is an example with The GraphQL supported directives: ```graphql query { dog { - name @include(true) - age @skip(true) + name @include(if: true) + age @skip(if: true) } } ``` -_Note: `@stream`, `@live`, `@defer` are not supported._ +> **Note:** `@stream`, `@live`, `@defer` are not supported. **Directive can only be used once at this location (#UniqueDirectivesPerLocationRule)** @@ -534,7 +535,7 @@ The following is invalid (and redundant): ```graphql query { dog { - name @include(true) @include(true) + name @include(if: true) @include(if: true) } } ```