diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ad9fc66b8..d4ab63e498 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# Web3API 0.0.1-prealpha.32 +## Features +* Improved the plugin developer experience by creating a new `w3 plugin codegen` command, which generated types based on the plugin's schema. For an example of how this works, see the updated plugin template project by running `w3 create plugin typescript my-plugin`. +* `@web3api/cli`: Refactored the `w3 codegen` command, making its default behavior the generation of types for Web3APIs. It's "old" behavior of loading a custom generation script is now usable through the `--custom` option. + +## Bugs +* `@web3api/cli`: Properly validate all required Wasm exports when compiling Web3APIs. + # Web3API 0.0.1-prealpha.31 ## Features * Use Binaryen's Asyncify to support async Wasm import calls. Deprecate the Wasm threading model we were using previously. This now means that the client now supports all browsers, as it no longer requires `SharedArrayBuffer` & the `atomics` library. diff --git a/VERSION b/VERSION index 6e944d003e..57961ef83a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.1-prealpha.31 +0.0.1-prealpha.32 \ No newline at end of file diff --git a/package.json b/package.json index 46e96585df..d13aafdfd9 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "clean": "npx rimraf ./**/node_modules ./**/build ./**/coverage ./**/.w3", "build": "lerna run build --no-private --ignore @web3api/cli* --ignore @web3api/react && lerna run build --scope @web3api/client-js --scope @web3api/react && lerna run build --scope @web3api/cli", "lint": "lerna run lint --ignore @web3api/uts46-plugin-js", - "lint:fix": "lerna run lint -- --fix", + "lint:fix": "lerna run lint --ignore @web3api/uts46-plugin-js -- --fix", "lint:ci": "yarn lint", "test": "lerna run test --no-private --ignore @web3api/client-js && lerna run test --scope @web3api/client-js", "test:ci": "lerna run test:ci --no-private --ignore @web3api/client-js && lerna run test:ci --scope @web3api/client-js", diff --git a/packages/apis/uniswapv2/src/query/schema.graphql b/packages/apis/uniswapv2/src/query/schema.graphql index 8df3450032..6da47b3eec 100644 --- a/packages/apis/uniswapv2/src/query/schema.graphql +++ b/packages/apis/uniswapv2/src/query/schema.graphql @@ -1,7 +1,6 @@ #import { Query, StaticTxResult } into Ethereum from "w3://ens/ethereum.web3api.eth" #import { Query } into SHA3 from "w3://ens/sha3.web3api.eth" #import { ChainId, TradeType, Rounding, Currency, Token, TokenAmount, TradeOptions, Pair, Route, Trade, BestTradeOptions, SwapParameters, TxOverrides } from "../common/schema.graphql" -#import { Query, LogLevel } into Logger from "w3://w3/logger" type Query { diff --git a/packages/apis/uniswapv2/web3api.build.yaml b/packages/apis/uniswapv2/web3api.build.yaml index cc2cb8681d..b2db9e40ed 100644 --- a/packages/apis/uniswapv2/web3api.build.yaml +++ b/packages/apis/uniswapv2/web3api.build.yaml @@ -1,4 +1,4 @@ -format: 0.0.1-prealpha.2 +format: 0.0.1-prealpha.1 config: node_version: "14.16.0" include: diff --git a/packages/cli/lang/en.json b/packages/cli/lang/en.json index eb38180757..3dbd5fc5d1 100644 --- a/packages/cli/lang/en.json +++ b/packages/cli/lang/en.json @@ -24,16 +24,16 @@ "commands_build_uriViewers": "URI Viewers", "commands_codegen_description": "Auto-generate API Types", "commands_codegen_error_domain": "domain", + "commands_codegen_error_customScriptMissingPath": "{option} option missing {argument} argument", "commands_codegen_options_e": "ENS address to lookup external schemas (default: 0x0000...2e1e)", "commands_codegen_options_e_address": "address", - "commands_codegen_options_genFile": "Generation file", - "commands_codegen_options_genFilePath": "Path to the generation file (default", "commands_codegen_options_h": "Show usage information", - "commands_codegen_options_i": "IPFS node to load external schemas (default: dev-server's node)", + "commands_codegen_options_c": "Path to a custom generation script (JavaScript | TypeScript)", + "commands_codegen_options_i": "IPFS node to load external schemas (default: ipfs.io & localhost)", "commands_codegen_options_i_node": "node", "commands_codegen_options_m": "Path to the Web3API manifest file (default", "commands_build_options_manifest": "manifest", - "commands_codegen_options_o": "Output directory for generated types (default: types/)", + "commands_codegen_options_o": "Output directory for custom generated types (default: 'types/')", "commands_codegen_options_o_path": "path", "commands_options_options": "options", "commands_codegen_success": "Types were generated successfully", @@ -64,6 +64,24 @@ "commands_create_readyPlugin": "You are ready to build a plugin into a Web3API", "commands_create_readyProtocol": "You are ready to turn your protocol into a Web3API", "commands_create_settingUp": "Setting everything up...", + "commands_plugin_description": "Build/generate types for the plugin", + "commands_plugin_error_domain": "domain", + "commands_plugin_error_noCommand": "Please provide a command", + "commands_plugin_error_outputDirMissingPath": "{option} option missing {argument} argument", + "commands_plugin_options_build": "Build the plugin", + "commands_plugin_options_codegen": "Generate code for the plugin", + "commands_plugin_options_command": "command", + "commands_plugin_options_e": "ENS address to lookup external schemas (default: 0x0000...2e1e)", + "commands_plugin_options_e_address": "address", + "commands_plugin_options_h": "Show usage information", + "commands_plugin_options_i": "IPFS node to load external schemas (default: dev-server's node)", + "commands_plugin_options_i_node": "node", + "commands_plugin_options_lang": "lang", + "commands_plugin_options_langs": "langs", + "commands_plugin_options_m": "Path to the Web3API manifest file (default: {default})", + "commands_plugin_options_path": "path", + "commands_plugins_options_schema": "Output path for the built schema (default: {default})", + "commands_plugins_options_types": "Output directory for the generated types (default: {default})", "commands_query_description": "Query Web3APIs using recipe scripts", "commands_query_error_missingScript": "Required argument {script} is missing", "commands_query_error_noApi": "API needs to be initialized", @@ -92,9 +110,16 @@ "lib_codeGenerator_templateNoModify": "NOTE: This is generated by 'w3 codegen', DO NOT MODIFY", "lib_codeGenerator_noRunMethod": "The generation file provided doesn't have the 'run' method.", "lib_codeGenerator_noComposedSchema": "The schema does not exist, please define one.", + "lib_codeGenerator_typeInfoMissing": "The TypeInfo is missing from the composer output.", "lib_compiler_compileError": "Failed to compile Web3API", "lib_compiler_compileText": "Compile Web3API", "lib_compiler_compileWarning": "Warnings while compiling Web3API", + "lib_compiler_codegenError": "Failed to generate Web3API schema bindings", + "lib_compiler_codegenText": "Codegen Web3API schema bindings", + "lib_compiler_codegenWarning": "Warnings while generating Web3API schema bindings", + "lib_compiler_compileWasmModulesError": "Failed to compile Wasm modules", + "lib_compiler_compileWasmModulesText": "Compile Wasm modules", + "lib_compiler_compileWasmModulesWarning": "Warnings while compiling Wasm modules", "lib_compiler_failedSchemaReturn": "Schema composer failed to return a combined schema.", "lib_compiler_noModulesToBuild": "No modules to build declared.", "lib_compiler_missingSchema": "Missing schema definition for the module {name}", @@ -106,6 +131,7 @@ "lib_compiler_noInvoke": "WASM module is missing the _w3_invoke export. This should never happen...", "lib_compiler_dup_code_folder": "Duplicate code generation folder found `{directory}`. Please ensure each module file is located in a unique directory.", "lib_compiler_missing_export": "{missingExport} is not exported from the WASM module `{moduleName}`", + "lib_compiler_cannotBuildInterfaceModules": "Cannot build modules for an Interface Web3API", "lib_generators_projectGenerator_fallback": "Falling back to the local Yarn cache.", "lib_generators_projectGenerator_offline": "You appear to be offline.", "lib_helpers_manifest_loadError": "Failed to load manifest from {path}", @@ -125,9 +151,12 @@ "lib_helpers_docker_projectFolderMissing": "Build image `{image}` missing /project folder", "lib_helpers_docker_projectBuildFolderMissing": "Build image `{image}` missing build artifact `{artifact}` in folder /project/build", "lib_helpers_parameters_unexpectedValue": "Unexpected value provided for one or more of {options}. See --help for more information.", + "lib_language_unsupportedManifestLanguage": "The manifest's language {language} is not supported.", "lib_publishers_ipfsPublisher_urlMalformed": "IPFS URL Malformed", "lib_project_invalid_build_language": "Unrecognized build language {language}. No default manifest found at {defaultPath}", "lib_project_language_not_found": "Build language not found. Please include the `language` property in the manifest file.", + "lib_typescript_notInstalled": "Your project uses typescript, but it's not installed", + "lib_typescript_tsNodeNotInstalled": "Your project uses typescript, but ts-node is not installed", "lib_watcher_alreadyWatching": "Watcher session is already in progress. Directory: {dir}", "lib_docker_invalidImageId": "Invalid docker image ID returned: {imageId}" } \ No newline at end of file diff --git a/packages/cli/lang/es.json b/packages/cli/lang/es.json index 154f6bdaa7..13821f2050 100644 --- a/packages/cli/lang/es.json +++ b/packages/cli/lang/es.json @@ -24,16 +24,16 @@ "commands_build_uriViewers": "URI Viewers", "commands_codegen_description": "Auto-generate API Types", "commands_codegen_error_domain": "domain", + "commands_codegen_error_customScriptMissingPath": "{option} option missing {argument} argument", "commands_codegen_options_e": "ENS address to lookup external schemas (default: 0x0000...2e1e)", "commands_codegen_options_e_address": "address", - "commands_codegen_options_genFile": "Generation file", - "commands_codegen_options_genFilePath": "Path to the generation file (default", "commands_codegen_options_h": "Show usage information", - "commands_codegen_options_i": "IPFS node to load external schemas (default: dev-server's node)", + "commands_codegen_options_c": "Path to a custom generation script (JavaScript | TypeScript)", + "commands_codegen_options_i": "IPFS node to load external schemas (default: ipfs.io & localhost)", "commands_codegen_options_i_node": "node", "commands_codegen_options_m": "Path to the Web3API manifest file (default", "commands_build_options_manifest": "manifest", - "commands_codegen_options_o": "Output directory for generated types (default: types/)", + "commands_codegen_options_o": "Output directory for custom generated types (default: 'types/')", "commands_codegen_options_o_path": "path", "commands_options_options": "options", "commands_codegen_success": "Types were generated successfully", @@ -64,6 +64,24 @@ "commands_create_readyPlugin": "You are ready to build a plugin into a Web3API", "commands_create_readyProtocol": "You are ready to turn your protocol into a Web3API", "commands_create_settingUp": "Setting everything up...", + "commands_plugin_description": "Build/generate types for the plugin", + "commands_plugin_error_domain": "domain", + "commands_plugin_error_noCommand": "Please provide a command", + "commands_plugin_error_outputDirMissingPath": "{option} option missing {argument} argument", + "commands_plugin_options_build": "Build the plugin", + "commands_plugin_options_codegen": "Generate code for the plugin", + "commands_plugin_options_command": "command", + "commands_plugin_options_e": "ENS address to lookup external schemas (default: 0x0000...2e1e)", + "commands_plugin_options_e_address": "address", + "commands_plugin_options_h": "Show usage information", + "commands_plugin_options_i": "IPFS node to load external schemas (default: dev-server's node)", + "commands_plugin_options_i_node": "node", + "commands_plugin_options_lang": "lang", + "commands_plugin_options_langs": "langs", + "commands_plugin_options_m": "Path to the Web3API manifest file (default: {default})", + "commands_plugin_options_path": "path", + "commands_plugins_options_schema": "Output path for the built schema (default: {default})", + "commands_plugins_options_types": "Output directory for the generated types (default: {default})", "commands_query_description": "Query Web3APIs using recipe scripts", "commands_query_error_missingScript": "Required argument {script} is missing", "commands_query_error_noApi": "API needs to be initialized", @@ -92,9 +110,16 @@ "lib_codeGenerator_templateNoModify": "NOTE: This is generated by 'w3 codegen', DO NOT MODIFY", "lib_codeGenerator_noRunMethod": "The generation file provided doesn't have the 'run' method.", "lib_codeGenerator_noComposedSchema": "The schema does not exist, please define one.", + "lib_codeGenerator_typeInfoMissing": "The TypeInfo is missing from the composer output.", "lib_compiler_compileError": "Failed to compile Web3API", "lib_compiler_compileText": "Compile Web3API", "lib_compiler_compileWarning": "Warnings while compiling Web3API", + "lib_compiler_codegenError": "Failed to generate Web3API schema bindings", + "lib_compiler_codegenText": "Codegen Web3API schema bindings", + "lib_compiler_codegenWarning": "Warnings while generating Web3API schema bindings", + "lib_compiler_compileWasmModulesError": "Failed to compile Wasm modules", + "lib_compiler_compileWasmModulesText": "Compile Wasm modules", + "lib_compiler_compileWasmModulesWarning": "Warnings while compiling Wasm modules", "lib_compiler_failedSchemaReturn": "Schema composer failed to return a combined schema.", "lib_compiler_noModulesToBuild": "No modules to build declared.", "lib_compiler_missingSchema": "Missing schema definition for the module {name}", @@ -106,6 +131,7 @@ "lib_compiler_noInvoke": "WASM module is missing the _w3_invoke export. This should never happen...", "lib_compiler_dup_code_folder": "Duplicate code generation folder found `{directory}`. Please ensure each module file is located in a unique directory.", "lib_compiler_missing_export": "{missingExport} is not exported from the WASM module `{moduleName}`", + "lib_compiler_cannotBuildInterfaceModules": "Cannot build modules for an Interface Web3API", "lib_generators_projectGenerator_fallback": "Falling back to the local Yarn cache.", "lib_generators_projectGenerator_offline": "You appear to be offline.", "lib_helpers_manifest_loadError": "Failed to load manifest from {path}", @@ -125,9 +151,12 @@ "lib_helpers_docker_projectFolderMissing": "Build image `{image}` missing /project folder", "lib_helpers_docker_projectBuildFolderMissing": "Build image `{image}` missing build artifact `{artifact}` in folder /project/build", "lib_helpers_parameters_unexpectedValue": "Unexpected value provided for one or more of {options}. See --help for more information.", + "lib_language_unsupportedManifestLanguage": "The manifest's language {language} is not supported.", "lib_publishers_ipfsPublisher_urlMalformed": "IPFS URL Malformed", "lib_project_invalid_build_language": "Unrecognized build language {language}. No default manifest found at {defaultPath}", "lib_project_language_not_found": "Build language not found. Please include the `language` property in the manifest file.", + "lib_typescript_notInstalled": "Your project uses typescript, but it's not installed", + "lib_typescript_tsNodeNotInstalled": "Your project uses typescript, but ts-node is not installed", "lib_watcher_alreadyWatching": "Watcher session is already in progress. Directory: {dir}", "lib_docker_invalidImageId": "Invalid docker image ID returned: {imageId}" } \ No newline at end of file diff --git a/packages/cli/package.json b/packages/cli/package.json index 922fe94cdc..5b498016cf 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -20,12 +20,13 @@ "build:envs": "copyfiles ./src/lib/build-envs/**/**/* ./build/lib/build-envs/ -u 3", "prebuild": "ts-node ./scripts/generateIntlTypes.ts", "lint": "eslint --color --ext .ts src/", - "test": "jest --passWithNoTests --runInBand --verbose", - "test:ci": "jest --passWithNoTests --runInBand --verbose", - "test:watch": "jest --watch --passWithNoTests --verbose" + "test": "cross-env TEST=true jest --passWithNoTests --runInBand --verbose", + "test:ci": "cross-env TEST=true jest --passWithNoTests --runInBand --verbose", + "test:watch": "cross-env TEST=true jest --watch --passWithNoTests --verbose" }, "dependencies": { "@formatjs/intl": "1.8.2", + "@web3api/asyncify-js": "0.0.1-prealpha.31", "@web3api/client-js": "0.0.1-prealpha.31", "@web3api/client-test-env": "0.0.1-prealpha.31", "@web3api/core-js": "0.0.1-prealpha.31", @@ -59,6 +60,8 @@ "@types/node": "12.7.11", "@types/rimraf": "3.0.0", "@web3api/test-env-js": "0.0.1-prealpha.31", + "cross-env": "7.0.3", + "dir-compare": "3.3.0", "eslint-plugin-formatjs": "2.12.7", "jest": "26.6.3", "ts-jest": "26.5.4", @@ -70,4 +73,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/packages/cli/src/__tests__/e2e/codegen.spec.ts b/packages/cli/src/__tests__/e2e/codegen.spec.ts index b1f69eb6e1..4eacac895e 100644 --- a/packages/cli/src/__tests__/e2e/codegen.spec.ts +++ b/packages/cli/src/__tests__/e2e/codegen.spec.ts @@ -1,23 +1,21 @@ import path from "path"; -import { defaultGenerationFile, defaultManifest } from "../../commands/codegen"; +import { defaultManifest } from "../../commands/codegen"; import { clearStyle, w3Cli } from "./utils"; import { runCLI } from "@web3api/test-env-js"; import rimraf from "rimraf"; const HELP = ` -w3 codegen [] [options] - -Generation file: - Path to the generation file (default: ${defaultGenerationFile}) +w3 codegen [options] Options: -h, --help Show usage information -m, --manifest-path Path to the Web3API manifest file (default: ${defaultManifest.join( " | " )}) - -i, --ipfs [] IPFS node to load external schemas (default: dev-server's node) - -o, --output-dir Output directory for generated types (default: types/) + -c, --custom Path to a custom generation script (JavaScript | TypeScript) + -o, --output-dir Output directory for custom generated types (default: 'types/') + -i, --ipfs [] IPFS node to load external schemas (default: ipfs.io & localhost) -e, --ens [
] ENS address to lookup external schemas (default: 0x0000...2e1e) `; @@ -64,7 +62,7 @@ ${HELP}`); test("Should throw error for invalid generation file - wrong file", async () => { const { exitCode: code, stdout: output, stderr: error } = await runCLI({ - args: ["codegen", `web3api-invalid.gen.js`], + args: ["codegen", "--custom", `web3api-invalid.gen.js`], cwd: projectRoot }, w3Cli); @@ -77,7 +75,7 @@ ${HELP}`); test("Should throw error for invalid generation file - no run() method", async () => { const { exitCode: code, stdout: output, stderr: error } = await runCLI({ - args: ["codegen", `web3api-norun.gen.js`], + args: ["codegen", "--custom", `web3api-norun.gen.js`], cwd: projectRoot }, w3Cli); diff --git a/packages/cli/src/__tests__/e2e/help.spec.ts b/packages/cli/src/__tests__/e2e/help.spec.ts index 63f838dc92..26cbb35f08 100644 --- a/packages/cli/src/__tests__/e2e/help.spec.ts +++ b/packages/cli/src/__tests__/e2e/help.spec.ts @@ -8,6 +8,7 @@ const HELP = ` help (h) - test-env (t) Manage a test environment for Web3API query (q) Query Web3APIs using recipe scripts + plugin (p) Build/generate types for the plugin create (c) Create a new project with w3 CLI codegen (g) Auto-generate API Types build (b) Builds a Web3API and (optionally) uploads it to IPFS @@ -15,7 +16,7 @@ const HELP = ` describe("e2e tests for no help", () => { const projectRoot = path.resolve(__dirname, "../project/"); - + test("Should display the help content", async () => { const { exitCode: code, stdout: output, stderr: error } = await runCLI({ args: ["help"], diff --git a/packages/cli/src/__tests__/e2e/plugin.spec.ts b/packages/cli/src/__tests__/e2e/plugin.spec.ts new file mode 100644 index 0000000000..295bcdd5fd --- /dev/null +++ b/packages/cli/src/__tests__/e2e/plugin.spec.ts @@ -0,0 +1,139 @@ +import path from "path"; +import { defaultManifest } from "../../commands/plugin"; +import { clearStyle } from "./utils"; + +import { runCLI } from "@web3api/test-env-js"; +import { compareSync } from "dir-compare"; + +const HELP = ` +w3 plugin command [options] + +Commands: + codegen Generate code for the plugin + +Options: + -h, --help Show usage information + -m, --manifest-path Path to the Web3API manifest file (default: ${defaultManifest.join( + " | " + )}) + -s, --output-schema-path Output path for the built schema (default: ./build/schema.graphql) + -t, --output-types-dir Output directory for the generated types (default: ./src/w3) + -i, --ipfs [] IPFS node to load external schemas (default: dev-server's node) + -e, --ens [
] ENS address to lookup external schemas (default: 0x0000...2e1e) + +`; + +describe("e2e tests for plugin command", () => { + const projectRoot = path.resolve(__dirname, "../plugin/"); + + test("Should show help text", async () => { + const { exitCode: code, stdout: output, stderr: error } = await runCLI( + { + args: ["plugin", "--help"], + cwd: projectRoot, + }, + "../../../bin/w3" + ); + + expect(code).toEqual(0); + expect(error).toBe(""); + expect(clearStyle(output)).toEqual(HELP); + }); + + test("Should throw error for invalid params - no command", async () => { + const { exitCode: code, stdout: output, stderr: error } = await runCLI( + { + args: ["plugin", "--output-dir"], + cwd: projectRoot, + }, + "../../../bin/w3" + ); + + expect(code).toEqual(0); + expect(error).toBe(""); + expect(clearStyle(output)).toEqual(`Please provide a command +${HELP}`); + }); + + test("Should throw error for invalid params - output-schema-path", async () => { + const { exitCode: code, stdout: output, stderr: error } = await runCLI( + { + args: ["plugin", "codegen", "--output-schema-path"], + cwd: projectRoot, + }, + "../../../bin/w3" + ); + + expect(code).toEqual(0); + expect(error).toBe(""); + expect(clearStyle(output)) + .toEqual(`--output-schema-path option missing argument +${HELP}`); + }); + + test("Should throw error for invalid params - output-types-dir", async () => { + const { exitCode: code, stdout: output, stderr: error } = await runCLI( + { + args: ["plugin", "codegen", "--output-types-dir"], + cwd: projectRoot, + }, + "../../../bin/w3" + ); + + expect(code).toEqual(0); + expect(error).toBe(""); + expect(clearStyle(output)) + .toEqual(`--output-types-dir option missing argument +${HELP}`); + }); + + test("Should throw error for invalid params - ens", async () => { + const { exitCode: code, stdout: output, stderr: error } = await runCLI( + { + args: ["plugin", "codegen", "--ens"], + cwd: projectRoot, + }, + "../../../bin/w3" + ); + + expect(code).toEqual(0); + expect(error).toBe(""); + expect(clearStyle(output)) + .toEqual(`--ens option missing <[address,]domain> argument +${HELP}`); + }); + + test("Should successfully generate types", async () => { + const { exitCode: code, stdout: output, stderr: error } = await runCLI( + { + args: ["plugin", "codegen"], + cwd: projectRoot, + }, + "../../../bin/w3" + ); + + expect(code).toEqual(0); + expect(error).toBe(""); + expect(clearStyle(output)).toEqual(`- Generate types +- Manifest loaded from ./web3api.plugin.yaml +✔ Manifest loaded from ./web3api.plugin.yaml +✔ Generate types +`); + + const expectedTypesResult = compareSync( + `${projectRoot}/src/w3`, + `${projectRoot}/expected-types`, + { compareContent: true } + ); + + expect(expectedTypesResult.differences).toBe(0); + + const expectedSchemaResult = compareSync( + `${projectRoot}/build`, + `${projectRoot}/expected-schema`, + { compareContent: true } + ); + + expect(expectedSchemaResult.differences).toBe(0); + }); +}); diff --git a/packages/cli/src/__tests__/plugin/expected-schema/schema.graphql b/packages/cli/src/__tests__/plugin/expected-schema/schema.graphql new file mode 100644 index 0000000000..de2a79ac23 --- /dev/null +++ b/packages/cli/src/__tests__/plugin/expected-schema/schema.graphql @@ -0,0 +1,238 @@ +### Web3API Header START ### +scalar UInt +scalar UInt8 +scalar UInt16 +scalar UInt32 +scalar Int +scalar Int8 +scalar Int16 +scalar Int32 +scalar Bytes +scalar BigInt + +directive @imported( + uri: String! + namespace: String! + nativeType: String! +) on OBJECT | ENUM + +directive @imports( + types: [String!]! +) on OBJECT +### Web3API Header END ### + +type Query @imports( + types: [ + "Ethereum_Query", + "Ethereum_Connection", + "Ethereum_TxOverrides", + "Ethereum_StaticTxResult", + "Ethereum_TxRequest", + "Ethereum_TxReceipt", + "Ethereum_Log", + "Ethereum_EventNotification" + ] +) { + method( + str: String! + optStr: String + ): Object! +} + +type Mutation { + method( + arg: UInt32! + ): String! +} + +type Object { + u: UInt! + array: [Boolean!]! + bytes: Bytes +} + +### Imported Queries START ### + +type Ethereum_Query @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Query" +) { + callContractView( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + ): String! + + callContractStatic( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + txOverrides: Ethereum_TxOverrides + ): Ethereum_StaticTxResult! + + encodeParams( + types: [String!]! + values: [String!]! + ): String! + + getSignerAddress( + connection: Ethereum_Connection + ): String! + + getSignerBalance( + blockTag: BigInt + connection: Ethereum_Connection + ): BigInt! + + getSignerTransactionCount( + blockTag: BigInt + connection: Ethereum_Connection + ): BigInt! + + getGasPrice( + connection: Ethereum_Connection + ): BigInt! + + estimateTransactionGas( + tx: Ethereum_TxRequest! + connection: Ethereum_Connection + ): BigInt! + + estimateContractCallGas( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + txOverrides: Ethereum_TxOverrides + ): BigInt! + + checkAddress( + address: String! + ): Boolean! + + toWei( + eth: String! + ): BigInt! + + toEth( + wei: BigInt! + ): String! + + awaitTransaction( + txHash: String! + confirmations: UInt32! + timeout: UInt32! + connection: Ethereum_Connection + ): Ethereum_TxReceipt! + + waitForEvent( + address: String! + event: String! + args: [String!] + timeout: UInt32 + connection: Ethereum_Connection + ): Ethereum_EventNotification! +} + +### Imported Queries END ### + +### Imported Objects START ### + +type Ethereum_Connection @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Connection" +) { + node: String + networkNameOrChainId: String +} + +type Ethereum_TxOverrides @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "TxOverrides" +) { + gasLimit: BigInt + gasPrice: BigInt + value: BigInt +} + +type Ethereum_StaticTxResult @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "StaticTxResult" +) { + result: String! + error: Boolean! +} + +type Ethereum_TxRequest @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "TxRequest" +) { + to: String + from: String + nonce: UInt32 + gasLimit: BigInt + gasPrice: BigInt + data: String + value: BigInt + chainId: UInt32 + type: UInt32 +} + +type Ethereum_TxReceipt @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "TxReceipt" +) { + to: String! + from: String! + contractAddress: String! + transactionIndex: UInt32! + root: String + gasUsed: BigInt! + logsBloom: String! + transactionHash: String! + logs: [Ethereum_Log!]! + blockNumber: BigInt! + blockHash: String! + confirmations: UInt32! + cumulativeGasUsed: BigInt! + effectiveGasPrice: BigInt! + byzantium: Boolean! + type: UInt32! + status: UInt32 +} + +type Ethereum_Log @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Log" +) { + blockNumber: BigInt! + blockHash: String! + transactionIndex: UInt32! + removed: Boolean! + address: String! + data: String! + topics: [String!]! + transactionHash: String! + logIndex: UInt32! +} + +type Ethereum_EventNotification @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "EventNotification" +) { + data: String! + address: String! + log: Ethereum_Log! +} + +### Imported Objects END ### diff --git a/packages/cli/src/__tests__/plugin/expected-types/index.ts b/packages/cli/src/__tests__/plugin/expected-types/index.ts new file mode 100644 index 0000000000..905246e513 --- /dev/null +++ b/packages/cli/src/__tests__/plugin/expected-types/index.ts @@ -0,0 +1,5 @@ +export * as Query from "./query"; +export * as Mutation from "./mutation"; +export * from "./types"; +export * from "./schema"; +export * from "./manifest"; diff --git a/packages/cli/src/__tests__/plugin/expected-types/manifest.ts b/packages/cli/src/__tests__/plugin/expected-types/manifest.ts new file mode 100644 index 0000000000..5e193c285e --- /dev/null +++ b/packages/cli/src/__tests__/plugin/expected-types/manifest.ts @@ -0,0 +1,10 @@ +// @ts-noCheck +import { schema } from "./"; + +import { PluginPackageManifest, Uri } from "@web3api/core-js"; + +export const manifest: PluginPackageManifest = { + schema, + implements: [ + ], +} diff --git a/packages/cli/src/__tests__/plugin/expected-types/mutation.ts b/packages/cli/src/__tests__/plugin/expected-types/mutation.ts new file mode 100644 index 0000000000..03a1e55d18 --- /dev/null +++ b/packages/cli/src/__tests__/plugin/expected-types/mutation.ts @@ -0,0 +1,33 @@ +// @ts-noCheck +import { + UInt, + UInt8, + UInt16, + UInt32, + Int, + Int8, + Int16, + Int32, + Bytes, + BigInt, + String, + Boolean +} from "./types"; +import * as Types from "./types"; + +import { + Client, + PluginModule, + MaybeAsync +} from "@web3api/core-js"; + +export interface Input_method extends Record { + arg: UInt32; +} + +export interface Module extends PluginModule { + method( + input: Input_method, + client: Client + ): MaybeAsync; +} diff --git a/packages/cli/src/__tests__/plugin/expected-types/query.ts b/packages/cli/src/__tests__/plugin/expected-types/query.ts new file mode 100644 index 0000000000..8621ad7150 --- /dev/null +++ b/packages/cli/src/__tests__/plugin/expected-types/query.ts @@ -0,0 +1,34 @@ +// @ts-noCheck +import { + UInt, + UInt8, + UInt16, + UInt32, + Int, + Int8, + Int16, + Int32, + Bytes, + BigInt, + String, + Boolean +} from "./types"; +import * as Types from "./types"; + +import { + Client, + PluginModule, + MaybeAsync +} from "@web3api/core-js"; + +export interface Input_method extends Record { + str: String; + optStr?: String | undefined; +} + +export interface Module extends PluginModule { + method( + input: Input_method, + client: Client + ): MaybeAsync; +} diff --git a/packages/cli/src/__tests__/plugin/expected-types/schema.ts b/packages/cli/src/__tests__/plugin/expected-types/schema.ts new file mode 100644 index 0000000000..4803945623 --- /dev/null +++ b/packages/cli/src/__tests__/plugin/expected-types/schema.ts @@ -0,0 +1,239 @@ +export const schema: string = `### Web3API Header START ### +scalar UInt +scalar UInt8 +scalar UInt16 +scalar UInt32 +scalar Int +scalar Int8 +scalar Int16 +scalar Int32 +scalar Bytes +scalar BigInt + +directive @imported( + uri: String! + namespace: String! + nativeType: String! +) on OBJECT | ENUM + +directive @imports( + types: [String!]! +) on OBJECT +### Web3API Header END ### + +type Query @imports( + types: [ + "Ethereum_Query", + "Ethereum_Connection", + "Ethereum_TxOverrides", + "Ethereum_StaticTxResult", + "Ethereum_TxRequest", + "Ethereum_TxReceipt", + "Ethereum_Log", + "Ethereum_EventNotification" + ] +) { + method( + str: String! + optStr: String + ): Object! +} + +type Mutation { + method( + arg: UInt32! + ): String! +} + +type Object { + u: UInt! + array: [Boolean!]! + bytes: Bytes +} + +### Imported Queries START ### + +type Ethereum_Query @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Query" +) { + callContractView( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + ): String! + + callContractStatic( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + txOverrides: Ethereum_TxOverrides + ): Ethereum_StaticTxResult! + + encodeParams( + types: [String!]! + values: [String!]! + ): String! + + getSignerAddress( + connection: Ethereum_Connection + ): String! + + getSignerBalance( + blockTag: BigInt + connection: Ethereum_Connection + ): BigInt! + + getSignerTransactionCount( + blockTag: BigInt + connection: Ethereum_Connection + ): BigInt! + + getGasPrice( + connection: Ethereum_Connection + ): BigInt! + + estimateTransactionGas( + tx: Ethereum_TxRequest! + connection: Ethereum_Connection + ): BigInt! + + estimateContractCallGas( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + txOverrides: Ethereum_TxOverrides + ): BigInt! + + checkAddress( + address: String! + ): Boolean! + + toWei( + eth: String! + ): BigInt! + + toEth( + wei: BigInt! + ): String! + + awaitTransaction( + txHash: String! + confirmations: UInt32! + timeout: UInt32! + connection: Ethereum_Connection + ): Ethereum_TxReceipt! + + waitForEvent( + address: String! + event: String! + args: [String!] + timeout: UInt32 + connection: Ethereum_Connection + ): Ethereum_EventNotification! +} + +### Imported Queries END ### + +### Imported Objects START ### + +type Ethereum_Connection @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Connection" +) { + node: String + networkNameOrChainId: String +} + +type Ethereum_TxOverrides @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "TxOverrides" +) { + gasLimit: BigInt + gasPrice: BigInt + value: BigInt +} + +type Ethereum_StaticTxResult @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "StaticTxResult" +) { + result: String! + error: Boolean! +} + +type Ethereum_TxRequest @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "TxRequest" +) { + to: String + from: String + nonce: UInt32 + gasLimit: BigInt + gasPrice: BigInt + data: String + value: BigInt + chainId: UInt32 + type: UInt32 +} + +type Ethereum_TxReceipt @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "TxReceipt" +) { + to: String! + from: String! + contractAddress: String! + transactionIndex: UInt32! + root: String + gasUsed: BigInt! + logsBloom: String! + transactionHash: String! + logs: [Ethereum_Log!]! + blockNumber: BigInt! + blockHash: String! + confirmations: UInt32! + cumulativeGasUsed: BigInt! + effectiveGasPrice: BigInt! + byzantium: Boolean! + type: UInt32! + status: UInt32 +} + +type Ethereum_Log @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Log" +) { + blockNumber: BigInt! + blockHash: String! + transactionIndex: UInt32! + removed: Boolean! + address: String! + data: String! + topics: [String!]! + transactionHash: String! + logIndex: UInt32! +} + +type Ethereum_EventNotification @imported( + uri: "ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "EventNotification" +) { + data: String! + address: String! + log: Ethereum_Log! +} + +### Imported Objects END ### +`; diff --git a/packages/cli/src/__tests__/plugin/expected-types/types.ts b/packages/cli/src/__tests__/plugin/expected-types/types.ts new file mode 100644 index 0000000000..6a474eb31a --- /dev/null +++ b/packages/cli/src/__tests__/plugin/expected-types/types.ts @@ -0,0 +1,370 @@ +// @ts-noCheck +import * as Types from "./"; + +import { + Client, + InvokeApiResult +} from "@web3api/core-js"; + +export type UInt = number; +export type UInt8 = number; +export type UInt16 = number; +export type UInt32 = number; +export type Int = number; +export type Int8 = number; +export type Int16 = number; +export type Int32 = number; +export type Bytes = Uint8Array; +export type BigInt = string; +export type String = string; +export type Boolean = boolean; + +export interface Object { + u: UInt; + array: Array; + bytes?: Bytes | undefined; +} + +/// Imported Objects START /// + +/* URI: "ens/ethereum.web3api.eth" */ +export interface Ethereum_Connection { + node?: String | undefined; + networkNameOrChainId?: String | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +export interface Ethereum_TxOverrides { + gasLimit?: BigInt | undefined; + gasPrice?: BigInt | undefined; + value?: BigInt | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +export interface Ethereum_StaticTxResult { + result: String; + error: Boolean; +} + +/* URI: "ens/ethereum.web3api.eth" */ +export interface Ethereum_TxRequest { + to?: String | undefined; + from?: String | undefined; + nonce?: UInt32 | undefined; + gasLimit?: BigInt | undefined; + gasPrice?: BigInt | undefined; + data?: String | undefined; + value?: BigInt | undefined; + chainId?: UInt32 | undefined; + type?: UInt32 | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +export interface Ethereum_TxReceipt { + to: String; + from: String; + contractAddress: String; + transactionIndex: UInt32; + root?: String | undefined; + gasUsed: BigInt; + logsBloom: String; + transactionHash: String; + logs: Array; + blockNumber: BigInt; + blockHash: String; + confirmations: UInt32; + cumulativeGasUsed: BigInt; + effectiveGasPrice: BigInt; + byzantium: Boolean; + type: UInt32; + status?: UInt32 | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +export interface Ethereum_Log { + blockNumber: BigInt; + blockHash: String; + transactionIndex: UInt32; + removed: Boolean; + address: String; + data: String; + topics: Array; + transactionHash: String; + logIndex: UInt32; +} + +/* URI: "ens/ethereum.web3api.eth" */ +export interface Ethereum_EventNotification { + data: String; + address: String; + log: Types.Ethereum_Log; +} + +/// Imported Objects END /// + +/// Imported Queries START /// + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_callContractView extends Record { + address: String; + method: String; + args?: Array | undefined; + connection?: Types.Ethereum_Connection | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_callContractStatic extends Record { + address: String; + method: String; + args?: Array | undefined; + connection?: Types.Ethereum_Connection | undefined; + txOverrides?: Types.Ethereum_TxOverrides | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_encodeParams extends Record { + types: Array; + values: Array; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_getSignerAddress extends Record { + connection?: Types.Ethereum_Connection | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_getSignerBalance extends Record { + blockTag?: BigInt | undefined; + connection?: Types.Ethereum_Connection | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_getSignerTransactionCount extends Record { + blockTag?: BigInt | undefined; + connection?: Types.Ethereum_Connection | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_getGasPrice extends Record { + connection?: Types.Ethereum_Connection | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_estimateTransactionGas extends Record { + tx: Types.Ethereum_TxRequest; + connection?: Types.Ethereum_Connection | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_estimateContractCallGas extends Record { + address: String; + method: String; + args?: Array | undefined; + connection?: Types.Ethereum_Connection | undefined; + txOverrides?: Types.Ethereum_TxOverrides | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_checkAddress extends Record { + address: String; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_toWei extends Record { + eth: String; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_toEth extends Record { + wei: BigInt; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_awaitTransaction extends Record { + txHash: String; + confirmations: UInt32; + timeout: UInt32; + connection?: Types.Ethereum_Connection | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +interface Ethereum_Query_Input_waitForEvent extends Record { + address: String; + event: String; + args?: Array | undefined; + timeout?: UInt32 | undefined; + connection?: Types.Ethereum_Connection | undefined; +} + +/* URI: "ens/ethereum.web3api.eth" */ +export const Ethereum_Query = { + callContractView: async ( + input: Ethereum_Query_Input_callContractView, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "callContractView", + input + }); + }, + + callContractStatic: async ( + input: Ethereum_Query_Input_callContractStatic, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "callContractStatic", + input + }); + }, + + encodeParams: async ( + input: Ethereum_Query_Input_encodeParams, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "encodeParams", + input + }); + }, + + getSignerAddress: async ( + input: Ethereum_Query_Input_getSignerAddress, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "getSignerAddress", + input + }); + }, + + getSignerBalance: async ( + input: Ethereum_Query_Input_getSignerBalance, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "getSignerBalance", + input + }); + }, + + getSignerTransactionCount: async ( + input: Ethereum_Query_Input_getSignerTransactionCount, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "getSignerTransactionCount", + input + }); + }, + + getGasPrice: async ( + input: Ethereum_Query_Input_getGasPrice, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "getGasPrice", + input + }); + }, + + estimateTransactionGas: async ( + input: Ethereum_Query_Input_estimateTransactionGas, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "estimateTransactionGas", + input + }); + }, + + estimateContractCallGas: async ( + input: Ethereum_Query_Input_estimateContractCallGas, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "estimateContractCallGas", + input + }); + }, + + checkAddress: async ( + input: Ethereum_Query_Input_checkAddress, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "checkAddress", + input + }); + }, + + toWei: async ( + input: Ethereum_Query_Input_toWei, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "toWei", + input + }); + }, + + toEth: async ( + input: Ethereum_Query_Input_toEth, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "toEth", + input + }); + }, + + awaitTransaction: async ( + input: Ethereum_Query_Input_awaitTransaction, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "awaitTransaction", + input + }); + }, + + waitForEvent: async ( + input: Ethereum_Query_Input_waitForEvent, + client: Client + ): Promise> => { + return client.invoke({ + uri: "ens/ethereum.web3api.eth", + module: "query", + method: "waitForEvent", + input + }); + } +} + +/// Imported Queries END /// diff --git a/packages/cli/src/__tests__/plugin/schema.graphql b/packages/cli/src/__tests__/plugin/schema.graphql new file mode 100644 index 0000000000..50ef74f214 --- /dev/null +++ b/packages/cli/src/__tests__/plugin/schema.graphql @@ -0,0 +1,20 @@ +#import { Query } into Ethereum from "ens/ethereum.web3api.eth" + +type Query { + method( + str: String! + optStr: String + ): Object! +} + +type Mutation { + method( + arg: UInt32! + ): String! +} + +type Object { + u: UInt! + array: [Boolean!]! + bytes: Bytes +} diff --git a/packages/cli/src/__tests__/plugin/src/.gitkeep b/packages/cli/src/__tests__/plugin/src/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/cli/src/__tests__/plugin/web3api.plugin.yaml b/packages/cli/src/__tests__/plugin/web3api.plugin.yaml new file mode 100644 index 0000000000..b21359a846 --- /dev/null +++ b/packages/cli/src/__tests__/plugin/web3api.plugin.yaml @@ -0,0 +1,3 @@ +format: 0.0.1-prealpha.1 +language: plugin/typescript +schema: ./schema.graphql diff --git a/packages/cli/src/__tests__/project/sample-types.ts b/packages/cli/src/__tests__/project/sample-types.ts new file mode 100644 index 0000000000..55ba42d882 --- /dev/null +++ b/packages/cli/src/__tests__/project/sample-types.ts @@ -0,0 +1,375 @@ +import { Client, PluginModule } from "@web3api/core-js"; + +export interface QueryModule extends PluginModule { + getData: ( + input: Input_getData + ) => number; +} + +export interface Input_getData { + address: string; + connection?: Types.Ethereum_Connection | null; +} +export interface MutationModule extends PluginModule { + setData: ( + input: Input_setData + ) => Types.SetDataResult; + deployContract: ( + input: Input_deployContract + ) => string; +} + +export interface Input_setData { + options: Types.SetDataOptions; + connection?: Types.Ethereum_Connection | null; +} +export interface Input_deployContract { + connection?: Types.Ethereum_Connection | null; +} + +export const schema = `### Web3API Header START ### +scalar UInt +scalar UInt8 +scalar UInt16 +scalar UInt32 +scalar UInt64 +scalar Int +scalar Int8 +scalar Int16 +scalar Int32 +scalar Int64 +scalar Bytes +scalar BigInt + +directive @imported( + uri: String! + namespace: String! + nativeType: String! +) on OBJECT | ENUM + +directive @imports( + types: [String!]! +) on OBJECT +### Web3API Header END ### + +type Query @imports( + types: [ + "Ethereum_Query", + "Ethereum_Connection", + "Ethereum_TxOverrides", + "Ethereum_StaticTxResult", + "Ethereum_TxRequest", + "Ethereum_TxReceipt", + "Ethereum_Log", + "Ethereum_EventNotification" + ] +) { + getData( + address: String! + connection: Ethereum_Connection + ): UInt32! +} + +type Mutation @imports( + types: [ + "Ethereum_Mutation", + "Ethereum_Connection", + "Ethereum_TxOverrides", + "Ethereum_TxResponse", + "Ethereum_Access", + "Ethereum_TxReceipt", + "Ethereum_Log", + "Ethereum_TxRequest" + ] +) { + setData( + options: SetDataOptions! + connection: Ethereum_Connection + ): SetDataResult! + + deployContract( + connection: Ethereum_Connection + ): String! +} + +type SetDataOptions { + address: String! + value: UInt32! +} + +type SetDataResult { + txReceipt: String! + value: UInt32! +} + +### Imported Queries START ### + +type Ethereum_Query @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Query" +) { + callContractView( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + ): String! + + callContractStatic( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + txOverrides: Ethereum_TxOverrides + ): Ethereum_StaticTxResult! + + encodeParams( + types: [String!]! + values: [String!]! + ): String! + + getSignerAddress( + connection: Ethereum_Connection + ): String! + + getSignerBalance( + blockTag: BigInt + connection: Ethereum_Connection + ): BigInt! + + getSignerTransactionCount( + blockTag: BigInt + connection: Ethereum_Connection + ): BigInt! + + getGasPrice( + connection: Ethereum_Connection + ): BigInt! + + estimateTransactionGas( + tx: Ethereum_TxRequest! + connection: Ethereum_Connection + ): BigInt! + + estimateContractCallGas( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + txOverrides: Ethereum_TxOverrides + ): BigInt! + + checkAddress( + address: String! + ): Boolean! + + toWei( + eth: String! + ): BigInt! + + toEth( + wei: BigInt! + ): String! + + awaitTransaction( + txHash: String! + confirmations: UInt32! + timeout: UInt32! + connection: Ethereum_Connection + ): Ethereum_TxReceipt! + + waitForEvent( + address: String! + event: String! + args: [String!] + timeout: UInt32 + connection: Ethereum_Connection + ): Ethereum_EventNotification! +} + +type Ethereum_Mutation @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Mutation" +) { + callContractMethod( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + txOverrides: Ethereum_TxOverrides + ): Ethereum_TxResponse! + + callContractMethodAndWait( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + txOverrides: Ethereum_TxOverrides + ): Ethereum_TxReceipt! + + sendTransaction( + tx: Ethereum_TxRequest! + connection: Ethereum_Connection + ): Ethereum_TxResponse! + + sendTransactionAndWait( + tx: Ethereum_TxRequest! + connection: Ethereum_Connection + ): Ethereum_TxReceipt! + + deployContract( + abi: String! + bytecode: String! + args: [String!] + connection: Ethereum_Connection + ): String! + + signMessage( + message: String! + connection: Ethereum_Connection + ): String! + + sendRPC( + method: String! + params: [String!]! + connection: Ethereum_Connection + ): String +} + +### Imported Queries END ### + +### Imported Objects START ### + +type Ethereum_Connection @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Connection" +) { + node: String + networkNameOrChainId: String +} + +type Ethereum_TxOverrides @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "TxOverrides" +) { + gasLimit: BigInt + gasPrice: BigInt + value: BigInt +} + +type Ethereum_StaticTxResult @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "StaticTxResult" +) { + result: String! + error: Boolean! +} + +type Ethereum_TxRequest @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "TxRequest" +) { + to: String + from: String + nonce: UInt32 + gasLimit: BigInt + gasPrice: BigInt + data: String + value: BigInt + chainId: UInt32 + type: UInt32 +} + +type Ethereum_TxReceipt @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "TxReceipt" +) { + to: String! + from: String! + contractAddress: String! + transactionIndex: UInt32! + root: String + gasUsed: BigInt! + logsBloom: String! + transactionHash: String! + logs: [Ethereum_Log!]! + blockNumber: BigInt! + blockHash: String! + confirmations: UInt32! + cumulativeGasUsed: BigInt! + effectiveGasPrice: BigInt! + byzantium: Boolean! + type: UInt32! + status: UInt32 +} + +type Ethereum_Log @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Log" +) { + blockNumber: BigInt! + blockHash: String! + transactionIndex: UInt32! + removed: Boolean! + address: String! + data: String! + topics: [String!]! + transactionHash: String! + logIndex: UInt32! +} + +type Ethereum_EventNotification @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "EventNotification" +) { + data: String! + address: String! + log: Ethereum_Log! +} + +type Ethereum_TxResponse @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "TxResponse" +) { + hash: String! + to: String + from: String! + nonce: UInt32! + gasLimit: BigInt! + gasPrice: BigInt + data: String! + value: BigInt! + chainId: UInt32! + blockNumber: BigInt + blockHash: String + timestamp: UInt32 + confirmations: UInt32! + raw: String + r: String + s: String + v: UInt32 + type: UInt32 + accessList: [Ethereum_Access!] +} + +type Ethereum_Access @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Access" +) { + address: String! + storageKeys: [String!]! +} + +### Imported Objects END ### +`; \ No newline at end of file diff --git a/packages/cli/src/__tests__/project/sample.ts b/packages/cli/src/__tests__/project/sample.ts index 4e820f1503..6db1122d96 100644 --- a/packages/cli/src/__tests__/project/sample.ts +++ b/packages/cli/src/__tests__/project/sample.ts @@ -475,24 +475,6 @@ directive @imports( ) on OBJECT ### Web3API Header END ### -type Query @imports( - types: [ - "Ethereum_Query", - "Ethereum_Connection", - "Ethereum_TxOverrides", - "Ethereum_StaticTxResult", - "Ethereum_TxRequest", - "Ethereum_TxReceipt", - "Ethereum_Log", - "Ethereum_EventNotification" - ] -) { - getData( - address: String! - connection: Ethereum_Connection - ): UInt32! -} - type Mutation @imports( types: [ "Ethereum_Mutation", @@ -515,6 +497,24 @@ type Mutation @imports( ): String! } +type Query @imports( + types: [ + "Ethereum_Query", + "Ethereum_Connection", + "Ethereum_TxOverrides", + "Ethereum_StaticTxResult", + "Ethereum_TxRequest", + "Ethereum_TxReceipt", + "Ethereum_Log", + "Ethereum_EventNotification" + ] +) { + getData( + address: String! + connection: Ethereum_Connection + ): UInt32! +} + type SetDataOptions { address: String! value: UInt32! @@ -527,6 +527,56 @@ type SetDataResult { ### Imported Queries START ### +type Ethereum_Mutation @imported( + uri: "w3://ens/ethereum.web3api.eth", + namespace: "Ethereum", + nativeType: "Mutation" +) { + callContractMethod( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + txOverrides: Ethereum_TxOverrides + ): Ethereum_TxResponse! + + callContractMethodAndWait( + address: String! + method: String! + args: [String!] + connection: Ethereum_Connection + txOverrides: Ethereum_TxOverrides + ): Ethereum_TxReceipt! + + sendTransaction( + tx: Ethereum_TxRequest! + connection: Ethereum_Connection + ): Ethereum_TxResponse! + + sendTransactionAndWait( + tx: Ethereum_TxRequest! + connection: Ethereum_Connection + ): Ethereum_TxReceipt! + + deployContract( + abi: String! + bytecode: String! + args: [String!] + connection: Ethereum_Connection + ): String! + + signMessage( + message: String! + connection: Ethereum_Connection + ): String! + + sendRPC( + method: String! + params: [String!]! + connection: Ethereum_Connection + ): String +} + type Ethereum_Query @imported( uri: "w3://ens/ethereum.web3api.eth", namespace: "Ethereum", @@ -611,56 +661,6 @@ type Ethereum_Query @imported( ): Ethereum_EventNotification! } -type Ethereum_Mutation @imported( - uri: "w3://ens/ethereum.web3api.eth", - namespace: "Ethereum", - nativeType: "Mutation" -) { - callContractMethod( - address: String! - method: String! - args: [String!] - connection: Ethereum_Connection - txOverrides: Ethereum_TxOverrides - ): Ethereum_TxResponse! - - callContractMethodAndWait( - address: String! - method: String! - args: [String!] - connection: Ethereum_Connection - txOverrides: Ethereum_TxOverrides - ): Ethereum_TxReceipt! - - sendTransaction( - tx: Ethereum_TxRequest! - connection: Ethereum_Connection - ): Ethereum_TxResponse! - - sendTransactionAndWait( - tx: Ethereum_TxRequest! - connection: Ethereum_Connection - ): Ethereum_TxReceipt! - - deployContract( - abi: String! - bytecode: String! - args: [String!] - connection: Ethereum_Connection - ): String! - - signMessage( - message: String! - connection: Ethereum_Connection - ): String! - - sendRPC( - method: String! - params: [String!]! - connection: Ethereum_Connection - ): String -} - ### Imported Queries END ### ### Imported Objects START ### @@ -684,29 +684,39 @@ type Ethereum_TxOverrides @imported( value: BigInt } -type Ethereum_StaticTxResult @imported( +type Ethereum_TxResponse @imported( uri: "w3://ens/ethereum.web3api.eth", namespace: "Ethereum", - nativeType: "StaticTxResult" + nativeType: "TxResponse" ) { - result: String! - error: Boolean! + hash: String! + to: String + from: String! + nonce: UInt32! + gasLimit: BigInt! + gasPrice: BigInt + data: String! + value: BigInt! + chainId: UInt32! + blockNumber: BigInt + blockHash: String + timestamp: UInt32 + confirmations: UInt32! + raw: String + r: String + s: String + v: UInt32 + type: UInt32 + accessList: [Ethereum_Access!] } -type Ethereum_TxRequest @imported( +type Ethereum_Access @imported( uri: "w3://ens/ethereum.web3api.eth", namespace: "Ethereum", - nativeType: "TxRequest" + nativeType: "Access" ) { - to: String - from: String - nonce: UInt32 - gasLimit: BigInt - gasPrice: BigInt - data: String - value: BigInt - chainId: UInt32 - type: UInt32 + address: String! + storageKeys: [String!]! } type Ethereum_TxReceipt @imported( @@ -749,49 +759,39 @@ type Ethereum_Log @imported( logIndex: UInt32! } -type Ethereum_EventNotification @imported( +type Ethereum_TxRequest @imported( uri: "w3://ens/ethereum.web3api.eth", namespace: "Ethereum", - nativeType: "EventNotification" + nativeType: "TxRequest" ) { - data: String! - address: String! - log: Ethereum_Log! + to: String + from: String + nonce: UInt32 + gasLimit: BigInt + gasPrice: BigInt + data: String + value: BigInt + chainId: UInt32 + type: UInt32 } -type Ethereum_TxResponse @imported( +type Ethereum_StaticTxResult @imported( uri: "w3://ens/ethereum.web3api.eth", namespace: "Ethereum", - nativeType: "TxResponse" + nativeType: "StaticTxResult" ) { - hash: String! - to: String - from: String! - nonce: UInt32! - gasLimit: BigInt! - gasPrice: BigInt - data: String! - value: BigInt! - chainId: UInt32! - blockNumber: BigInt - blockHash: String - timestamp: UInt32 - confirmations: UInt32! - raw: String - r: String - s: String - v: UInt32 - type: UInt32 - accessList: [Ethereum_Access!] + result: String! + error: Boolean! } -type Ethereum_Access @imported( +type Ethereum_EventNotification @imported( uri: "w3://ens/ethereum.web3api.eth", namespace: "Ethereum", - nativeType: "Access" + nativeType: "EventNotification" ) { + data: String! address: String! - storageKeys: [String!]! + log: Ethereum_Log! } ### Imported Objects END ### diff --git a/packages/cli/src/__tests__/project/web3api.build.docker.yaml b/packages/cli/src/__tests__/project/web3api.build.docker.yaml index 48ebe15c46..f15b12c4c1 100644 --- a/packages/cli/src/__tests__/project/web3api.build.docker.yaml +++ b/packages/cli/src/__tests__/project/web3api.build.docker.yaml @@ -1,4 +1,4 @@ -format: 0.0.1-prealpha.2 +format: 0.0.1-prealpha.1 docker: name: build-env dockerfile: ./Dockerfile diff --git a/packages/cli/src/__tests__/project/web3api.build.no-docker.yaml b/packages/cli/src/__tests__/project/web3api.build.no-docker.yaml index 57b68c7c2c..42845d3bc1 100644 --- a/packages/cli/src/__tests__/project/web3api.build.no-docker.yaml +++ b/packages/cli/src/__tests__/project/web3api.build.no-docker.yaml @@ -1,4 +1,4 @@ -format: 0.0.1-prealpha.2 +format: 0.0.1-prealpha.1 docker: name: build-env config: diff --git a/packages/cli/src/__tests__/project/web3api.build.wrong-config.yaml b/packages/cli/src/__tests__/project/web3api.build.wrong-config.yaml index 89fe44c88b..4d4e5eb365 100644 --- a/packages/cli/src/__tests__/project/web3api.build.wrong-config.yaml +++ b/packages/cli/src/__tests__/project/web3api.build.wrong-config.yaml @@ -1,4 +1,4 @@ -format: 0.0.1-prealpha.2 +format: 0.0.1-prealpha.1 docker: name: build-env config: diff --git a/packages/cli/src/__tests__/unit/CodeGenerator.spec.ts b/packages/cli/src/__tests__/unit/CodeGenerator.spec.ts index 75f8f4740d..e23439a089 100644 --- a/packages/cli/src/__tests__/unit/CodeGenerator.spec.ts +++ b/packages/cli/src/__tests__/unit/CodeGenerator.spec.ts @@ -1,17 +1,17 @@ import fs from "fs"; import path from "path"; -import { SchemaComposer, Project, CodeGenerator } from "../../lib"; +import { SchemaComposer, Web3ApiProject, CodeGenerator } from "../../lib"; import { composedSchema } from "../project/sample"; import rimraf from "rimraf"; describe("CodeGenerator validation", () => { const manifestPath = path.join(__dirname, "../project", "web3api.yaml"); - const generationFile = path.join(__dirname, "../project", "web3api.gen.js"); + const customScript = path.join(__dirname, "../project", "web3api.gen.js"); const outputDir = path.join(__dirname, "../project", "types"); it("Should fail with invalid manifest path", async () => { - const project = new Project({ + const project = new Web3ApiProject({ web3apiManifestPath: "invalidManifest", quiet: true, }); @@ -21,7 +21,7 @@ describe("CodeGenerator validation", () => { const generator = new CodeGenerator({ project, schemaComposer, - generationFile, + customScript, outputDir, }); @@ -30,7 +30,7 @@ describe("CodeGenerator validation", () => { }); it("Should fail with invalid generation file", async () => { - const project = new Project({ + const project = new Web3ApiProject({ web3apiManifestPath: manifestPath, quiet: true, }); @@ -40,7 +40,7 @@ describe("CodeGenerator validation", () => { const generator = new CodeGenerator({ project, schemaComposer, - generationFile: path.join( + customScript: path.join( __dirname, "../project", "web3api-norun.gen.js" @@ -57,7 +57,7 @@ describe("CodeGenerator validation", () => { rimraf.sync(outputDir); } - const project = new Project({ + const project = new Web3ApiProject({ web3apiManifestPath: manifestPath, quiet: true, }); @@ -67,7 +67,7 @@ describe("CodeGenerator validation", () => { const generator = new CodeGenerator({ project, schemaComposer, - generationFile, + customScript, outputDir, }); diff --git a/packages/cli/src/__tests__/unit/SchemaComposer.spec.ts b/packages/cli/src/__tests__/unit/SchemaComposer.spec.ts index 05a37864c3..f5e1e93b66 100644 --- a/packages/cli/src/__tests__/unit/SchemaComposer.spec.ts +++ b/packages/cli/src/__tests__/unit/SchemaComposer.spec.ts @@ -1,5 +1,5 @@ import path from "path"; -import { SchemaComposer, Project } from "../../lib"; +import { SchemaComposer, Web3ApiProject } from "../../lib"; import { composedSchema } from "../project/sample"; import { ComposerFilter } from "@web3api/schema-compose"; @@ -8,7 +8,7 @@ describe("SchemaComposer validation", () => { const manifestPath = path.join(__dirname, "../project", "web3api.yaml"); it("Should load & compose schema properly", async () => { - const project = new Project({ + const project = new Web3ApiProject({ web3apiManifestPath: manifestPath, }); const composer = new SchemaComposer({ diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index d126bbdc8b..df43ffbf77 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -1,7 +1,7 @@ /* eslint-disable prefer-const */ import { Compiler, - Project, + Web3ApiProject, SchemaComposer, Watcher, WatchEvent, @@ -164,7 +164,7 @@ export default { } } - const project = new Project({ + const project = new Web3ApiProject({ web3apiManifestPath: manifestPath, quiet: verbose ? false : true, }); diff --git a/packages/cli/src/commands/codegen.ts b/packages/cli/src/commands/codegen.ts index 7788781f5b..38a9f2e150 100644 --- a/packages/cli/src/commands/codegen.ts +++ b/packages/cli/src/commands/codegen.ts @@ -1,19 +1,18 @@ /* eslint-disable prefer-const */ -import { CodeGenerator, Project, SchemaComposer } from "../lib"; -import { fixParameters } from "../lib/helpers/parameters"; +import { + CodeGenerator, + Compiler, + Web3ApiProject, + SchemaComposer, +} from "../lib"; import { intlMsg } from "../lib/intl"; import chalk from "chalk"; import axios from "axios"; import { GluegunToolbox } from "gluegun"; -export const defaultGenerationFile = "web3api.gen.js"; export const defaultManifest = ["web3api.yaml", "web3api.yml"]; -const genFileOp = intlMsg - .commands_codegen_options_genFile() - .toLowerCase() - .replace(" ", "-"); const optionsStr = intlMsg.commands_options_options(); const nodeStr = intlMsg.commands_codegen_options_i_node(); const pathStr = intlMsg.commands_codegen_options_o_path(); @@ -21,16 +20,14 @@ const addrStr = intlMsg.commands_codegen_options_e_address(); const defaultManifestStr = defaultManifest.join(" | "); const HELP = ` -${chalk.bold("w3 codegen")} ${chalk.bold(`[<${genFileOp}>]`)} [${optionsStr}] - -${intlMsg.commands_codegen_options_genFile()}: - ${intlMsg.commands_codegen_options_genFilePath()}: ${defaultGenerationFile}) +${chalk.bold("w3 codegen")} [${optionsStr}] ${optionsStr[0].toUpperCase() + optionsStr.slice(1)}: -h, --help ${intlMsg.commands_codegen_options_h()} -m, --manifest-path <${pathStr}> ${intlMsg.commands_codegen_options_m()}: ${defaultManifestStr}) - -i, --ipfs [<${nodeStr}>] ${intlMsg.commands_codegen_options_i()} + -c, --custom <${pathStr}> ${intlMsg.commands_codegen_options_c()} -o, --output-dir <${pathStr}> ${intlMsg.commands_codegen_options_o()} + -i, --ipfs [<${nodeStr}>] ${intlMsg.commands_codegen_options_i()} -e, --ens [<${addrStr}>] ${intlMsg.commands_codegen_options_e()} `; @@ -40,35 +37,36 @@ export default { run: async (toolbox: GluegunToolbox): Promise => { const { filesystem, parameters, print } = toolbox; - const { h, m, i, o, e } = parameters.options; - let { help, manifestPath, ipfs, outputDir, ens } = parameters.options; + const { h, c, m, i, o, e } = parameters.options; + let { + help, + custom, + manifestPath, + ipfs, + outputDir, + ens, + } = parameters.options; help = help || h; + custom = custom || c; manifestPath = manifestPath || m; ipfs = ipfs || i; outputDir = outputDir || o; ens = ens || e; - let generationFile; - try { - const params = toolbox.parameters; - [generationFile] = fixParameters( - { - options: params.options, - array: params.array, - }, - { - h, - help, - } - ); - } catch (e) { - print.error(e.message); - process.exitCode = 1; + if (help) { + print.info(HELP); return; } - if (help) { + if (custom === true) { + const customScriptMissingPathMessage = intlMsg.commands_codegen_error_customScriptMissingPath( + { + option: "--custom", + argument: `<${pathStr}>`, + } + ); + print.error(customScriptMissingPathMessage); print.info(HELP); return; } @@ -119,18 +117,15 @@ export default { } // Resolve generation file & output directories - generationFile = - (generationFile && filesystem.resolve(generationFile)) || - filesystem.resolve(defaultGenerationFile); + const customScript = custom && filesystem.resolve(custom); manifestPath = (manifestPath && filesystem.resolve(manifestPath)) || ((await filesystem.existsAsync(defaultManifest[0])) ? filesystem.resolve(defaultManifest[0]) : filesystem.resolve(defaultManifest[1])); - outputDir = - (outputDir && filesystem.resolve(outputDir)) || filesystem.path("types"); + outputDir = outputDir && filesystem.resolve(outputDir); - const project = new Project({ + const project = new Web3ApiProject({ web3apiManifestPath: manifestPath, }); @@ -141,14 +136,28 @@ export default { ensAddress, }); - const codeGenerator = new CodeGenerator({ - project, - schemaComposer, - generationFile, - outputDir, - }); + let result = false; + + if (customScript) { + const codeGenerator = new CodeGenerator({ + project, + schemaComposer, + customScript, + outputDir: outputDir || filesystem.path("types"), + }); + + result = await codeGenerator.generate(); + } else { + const compiler = new Compiler({ + project, + outputDir: filesystem.path("build"), + schemaComposer, + }); + + result = await compiler.codegen(); + } - if (await codeGenerator.generate()) { + if (result) { print.success(`🔥 ${intlMsg.commands_codegen_success()} 🔥`); process.exitCode = 0; } else { diff --git a/packages/cli/src/commands/create.ts b/packages/cli/src/commands/create.ts index e3836683ad..925f8e2302 100644 --- a/packages/cli/src/commands/create.ts +++ b/packages/cli/src/commands/create.ts @@ -1,4 +1,4 @@ -import { generateProjectTemplate } from "../lib/project-templates"; +import { generateProjectTemplate } from "../lib/templates"; import { fixParameters } from "../lib/helpers/parameters"; import { intlMsg } from "../lib/intl"; diff --git a/packages/cli/src/commands/plugin.ts b/packages/cli/src/commands/plugin.ts new file mode 100644 index 0000000000..e7d98d6658 --- /dev/null +++ b/packages/cli/src/commands/plugin.ts @@ -0,0 +1,209 @@ +/* eslint-disable prefer-const */ +import { CodeGenerator, PluginProject, SchemaComposer } from "../lib"; +import { fixParameters } from "../lib/helpers"; +import { intlMsg } from "../lib/intl"; + +import { ComposerFilter } from "@web3api/schema-compose"; +import { writeFileSync } from "@web3api/os-js"; +import { GluegunToolbox, print } from "gluegun"; +import axios from "axios"; +import chalk from "chalk"; +import path from "path"; +import fs from "fs"; + +export const defaultManifest = ["web3api.plugin.yaml", "web3api.plugin.yml"]; + +const cmdStr = intlMsg.commands_plugin_options_command(); +const optionsStr = intlMsg.commands_options_options(); +const codegenStr = intlMsg.commands_plugin_options_codegen(); +const pathStr = intlMsg.commands_plugin_options_path(); +const defaultManifestStr = defaultManifest.join(" | "); +const defaultOutputSchemaStr = "./build/schema.graphql"; +const defaultOutputTypesStr = "./src/w3"; +const nodeStr = intlMsg.commands_plugin_options_i_node(); +const addrStr = intlMsg.commands_plugin_options_e_address(); + +const HELP = ` +${chalk.bold("w3 plugin")} ${cmdStr} [${optionsStr}] + +Commands: + ${chalk.bold("codegen")} ${codegenStr} + +Options: + -h, --help ${intlMsg.commands_plugin_options_h()} + -m, --manifest-path <${pathStr}> ${intlMsg.commands_plugin_options_m({ + default: defaultManifestStr, +})} + -s, --output-schema-path <${pathStr}> ${intlMsg.commands_plugins_options_schema( + { default: defaultOutputSchemaStr } +)} + -t, --output-types-dir <${pathStr}> ${intlMsg.commands_plugins_options_types( + { default: defaultOutputTypesStr } +)} + -i, --ipfs [<${nodeStr}>] ${intlMsg.commands_plugin_options_i()} + -e, --ens [<${addrStr}>] ${intlMsg.commands_plugin_options_e()} +`; + +export default { + alias: ["p"], + description: intlMsg.commands_plugin_description(), + run: async (toolbox: GluegunToolbox): Promise => { + const { filesystem, parameters } = toolbox; + + // Options + let { + help, + manifestPath, + outputSchemaPath, + outputTypesDir, + ipfs, + ens, + } = parameters.options; + const { h, m, s, t, i, e } = parameters.options; + + help = help || h; + manifestPath = manifestPath || m; + outputSchemaPath = outputSchemaPath || s; + outputTypesDir = outputTypesDir || t; + ipfs = ipfs || i; + ens = ens || e; + + let command = ""; + try { + const params = parameters; + [command] = fixParameters( + { + options: params.options, + array: params.array, + }, + { + h, + help, + } + ); + } catch (e) { + print.error(e.message); + process.exitCode = 1; + return; + } + + if (help) { + print.info(HELP); + return; + } + + if (!command) { + print.error(intlMsg.commands_plugin_error_noCommand()); + print.info(HELP); + return; + } + + if (outputSchemaPath === true) { + const outputSchemaMissingPathMessage = intlMsg.commands_plugin_error_outputDirMissingPath( + { + option: "--output-schema-path", + argument: `<${pathStr}>`, + } + ); + print.error(outputSchemaMissingPathMessage); + print.info(HELP); + return; + } else if (!outputSchemaPath) { + outputSchemaPath = defaultOutputSchemaStr; + } + + if (outputTypesDir === true) { + const outputTypesMissingPathMessage = intlMsg.commands_plugin_error_outputDirMissingPath( + { + option: "--output-types-dir", + argument: `<${pathStr}>`, + } + ); + print.error(outputTypesMissingPathMessage); + print.info(HELP); + return; + } else if (!outputTypesDir) { + outputTypesDir = defaultOutputTypesStr; + } + + if (ens === true) { + const domStr = intlMsg.commands_plugin_error_domain(); + const ensAddressMissingMessage = intlMsg.commands_build_error_testEnsAddressMissing( + { + option: "--ens", + argument: `<[${addrStr},]${domStr}>`, + } + ); + print.error(ensAddressMissingMessage); + print.info(HELP); + return; + } + + let ipfsProvider: string | undefined; + let ethProvider: string | undefined; + let ensAddress: string | undefined = ens; + + if (typeof ipfs === "string") { + // Custom IPFS provider + ipfsProvider = ipfs; + } else if (ipfs) { + // Dev-server IPFS provider + try { + const { + data: { ipfs, ethereum }, + } = await axios.get("http://localhost:4040/providers"); + ipfsProvider = ipfs; + ethProvider = ethereum; + } catch (e) { + // Dev server not found + } + } + + manifestPath = + (manifestPath && filesystem.resolve(manifestPath)) || + ((await filesystem.existsAsync(defaultManifest[0])) + ? filesystem.resolve(defaultManifest[0]) + : filesystem.resolve(defaultManifest[1])); + outputSchemaPath = outputSchemaPath && filesystem.resolve(outputSchemaPath); + outputTypesDir = outputTypesDir && filesystem.resolve(outputTypesDir); + + const project = new PluginProject({ + pluginManifestPath: manifestPath, + }); + + const schemaComposer = new SchemaComposer({ + project, + ipfsProvider, + ethProvider, + ensAddress, + }); + + let result = false; + + const codeGenerator = new CodeGenerator({ + project, + schemaComposer, + outputDir: outputTypesDir, + }); + + result = await codeGenerator.generate(); + + if (result) { + process.exitCode = 0; + } else { + process.exitCode = 1; + } + + // Output the built schema file + const schemas = await schemaComposer.getComposedSchemas( + ComposerFilter.Schema + ); + const outputSchemaDir = path.dirname(outputSchemaPath); + + if (!fs.existsSync(outputSchemaDir)) { + fs.mkdirSync(outputSchemaDir); + } + + writeFileSync(outputSchemaPath, schemas.combined.schema); + }, +}; diff --git a/packages/cli/src/lib/CodeGenerator.ts b/packages/cli/src/lib/CodeGenerator.ts index f71f8e0b79..75a32c5241 100644 --- a/packages/cli/src/lib/CodeGenerator.ts +++ b/packages/cli/src/lib/CodeGenerator.ts @@ -1,20 +1,37 @@ import { SchemaComposer } from "./SchemaComposer"; -import { Project } from "./Project"; -import { step, withSpinner } from "./helpers"; +import { Project } from "./project"; +import { step, withSpinner, isTypescriptFile, loadTsNode } from "./helpers"; import { intlMsg } from "./intl"; -import { OutputDirectory, writeDirectory } from "@web3api/schema-bind"; +import { TypeInfo } from "@web3api/schema-parse"; +import { + OutputDirectory, + writeDirectory, + bindSchema, +} from "@web3api/schema-bind"; import path from "path"; import fs, { readFileSync } from "fs"; import * as gluegun from "gluegun"; import { Ora } from "ora"; import Mustache from "mustache"; +export interface CustomScriptConfig { + typeInfo: TypeInfo; + generate: (templatePath: string, config: unknown) => string; +} + +export { OutputDirectory }; + +export type CustomScriptRunFn = ( + output: OutputDirectory, + config: CustomScriptConfig +) => void; + export interface CodeGeneratorConfig { outputDir: string; - generationFile: string; project: Project; schemaComposer: SchemaComposer; + customScript?: string; } export class CodeGenerator { @@ -53,31 +70,55 @@ export class CodeGenerator { const typeInfo = composed.combined.typeInfo; this._schema = composed.combined.schema; - // Check the generation file if it has the proper run() method - // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, @typescript-eslint/naming-convention - const generator = await require(this._config.generationFile); - if (!generator) { - throw Error(intlMsg.lib_codeGenerator_wrongGenFile()); + if (!typeInfo) { + throw Error(intlMsg.lib_codeGenerator_typeInfoMissing()); } - const { run } = generator; - if (!run) { - throw Error(intlMsg.lib_codeGenerator_noRunMethod()); - } + if (this._config.customScript) { + const output: OutputDirectory = { + entries: [], + }; - const output: OutputDirectory = { - entries: [], - }; + if (isTypescriptFile(this._config.customScript)) { + loadTsNode(); + } - await run(output, { - typeInfo, - generate: (templatePath: string, config: unknown) => - this._generateTemplate(templatePath, config, spinner), - }); + // Check the generation file if it has the proper run() method + // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, @typescript-eslint/naming-convention + const generator = await require(this._config.customScript); + if (!generator) { + throw Error(intlMsg.lib_codeGenerator_wrongGenFile()); + } - writeDirectory(this._config.outputDir, output, (templatePath: string) => - this._generateTemplate(templatePath, typeInfo, spinner) - ); + const { run } = generator as { run: CustomScriptRunFn }; + if (!run) { + throw Error(intlMsg.lib_codeGenerator_noRunMethod()); + } + + await run(output, { + typeInfo, + generate: (templatePath: string, config: unknown) => + this._generateTemplate(templatePath, config, spinner), + }); + + writeDirectory(this._config.outputDir, output, (templatePath: string) => + this._generateTemplate(templatePath, typeInfo, spinner) + ); + } else { + const content = bindSchema({ + combined: { + typeInfo: composed.combined?.typeInfo as TypeInfo, + schema: composed.combined?.schema as string, + outputDirAbs: "", + }, + language: await project.getLanguage(), + }); + + writeDirectory( + this._config.outputDir, + content.combined as OutputDirectory + ); + } }; if (project.quiet) { @@ -108,10 +149,13 @@ export class CodeGenerator { step(spinner, stepMessage); } - templatePath = path.join( - path.dirname(this._config.generationFile), - templatePath - ); + if (this._config.customScript) { + // Update template path when the generation file is given + templatePath = path.join( + path.dirname(this._config.customScript), + templatePath + ); + } const template = readFileSync(templatePath); const types = diff --git a/packages/cli/src/lib/Compiler.ts b/packages/cli/src/lib/Compiler.ts index d758b6de35..8be776e916 100644 --- a/packages/cli/src/lib/Compiler.ts +++ b/packages/cli/src/lib/Compiler.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/no-empty-function */ -import { Project } from "./Project"; +import { Web3ApiProject } from "./project"; import { SchemaComposer } from "./SchemaComposer"; import { withSpinner, @@ -9,6 +9,7 @@ import { generateDockerfile, createBuildImage, copyArtifactsFromBuildImage, + manifestLanguageToTargetLanguage, } from "./helpers"; import { intlMsg } from "./intl"; @@ -17,250 +18,299 @@ import { Web3ApiManifest, BuildManifest, } from "@web3api/core-js"; -import { - bindSchema, - writeDirectory, - BindModuleOptions, -} from "@web3api/schema-bind"; +import { WasmWeb3Api } from "@web3api/client-js"; +import { AsyncWasmInstance } from "@web3api/asyncify-js"; +import { bindSchema, writeDirectory } from "@web3api/schema-bind"; import { TypeInfo } from "@web3api/schema-parse"; import { ComposerOutput } from "@web3api/schema-compose"; import { writeFileSync } from "@web3api/os-js"; +import * as gluegun from "gluegun"; import fs from "fs"; import path from "path"; -import * as gluegun from "gluegun"; // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports const fsExtra = require("fs-extra"); +type ModulesToBuild = Record; + +interface CompilerState { + web3ApiManifest: Web3ApiManifest; + composerOutput: ComposerOutput; + modulesToBuild: ModulesToBuild; +} + export interface CompilerConfig { outputDir: string; - project: Project; + project: Web3ApiProject; schemaComposer: SchemaComposer; } export class Compiler { constructor(private _config: CompilerConfig) {} - public async compile(): Promise { - try { - // Compile the API - await this._compileWeb3Api(); - - return true; - } catch (e) { - gluegun.print.error(e); - return false; - } - } + public async codegen(): Promise { + const { project } = this._config; - public reset(): void { - this._config.project.reset(); - this._config.schemaComposer.reset(); + const run = async (): Promise => { + const state = await this._getCompilerState(); + + if (!(await this._isInterface())) { + // Generate the bindings + await this._generateCode(state); + } + }; + + if (project.quiet) { + try { + await run(); + return true; + } catch (e) { + gluegun.print.error(e); + return false; + } + } else { + try { + await withSpinner( + intlMsg.lib_compiler_codegenText(), + intlMsg.lib_compiler_codegenError(), + intlMsg.lib_compiler_codegenWarning(), + async () => { + return run(); + } + ); + return true; + } catch (e) { + gluegun.print.error(e); + return false; + } + } } - private async _compileWeb3Api() { - const { project, schemaComposer } = this._config; + public async compile(): Promise { + const { project } = this._config; const run = async (): Promise => { - // Init & clean build directory - this._cleanDir(this._config.outputDir); + const state = await this._getCompilerState(); - const web3apiManifest = await project.getWeb3ApiManifest(); + // Init & clean output directory + this._cleanDir(this._config.outputDir); - // Get the fully composed schema - const composerOutput = await schemaComposer.getComposedSchemas(); + await this._outputComposedSchema(state); - if (!composerOutput.combined) { - throw Error(intlMsg.lib_compiler_failedSchemaReturn()); - } + let buildManifest: BuildManifest | undefined = undefined; - const modulesToBuild = this._determineModulesToBuild(web3apiManifest); + if (!(await this._isInterface())) { + // Generate the bindings + await this._generateCode(state); - if (modulesToBuild.length === 0) { - throw new Error(intlMsg.lib_compiler_noModulesToBuild()); + // Compile the API + buildManifest = await this._buildModules(state); } - // Generate the schema bindings and output the built WASM modules - await this._generateAndBuildModules( - web3apiManifest, - composerOutput, - modulesToBuild - ); + await this._outputManifests(state.web3ApiManifest, buildManifest); }; if (project.quiet) { - return run(); + try { + await run(); + return true; + } catch (e) { + gluegun.print.error(e); + return false; + } } else { - return await withSpinner( - intlMsg.lib_compiler_compileText(), - intlMsg.lib_compiler_compileError(), - intlMsg.lib_compiler_compileWarning(), - async () => { - return run(); - } - ); + try { + await withSpinner( + intlMsg.lib_compiler_compileText(), + intlMsg.lib_compiler_compileError(), + intlMsg.lib_compiler_compileWarning(), + async () => { + return run(); + } + ); + return true; + } catch (e) { + gluegun.print.error(e); + return false; + } } } - private async _generateAndBuildModules( - web3apiManifest: Web3ApiManifest, - composerOutput: ComposerOutput, - modulesToBuild: InvokableModules[] - ) { - const { outputDir, project } = this._config; - const buildQuery = modulesToBuild.indexOf("query") > -1; - const buildMutation = modulesToBuild.indexOf("mutation") > -1; - const isInterface = !!web3apiManifest.interface; + public reset(): void { + this._config.project.reset(); + this._config.schemaComposer.reset(); + } + + private async _getCompilerState(): Promise { + const { project } = this._config; - this._validateBuildConfig( - web3apiManifest, + // Get the Web3ApiManifest + const web3ApiManifest = await project.getWeb3ApiManifest(); + + // Determine what modules to build + const modulesToBuild = this._getModulesToBuild(web3ApiManifest); + + // Compose the schema + const composerOutput = await this._composeSchema(); + + const state: CompilerState = { + web3ApiManifest: Object.assign({}, web3ApiManifest), composerOutput, - buildQuery, - buildMutation, - isInterface - ); + modulesToBuild, + }; - if (isInterface) { - // Output the schema & manifest files - writeFileSync( - `${outputDir}/schema.graphql`, - composerOutput.combined.schema, - "utf-8" - ); + this._validateState(state); - const outputWeb3ApiManifest = Object.assign({}, web3apiManifest); + return state; + } - if (buildQuery) { - const queryManifest = outputWeb3ApiManifest as Required< - typeof outputWeb3ApiManifest - >; - queryManifest.modules.query = { - schema: "./schema.graphql", - }; - } + private async _isInterface(): Promise { + const state = await this._getCompilerState(); + return state.web3ApiManifest.language === "interface"; + } - if (buildMutation) { - const mutationManifest = outputWeb3ApiManifest as Required< - typeof outputWeb3ApiManifest - >; - mutationManifest.modules.mutation = { - schema: "./schema.graphql", - }; - } + private async _composeSchema(): Promise { + const { schemaComposer } = this._config; - await outputManifest( - outputWeb3ApiManifest, - `${outputDir}/web3api.yaml`, - project.quiet - ); - } else { - const queryModule = web3apiManifest.modules.query?.module as string; - const queryDirectory = web3apiManifest.modules.query - ? this._getGenerationDirectory(queryModule) - : undefined; - const mutationModule = web3apiManifest.modules.mutation?.module as string; - const mutationDirectory = web3apiManifest.modules.mutation - ? this._getGenerationDirectory(mutationModule) - : undefined; - - if ( - queryDirectory && - mutationDirectory && - queryDirectory === mutationDirectory - ) { - throw Error( - intlMsg.lib_compiler_dup_code_folder({ directory: queryDirectory }) - ); - } + // Get the fully composed schema + const composerOutput = await schemaComposer.getComposedSchemas(); - this._generateCode( - buildQuery - ? { - typeInfo: composerOutput.query?.typeInfo as TypeInfo, - outputDirAbs: queryDirectory as string, - } - : undefined, - buildMutation - ? { - typeInfo: composerOutput.mutation?.typeInfo as TypeInfo, - outputDirAbs: mutationDirectory as string, - } - : undefined - ); + if (!composerOutput.combined) { + throw Error(intlMsg.lib_compiler_failedSchemaReturn()); + } - // Build the sources - const dockerImageId = await this._buildSourcesInDocker(); + return composerOutput; + } - // Validate the WASM exports - await Promise.all( - modulesToBuild.map((module) => this._validateExports(module, outputDir)) - ); + private async _generateCode(state: CompilerState): Promise { + const { web3ApiManifest, composerOutput, modulesToBuild } = state; - // Output the schema & manifest files - writeFileSync( - `${outputDir}/schema.graphql`, - composerOutput.combined.schema, - "utf-8" + const queryModule = web3ApiManifest.modules.query?.module as string; + const queryDirectory = web3ApiManifest.modules.query + ? this._getGenerationDirectory(queryModule) + : undefined; + const mutationModule = web3ApiManifest.modules.mutation?.module as string; + const mutationDirectory = web3ApiManifest.modules.mutation + ? this._getGenerationDirectory(mutationModule) + : undefined; + + if ( + queryDirectory && + mutationDirectory && + queryDirectory === mutationDirectory + ) { + throw Error( + intlMsg.lib_compiler_dup_code_folder({ directory: queryDirectory }) ); + } - const outputWeb3ApiManifest = Object.assign({}, web3apiManifest); + // Clean the code generation + if (queryDirectory) { + this._cleanDir(queryDirectory); + } - if (buildQuery) { - const queryManifest = outputWeb3ApiManifest as Required< - typeof outputWeb3ApiManifest - >; - queryManifest.modules.query = { - module: "./query.wasm", - schema: "./schema.graphql", - }; - } + if (mutationDirectory) { + this._cleanDir(mutationDirectory); + } - if (buildMutation) { - const mutationManifest = outputWeb3ApiManifest as Required< - typeof outputWeb3ApiManifest - >; - mutationManifest.modules.mutation = { - module: "./mutation.wasm", - schema: "./schema.graphql", - }; - } + // Generate the bindings + const output = bindSchema({ + language: web3ApiManifest.language + ? manifestLanguageToTargetLanguage(web3ApiManifest.language) + : "wasm-as", + query: modulesToBuild.query + ? { + typeInfo: composerOutput.query?.typeInfo as TypeInfo, + schema: composerOutput.combined?.schema as string, + outputDirAbs: queryDirectory as string, + } + : undefined, + mutation: modulesToBuild.mutation + ? { + typeInfo: composerOutput.mutation?.typeInfo as TypeInfo, + schema: composerOutput.combined?.schema as string, + outputDirAbs: mutationDirectory as string, + } + : undefined, + }); - outputWeb3ApiManifest.build = "./web3api.build.yaml"; + // Output the bindings + const filesWritten: string[] = []; - await outputManifest( - outputWeb3ApiManifest, - `${outputDir}/web3api.yaml`, - project.quiet - ); + if (output.query && queryDirectory) { + filesWritten.push(...writeDirectory(queryDirectory, output.query)); + } - const outputBuildManifest: BuildManifest = { - format: "0.0.1-prealpha.2", - docker: { - buildImageId: dockerImageId, - }, + if (output.mutation && mutationDirectory) { + filesWritten.push(...writeDirectory(mutationDirectory, output.mutation)); + } + + return filesWritten; + } + + private async _buildModules(state: CompilerState): Promise { + const { outputDir } = this._config; + const { web3ApiManifest, modulesToBuild } = state; + + if (await this._isInterface()) { + throw Error(intlMsg.lib_compiler_cannotBuildInterfaceModules()); + } + + // Build the sources + const dockerImageId = await this._buildSourcesInDocker(); + + // Validate the WASM exports + await Promise.all( + Object.keys(modulesToBuild) + .filter((module: InvokableModules) => modulesToBuild[module]) + .map((module: InvokableModules) => + this._validateExports(module, outputDir) + ) + ); + + // Update the Web3ApiManifest + if (modulesToBuild.query && web3ApiManifest.modules.query) { + web3ApiManifest.modules.query = { + module: "./query.wasm", + schema: "./schema.graphql", }; + } - await outputManifest( - outputBuildManifest, - `${outputDir}/web3api.build.yaml`, - project.quiet - ); + if (modulesToBuild.mutation && web3ApiManifest.modules.mutation) { + web3ApiManifest.modules.mutation = { + module: "./mutation.wasm", + schema: "./schema.graphql", + }; } + + web3ApiManifest.build = "./web3api.build.yaml"; + + // Create the BuildManifest + const buildManifest: BuildManifest = { + format: "0.0.1-prealpha.1", + __type: "BuildManifest", + docker: { + buildImageId: dockerImageId, + }, + }; + + return buildManifest; } - private _determineModulesToBuild( - manifest: Web3ApiManifest - ): InvokableModules[] { + private _getModulesToBuild(manifest: Web3ApiManifest): ModulesToBuild { const manifestMutation = manifest.modules.mutation; const manifestQuery = manifest.modules.query; - const modulesToBuild: InvokableModules[] = []; + const modulesToBuild: ModulesToBuild = { + mutation: false, + query: false, + }; if (manifestMutation) { - modulesToBuild.push("mutation"); + modulesToBuild.mutation = true; } if (manifestQuery) { - modulesToBuild.push("query"); + modulesToBuild.query = true; } return modulesToBuild; @@ -275,42 +325,6 @@ export class Compiler { return `${path.dirname(absolute)}/w3`; } - private _generateCode( - query?: BindModuleOptions, - mutation?: BindModuleOptions - ): string[] { - // Clean the code generation - if (query) { - this._cleanDir(query.outputDirAbs); - } - - if (mutation) { - this._cleanDir(mutation.outputDirAbs); - } - - // Generate the bindings - const output = bindSchema({ - language: "wasm-as", - query, - mutation, - }); - - // Output the bindings - const filesWritten: string[] = []; - - if (query && output.query) { - filesWritten.push(...writeDirectory(query.outputDirAbs, output.query)); - } - - if (mutation && output.mutation) { - filesWritten.push( - ...writeDirectory(mutation.outputDirAbs, output.mutation) - ); - } - - return filesWritten; - } - private async _buildSourcesInDocker(): Promise { const { project, outputDir } = this._config; const buildManifestDir = await project.getBuildManifestDir(); @@ -360,13 +374,58 @@ export class Compiler { fsExtra.emptyDirSync(dir); } - private _validateBuildConfig( - web3apiManifest: Web3ApiManifest, - composerOutput: ComposerOutput, - buildQuery: boolean, - buildMutation: boolean, - isInterface: boolean - ) { + private async _outputComposedSchema(state: CompilerState): Promise { + const { outputDir } = this._config; + + writeFileSync( + `${outputDir}/schema.graphql`, + state.composerOutput.combined.schema, + "utf-8" + ); + + // Update the Web3ApiManifest schema paths + if (state.modulesToBuild.query && state.web3ApiManifest.modules.query) { + state.web3ApiManifest.modules.query = { + schema: "./schema.graphql", + module: state.web3ApiManifest.modules.query.module, + }; + } + + if ( + state.modulesToBuild.mutation && + state.web3ApiManifest.modules.mutation + ) { + state.web3ApiManifest.modules.mutation = { + schema: "./schema.graphql", + module: state.web3ApiManifest.modules.mutation.module, + }; + } + } + + private async _outputManifests( + web3ApiManifest: Web3ApiManifest, + buildManifest?: BuildManifest + ): Promise { + const { outputDir, project } = this._config; + + await outputManifest( + web3ApiManifest, + `${outputDir}/web3api.yaml`, + project.quiet + ); + + if (buildManifest) { + await outputManifest( + buildManifest, + `${outputDir}/web3api.build.yaml`, + project.quiet + ); + } + } + + private _validateState(state: CompilerState) { + const { composerOutput, modulesToBuild, web3ApiManifest } = state; + const throwMissingSchema = (moduleName: string) => { const missingSchemaMessage = intlMsg.lib_compiler_missingSchema({ name: `"${moduleName}"`, @@ -374,12 +433,15 @@ export class Compiler { throw Error(missingSchemaMessage); }; - if (buildQuery && (!composerOutput.query || !composerOutput.query.schema)) { + if ( + modulesToBuild.query && + (!composerOutput.query || !composerOutput.query.schema) + ) { throwMissingSchema("query"); } if ( - buildMutation && + modulesToBuild.mutation && (!composerOutput.mutation || !composerOutput.mutation.schema) ) { throwMissingSchema("mutation"); @@ -392,14 +454,18 @@ export class Compiler { throw Error(missingModuleMessage); }; - if (buildQuery && !isInterface && !web3apiManifest.modules.query?.module) { + if ( + modulesToBuild.query && + web3ApiManifest.language !== "interface" && + !web3ApiManifest.modules.query?.module + ) { throwMissingModule("query"); } if ( - buildMutation && - !isInterface && - !web3apiManifest.modules.mutation?.module + modulesToBuild.mutation && + web3ApiManifest.language !== "interface" && + !web3ApiManifest.modules.mutation?.module ) { throwMissingModule("mutation"); } @@ -411,11 +477,17 @@ export class Compiler { throw Error(noInterfaceModule); }; - if (isInterface && web3apiManifest.modules.query?.module) { + if ( + web3ApiManifest.language === "interface" && + web3ApiManifest.modules.query?.module + ) { throwNoInterfaceModule("query"); } - if (isInterface && web3apiManifest.modules.mutation?.module) { + if ( + web3ApiManifest.language === "interface" && + web3ApiManifest.modules.mutation?.module + ) { throwNoInterfaceModule("mutation"); } } @@ -424,7 +496,6 @@ export class Compiler { moduleName: InvokableModules, buildDir: string ): Promise { - let missingExport: string | undefined; const wasmSource = fs.readFileSync( path.join(buildDir, `${moduleName}.wasm`) ); @@ -449,21 +520,34 @@ export class Compiler { }, }); - if (!instance.exports._w3_init) { - missingExport = "_w3_init"; - } + const requiredExports = [ + ...WasmWeb3Api.requiredExports, + ...AsyncWasmInstance.requiredExports, + ]; + const missingExports: string[] = []; - if (!instance.exports._w3_invoke) { - missingExport = "_w3_invoke"; - } - - if (!instance.exports.w3Abort) { - missingExport = "w3Abort"; + for (const requiredExport of requiredExports) { + if (!instance.exports[requiredExport]) { + missingExports.push(requiredExport); + } } - if (missingExport) { + if (missingExports.length) { throw Error( - intlMsg.lib_compiler_missing_export({ missingExport, moduleName }) + intlMsg.lib_compiler_missing_export({ + missingExport: missingExports + .map((missingExport, index) => { + if (missingExports.length === 1) { + return missingExport; + } else if (index === missingExports.length - 1) { + return "& " + missingExport; + } else { + return missingExport + ", "; + } + }) + .join(), + moduleName, + }) ); } } diff --git a/packages/cli/src/lib/SchemaComposer.ts b/packages/cli/src/lib/SchemaComposer.ts index f31028c0c9..31e8d85eb6 100644 --- a/packages/cli/src/lib/SchemaComposer.ts +++ b/packages/cli/src/lib/SchemaComposer.ts @@ -1,18 +1,14 @@ /* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/no-empty-function */ -import { Project } from "./Project"; +import { Project } from "./project"; -import { - Uri, - Web3ApiClient, - PluginRegistration, - Web3ApiManifest, -} from "@web3api/client-js"; +import { Uri, Web3ApiClient, PluginRegistration } from "@web3api/client-js"; import { composeSchema, ComposerOutput, ComposerFilter, + ComposerOptions, } from "@web3api/schema-compose"; import { ensPlugin } from "@web3api/ens-plugin-js"; import { ethereumPlugin } from "@web3api/ethereum-plugin-js"; @@ -22,7 +18,7 @@ import path from "path"; import * as gluegun from "gluegun"; import { SchemaFile } from "@web3api/schema-compose"; -export interface SchemaConfig { +export interface SchemaComposerConfig { project: Project; // TODO: add this to the project configuration @@ -36,7 +32,7 @@ export class SchemaComposer { private _client: Web3ApiClient; private _composerOutput: ComposerOutput | undefined; - constructor(private _config: SchemaConfig) { + constructor(private _config: SchemaComposerConfig) { const { ensAddress, ethProvider, ipfsProvider } = this._config; const plugins: PluginRegistration[] = []; @@ -86,10 +82,10 @@ export class SchemaComposer { const { project } = this._config; - const manifest = await project.getWeb3ApiManifest(); - const querySchemaPath = manifest.modules.query?.schema; - const mutationSchemaPath = manifest.modules.mutation?.schema; - const getSchema = (schemaPath?: string): SchemaFile | undefined => + const schemaNamedPaths = await project.getSchemaNamedPaths(); + const import_redirects = await project.getImportRedirects(); + + const getSchemaFile = (schemaPath?: string): SchemaFile | undefined => schemaPath ? { schema: this._fetchLocalSchema(schemaPath), @@ -97,17 +93,28 @@ export class SchemaComposer { } : undefined; - this._composerOutput = await composeSchema({ - schemas: { - query: getSchema(querySchemaPath), - mutation: getSchema(mutationSchemaPath), - }, + const options: ComposerOptions = { + schemas: {}, resolvers: { - external: (uri: string) => this._fetchExternalSchema(uri, manifest), + external: (uri: string) => + this._fetchExternalSchema(uri, import_redirects), local: (path: string) => Promise.resolve(this._fetchLocalSchema(path)), }, output, - }); + }; + + for (const name of Object.keys(schemaNamedPaths)) { + const schemaPath = schemaNamedPaths[name]; + const schemaFile = getSchemaFile(schemaPath); + + if (!schemaFile) { + throw Error(`Schema "${name}" cannot be loaded at path: ${schemaPath}`); + } + + options.schemas[name] = schemaFile; + } + + this._composerOutput = await composeSchema(options); return this._composerOutput; } @@ -118,11 +125,14 @@ export class SchemaComposer { private async _fetchExternalSchema( uri: string, - manifest: Web3ApiManifest + import_redirects?: { + uri: string; + schema: string; + }[] ): Promise { // Check to see if we have any import redirects that match - if (manifest.import_redirects) { - for (const redirect of manifest.import_redirects) { + if (import_redirects) { + for (const redirect of import_redirects) { const redirectUri = new Uri(redirect.uri); const uriParsed = new Uri(uri); @@ -145,7 +155,7 @@ export class SchemaComposer { return fs.readFileSync( path.isAbsolute(schemaPath) ? schemaPath - : path.join(this._config.project.getWeb3ApiManifestDir(), schemaPath), + : path.join(this._config.project.getRootDir(), schemaPath), "utf-8" ); } diff --git a/packages/cli/src/lib/build-envs/wasm/assemblyscript/web3api.build.yaml b/packages/cli/src/lib/build-envs/wasm/assemblyscript/web3api.build.yaml index 64d8d19fbd..ad72523cd7 100644 --- a/packages/cli/src/lib/build-envs/wasm/assemblyscript/web3api.build.yaml +++ b/packages/cli/src/lib/build-envs/wasm/assemblyscript/web3api.build.yaml @@ -1,4 +1,4 @@ -format: 0.0.1-prealpha.2 +format: 0.0.1-prealpha.1 docker: name: build-env dockerfile: ./Dockerfile.mustache diff --git a/packages/cli/src/lib/helpers/index.ts b/packages/cli/src/lib/helpers/index.ts index 6cf756325d..8afb73c928 100644 --- a/packages/cli/src/lib/helpers/index.ts +++ b/packages/cli/src/lib/helpers/index.ts @@ -3,3 +3,5 @@ export * from "./manifest"; export * from "./parameters"; export * from "./spinner"; export * from "./docker"; +export * from "./language"; +export * from "./typescript-support"; diff --git a/packages/cli/src/lib/helpers/language.ts b/packages/cli/src/lib/helpers/language.ts new file mode 100644 index 0000000000..c378294963 --- /dev/null +++ b/packages/cli/src/lib/helpers/language.ts @@ -0,0 +1,20 @@ +import { intlMsg } from "../intl"; + +import { TargetLanguage } from "@web3api/schema-bind"; + +export function manifestLanguageToTargetLanguage( + manifestLanguage: string +): TargetLanguage { + switch (manifestLanguage) { + case "wasm/assemblyscript": + return "wasm-as"; + case "plugin/typescript": + return "plugin-ts"; + default: + throw Error( + intlMsg.lib_language_unsupportedManifestLanguage({ + language: manifestLanguage, + }) + ); + } +} diff --git a/packages/cli/src/lib/helpers/manifest.ts b/packages/cli/src/lib/helpers/manifest.ts index daae688fa4..3c51c0a783 100644 --- a/packages/cli/src/lib/helpers/manifest.ts +++ b/packages/cli/src/lib/helpers/manifest.ts @@ -1,6 +1,5 @@ import { displayPath } from "./path"; import { withSpinner } from "./spinner"; -import { Project } from "../Project"; import { intlMsg } from "../intl"; import { @@ -8,6 +7,8 @@ import { Web3ApiManifest, deserializeWeb3ApiManifest, deserializeBuildManifest, + deserializePluginManifest, + PluginManifest, } from "@web3api/core-js"; import { writeFileSync, normalizePath } from "@web3api/os-js"; import { Schema as JsonSchema } from "jsonschema"; @@ -54,7 +55,6 @@ export async function loadWeb3ApiManifest( export async function loadBuildManifest( manifestPath: string, - project: Project, quiet = false ): Promise { const run = (): Promise => { @@ -108,6 +108,43 @@ export async function loadBuildManifest( } } +export async function loadPluginManifest( + manifestPath: string, + quiet = false +): Promise { + const run = (): Promise => { + const manifest = fs.readFileSync(manifestPath, "utf-8"); + + if (!manifest) { + const noLoadMessage = intlMsg.lib_helpers_manifest_unableToLoad({ + path: `${manifestPath}`, + }); + throw Error(noLoadMessage); + } + + try { + const result = deserializePluginManifest(manifest); + return Promise.resolve(result); + } catch (e) { + return Promise.reject(e); + } + }; + + if (quiet) { + return await run(); + } else { + manifestPath = displayPath(manifestPath); + return (await withSpinner( + intlMsg.lib_helpers_manifest_loadText({ path: manifestPath }), + intlMsg.lib_helpers_manifest_loadError({ path: manifestPath }), + intlMsg.lib_helpers_manifest_loadWarning({ path: manifestPath }), + async (_spinner) => { + return await run(); + } + )) as PluginManifest; + } +} + export async function outputManifest( manifest: Web3ApiManifest | BuildManifest, manifestPath: string, @@ -136,7 +173,7 @@ export async function outputManifest( if (result) { newObj[key] = result; } - } else { + } else if (!key.startsWith("__")) { newObj[key] = input[key]; } } diff --git a/packages/cli/src/lib/helpers/spinner.ts b/packages/cli/src/lib/helpers/spinner.ts index fd99e00fab..4dd49de557 100644 --- a/packages/cli/src/lib/helpers/spinner.ts +++ b/packages/cli/src/lib/helpers/spinner.ts @@ -10,12 +10,12 @@ import { Ora } from "ora"; // spinner stops with the warning message and returns the `result` value. // Otherwise the spinner prints the in-progress message with a check mark // and simply returns the value returned by `f`. -export const withSpinner = async ( +export const withSpinner = async ( text: string, errorText: string, warningText: string, - execute: (spinner: Ora) => Promise -): Promise => { + execute: (spinner: Ora) => Promise +): Promise => { const spinner = gluegun.print.spin({ text, stream: process.stdout, @@ -31,7 +31,7 @@ export const withSpinner = async ( spinner.warn(`${warningText}: ${res.warning}`); } spinner.succeed(text); - return res.result; + return res.result as TReturn; } else { spinner.succeed(text); return result; diff --git a/packages/cli/src/lib/helpers/typescript-support.ts b/packages/cli/src/lib/helpers/typescript-support.ts new file mode 100644 index 0000000000..3c7013b372 --- /dev/null +++ b/packages/cli/src/lib/helpers/typescript-support.ts @@ -0,0 +1,30 @@ +/* eslint-disable @typescript-eslint/no-require-imports */ +import { intlMsg } from "../intl"; + +export function loadTsNode(): void { + try { + require.resolve("typescript"); + } catch (error) { + throw new Error(intlMsg.lib_typescript_notInstalled()); + } + + try { + require.resolve("ts-node"); + } catch (error) { + throw new Error(intlMsg.lib_typescript_tsNodeNotInstalled()); + } + + // If we are running tests we just want to transpile + if (process.env.TEST) { + // eslint-disable-next-line import/no-extraneous-dependencies + require("ts-node/register/transpile-only"); + return; + } + + // eslint-disable-next-line import/no-extraneous-dependencies + require("ts-node/register"); +} + +export function isTypescriptFile(path: string): boolean { + return path.endsWith(".ts"); +} diff --git a/packages/cli/src/lib/index.ts b/packages/cli/src/lib/index.ts index bc09542bb3..1367fc6f6b 100644 --- a/packages/cli/src/lib/index.ts +++ b/packages/cli/src/lib/index.ts @@ -1,4 +1,4 @@ -export * from "./Project"; +export * from "./project"; export * from "./Compiler"; export * from "./CodeGenerator"; export * from "./SchemaComposer"; diff --git a/packages/cli/src/lib/project/PluginProject.ts b/packages/cli/src/lib/project/PluginProject.ts new file mode 100644 index 0000000000..06deaf4c73 --- /dev/null +++ b/packages/cli/src/lib/project/PluginProject.ts @@ -0,0 +1,79 @@ +import { Project, ProjectConfig } from "./Project"; +import { + loadPluginManifest, + manifestLanguageToTargetLanguage, +} from "../helpers"; + +import { PluginManifest } from "@web3api/core-js"; +import { TargetLanguage } from "@web3api/schema-bind"; +import path from "path"; + +export interface PluginProjectConfig extends ProjectConfig { + pluginManifestPath: string; +} + +export class PluginProject extends Project { + private _pluginManifest: PluginManifest | undefined; + + constructor(protected _config: PluginProjectConfig) { + super(_config); + } + + /// Project Base Methods + + public reset(): void { + this._pluginManifest = undefined; + } + + public getRootDir(): string { + return this.getPluginManifestDir(); + } + + public async getLanguage(): Promise { + const language = (await this.getPluginManifest()).language; + return manifestLanguageToTargetLanguage(language); + } + + public async getSchemaNamedPaths(): Promise<{ + [name: string]: string; + }> { + const manifest = await this.getPluginManifest(); + const dir = this.getPluginManifestDir(); + const namedPaths: { [name: string]: string } = {}; + + namedPaths["combined"] = path.join(dir, manifest.schema); + loadPluginManifest; + return namedPaths; + } + + public async getImportRedirects(): Promise< + { + uri: string; + schema: string; + }[] + > { + const manifest = await this.getPluginManifest(); + return manifest.import_redirects || []; + } + + /// Plugin Manifest (web3api.plugin.yaml) + + public getPluginManifestPath(): string { + return this._config.pluginManifestPath; + } + + public getPluginManifestDir(): string { + return path.dirname(this._config.pluginManifestPath); + } + + public async getPluginManifest(): Promise { + if (!this._pluginManifest) { + this._pluginManifest = await loadPluginManifest( + this.getPluginManifestPath(), + this.quiet + ); + } + + return Promise.resolve(this._pluginManifest); + } +} diff --git a/packages/cli/src/lib/project/Project.ts b/packages/cli/src/lib/project/Project.ts new file mode 100644 index 0000000000..82e8d6e8d0 --- /dev/null +++ b/packages/cli/src/lib/project/Project.ts @@ -0,0 +1,81 @@ +import fs from "fs"; +import path from "path"; +import rimraf from "rimraf"; +import copyfiles from "copyfiles"; +import { TargetLanguage } from "@web3api/schema-bind"; + +export interface ProjectConfig { + quiet?: boolean; +} + +export abstract class Project { + constructor(protected _config: ProjectConfig) {} + + public get quiet(): boolean { + return !!this._config.quiet; + } + + /// Cache (.w3 folder) + + public getCacheDir(): string { + return path.join(this.getRootDir(), ".w3"); + } + + public readCacheFile(file: string): string | undefined { + const filePath = path.join(this.getCacheDir(), file); + + if (!fs.existsSync(filePath)) { + return undefined; + } + + return fs.readFileSync(filePath, "utf-8"); + } + + public removeCacheDir(subfolder: string): void { + const folderPath = path.join(this.getCacheDir(), subfolder); + rimraf.sync(folderPath); + } + + public getCachePath(subpath: string): string { + return path.join(this.getCacheDir(), subpath); + } + + public async copyFilesIntoCache( + destSubfolder: string, + sourceFolder: string + ): Promise { + const dest = this.getCachePath(destSubfolder); + + if (!fs.existsSync(dest)) { + fs.mkdirSync(dest, { recursive: true }); + } + + await new Promise((resolve, reject) => { + copyfiles([sourceFolder, dest], { up: true }, (error) => { + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); + } + + /// Abstract Interface + public abstract reset(): void; + + public abstract getRootDir(): string; + + public abstract getLanguage(): Promise; + + public abstract getSchemaNamedPaths(): Promise<{ + [name: string]: string; + }>; + + public abstract getImportRedirects(): Promise< + { + uri: string; + schema: string; + }[] + >; +} diff --git a/packages/cli/src/lib/Project.ts b/packages/cli/src/lib/project/Web3ApiProject.ts similarity index 77% rename from packages/cli/src/lib/Project.ts rename to packages/cli/src/lib/project/Web3ApiProject.ts index 53f4d79858..e7719d5042 100644 --- a/packages/cli/src/lib/Project.ts +++ b/packages/cli/src/lib/project/Web3ApiProject.ts @@ -1,36 +1,31 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { loadWeb3ApiManifest, loadBuildManifest } from "./helpers"; -import { intlMsg } from "./intl"; +import { Project, ProjectConfig } from "./Project"; +import { + loadWeb3ApiManifest, + loadBuildManifest, + manifestLanguageToTargetLanguage, +} from "../helpers"; +import { intlMsg } from "../intl"; import { Web3ApiManifest, BuildManifest } from "@web3api/core-js"; +import { TargetLanguage } from "@web3api/schema-bind"; import { normalizePath } from "@web3api/os-js"; import path from "path"; import fs from "fs"; -import rimraf from "rimraf"; -import copyfiles from "copyfiles"; -export interface ProjectConfig { +export interface Web3ApiProjectConfig extends ProjectConfig { web3apiManifestPath: string; buildManifestPath?: string; - quiet?: boolean; } -export class Project { +export class Web3ApiProject extends Project { private _web3apiManifest: Web3ApiManifest | undefined; private _buildManifest: BuildManifest | undefined; private _defaultBuildManifestCached = false; - constructor(private _config: ProjectConfig) {} - - get quiet(): boolean { - return !!this._config.quiet; - } - - public reset(): void { - this._web3apiManifest = undefined; - this._buildManifest = undefined; - this._defaultBuildManifestCached = false; + constructor(protected _config: Web3ApiProjectConfig) { + super(_config); } public async getManifestPaths(absolute = false): Promise { @@ -45,6 +40,51 @@ export class Project { ]; } + /// Project Base Methods + + public reset(): void { + this._web3apiManifest = undefined; + this._buildManifest = undefined; + this._defaultBuildManifestCached = false; + } + + public getRootDir(): string { + return this.getWeb3ApiManifestDir(); + } + + public async getLanguage(): Promise { + const language = (await this.getWeb3ApiManifest()).language; + return manifestLanguageToTargetLanguage(language); + } + + public async getSchemaNamedPaths(): Promise<{ + [name: string]: string; + }> { + const manifest = await this.getWeb3ApiManifest(); + const dir = this.getWeb3ApiManifestDir(); + const namedPaths: { [name: string]: string } = {}; + + if (manifest.modules.mutation) { + namedPaths["mutation"] = path.join(dir, manifest.modules.mutation.schema); + } + + if (manifest.modules.query) { + namedPaths["query"] = path.join(dir, manifest.modules.query.schema); + } + + return namedPaths; + } + + public async getImportRedirects(): Promise< + { + uri: string; + schema: string; + }[] + > { + const manifest = await this.getWeb3ApiManifest(); + return manifest.import_redirects || []; + } + /// Web3API Manifest (web3api.yaml) public getWeb3ApiManifestPath(): string { @@ -150,7 +190,6 @@ export class Project { if (!this._buildManifest) { this._buildManifest = await loadBuildManifest( await this.getBuildManifestPath(), - this, this.quiet ); @@ -195,7 +234,7 @@ export class Project { throw Error(intlMsg.lib_project_language_not_found()); } - const defaultPath = `${__dirname}/build-envs/${language}/web3api.build.yaml`; + const defaultPath = `${__dirname}/../build-envs/${language}/web3api.build.yaml`; if (!fs.existsSync(defaultPath)) { throw Error( @@ -207,54 +246,8 @@ export class Project { this.removeCacheDir("build/env"); await this.copyFilesIntoCache( "build/env/", - `${__dirname}/build-envs/${language}/*` + `${__dirname}/../build-envs/${language}/*` ); this._defaultBuildManifestCached = true; } - - /// Cache (.w3 folder) - - public getCacheDir(): string { - return path.join(this.getWeb3ApiManifestDir(), ".w3"); - } - - public readCacheFile(file: string): string | undefined { - const filePath = path.join(this.getCacheDir(), file); - - if (!fs.existsSync(filePath)) { - return undefined; - } - - return fs.readFileSync(filePath, "utf-8"); - } - - public removeCacheDir(subfolder: string): void { - const folderPath = path.join(this.getCacheDir(), subfolder); - rimraf.sync(folderPath); - } - - public getCachePath(subpath: string): string { - return path.join(this.getCacheDir(), subpath); - } - - public async copyFilesIntoCache( - destSubfolder: string, - sourceFolder: string - ): Promise { - const dest = this.getCachePath(destSubfolder); - - if (!fs.existsSync(dest)) { - fs.mkdirSync(dest, { recursive: true }); - } - - await new Promise((resolve, reject) => { - copyfiles([sourceFolder, dest], { up: true }, (error) => { - if (error) { - reject(error); - } else { - resolve(); - } - }); - }); - } } diff --git a/packages/cli/src/lib/project/index.ts b/packages/cli/src/lib/project/index.ts new file mode 100644 index 0000000000..75af06fe7e --- /dev/null +++ b/packages/cli/src/lib/project/index.ts @@ -0,0 +1,3 @@ +export * from "./Project"; +export * from "./Web3ApiProject"; +export * from "./PluginProject"; diff --git a/packages/cli/src/lib/project-templates/index.ts b/packages/cli/src/lib/templates/index.ts similarity index 100% rename from packages/cli/src/lib/project-templates/index.ts rename to packages/cli/src/lib/templates/index.ts diff --git a/packages/core-interfaces/logger/web3api.yaml b/packages/core-interfaces/logger/web3api.yaml index a147deb3f1..ada4b79471 100644 --- a/packages/core-interfaces/logger/web3api.yaml +++ b/packages/core-interfaces/logger/web3api.yaml @@ -1,6 +1,6 @@ -format: 0.0.1-prealpha.3 +format: 0.0.1-prealpha.4 repository: https://github.com/web3-api/monorepo -interface: true +language: interface modules: query: schema: ./src/query.graphql diff --git a/packages/core-interfaces/uri-resolver/web3api.yaml b/packages/core-interfaces/uri-resolver/web3api.yaml index 69e4bdfbd4..47ab784f0b 100644 --- a/packages/core-interfaces/uri-resolver/web3api.yaml +++ b/packages/core-interfaces/uri-resolver/web3api.yaml @@ -1,5 +1,5 @@ -format: 0.0.1-prealpha.3 -interface: true +format: 0.0.1-prealpha.4 +language: interface modules: query: schema: ./src/query.graphql diff --git a/packages/js/asyncify/src/AsyncWasmInstance.ts b/packages/js/asyncify/src/AsyncWasmInstance.ts index 7580c3d6ec..37b4da6b84 100644 --- a/packages/js/asyncify/src/AsyncWasmInstance.ts +++ b/packages/js/asyncify/src/AsyncWasmInstance.ts @@ -41,11 +41,7 @@ enum AsyncifyState { } export class AsyncWasmInstance { - private static _dataAddr = 16; - private static _dataStart = AsyncWasmInstance._dataAddr + 8; - private static _dataEnd = 1024; - - private static _requiredExports: string[] = [ + public static requiredExports: readonly string[] = [ "asyncify_start_unwind", "asyncify_stop_unwind", "asyncify_start_rewind", @@ -53,6 +49,10 @@ export class AsyncWasmInstance { "asyncify_get_state", ]; + private static _dataAddr = 16; + private static _dataStart = AsyncWasmInstance._dataAddr + 8; + private static _dataEnd = 1024; + private _instance: WasmInstance; private _wrappedImports: WasmImports; private _wrappedExports: AsyncifyExports; @@ -61,7 +61,7 @@ export class AsyncWasmInstance { constructor(config: { module: WasmModule; imports: WasmImports; - requiredExports?: string[]; + requiredExports?: readonly string[]; }) { // Wrap imports this._wrappedImports = this._wrapImports(config.imports); @@ -75,7 +75,7 @@ export class AsyncWasmInstance { // Ensure all required exports exist on Wasm module const exportKeys = Object.keys(this._instance.exports); const missingExports = [ - ...AsyncWasmInstance._requiredExports, + ...AsyncWasmInstance.requiredExports, ...(config.requiredExports || []), ].filter((name) => !exportKeys.includes(name)); diff --git a/packages/js/client/package.json b/packages/js/client/package.json index 15939af0be..3baa7d024e 100644 --- a/packages/js/client/package.json +++ b/packages/js/client/package.json @@ -15,9 +15,9 @@ "build": "rimraf ./build && tsc --project tsconfig.build.json", "prebuild": "ts-node ./scripts/extractPluginConfigs.ts", "lint": "eslint --color --ext .ts src/", - "test": "cross-env TEST=true jest --passWithNoTests --runInBand --verbose=true", - "test:ci": "cross-env TEST=true jest --passWithNoTests --runInBand --verbose", - "test:watch": "cross-env TEST=true jest --watch --passWithNoTests --verbose" + "test": "jest --passWithNoTests --runInBand --verbose=true", + "test:ci": "jest --passWithNoTests --runInBand --verbose", + "test:watch": "jest --watch --passWithNoTests --verbose" }, "dependencies": { "@msgpack/msgpack": "2.3.0", @@ -38,12 +38,10 @@ "devDependencies": { "@types/jest": "26.0.8", "@types/js-yaml": "3.11.1", - "@types/semver": "^7.3.4", "@web3api/cli": "0.0.1-prealpha.31", "@web3api/os-js": "0.0.1-prealpha.31", "@web3api/test-cases": "0.0.1-prealpha.31", "@web3api/test-env-js": "0.0.1-prealpha.31", - "cross-env": "7.0.3", "jest": "26.6.3", "rimraf": "3.0.2", "ts-jest": "26.5.4", diff --git a/packages/js/client/src/Web3ApiClient.ts b/packages/js/client/src/Web3ApiClient.ts index f5b7748564..71958d1329 100644 --- a/packages/js/client/src/Web3ApiClient.ts +++ b/packages/js/client/src/Web3ApiClient.ts @@ -1,6 +1,6 @@ import { getDefaultClientConfig } from "./default-client-config"; import { PluginWeb3Api } from "./plugin/PluginWeb3Api"; -import { WasmWeb3Api } from "./wasm/WasmWeb3Api"; +import { WasmWeb3Api } from "./wasm"; import { Api, @@ -26,6 +26,8 @@ import { } from "@web3api/core-js"; import { Tracer } from "@web3api/tracing-js"; +export { WasmWeb3Api }; + export interface ClientConfig { redirects?: UriRedirect[]; plugins?: PluginRegistration[]; diff --git a/packages/js/client/src/wasm/WasmWeb3Api.ts b/packages/js/client/src/wasm/WasmWeb3Api.ts index 43da417523..dfd5faac36 100644 --- a/packages/js/client/src/wasm/WasmWeb3Api.ts +++ b/packages/js/client/src/wasm/WasmWeb3Api.ts @@ -36,6 +36,8 @@ export interface State { } export class WasmWeb3Api extends Api { + public static requiredExports: readonly string[] = ["_w3_init", "_w3_invoke"]; + private _schema?: string; private _wasm: { @@ -102,7 +104,7 @@ export class WasmWeb3Api extends Api { memory, abort, }), - requiredExports: ["_w3_init", "_w3_invoke"], + requiredExports: WasmWeb3Api.requiredExports, }); const exports = instance.exports as W3Exports; diff --git a/packages/js/client/src/wasm/index.ts b/packages/js/client/src/wasm/index.ts new file mode 100644 index 0000000000..14999b16aa --- /dev/null +++ b/packages/js/client/src/wasm/index.ts @@ -0,0 +1 @@ +export { WasmWeb3Api } from "./WasmWeb3Api"; diff --git a/packages/js/core/package.json b/packages/js/core/package.json index 82ccb2411a..540c118a27 100644 --- a/packages/js/core/package.json +++ b/packages/js/core/package.json @@ -26,10 +26,11 @@ "graphql-tag": "2.10.4", "js-yaml": "3.14.0", "jsonschema": "1.4.0", - "semver": "7.3.4" + "semver": "7.3.5" }, "devDependencies": { "@types/jest": "26.0.8", + "@types/semver": "7.3.8", "@web3api/os-js": "0.0.1-prealpha.31", "jest": "26.6.3", "json-schema-to-typescript": "10.1.3", diff --git a/packages/js/core/scripts/manifest/deserialize-ts.mustache b/packages/js/core/scripts/manifest/deserialize-ts.mustache index acd6e75ad4..a2d12e5ce9 100644 --- a/packages/js/core/scripts/manifest/deserialize-ts.mustache +++ b/packages/js/core/scripts/manifest/deserialize-ts.mustache @@ -33,6 +33,8 @@ export const deserialize{{type}} = Tracer.traceFunc( validate{{type}}(any{{type}}, options?.extSchema); } + any{{type}}.__type = "{{type}}"; + const versionCompare = compare( any{{type}}.format, latest{{type}}Format diff --git a/packages/js/core/scripts/manifest/generateFormatTypes.js b/packages/js/core/scripts/manifest/generateFormatTypes.js index 37d47ef364..4443d7446c 100644 --- a/packages/js/core/scripts/manifest/generateFormatTypes.js +++ b/packages/js/core/scripts/manifest/generateFormatTypes.js @@ -37,6 +37,16 @@ async function generateFormatTypes() { fs.readFileSync(formatSchemaPath, { encoding: "utf-8" }) ); + // Insert the __type property for introspection + formatSchema.properties["__type"] = { + type: "string", + const: formatSchema.id + }; + formatSchema.required = [ + ...formatSchema.required, + "__type" + ]; + formatSchemas.push(formatSchema); // Convert it to a TypeScript interface diff --git a/packages/js/core/src/__tests__/Plugin.spec.ts b/packages/js/core/src/__tests__/Plugin.spec.ts index ba0b601c0a..ade56938bf 100644 --- a/packages/js/core/src/__tests__/Plugin.spec.ts +++ b/packages/js/core/src/__tests__/Plugin.spec.ts @@ -2,11 +2,11 @@ import { Client, Plugin, PluginModules, - PluginManifest, + PluginPackageManifest, Uri, } from ".."; -const testPluginManifest: PluginManifest = { +const testPluginManifest: PluginPackageManifest = { schema: ` type Query { testQuery: Number! diff --git a/packages/js/core/src/__tests__/resolve-uri.spec.ts b/packages/js/core/src/__tests__/resolve-uri.spec.ts index a107575b52..9c488a308a 100644 --- a/packages/js/core/src/__tests__/resolve-uri.spec.ts +++ b/packages/js/core/src/__tests__/resolve-uri.spec.ts @@ -93,7 +93,7 @@ describe("resolveUri", () => { ) => { return { manifest: - input.authority === "ipfs" ? "format: 0.0.1-prealpha.3\ndog: cat" : undefined, + input.authority === "ipfs" ? "format: 0.0.1-prealpha.4\ndog: cat" : undefined, }; }, }, @@ -107,7 +107,7 @@ describe("resolveUri", () => { ) => { return { manifest: - input.authority === "my" ? "format: 0.0.1-prealpha.3" : undefined, + input.authority === "my" ? "format: 0.0.1-prealpha.4" : undefined, }; }, }, @@ -174,7 +174,7 @@ describe("resolveUri", () => { expect(apiIdentity).toMatchObject({ uri: new Uri("ipfs/QmHash"), manifest: { - format: "0.0.1-prealpha.3" + format: "0.0.1-prealpha.4" }, uriResolver: new Uri("ens/ipfs"), }); @@ -200,7 +200,7 @@ describe("resolveUri", () => { expect(apiIdentity).toMatchObject({ uri: new Uri("my/something-different"), manifest: { - format: "0.0.1-prealpha.3" + format: "0.0.1-prealpha.4" }, uriResolver: new Uri("ens/my-plugin"), }); @@ -226,7 +226,7 @@ describe("resolveUri", () => { expect(apiIdentity).toMatchObject({ uri: new Uri("ipfs/QmHash"), manifest: { - format: "0.0.1-prealpha.3", + format: "0.0.1-prealpha.4", dog: "cat" }, uriResolver: new Uri("ens/ipfs"), @@ -253,7 +253,7 @@ describe("resolveUri", () => { expect(apiIdentity).toMatchObject({ uri: new Uri("my/something-different"), manifest: { - format: "0.0.1-prealpha.3" + format: "0.0.1-prealpha.4" }, uriResolver: new Uri("ens/my-plugin"), }); diff --git a/packages/js/core/src/manifest/formats/index.ts b/packages/js/core/src/manifest/formats/index.ts index 0488d675d8..878023ada7 100644 --- a/packages/js/core/src/manifest/formats/index.ts +++ b/packages/js/core/src/manifest/formats/index.ts @@ -1,2 +1,3 @@ export * from "./web3api"; export * from "./web3api.build"; +export * from "./web3api.plugin"; diff --git a/packages/js/core/src/manifest/formats/web3api.build/0.0.1-prealpha.1.ts b/packages/js/core/src/manifest/formats/web3api.build/0.0.1-prealpha.1.ts new file mode 100644 index 0000000000..40d26eb91a --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api.build/0.0.1-prealpha.1.ts @@ -0,0 +1,20 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/* tslint:disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export interface BuildManifest { + format: "0.0.1-prealpha.1"; + docker?: { + name?: string; + dockerfile?: string; + buildImageId?: string; + }; + config?: { + [k: string]: unknown; + }; + __type: "BuildManifest"; +} diff --git a/packages/js/core/src/manifest/formats/web3api.build/0.0.1-prealpha.2.ts b/packages/js/core/src/manifest/formats/web3api.build/0.0.1-prealpha.2.ts index c45d4e221c..de59befad0 100644 --- a/packages/js/core/src/manifest/formats/web3api.build/0.0.1-prealpha.2.ts +++ b/packages/js/core/src/manifest/formats/web3api.build/0.0.1-prealpha.2.ts @@ -16,4 +16,5 @@ export interface BuildManifest { config?: { [k: string]: unknown; }; + __type: "BuildManifest"; } diff --git a/packages/js/core/src/manifest/formats/web3api.build/deserialize.ts b/packages/js/core/src/manifest/formats/web3api.build/deserialize.ts index eb73bdb6e0..052129312c 100644 --- a/packages/js/core/src/manifest/formats/web3api.build/deserialize.ts +++ b/packages/js/core/src/manifest/formats/web3api.build/deserialize.ts @@ -33,6 +33,8 @@ export const deserializeBuildManifest = Tracer.traceFunc( validateBuildManifest(anyBuildManifest, options?.extSchema); } + anyBuildManifest.__type = "BuildManifest"; + const versionCompare = compare( anyBuildManifest.format, latestBuildManifestFormat diff --git a/packages/js/core/src/manifest/formats/web3api.build/index.ts b/packages/js/core/src/manifest/formats/web3api.build/index.ts index d4faed7411..1c65d69a8e 100644 --- a/packages/js/core/src/manifest/formats/web3api.build/index.ts +++ b/packages/js/core/src/manifest/formats/web3api.build/index.ts @@ -6,23 +6,23 @@ */ import { - BuildManifest as BuildManifest0_0_1_prealpha_2 -} from "./0.0.1-prealpha.2"; + BuildManifest as BuildManifest0_0_1_prealpha_1 +} from "./0.0.1-prealpha.1"; export { - BuildManifest0_0_1_prealpha_2, + BuildManifest0_0_1_prealpha_1, }; export enum BuildManifestFormats { - "0.0.1-prealpha.2" = "0.0.1-prealpha.2", + "0.0.1-prealpha.1" = "0.0.1-prealpha.1", } export type AnyBuildManifest = - | BuildManifest0_0_1_prealpha_2 + | BuildManifest0_0_1_prealpha_1 -export type BuildManifest = BuildManifest0_0_1_prealpha_2; +export type BuildManifest = BuildManifest0_0_1_prealpha_1; -export const latestBuildManifestFormat = BuildManifestFormats["0.0.1-prealpha.2"] +export const latestBuildManifestFormat = BuildManifestFormats["0.0.1-prealpha.1"] export { migrateBuildManifest } from "./migrate"; diff --git a/packages/js/core/src/manifest/formats/web3api.build/validate.ts b/packages/js/core/src/manifest/formats/web3api.build/validate.ts index c0e685d624..107d3c731b 100644 --- a/packages/js/core/src/manifest/formats/web3api.build/validate.ts +++ b/packages/js/core/src/manifest/formats/web3api.build/validate.ts @@ -10,7 +10,7 @@ import { } from "."; import * as Validators from "../../validators"; -import schema_0_0_1_prealpha_2 from "@web3api/manifest-schemas/formats/web3api.build/0.0.1-prealpha.2.json"; +import schema_0_0_1_prealpha_1 from "@web3api/manifest-schemas/formats/web3api.build/0.0.1-prealpha.1.json"; import { Tracer } from "@web3api/tracing-js" import { @@ -25,7 +25,7 @@ type BuildManifestSchemas = { }; const schemas: BuildManifestSchemas = { - "0.0.1-prealpha.2": schema_0_0_1_prealpha_2, + "0.0.1-prealpha.1": schema_0_0_1_prealpha_1, }; const validator = new Validator(); diff --git a/packages/js/core/src/manifest/formats/web3api.plugin/0.0.1-prealpha.1.ts b/packages/js/core/src/manifest/formats/web3api.plugin/0.0.1-prealpha.1.ts new file mode 100644 index 0000000000..3987884f94 --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api.plugin/0.0.1-prealpha.1.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/* tslint:disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export interface PluginManifest { + format: "0.0.1-prealpha.1"; + language: string; + schema: string; + import_redirects?: { + uri: string; + schema: string; + }[]; + __type: "PluginManifest"; +} diff --git a/packages/js/core/src/manifest/formats/web3api.plugin/0.0.1-prealpha.3.ts b/packages/js/core/src/manifest/formats/web3api.plugin/0.0.1-prealpha.3.ts new file mode 100644 index 0000000000..f8b85a66e8 --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api.plugin/0.0.1-prealpha.3.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/* tslint:disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export interface PluginManifest { + format: "0.0.1-prealpha.3"; + language: string; + schema: string; + import_redirects?: { + uri: string; + schema: string; + }[]; + __type: "PluginManifest"; +} diff --git a/packages/js/core/src/manifest/formats/web3api.plugin/deserialize.ts b/packages/js/core/src/manifest/formats/web3api.plugin/deserialize.ts new file mode 100644 index 0000000000..ba2c1cb91b --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api.plugin/deserialize.ts @@ -0,0 +1,56 @@ +/* eslint-disable */ +/** + * This file was automatically generated by scripts/manifest/deserialize-ts.mustache. + * DO NOT MODIFY IT BY HAND. Instead, modify scripts/manifest/deserialize-ts.mustache, + * and run node ./scripts/manifest/generateFormatTypes.js to regenerate this file. + */ + +import { + PluginManifest, + AnyPluginManifest, + migratePluginManifest, + validatePluginManifest, + latestPluginManifestFormat, +} from "."; +import { DeserializeManifestOptions } from "../../"; + +import { compare } from "semver"; +import YAML from "js-yaml"; +import { Tracer } from "@web3api/tracing-js"; + +export const deserializePluginManifest = Tracer.traceFunc( + "core: deserializePluginManifest", + (manifest: string, options?: DeserializeManifestOptions): PluginManifest => { + const anyPluginManifest = YAML.safeLoad(manifest) as + | AnyPluginManifest + | undefined; + + if (!anyPluginManifest) { + throw Error(`Unable to parse PluginManifest: ${manifest}`); + } + + if (!options || !options.noValidate) { + validatePluginManifest(anyPluginManifest, options?.extSchema); + } + + anyPluginManifest.__type = "PluginManifest"; + + const versionCompare = compare( + anyPluginManifest.format, + latestPluginManifestFormat + ); + + if (versionCompare === -1) { + // Upgrade + return migratePluginManifest(anyPluginManifest, latestPluginManifestFormat); + } else if (versionCompare === 1) { + // Downgrade + throw Error( + `Cannot downgrade Web3API version ${anyPluginManifest.format}, please upgrade your Web3ApiClient package.` + ); + } else { + // Latest + return anyPluginManifest as PluginManifest; + } + } +); diff --git a/packages/js/core/src/manifest/formats/web3api.plugin/index.ts b/packages/js/core/src/manifest/formats/web3api.plugin/index.ts new file mode 100644 index 0000000000..89bc4c0fbf --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api.plugin/index.ts @@ -0,0 +1,31 @@ +/* eslint-disable */ +/** + * This file was automatically generated by scripts/manifest/index-ts.mustache. + * DO NOT MODIFY IT BY HAND. Instead, modify scripts/manifest/index-ts.mustache, + * and run node ./scripts/manifest/generateFormatTypes.js to regenerate this file. + */ + +import { + PluginManifest as PluginManifest0_0_1_prealpha_1 +} from "./0.0.1-prealpha.1"; + +export { + PluginManifest0_0_1_prealpha_1, +}; + +export enum PluginManifestFormats { + "0.0.1-prealpha.1" = "0.0.1-prealpha.1", +} + +export type AnyPluginManifest = + | PluginManifest0_0_1_prealpha_1 + +export type PluginManifest = PluginManifest0_0_1_prealpha_1; + +export const latestPluginManifestFormat = PluginManifestFormats["0.0.1-prealpha.1"] + +export { migratePluginManifest } from "./migrate"; + +export { deserializePluginManifest } from "./deserialize"; + +export { validatePluginManifest } from "./validate"; diff --git a/packages/js/core/src/manifest/formats/web3api.plugin/migrate.ts b/packages/js/core/src/manifest/formats/web3api.plugin/migrate.ts new file mode 100644 index 0000000000..efc4ef2183 --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api.plugin/migrate.ts @@ -0,0 +1,39 @@ +/* eslint-disable */ +/** + * This file was automatically generated by scripts/manifest/migrate-ts.mustache. + * DO NOT MODIFY IT BY HAND. Instead, modify scripts/manifest/migrate-ts.mustache, + * and run node ./scripts/manifest/generateFormatTypes.js to regenerate this file. + */ +import { + AnyPluginManifest, + PluginManifest, + PluginManifestFormats, + latestPluginManifestFormat +} from "."; + + +import { Tracer } from "@web3api/tracing-js"; + +type Migrator = { + [key in PluginManifestFormats]?: (m: AnyPluginManifest) => PluginManifest; +}; + +export const migrators: Migrator = { +}; + +export const migratePluginManifest = Tracer.traceFunc( + "core: migratePluginManifest", + (manifest: AnyPluginManifest, to: PluginManifestFormats): PluginManifest => { + const from = manifest.format as PluginManifestFormats; + + if (from === latestPluginManifestFormat) { + return manifest as PluginManifest; + } + + if (!(from in PluginManifestFormats)) { + throw new Error(`Unrecognized PluginManifestFormat "${manifest.format}"`); + } + + throw new Error(`This should never happen, PluginManifest migrators is empty. from: ${from}, to: ${to}`); + } +); diff --git a/packages/js/core/src/manifest/formats/web3api.plugin/validate.ts b/packages/js/core/src/manifest/formats/web3api.plugin/validate.ts new file mode 100644 index 0000000000..882e4ff03a --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api.plugin/validate.ts @@ -0,0 +1,63 @@ +/* eslint-disable */ +/** + * This file was automatically generated by scripts/manifest/validate-ts.mustache. + * DO NOT MODIFY IT BY HAND. Instead, modify scripts/manifest/validate-ts.mustache, + * and run node ./scripts/manifest/generateFormatTypes.js to regenerate this file. + */ +import { + AnyPluginManifest, + PluginManifestFormats +} from "."; +import * as Validators from "../../validators"; + +import schema_0_0_1_prealpha_1 from "@web3api/manifest-schemas/formats/web3api.plugin/0.0.1-prealpha.1.json"; +import { Tracer } from "@web3api/tracing-js" + +import { + Schema, + Validator, + ValidationError, + ValidatorResult +} from "jsonschema"; + +type PluginManifestSchemas = { + [key in PluginManifestFormats]: Schema | undefined +}; + +const schemas: PluginManifestSchemas = { + "0.0.1-prealpha.1": schema_0_0_1_prealpha_1, +}; + +const validator = new Validator(); + +Validator.prototype.customFormats.pluginLanguage = Validators.pluginLanguage; +Validator.prototype.customFormats.file = Validators.file; + +export const validatePluginManifest = Tracer.traceFunc( + "core: validatePluginManifest", + ( + manifest: AnyPluginManifest, + extSchema: Schema | undefined = undefined + ): void => { + const schema = schemas[manifest.format as PluginManifestFormats]; + + if (!schema) { + throw Error(`Unrecognized PluginManifest schema format "${manifest.format}"`); + } + + const throwIfErrors = (result: ValidatorResult) => { + if (result.errors.length) { + throw new Error([ + `Validation errors encountered while sanitizing PluginManifest format ${manifest.format}`, + ...result.errors.map((error: ValidationError) => error.toString()) + ].join("\n")); + } + }; + + throwIfErrors(validator.validate(manifest, schema)); + + if (extSchema) { + throwIfErrors(validator.validate(manifest, extSchema)); + } + } +); diff --git a/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.1.ts b/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.1.ts index b5aa6eb573..f3f34a16dd 100644 --- a/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.1.ts +++ b/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.1.ts @@ -28,12 +28,9 @@ export interface Web3ApiManifest { file: string; }; }; - import_redirects?: - | [] - | [ - { - uri: string; - schema: string; - } - ]; + import_redirects?: { + uri: string; + schema: string; + }[]; + __type: "Web3ApiManifest"; } diff --git a/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.2.ts b/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.2.ts index 7ff908903b..0c5f999364 100644 --- a/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.2.ts +++ b/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.2.ts @@ -21,12 +21,9 @@ export interface Web3ApiManifest { module: string; }; }; - import_redirects?: - | [] - | [ - { - uri: string; - schema: string; - } - ]; + import_redirects?: { + uri: string; + schema: string; + }[]; + __type: "Web3ApiManifest"; } diff --git a/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.3.ts b/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.3.ts index 85fb6f215e..31c552c53e 100644 --- a/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.3.ts +++ b/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.3.ts @@ -22,12 +22,9 @@ export interface Web3ApiManifest { module?: string; }; }; - import_redirects?: - | [] - | [ - { - uri: string; - schema: string; - } - ]; + import_redirects?: { + uri: string; + schema: string; + }[]; + __type: "Web3ApiManifest"; } diff --git a/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.4.ts b/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.4.ts new file mode 100644 index 0000000000..239976560a --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api/0.0.1-prealpha.4.ts @@ -0,0 +1,29 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/* tslint:disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export interface Web3ApiManifest { + format: "0.0.1-prealpha.4"; + repository?: string; + build?: string; + language: string; + modules: { + mutation?: { + schema: string; + module?: string; + }; + query?: { + schema: string; + module?: string; + }; + }; + import_redirects?: { + uri: string; + schema: string; + }[]; + __type: "Web3ApiManifest"; +} diff --git a/packages/js/core/src/manifest/formats/web3api/deserialize.ts b/packages/js/core/src/manifest/formats/web3api/deserialize.ts index 2299e597f7..ff3dffdd4c 100644 --- a/packages/js/core/src/manifest/formats/web3api/deserialize.ts +++ b/packages/js/core/src/manifest/formats/web3api/deserialize.ts @@ -33,6 +33,8 @@ export const deserializeWeb3ApiManifest = Tracer.traceFunc( validateWeb3ApiManifest(anyWeb3ApiManifest, options?.extSchema); } + anyWeb3ApiManifest.__type = "Web3ApiManifest"; + const versionCompare = compare( anyWeb3ApiManifest.format, latestWeb3ApiManifestFormat diff --git a/packages/js/core/src/manifest/formats/web3api/index.ts b/packages/js/core/src/manifest/formats/web3api/index.ts index 3153950981..b07d744756 100644 --- a/packages/js/core/src/manifest/formats/web3api/index.ts +++ b/packages/js/core/src/manifest/formats/web3api/index.ts @@ -14,27 +14,33 @@ import { import { Web3ApiManifest as Web3ApiManifest0_0_1_prealpha_3 } from "./0.0.1-prealpha.3"; +import { + Web3ApiManifest as Web3ApiManifest0_0_1_prealpha_4 +} from "./0.0.1-prealpha.4"; export { Web3ApiManifest0_0_1_prealpha_1, Web3ApiManifest0_0_1_prealpha_2, Web3ApiManifest0_0_1_prealpha_3, + Web3ApiManifest0_0_1_prealpha_4, }; export enum Web3ApiManifestFormats { "0.0.1-prealpha.1" = "0.0.1-prealpha.1", "0.0.1-prealpha.2" = "0.0.1-prealpha.2", "0.0.1-prealpha.3" = "0.0.1-prealpha.3", + "0.0.1-prealpha.4" = "0.0.1-prealpha.4", } export type AnyWeb3ApiManifest = | Web3ApiManifest0_0_1_prealpha_1 | Web3ApiManifest0_0_1_prealpha_2 | Web3ApiManifest0_0_1_prealpha_3 + | Web3ApiManifest0_0_1_prealpha_4 -export type Web3ApiManifest = Web3ApiManifest0_0_1_prealpha_3; +export type Web3ApiManifest = Web3ApiManifest0_0_1_prealpha_4; -export const latestWeb3ApiManifestFormat = Web3ApiManifestFormats["0.0.1-prealpha.3"] +export const latestWeb3ApiManifestFormat = Web3ApiManifestFormats["0.0.1-prealpha.4"] export { migrateWeb3ApiManifest } from "./migrate"; diff --git a/packages/js/core/src/manifest/formats/web3api/migrate.ts b/packages/js/core/src/manifest/formats/web3api/migrate.ts index 402b0ad069..b04c9154f9 100644 --- a/packages/js/core/src/manifest/formats/web3api/migrate.ts +++ b/packages/js/core/src/manifest/formats/web3api/migrate.ts @@ -12,11 +12,14 @@ import { } from "."; import { - migrate as migrate_0_0_1_prealpha_1_to_0_0_1_prealpha_3 -} from "./migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.3"; + migrate as migrate_0_0_1_prealpha_1_to_0_0_1_prealpha_4 +} from "./migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.4"; import { - migrate as migrate_0_0_1_prealpha_2_to_0_0_1_prealpha_3 -} from "./migrators/0.0.1-prealpha.2_to_0.0.1-prealpha.3"; + migrate as migrate_0_0_1_prealpha_2_to_0_0_1_prealpha_4 +} from "./migrators/0.0.1-prealpha.2_to_0.0.1-prealpha.4"; +import { + migrate as migrate_0_0_1_prealpha_3_to_0_0_1_prealpha_4 +} from "./migrators/0.0.1-prealpha.3_to_0.0.1-prealpha.4"; import { Tracer } from "@web3api/tracing-js"; @@ -25,8 +28,9 @@ type Migrator = { }; export const migrators: Migrator = { - "0.0.1-prealpha.1": migrate_0_0_1_prealpha_1_to_0_0_1_prealpha_3, - "0.0.1-prealpha.2": migrate_0_0_1_prealpha_2_to_0_0_1_prealpha_3, + "0.0.1-prealpha.1": migrate_0_0_1_prealpha_1_to_0_0_1_prealpha_4, + "0.0.1-prealpha.2": migrate_0_0_1_prealpha_2_to_0_0_1_prealpha_4, + "0.0.1-prealpha.3": migrate_0_0_1_prealpha_3_to_0_0_1_prealpha_4, }; export const migrateWeb3ApiManifest = Tracer.traceFunc( diff --git a/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.3.ts b/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.4.ts similarity index 92% rename from packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.3.ts rename to packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.4.ts index a5bc819f7f..fdf66dada7 100644 --- a/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.3.ts +++ b/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.1_to_0.0.1-prealpha.4.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Web3ApiManifest as OldManifest } from "../0.0.1-prealpha.1"; -import { Web3ApiManifest as NewManifest } from "../0.0.1-prealpha.3"; +import { Web3ApiManifest as NewManifest } from "../0.0.1-prealpha.4"; export function migrate(old: OldManifest): NewManifest { const module = old.mutation || old.query; @@ -13,7 +13,8 @@ export function migrate(old: OldManifest): NewManifest { const language = module.module.language; return { - format: "0.0.1-prealpha.3", + __type: "Web3ApiManifest", + format: "0.0.1-prealpha.4", repository: old.repository, language, modules: { diff --git a/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.2_to_0.0.1-prealpha.3.ts b/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.2_to_0.0.1-prealpha.4.ts similarity index 80% rename from packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.2_to_0.0.1-prealpha.3.ts rename to packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.2_to_0.0.1-prealpha.4.ts index f7545a80c8..513f0aa782 100644 --- a/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.2_to_0.0.1-prealpha.3.ts +++ b/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.2_to_0.0.1-prealpha.4.ts @@ -1,11 +1,12 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Web3ApiManifest as OldManifest } from "../0.0.1-prealpha.2"; -import { Web3ApiManifest as NewManifest } from "../0.0.1-prealpha.3"; +import { Web3ApiManifest as NewManifest } from "../0.0.1-prealpha.4"; export function migrate(old: OldManifest): NewManifest { return { ...old, - format: "0.0.1-prealpha.3", + __type: "Web3ApiManifest", + format: "0.0.1-prealpha.4", }; } diff --git a/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.3_to_0.0.1-prealpha.4.ts b/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.3_to_0.0.1-prealpha.4.ts new file mode 100644 index 0000000000..73eea17770 --- /dev/null +++ b/packages/js/core/src/manifest/formats/web3api/migrators/0.0.1-prealpha.3_to_0.0.1-prealpha.4.ts @@ -0,0 +1,26 @@ +/* eslint-disable @typescript-eslint/naming-convention */ + +import { Web3ApiManifest as OldManifest } from "../0.0.1-prealpha.3"; +import { Web3ApiManifest as NewManifest } from "../0.0.1-prealpha.4"; + +export function migrate(old: OldManifest): NewManifest { + let language = old.language; + + if (!language) { + if (old.interface) { + language = "interface"; + } else { + language = "wasm/assemblyscript"; + } + } + + return { + __type: "Web3ApiManifest", + format: "0.0.1-prealpha.4", + repository: old.repository, + build: old.build, + language, + modules: old.modules, + import_redirects: old.import_redirects, + }; +} diff --git a/packages/js/core/src/manifest/formats/web3api/validate.ts b/packages/js/core/src/manifest/formats/web3api/validate.ts index ec1afe777d..f34b003067 100644 --- a/packages/js/core/src/manifest/formats/web3api/validate.ts +++ b/packages/js/core/src/manifest/formats/web3api/validate.ts @@ -13,6 +13,7 @@ import * as Validators from "../../validators"; import schema_0_0_1_prealpha_1 from "@web3api/manifest-schemas/formats/web3api/0.0.1-prealpha.1.json"; import schema_0_0_1_prealpha_2 from "@web3api/manifest-schemas/formats/web3api/0.0.1-prealpha.2.json"; import schema_0_0_1_prealpha_3 from "@web3api/manifest-schemas/formats/web3api/0.0.1-prealpha.3.json"; +import schema_0_0_1_prealpha_4 from "@web3api/manifest-schemas/formats/web3api/0.0.1-prealpha.4.json"; import { Tracer } from "@web3api/tracing-js" import { @@ -30,6 +31,7 @@ const schemas: Web3ApiManifestSchemas = { "0.0.1-prealpha.1": schema_0_0_1_prealpha_1, "0.0.1-prealpha.2": schema_0_0_1_prealpha_2, "0.0.1-prealpha.3": schema_0_0_1_prealpha_3, + "0.0.1-prealpha.4": schema_0_0_1_prealpha_4, }; const validator = new Validator(); diff --git a/packages/js/core/src/manifest/validators.ts b/packages/js/core/src/manifest/validators.ts index 40c697822f..7cbbceafec 100644 --- a/packages/js/core/src/manifest/validators.ts +++ b/packages/js/core/src/manifest/validators.ts @@ -15,45 +15,26 @@ export function file(path: unknown): boolean { } export function dockerImageName(name: unknown): boolean { - if (typeof name !== "string") { - return false; - } - - return true; + return typeof name === "string"; } export function dockerfileName(value: unknown): boolean { - if (typeof value !== "string") { - return false; - } - - if (file(value) && value.indexOf("Dockerfile") > -1) { - return true; - } - - return true; + return ( + typeof value === "string" && file(value) && value.indexOf("Dockerfile") > -1 + ); } export function dockerImageId(value: unknown): boolean { - if (typeof value !== "string") { - return false; - } - - if (value.indexOf("sha256:") === -1) { - return false; - } - - return true; + return typeof value === "string" && value.indexOf("sha256:") > -1; } export function wasmLanguage(language: unknown): boolean { - if (typeof language !== "string") { - return false; - } - - if (language.indexOf("wasm/") > -1) { - return true; - } + return ( + typeof language === "string" && + (language === "interface" || language.indexOf("wasm/") > -1) + ); +} - return false; +export function pluginLanguage(language: unknown): boolean { + return typeof language === "string" && language.indexOf("plugin/") > -1; } diff --git a/packages/js/core/src/types/Plugin.ts b/packages/js/core/src/types/Plugin.ts index c533828af4..5ef63c30d3 100644 --- a/packages/js/core/src/types/Plugin.ts +++ b/packages/js/core/src/types/Plugin.ts @@ -1,14 +1,5 @@ import { Uri, Client, InvokableModules, MaybeAsync } from "."; -/** The plugin's configuration */ -export interface PluginManifest { - /** The API's schema */ - schema: string; - - /** All interface schemas implemented by this plugin. */ - implements: Uri[]; -} - /** * Invocable plugin method. * @@ -49,9 +40,18 @@ export abstract class Plugin { public abstract getModules(client: Client): PluginModules; } +/** The plugin package's manifest */ +export interface PluginPackageManifest { + /** The API's schema */ + schema: string; + + /** All interface schemas implemented by this plugin. */ + implements: Uri[]; +} + export type PluginPackage = { factory: () => Plugin; - manifest: PluginManifest; + manifest: PluginPackageManifest; }; export type PluginFactory = (opts: TOpts) => PluginPackage; diff --git a/packages/js/plugins/ens/schema.graphql b/packages/js/plugins/ens/schema.graphql index 84e70f302d..d132e26dea 100644 --- a/packages/js/plugins/ens/schema.graphql +++ b/packages/js/plugins/ens/schema.graphql @@ -1,49 +1,6 @@ -### Web3API Header START ### -scalar UInt -scalar UInt8 -scalar UInt16 -scalar UInt32 -scalar Int -scalar Int8 -scalar Int16 -scalar Int32 -scalar Bytes -scalar BigInt +#import { Query, MaybeUriOrManifest } into UriResolver from "ens/uri-resolver.core.web3api.eth" -directive @imported( - uri: String! - namespace: String! - nativeType: String! -) on OBJECT | ENUM - -directive @imports( - types: [String!]! -) on OBJECT -### Web3API Header END ### - -type Query implements UriResolver_Query @imports( - types: [ - "UriResolver_Query", - "UriResolver_MaybeUriOrManifest" - ] -) { - tryResolveUri( - authority: String! - path: String! - ): UriResolver_MaybeUriOrManifest - - getFile( - path: String! - ): Bytes -} - -### Imported Queries START ### - -type UriResolver_Query @imported( - uri: "w3://ens/uri-resolver.core.web3api.eth", - namespace: "UriResolver", - nativeType: "Query" -) { +type Query implements UriResolver_Query { tryResolveUri( authority: String! path: String! @@ -53,18 +10,3 @@ type UriResolver_Query @imported( path: String! ): Bytes } - -### Imported Queries END ### - -### Imported Objects START ### - -type UriResolver_MaybeUriOrManifest @imported( - uri: "w3://ens/uri-resolver.core.web3api.eth", - namespace: "UriResolver", - nativeType: "MaybeUriOrManifest" -) { - uri: String - manifest: String -} - -### Imported Objects END ### diff --git a/packages/js/plugins/ens/src/index.ts b/packages/js/plugins/ens/src/index.ts index 44317b1ea2..2bd3d90a45 100644 --- a/packages/js/plugins/ens/src/index.ts +++ b/packages/js/plugins/ens/src/index.ts @@ -5,7 +5,7 @@ import { manifest } from "./manifest"; import { Client, Plugin, - PluginManifest, + PluginPackageManifest, PluginModules, PluginFactory, } from "@web3api/core-js"; @@ -36,7 +36,7 @@ export class EnsPlugin extends Plugin { } } - public static manifest(): PluginManifest { + public static manifest(): PluginPackageManifest { return manifest; } diff --git a/packages/js/plugins/ens/src/manifest.ts b/packages/js/plugins/ens/src/manifest.ts index 405c7a3bd9..a7dbd1f165 100644 --- a/packages/js/plugins/ens/src/manifest.ts +++ b/packages/js/plugins/ens/src/manifest.ts @@ -1,6 +1,6 @@ -import { PluginManifest, coreInterfaceUris } from "@web3api/core-js"; +import { PluginPackageManifest, coreInterfaceUris } from "@web3api/core-js"; -export const manifest: PluginManifest = { +export const manifest: PluginPackageManifest = { // TODO: use the schema.graphql // https://github.com/web3-api/monorepo/issues/101 schema: `### Web3API Header START ### @@ -8,24 +8,23 @@ scalar UInt scalar UInt8 scalar UInt16 scalar UInt32 +scalar UInt64 scalar Int scalar Int8 scalar Int16 scalar Int32 +scalar Int64 scalar Bytes scalar BigInt - directive @imported( uri: String! namespace: String! nativeType: String! ) on OBJECT | ENUM - directive @imports( types: [String!]! ) on OBJECT ### Web3API Header END ### - type Query implements UriResolver_Query @imports( types: [ "UriResolver_Query", @@ -36,14 +35,11 @@ type Query implements UriResolver_Query @imports( authority: String! path: String! ): UriResolver_MaybeUriOrManifest - getFile( path: String! ): Bytes } - ### Imported Queries START ### - type UriResolver_Query @imported( uri: "w3://ens/uri-resolver.core.web3api.eth", namespace: "UriResolver", @@ -53,16 +49,12 @@ type UriResolver_Query @imported( authority: String! path: String! ): UriResolver_MaybeUriOrManifest - getFile( path: String! ): Bytes } - ### Imported Queries END ### - ### Imported Objects START ### - type UriResolver_MaybeUriOrManifest @imported( uri: "w3://ens/uri-resolver.core.web3api.eth", namespace: "UriResolver", @@ -71,7 +63,6 @@ type UriResolver_MaybeUriOrManifest @imported( uri: String manifest: String } - ### Imported Objects END ### `, implements: [coreInterfaceUris.uriResolver], diff --git a/packages/js/plugins/ens/web3api.plugin.yaml b/packages/js/plugins/ens/web3api.plugin.yaml new file mode 100644 index 0000000000..b21359a846 --- /dev/null +++ b/packages/js/plugins/ens/web3api.plugin.yaml @@ -0,0 +1,3 @@ +format: 0.0.1-prealpha.1 +language: plugin/typescript +schema: ./schema.graphql diff --git a/packages/js/plugins/ethereum/src/index.ts b/packages/js/plugins/ethereum/src/index.ts index 9be65fbbf6..1e999d4e71 100644 --- a/packages/js/plugins/ethereum/src/index.ts +++ b/packages/js/plugins/ethereum/src/index.ts @@ -17,7 +17,7 @@ import * as Mapping from "./mapping"; import { Client, Plugin, - PluginManifest, + PluginPackageManifest, PluginModules, PluginFactory, } from "@web3api/core-js"; @@ -63,7 +63,7 @@ export class EthereumPlugin extends Plugin { } } - public static manifest(): PluginManifest { + public static manifest(): PluginPackageManifest { return manifest; } diff --git a/packages/js/plugins/ethereum/src/manifest.ts b/packages/js/plugins/ethereum/src/manifest.ts index 8204933916..aab5b15194 100644 --- a/packages/js/plugins/ethereum/src/manifest.ts +++ b/packages/js/plugins/ethereum/src/manifest.ts @@ -1,6 +1,6 @@ -import { PluginManifest } from "@web3api/core-js"; +import { PluginPackageManifest } from "@web3api/core-js"; -export const manifest: PluginManifest = { +export const manifest: PluginPackageManifest = { // TODO: use the schema.graphql // https://github.com/web3-api/monorepo/issues/101 schema: ` diff --git a/packages/js/plugins/ethereum/src/types.ts b/packages/js/plugins/ethereum/src/types.ts index d1b47b08a2..fbe2a13eec 100644 --- a/packages/js/plugins/ethereum/src/types.ts +++ b/packages/js/plugins/ethereum/src/types.ts @@ -4,8 +4,18 @@ // https://github.com/web3-api/monorepo/issues/101 import { PluginModule, Client } from "@web3api/core-js"; -type UInt32 = number; -type BigInt = string; +export type UInt = number; +export type UInt8 = number; +export type UInt16 = number; +export type UInt32 = number; +export type Int = number; +export type Int8 = number; +export type Int16 = number; +export type Int32 = number; +export type Bytes = Uint8Array; +export type BigInt = string; +export type String = string; +export type Boolean = boolean; /// Objects diff --git a/packages/js/plugins/ethereum/web3api.plugin.yaml b/packages/js/plugins/ethereum/web3api.plugin.yaml new file mode 100644 index 0000000000..b21359a846 --- /dev/null +++ b/packages/js/plugins/ethereum/web3api.plugin.yaml @@ -0,0 +1,3 @@ +format: 0.0.1-prealpha.1 +language: plugin/typescript +schema: ./schema.graphql diff --git a/packages/js/plugins/graph-node/src/index.ts b/packages/js/plugins/graph-node/src/index.ts index 503ed10a48..da1177fd42 100644 --- a/packages/js/plugins/graph-node/src/index.ts +++ b/packages/js/plugins/graph-node/src/index.ts @@ -6,7 +6,7 @@ import { Client, Plugin, PluginFactory, - PluginManifest, + PluginPackageManifest, PluginModules, } from "@web3api/core-js"; @@ -19,7 +19,7 @@ export class GraphNodePlugin extends Plugin { super(); } - public static manifest(): PluginManifest { + public static manifest(): PluginPackageManifest { return manifest; } diff --git a/packages/js/plugins/graph-node/src/manifest.ts b/packages/js/plugins/graph-node/src/manifest.ts index 4aef00c400..ca2cbeaeb4 100644 --- a/packages/js/plugins/graph-node/src/manifest.ts +++ b/packages/js/plugins/graph-node/src/manifest.ts @@ -1,6 +1,8 @@ -import { PluginManifest } from "@web3api/core-js"; +import { PluginPackageManifest } from "@web3api/core-js"; -export const manifest: PluginManifest = { +export const manifest: PluginPackageManifest = { + // TODO: use the schema.graphql + // https://github.com/web3-api/monorepo/issues/101 schema: ` type Query { querySubgraph( diff --git a/packages/js/plugins/http/src/index.ts b/packages/js/plugins/http/src/index.ts index b7203ccd32..ce38a30415 100644 --- a/packages/js/plugins/http/src/index.ts +++ b/packages/js/plugins/http/src/index.ts @@ -9,7 +9,7 @@ import { Client, Plugin, PluginModules, - PluginManifest, + PluginPackageManifest, PluginPackage, } from "@web3api/core-js"; @@ -18,7 +18,7 @@ export class HttpPlugin extends Plugin { super(); } - public static manifest(): PluginManifest { + public static manifest(): PluginPackageManifest { return manifest; } diff --git a/packages/js/plugins/http/src/manifest.ts b/packages/js/plugins/http/src/manifest.ts index f17fd26adc..d06d1e48eb 100644 --- a/packages/js/plugins/http/src/manifest.ts +++ b/packages/js/plugins/http/src/manifest.ts @@ -1,6 +1,6 @@ -import { PluginManifest } from "@web3api/core-js"; +import { PluginPackageManifest } from "@web3api/core-js"; -export const manifest: PluginManifest = { +export const manifest: PluginPackageManifest = { // TODO: use the schema.graphql // https://github.com/web3-api/monorepo/issues/101 schema: ` diff --git a/packages/js/plugins/ipfs/src/index.ts b/packages/js/plugins/ipfs/src/index.ts index 3e602d847c..fb3b8862d8 100644 --- a/packages/js/plugins/ipfs/src/index.ts +++ b/packages/js/plugins/ipfs/src/index.ts @@ -6,7 +6,7 @@ import { Client, Plugin, PluginFactory, - PluginManifest, + PluginPackageManifest, PluginModules, } from "@web3api/core-js"; import CID from "cids"; @@ -53,7 +53,7 @@ export class IpfsPlugin extends Plugin { this.setProvider(this._config.provider); } - public static manifest(): PluginManifest { + public static manifest(): PluginPackageManifest { return manifest; } diff --git a/packages/js/plugins/ipfs/src/manifest.ts b/packages/js/plugins/ipfs/src/manifest.ts index e33f3b8dfe..317523fbfa 100644 --- a/packages/js/plugins/ipfs/src/manifest.ts +++ b/packages/js/plugins/ipfs/src/manifest.ts @@ -1,6 +1,6 @@ -import { PluginManifest, coreInterfaceUris } from "@web3api/core-js"; +import { PluginPackageManifest, coreInterfaceUris } from "@web3api/core-js"; -export const manifest: PluginManifest = { +export const manifest: PluginPackageManifest = { // TODO: use the schema.graphql // https://github.com/web3-api/monorepo/issues/101 schema: `### Web3API Header START ### diff --git a/packages/js/plugins/logger/src/index.ts b/packages/js/plugins/logger/src/index.ts index 6693d443eb..0d31bfcce6 100644 --- a/packages/js/plugins/logger/src/index.ts +++ b/packages/js/plugins/logger/src/index.ts @@ -3,7 +3,7 @@ import { manifest } from "./manifest"; import { Plugin, - PluginManifest, + PluginPackageManifest, PluginModules, PluginPackage, } from "@web3api/core-js"; @@ -25,7 +25,7 @@ export class LoggerPlugin extends Plugin { this._logFunc = logFunc; } - public static manifest(): PluginManifest { + public static manifest(): PluginPackageManifest { return manifest; } diff --git a/packages/js/plugins/logger/src/manifest.ts b/packages/js/plugins/logger/src/manifest.ts index 530dceaa8a..36588603b5 100644 --- a/packages/js/plugins/logger/src/manifest.ts +++ b/packages/js/plugins/logger/src/manifest.ts @@ -1,6 +1,6 @@ -import { PluginManifest, coreInterfaceUris } from "@web3api/core-js"; +import { PluginPackageManifest, coreInterfaceUris } from "@web3api/core-js"; -export const manifest: PluginManifest = { +export const manifest: PluginPackageManifest = { // TODO: use the schema.graphql // https://github.com/web3-api/monorepo/issues/101 schema: `### Web3API Header START ### diff --git a/packages/js/plugins/sha3/src/index.ts b/packages/js/plugins/sha3/src/index.ts index c43c03729e..5e1af4ee9b 100644 --- a/packages/js/plugins/sha3/src/index.ts +++ b/packages/js/plugins/sha3/src/index.ts @@ -3,13 +3,13 @@ import { query } from "./resolvers"; import { Plugin, - PluginManifest, + PluginPackageManifest, PluginModules, PluginPackage, } from "@web3api/core-js"; export class SHA3Plugin extends Plugin { - public static manifest(): PluginManifest { + public static manifest(): PluginPackageManifest { return manifest; } diff --git a/packages/js/plugins/sha3/src/manifest.ts b/packages/js/plugins/sha3/src/manifest.ts index 68bb67187d..15c70eb4de 100644 --- a/packages/js/plugins/sha3/src/manifest.ts +++ b/packages/js/plugins/sha3/src/manifest.ts @@ -1,6 +1,6 @@ -import { PluginManifest } from "@web3api/core-js"; +import { PluginPackageManifest } from "@web3api/core-js"; -export const manifest: PluginManifest = { +export const manifest: PluginPackageManifest = { // TODO: use the schema.graphql // https://github.com/Web3-API/prototype/issues/101 schema: `type Query { diff --git a/packages/js/plugins/uts46/src/index.ts b/packages/js/plugins/uts46/src/index.ts index 9504ce1a54..8409903c2d 100644 --- a/packages/js/plugins/uts46/src/index.ts +++ b/packages/js/plugins/uts46/src/index.ts @@ -3,13 +3,13 @@ import { query } from "./resolvers"; import { Plugin, - PluginManifest, + PluginPackageManifest, PluginModules, PluginPackage, } from "@web3api/core-js"; export class UTS46Plugin extends Plugin { - public static manifest(): PluginManifest { + public static manifest(): PluginPackageManifest { return manifest; } diff --git a/packages/js/plugins/uts46/src/manifest.ts b/packages/js/plugins/uts46/src/manifest.ts index 62892b3ad7..d90f51927b 100644 --- a/packages/js/plugins/uts46/src/manifest.ts +++ b/packages/js/plugins/uts46/src/manifest.ts @@ -1,6 +1,6 @@ -import { PluginManifest } from "@web3api/core-js"; +import { PluginPackageManifest } from "@web3api/core-js"; -export const manifest: PluginManifest = { +export const manifest: PluginPackageManifest = { // TODO: use the schema.graphql // https://github.com/Web3-API/prototype/issues/101 schema: `type Query { diff --git a/packages/manifest-schemas/formats/web3api.build/0.0.1-prealpha.2.json b/packages/manifest-schemas/formats/web3api.build/0.0.1-prealpha.1.json similarity index 94% rename from packages/manifest-schemas/formats/web3api.build/0.0.1-prealpha.2.json rename to packages/manifest-schemas/formats/web3api.build/0.0.1-prealpha.1.json index 0b6daf1204..4537b545e1 100644 --- a/packages/manifest-schemas/formats/web3api.build/0.0.1-prealpha.2.json +++ b/packages/manifest-schemas/formats/web3api.build/0.0.1-prealpha.1.json @@ -8,7 +8,7 @@ "properties": { "format": { "type": "string", - "const": "0.0.1-prealpha.2" + "const": "0.0.1-prealpha.1" }, "docker": { "type": "object", diff --git a/packages/manifest-schemas/formats/web3api.plugin/0.0.1-prealpha.1.json b/packages/manifest-schemas/formats/web3api.plugin/0.0.1-prealpha.1.json new file mode 100644 index 0000000000..77f8bb2cfa --- /dev/null +++ b/packages/manifest-schemas/formats/web3api.plugin/0.0.1-prealpha.1.json @@ -0,0 +1,43 @@ +{ + "id": "PluginManifest", + "type": "object", + "additionalProperties": false, + "required": [ + "format", + "language", + "schema" + ], + "properties": { + "format": { + "type": "string", + "const": "0.0.1-prealpha.1" + }, + "language": { + "type": "string", + "format": "pluginLanguage" + }, + "schema": { + "type": "string", + "format": "file" + }, + "import_redirects": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "uri": { + "type": "string" + }, + "schema": { + "type": "string" + } + }, + "required": [ + "uri", + "schema" + ] + } + } + } +} diff --git a/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.1.json b/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.1.json index c328fadef0..f2e0c9e9e4 100644 --- a/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.1.json +++ b/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.1.json @@ -98,24 +98,22 @@ }, "import_redirects": { "type": "array", - "items": [ - { - "type": "object", - "additionalProperties": false, - "properties": { - "uri": { - "type": "string" - }, - "schema": { - "type": "string" - } + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "uri": { + "type": "string" }, - "required": [ - "uri", - "schema" - ] - } - ] + "schema": { + "type": "string" + } + }, + "required": [ + "uri", + "schema" + ] + } } } } diff --git a/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.2.json b/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.2.json index c92cfa7399..b627b5d034 100644 --- a/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.2.json +++ b/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.2.json @@ -67,24 +67,22 @@ }, "import_redirects": { "type": "array", - "items": [ - { - "type": "object", - "additionalProperties": false, - "properties": { - "uri": { - "type": "string" - }, - "schema": { - "type": "string" - } + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "uri": { + "type": "string" }, - "required": [ - "uri", - "schema" - ] - } - ] + "schema": { + "type": "string" + } + }, + "required": [ + "uri", + "schema" + ] + } } } } diff --git a/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.3.json b/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.3.json index 5bacd6fc55..2e87c84df9 100644 --- a/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.3.json +++ b/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.3.json @@ -67,24 +67,22 @@ }, "import_redirects": { "type": "array", - "items": [ - { - "type": "object", - "additionalProperties": false, - "properties": { - "uri": { - "type": "string" - }, - "schema": { - "type": "string" - } + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "uri": { + "type": "string" }, - "required": [ - "uri", - "schema" - ] - } - ] + "schema": { + "type": "string" + } + }, + "required": [ + "uri", + "schema" + ] + } } } } diff --git a/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.4.json b/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.4.json new file mode 100644 index 0000000000..4b4fc6a30a --- /dev/null +++ b/packages/manifest-schemas/formats/web3api/0.0.1-prealpha.4.json @@ -0,0 +1,86 @@ +{ + "id": "Web3ApiManifest", + "type": "object", + "additionalProperties": false, + "required": [ + "format", + "modules", + "language" + ], + "properties": { + "format": { + "type": "string", + "const": "0.0.1-prealpha.4" + }, + "repository": { + "type": "string" + }, + "build": { + "type": "string", + "format": "file" + }, + "language": { + "type": "string", + "format": "wasmLanguage" + }, + "modules": { + "type": "object", + "additionalProperties": false, + "properties": { + "mutation": { + "type": "object", + "additionalProperties": false, + "properties": { + "schema": { + "type": "string", + "format": "file" + }, + "module": { + "type": "string", + "format": "file" + } + }, + "required": [ + "schema" + ] + }, + "query": { + "type": "object", + "additionalProperties": false, + "properties": { + "schema": { + "type": "string", + "format": "file" + }, + "module": { + "type": "string", + "format": "file" + } + }, + "required": [ + "schema" + ] + } + } + }, + "import_redirects": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "uri": { + "type": "string" + }, + "schema": { + "type": "string" + } + }, + "required": [ + "uri", + "schema" + ] + } + } + } +} diff --git a/packages/schema/bind/.gitignore b/packages/schema/bind/.gitignore new file mode 100644 index 0000000000..368d336f26 --- /dev/null +++ b/packages/schema/bind/.gitignore @@ -0,0 +1 @@ +test-results/ \ No newline at end of file diff --git a/packages/schema/bind/src/__tests__/index.ts b/packages/schema/bind/src/__tests__/index.ts index f0775fb3d4..441dde3981 100644 --- a/packages/schema/bind/src/__tests__/index.ts +++ b/packages/schema/bind/src/__tests__/index.ts @@ -15,12 +15,14 @@ export type TestCase = { input: { query?: BindModuleOptions; mutation?: BindModuleOptions; + combined?: BindModuleOptions; }, outputLanguages: { language: string; directories: { query?: string; mutation?: string; + combined?: string; }; }[]; }; @@ -63,17 +65,27 @@ export function fetchTestCases(): TestCases { const outputDir = path.join(root, dirent.name, "output"); const outputLanguages = fs.readdirSync(outputDir, { withFileTypes: true }) .filter((item: fs.Dirent) => item.isDirectory()) - .map((item: fs.Dirent) => ({ - language: item.name, - directories: { - query: querySchema - ? path.join(outputDir, item.name, "query") - : undefined, - mutation: mutationSchema - ? path.join(outputDir, item.name, "mutation") - : undefined, - } - })); + .map((item: fs.Dirent) => { + const outputMutationDir = path.join(outputDir, item.name, "mutation"); + const outputMutation = fs.existsSync(outputMutationDir); + const outputQueryDir = path.join(outputDir, item.name, "query"); + const outputQuery = fs.existsSync(outputQueryDir); + + return { + language: item.name, + directories: { + query: outputMutation + ? path.join(outputDir, item.name, "query") + : undefined, + mutation: outputQuery + ? path.join(outputDir, item.name, "mutation") + : undefined, + combined: !outputMutation && !outputQuery + ? path.join(outputDir, item.name) + : undefined, + } + }; + }); // Compose the input schemas into TypeInfo structures const composed = await composeSchema({ @@ -99,7 +111,7 @@ export function fetchTestCases(): TestCases { return Promise.resolve(fetchIfExists(path) || ""); } }, - output: ComposerFilter.TypeInfo + output: ComposerFilter.All }) // Add the newly formed test case @@ -109,12 +121,19 @@ export function fetchTestCases(): TestCases { input: { query: querySchema ? { typeInfo: composed.query?.typeInfo as TypeInfo, + schema: composed.query?.schema as string, outputDirAbs: path.join(root, "query") } : undefined, mutation: mutationSchema ? { typeInfo: composed.mutation?.typeInfo as TypeInfo, + schema: composed.mutation?.schema as string, outputDirAbs: path.join(root, "mutation") }: undefined, + combined: { + typeInfo: composed.combined.typeInfo as TypeInfo, + schema: composed.combined.schema as string, + outputDirAbs: "" + } }, outputLanguages }; diff --git a/packages/schema/bind/src/__tests__/test-cases.spec.ts b/packages/schema/bind/src/__tests__/test-cases.spec.ts index d16a6e1059..49bd425270 100644 --- a/packages/schema/bind/src/__tests__/test-cases.spec.ts +++ b/packages/schema/bind/src/__tests__/test-cases.spec.ts @@ -3,6 +3,11 @@ import { readDirectory } from "../utils/fs"; import { alphabeticalNamedSort } from "../utils/sort"; import { bindSchema, OutputEntry, TargetLanguage } from "../"; +import { writeFileSync } from "@web3api/os-js"; + +import fs from "fs"; +import path from "path"; + describe("Web3API Binding Test Suite", () => { const cases = fetchTestCases(); @@ -27,12 +32,16 @@ describe("Web3API Binding Test Suite", () => { mutation: directories.mutation ? readDirectory(directories.mutation) : undefined, + combined: directories.combined + ? readDirectory(directories.combined) + : undefined, }; const output = bindSchema({ language: language as TargetLanguage, - query: testCase.input.query, - mutation: testCase.input.mutation + query: expectedOutput.query ? testCase.input.query : undefined, + mutation: expectedOutput.mutation ? testCase.input.mutation : undefined, + combined: expectedOutput.combined ? testCase.input.combined : undefined, }); const sort = (array: OutputEntry[]): OutputEntry[] => { @@ -51,6 +60,25 @@ describe("Web3API Binding Test Suite", () => { output.mutation.entries = sort(output.mutation.entries); } + if (output.combined) { + output.combined.entries = sort(output.combined.entries); + } + + const testResultDir = path.join(__dirname, "/test-results/"); + + if (!fs.existsSync(testResultDir)) { + fs.mkdirSync(testResultDir); + } + + writeFileSync( + path.join(testResultDir, `${language}-output.json`), + JSON.stringify(output, null, 2), + ); + writeFileSync( + path.join(testResultDir, `${language}-expected.json`), + JSON.stringify(expectedOutput, null, 2), + ); + expect(output).toMatchObject(expectedOutput); } }); diff --git a/packages/schema/bind/src/bindings/index.ts b/packages/schema/bind/src/bindings/index.ts index 81e1be60f8..ba70cadf7a 100644 --- a/packages/schema/bind/src/bindings/index.ts +++ b/packages/schema/bind/src/bindings/index.ts @@ -1,15 +1,19 @@ import { OutputDirectory, TargetLanguage } from "../"; import * as WasmAs from "./wasm-as"; +import * as PluginTs from "./plugin-ts"; import { TypeInfo } from "@web3api/schema-parse"; export function generateBinding( language: TargetLanguage, - typeInfo: TypeInfo + typeInfo: TypeInfo, + schema: string ): OutputDirectory { switch (language) { case "wasm-as": return WasmAs.generateBinding(typeInfo); + case "plugin-ts": + return PluginTs.generateBinding(typeInfo, schema); default: throw Error(`Error: Language binding unsupported - ${language}`); } diff --git a/packages/schema/bind/src/bindings/plugin-ts/functions.ts b/packages/schema/bind/src/bindings/plugin-ts/functions.ts new file mode 100644 index 0000000000..d1d472ca2a --- /dev/null +++ b/packages/schema/bind/src/bindings/plugin-ts/functions.ts @@ -0,0 +1,63 @@ +import { MustacheFunction } from "../types"; + +export const toTypescript: MustacheFunction = () => { + return (value: string, render: (template: string) => string) => { + let type = render(value); + + let nullable = false; + if (type[type.length - 1] === "!") { + type = type.substr(0, type.length - 1); + } else { + nullable = true; + } + + if (type[0] === "[") { + return toTypescriptArray(type, nullable); + } + + switch (type) { + case "Int": + case "Int8": + case "Int16": + case "Int32": + case "Int64": + case "UInt": + case "UInt32": + case "UInt8": + case "UInt16": + case "UInt64": + case "String": + case "Boolean": + case "Bytes": + case "BigInt": + break; + default: + if (type.includes("Enum_")) { + type = `Types.${type.replace("Enum_", "")}`; + } else { + type = `Types.${type}`; + } + } + + return applyNullable(type, nullable); + }; +}; + +const toTypescriptArray = (type: string, nullable: boolean): string => { + const result = type.match(/(\[)([[\]A-Za-z1-9_.!]+)(\])/); + + if (!result || result.length !== 4) { + throw Error(`Invalid Array: ${type}`); + } + + const tsType = toTypescript()(result[2], (str) => str); + return applyNullable("Array<" + tsType + ">", nullable); +}; + +const applyNullable = (type: string, nullable: boolean): string => { + if (nullable) { + return `${type} | undefined`; + } else { + return type; + } +}; diff --git a/packages/schema/bind/src/bindings/plugin-ts/index.ts b/packages/schema/bind/src/bindings/plugin-ts/index.ts new file mode 100644 index 0000000000..071fde312b --- /dev/null +++ b/packages/schema/bind/src/bindings/plugin-ts/index.ts @@ -0,0 +1,81 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { OutputDirectory, OutputEntry } from "../.."; +import * as Functions from "./functions"; + +import { + transformTypeInfo, + extendType, + addFirstLast, + toPrefixedGraphQLType, + methodParentPointers, + interfaceUris, + TypeInfo, + QueryDefinition, +} from "@web3api/schema-parse"; +import Mustache from "mustache"; +import { readFileSync } from "fs"; +import path from "path"; + +export function generateBinding( + typeInfo: TypeInfo, + schema?: string +): OutputDirectory { + const entries: OutputEntry[] = []; + + // Transform the TypeInfo to our liking + const transforms = [ + extendType(Functions), + addFirstLast, + toPrefixedGraphQLType, + methodParentPointers(), + interfaceUris(), + ]; + + for (const transform of transforms) { + typeInfo = transformTypeInfo(typeInfo, transform); + } + + const renderTemplate = (subPath: string, context: unknown) => { + const absPath = path.join(__dirname, subPath); + const template = readFileSync(absPath, { encoding: "utf-8" }); + const fileName = absPath + .replace(path.dirname(absPath), "") + .replace(".mustache", "") + .replace("/", "") + .replace("\\", "") + .replace("-", "."); + + entries.push({ + type: "File", + name: fileName, + data: Mustache.render(template, context), + }); + }; + + const queryContext = typeInfo.queryTypes.find((def: QueryDefinition) => { + return def.type === "Query"; + }); + const mutationContext = typeInfo.queryTypes.find((def: QueryDefinition) => { + return def.type === "Mutation"; + }); + + const rootContext = { + ...typeInfo, + schema, + __mutation: !!mutationContext, + __query: !!queryContext, + }; + + renderTemplate("./templates/index-ts.mustache", rootContext); + renderTemplate("./templates/manifest-ts.mustache", rootContext); + if (mutationContext) { + renderTemplate("./templates/mutation-ts.mustache", mutationContext); + } + if (queryContext) { + renderTemplate("./templates/query-ts.mustache", queryContext); + } + renderTemplate("./templates/schema-ts.mustache", rootContext); + renderTemplate("./templates/types-ts.mustache", rootContext); + + return { entries }; +} diff --git a/packages/schema/bind/src/bindings/plugin-ts/templates/index-ts.mustache b/packages/schema/bind/src/bindings/plugin-ts/templates/index-ts.mustache new file mode 100644 index 0000000000..cd1552743f --- /dev/null +++ b/packages/schema/bind/src/bindings/plugin-ts/templates/index-ts.mustache @@ -0,0 +1,9 @@ +{{#__query}} +export * as Query from "./query"; +{{/__query}} +{{#__mutation}} +export * as Mutation from "./mutation"; +{{/__mutation}} +export * from "./types"; +export * from "./schema"; +export * from "./manifest"; diff --git a/packages/schema/bind/src/bindings/plugin-ts/templates/manifest-ts.mustache b/packages/schema/bind/src/bindings/plugin-ts/templates/manifest-ts.mustache new file mode 100644 index 0000000000..ef22d2dced --- /dev/null +++ b/packages/schema/bind/src/bindings/plugin-ts/templates/manifest-ts.mustache @@ -0,0 +1,13 @@ +// @ts-noCheck +import { schema } from "./"; + +import { PluginPackageManifest, Uri } from "@web3api/core-js"; + +export const manifest: PluginPackageManifest = { + schema, + implements: [ + {{#interfaceUris}} + new Uri("{{.}}"), + {{/interfaceUris}} + ], +} diff --git a/packages/schema/bind/src/bindings/plugin-ts/templates/mutation-ts.mustache b/packages/schema/bind/src/bindings/plugin-ts/templates/mutation-ts.mustache new file mode 100644 index 0000000000..0cb6b45fb2 --- /dev/null +++ b/packages/schema/bind/src/bindings/plugin-ts/templates/mutation-ts.mustache @@ -0,0 +1,42 @@ +// @ts-noCheck +import { + UInt, + UInt8, + UInt16, + UInt32, + Int, + Int8, + Int16, + Int32, + Bytes, + BigInt, + String, + Boolean +} from "./types"; +import * as Types from "./types"; + +import { + Client, + PluginModule, + MaybeAsync +} from "@web3api/core-js"; + +{{#methods}} +export interface Input_{{name}} extends Record { + {{#arguments}} + {{name}}{{^required}}?{{/required}}: {{#toTypescript}}{{toGraphQLType}}{{/toTypescript}}; + {{/arguments}} +} + +{{/methods}} +export interface Module extends PluginModule { + {{#methods}} + {{name}}( + input: Input_{{name}}, + client: Client + ): MaybeAsync<{{#return}}{{#toTypescript}}{{toGraphQLType}}{{/toTypescript}}{{/return}}>; + {{^last}} + + {{/last}} + {{/methods}} +} diff --git a/packages/schema/bind/src/bindings/plugin-ts/templates/query-ts.mustache b/packages/schema/bind/src/bindings/plugin-ts/templates/query-ts.mustache new file mode 100644 index 0000000000..0cb6b45fb2 --- /dev/null +++ b/packages/schema/bind/src/bindings/plugin-ts/templates/query-ts.mustache @@ -0,0 +1,42 @@ +// @ts-noCheck +import { + UInt, + UInt8, + UInt16, + UInt32, + Int, + Int8, + Int16, + Int32, + Bytes, + BigInt, + String, + Boolean +} from "./types"; +import * as Types from "./types"; + +import { + Client, + PluginModule, + MaybeAsync +} from "@web3api/core-js"; + +{{#methods}} +export interface Input_{{name}} extends Record { + {{#arguments}} + {{name}}{{^required}}?{{/required}}: {{#toTypescript}}{{toGraphQLType}}{{/toTypescript}}; + {{/arguments}} +} + +{{/methods}} +export interface Module extends PluginModule { + {{#methods}} + {{name}}( + input: Input_{{name}}, + client: Client + ): MaybeAsync<{{#return}}{{#toTypescript}}{{toGraphQLType}}{{/toTypescript}}{{/return}}>; + {{^last}} + + {{/last}} + {{/methods}} +} diff --git a/packages/schema/bind/src/bindings/plugin-ts/templates/schema-ts.mustache b/packages/schema/bind/src/bindings/plugin-ts/templates/schema-ts.mustache new file mode 100644 index 0000000000..394b057efc --- /dev/null +++ b/packages/schema/bind/src/bindings/plugin-ts/templates/schema-ts.mustache @@ -0,0 +1 @@ +export const schema: string = `{{schema}}`; diff --git a/packages/schema/bind/src/bindings/plugin-ts/templates/types-ts.mustache b/packages/schema/bind/src/bindings/plugin-ts/templates/types-ts.mustache new file mode 100644 index 0000000000..3c96711ccd --- /dev/null +++ b/packages/schema/bind/src/bindings/plugin-ts/templates/types-ts.mustache @@ -0,0 +1,93 @@ +// @ts-noCheck +import * as Types from "./"; + +import { + Client, + InvokeApiResult +} from "@web3api/core-js"; + +export type UInt = number; +export type UInt8 = number; +export type UInt16 = number; +export type UInt32 = number; +export type Int = number; +export type Int8 = number; +export type Int16 = number; +export type Int32 = number; +export type Bytes = Uint8Array; +export type BigInt = string; +export type String = string; +export type Boolean = boolean; + +{{#objectTypes}} +export interface {{type}} { + {{#properties}} + {{name}}{{^required}}?{{/required}}: {{#toTypescript}}{{toGraphQLType}}{{/toTypescript}}; + {{/properties}} +} + +{{/objectTypes}} +{{#enumTypes}} +export enum {{type}} { + {{#constants}} + {{.}}, + {{/constants}} +} + +{{/enumTypes}} +/// Imported Objects START /// + +{{#importedObjectTypes}} +/* URI: "{{uri}}" */ +export interface {{type}} { + {{#properties}} + {{name}}{{^required}}?{{/required}}: {{#toTypescript}}{{toGraphQLType}}{{/toTypescript}}; + {{/properties}} +} + +{{/importedObjectTypes}} +{{#importedEnumTypes}} +/* URI: "{{uri}}" */ +export enum {{type}} { + {{#constants}} + {{.}}, + {{/constants}} +} + +{{/importedEnumTypes}} +/// Imported Objects END /// + +/// Imported Queries START /// + +{{#importedQueryTypes}} +{{#methods}} +/* URI: "{{parent.uri}}" */ +interface {{parent.type}}_Input_{{name}} extends Record { + {{#arguments}} + {{name}}{{^required}}?{{/required}}: {{#toTypescript}}{{toGraphQLType}}{{/toTypescript}}; + {{/arguments}} +} + +{{/methods}} +/* URI: "{{uri}}" */ +export const {{type}} = { + {{#methods}} + {{name}}: async ( + input: {{parent.type}}_Input_{{name}}, + client: Client + ): Promise> => { + return client.invoke<{{#return}}{{#toTypescript}}{{toGraphQLType}}{{/toTypescript}}{{/return}}>({ + uri: "{{parent.uri}}", + module: "{{type}}", + method: "{{name}}", + input + }); + }{{^last}},{{/last}} + {{^last}} + + {{/last}} + {{/methods}} +} + +{{/importedQueryTypes}} +/// Imported Queries END /// diff --git a/packages/schema/bind/src/bindings/plugin-ts/types.ts b/packages/schema/bind/src/bindings/plugin-ts/types.ts new file mode 100644 index 0000000000..62f69945d9 --- /dev/null +++ b/packages/schema/bind/src/bindings/plugin-ts/types.ts @@ -0,0 +1,13 @@ +const baseTypes = { + boolean: "boolean", + number: "number", + string: "string", +}; + +export type BaseTypes = typeof baseTypes; + +export type BaseType = keyof BaseTypes; + +export function isBaseType(type: string): type is BaseType { + return type in baseTypes; +} diff --git a/packages/schema/bind/src/bindings/types.ts b/packages/schema/bind/src/bindings/types.ts new file mode 100644 index 0000000000..9a85a0af6b --- /dev/null +++ b/packages/schema/bind/src/bindings/types.ts @@ -0,0 +1,4 @@ +export type MustacheFunction = () => ( + value: string, + render: (template: string) => string +) => string; diff --git a/packages/schema/bind/src/bindings/wasm-as/functions.ts b/packages/schema/bind/src/bindings/wasm-as/functions.ts index dce9740777..dee6d670ce 100644 --- a/packages/schema/bind/src/bindings/wasm-as/functions.ts +++ b/packages/schema/bind/src/bindings/wasm-as/functions.ts @@ -1,9 +1,5 @@ import { isBaseType } from "./types"; - -type MustacheFunction = () => ( - value: string, - render: (template: string) => string -) => string; +import { MustacheFunction } from "../types"; export const toMsgPack: MustacheFunction = () => { return (value: string, render: (template: string) => string) => { diff --git a/packages/schema/bind/src/index.ts b/packages/schema/bind/src/index.ts index a8643af733..cc80669c1b 100644 --- a/packages/schema/bind/src/index.ts +++ b/packages/schema/bind/src/index.ts @@ -6,7 +6,7 @@ import { transformTypeInfo, TypeInfo } from "@web3api/schema-parse"; export * from "./utils"; -export type TargetLanguage = "wasm-as"; +export type TargetLanguage = "wasm-as" | "plugin-ts"; export type OutputEntry = FileEntry | DirectoryEntry | TemplateEntry; @@ -33,23 +33,26 @@ export interface OutputDirectory { } export interface BindOutput { + combined?: OutputDirectory; query?: OutputDirectory; mutation?: OutputDirectory; } export interface BindModuleOptions { typeInfo: TypeInfo; + schema: string; outputDirAbs: string; } export interface BindOptions { language: TargetLanguage; + combined?: BindModuleOptions; query?: BindModuleOptions; mutation?: BindModuleOptions; } export function bindSchema(options: BindOptions): BindOutput { - const { query, mutation, language } = options; + const { combined, query, mutation, language } = options; // If both Query & Mutation modules are present, // determine which types are shared between them, @@ -79,9 +82,14 @@ export function bindSchema(options: BindOptions): BindOutput { } return { - query: query ? generateBinding(language, query.typeInfo) : undefined, + combined: combined + ? generateBinding(language, combined.typeInfo, combined.schema) + : undefined, + query: query + ? generateBinding(language, query.typeInfo, query.schema) + : undefined, mutation: mutation - ? generateBinding(language, mutation.typeInfo) + ? generateBinding(language, mutation.typeInfo, mutation.schema) : undefined, }; } diff --git a/packages/schema/compose/src/__tests__/index.ts b/packages/schema/compose/src/__tests__/index.ts index 8915731a42..6b32e1b0a6 100644 --- a/packages/schema/compose/src/__tests__/index.ts +++ b/packages/schema/compose/src/__tests__/index.ts @@ -18,7 +18,7 @@ export interface TestCase { type TestCases = { promise: Promise; name: string; -}[] +}[]; export function fetchTestCases(): TestCases { @@ -96,51 +96,66 @@ export function fetchTestCases(): TestCases { return Promise.resolve(fetchIfExists(path, true) || ""); }; + const input: ComposerOptions = { + schemas: { }, + resolvers: { + external: resolveExternal, + local: resolveLocal, + }, + output: ComposerFilter.All + }; + + if (queryInput) { + input.schemas.query = { + schema: queryInput, + absolutePath: path.join( + root, + dirent.name, + "input/query.graphql" + ), + }; + } + + if (mutationInput) { + input.schemas.mutation = { + schema: mutationInput, + absolutePath: path.join( + root, + dirent.name, + "input/mutation.graphql" + ), + }; + } + + const output: ComposerOutput = { + combined: {} + }; + + if (querySchema && queryTypeInfo) { + output.query = { + schema: querySchema, + typeInfo: queryTypeInfo + }; + } + + if (mutationSchema && mutationTypeInfo) { + output.mutation = { + schema: mutationSchema, + typeInfo: mutationTypeInfo + }; + } + + if (schemaSchema && schemaTypeInfo) { + output.combined = { + schema: schemaSchema, + typeInfo: schemaTypeInfo + }; + } + return { name: dirent.name, - input: { - schemas: { - query: queryInput - ? { - schema: queryInput, - absolutePath: path.join( - root, - dirent.name, - "input/query.graphql" - ), - } - : undefined, - mutation: mutationInput - ? { - schema: mutationInput, - absolutePath: path.join( - root, - dirent.name, - "input/mutation.graphql" - ), - } - : undefined, - }, - resolvers: { - external: resolveExternal, - local: resolveLocal, - }, - output: ComposerFilter.All - }, - output: { - query: querySchema && queryTypeInfo ? { - schema: querySchema, - typeInfo: queryTypeInfo - } : undefined, - mutation: mutationSchema && mutationTypeInfo ? { - schema: mutationSchema, - typeInfo: mutationTypeInfo - } : undefined, - combined: schemaSchema && schemaTypeInfo ? { - schema: schemaSchema, - typeInfo: schemaTypeInfo - } : undefined - }, + input, + output, }; }; diff --git a/packages/schema/compose/src/index.ts b/packages/schema/compose/src/index.ts index a269e0848c..d1e4a7418d 100644 --- a/packages/schema/compose/src/index.ts +++ b/packages/schema/compose/src/index.ts @@ -12,8 +12,7 @@ export interface SchemaInfo { } export interface ComposerOutput { - query?: SchemaInfo; - mutation?: SchemaInfo; + [name: string]: SchemaInfo; combined: SchemaInfo; } @@ -25,8 +24,7 @@ export enum ComposerFilter { export interface ComposerOptions { schemas: { - query?: SchemaFile; - mutation?: SchemaFile; + [name: string]: SchemaFile; }; resolvers: SchemaResolvers; output: ComposerFilter; @@ -36,26 +34,21 @@ export async function composeSchema( options: ComposerOptions ): Promise { const { schemas, resolvers } = options; - const { query, mutation } = schemas; const typeInfos: { - query?: TypeInfo; - mutation?: TypeInfo; + [name: string]: TypeInfo; } = {}; - if (query && query.schema) { - typeInfos.query = await resolveImportsAndParseSchemas( - query.schema, - query.absolutePath, - false, - resolvers - ); + if (Object.keys(schemas).length === 0) { + throw Error("No schema provided"); } - if (mutation && mutation.schema) { - typeInfos.mutation = await resolveImportsAndParseSchemas( - mutation.schema, - mutation.absolutePath, - true, + for (const name of Object.keys(schemas)) { + const schema = schemas[name]; + + typeInfos[name] = await resolveImportsAndParseSchemas( + schema.schema, + schema.absolutePath, + name === "mutation", resolvers ); } @@ -69,26 +62,21 @@ export async function composeSchema( schema: includeSchema ? renderSchema(typeInfo, true) : undefined, typeInfo: includeTypeInfo ? typeInfo : undefined, }); + const typeInfoNames = Object.keys(typeInfos); - if (typeInfos.query) { - output.query = createSchemaInfo(typeInfos.query); + for (const name of typeInfoNames) { + const typeInfo = typeInfos[name]; + output[name] = createSchemaInfo(typeInfo); } - if (typeInfos.mutation) { - output.mutation = createSchemaInfo(typeInfos.mutation); - } - - if (typeInfos.query && typeInfos.mutation) { - const combinedTypeInfo = combineTypeInfo([ - typeInfos.query, - typeInfos.mutation, - ]); + if (typeInfoNames.length > 1) { + const combinedTypeInfo = combineTypeInfo( + typeInfoNames.map((name) => typeInfos[name]) + ); output.combined = createSchemaInfo(combinedTypeInfo); - } else if (typeInfos.query && output.query) { - output.combined = output.query; - } else if (typeInfos.mutation && output.mutation) { - output.combined = output.mutation; + } else { + output.combined = output[typeInfoNames[0]]; } return output; diff --git a/packages/schema/parse/src/transform/addFirstLast.ts b/packages/schema/parse/src/transform/addFirstLast.ts index 144201423d..6e58a3342b 100644 --- a/packages/schema/parse/src/transform/addFirstLast.ts +++ b/packages/schema/parse/src/transform/addFirstLast.ts @@ -1,47 +1,44 @@ import { TypeInfoTransforms } from "."; -import { - MethodDefinition, - ObjectDefinition, - QueryDefinition, - TypeInfo, - ImportedQueryDefinition, -} from "../typeInfo"; +import { TypeInfo, GenericDefinition } from "../typeInfo"; export const addFirstLast: TypeInfoTransforms = { enter: { - TypeInfo: (typeInfo: TypeInfo) => ({ + GenericDefinition: (def: GenericDefinition): GenericDefinition => { + const arrays: Record = {}; + + for (const key of Object.keys(def)) { + const value = ((def as unknown) as Record)[key]; + + if (Array.isArray(value)) { + arrays[key] = setFirstLast(value); + } + } + + return { + ...def, + ...arrays, + }; + }, + TypeInfo: (typeInfo: TypeInfo): TypeInfo => ({ ...typeInfo, objectTypes: setFirstLast(typeInfo.objectTypes), queryTypes: setFirstLast(typeInfo.queryTypes), importedObjectTypes: setFirstLast(typeInfo.importedObjectTypes), importedQueryTypes: setFirstLast(typeInfo.importedQueryTypes), }), - ObjectDefinition: (def: ObjectDefinition) => ({ - ...def, - properties: setFirstLast(def.properties), - interfaces: setFirstLast(def.interfaces), - }), - MethodDefinition: (def: MethodDefinition) => ({ - ...def, - arguments: setFirstLast(def.arguments), - }), - QueryDefinition: (def: QueryDefinition) => ({ - ...def, - methods: setFirstLast(def.methods), - imports: setFirstLast(def.imports), - interfaces: setFirstLast(def.interfaces), - }), - ImportedQueryDefinition: (def: ImportedQueryDefinition) => ({ - ...def, - methods: setFirstLast(def.methods), - }), }, }; function setFirstLast(array: T[]): T[] { - return array.map((item, index) => ({ - ...item, - first: index === 0 ? true : null, - last: index === array.length - 1 ? true : null, - })); + return array.map((item, index) => { + if (typeof item === "object") { + return { + ...item, + first: index === 0 ? true : null, + last: index === array.length - 1 ? true : null, + }; + } else { + return item; + } + }); } diff --git a/packages/schema/parse/src/transform/index.ts b/packages/schema/parse/src/transform/index.ts index c07e85b3bb..4fdf99f0a0 100644 --- a/packages/schema/parse/src/transform/index.ts +++ b/packages/schema/parse/src/transform/index.ts @@ -24,6 +24,8 @@ import { export * from "./finalizePropertyDef"; export * from "./extendType"; export * from "./addFirstLast"; +export * from "./interfaceUris"; +export * from "./methodParentPointers"; export * from "./toGraphQLType"; export interface TypeInfoTransforms { diff --git a/packages/schema/parse/src/transform/interfaceUris.ts b/packages/schema/parse/src/transform/interfaceUris.ts new file mode 100644 index 0000000000..e107d1862e --- /dev/null +++ b/packages/schema/parse/src/transform/interfaceUris.ts @@ -0,0 +1,53 @@ +import { TypeInfoTransforms } from "."; +import { TypeInfo, QueryDefinition, ObjectDefinition } from "../typeInfo"; + +export function interfaceUris(): TypeInfoTransforms { + const uniqueInterfaceUris: Record = {}; + const uniqueQueryInterfaceTypes: Record = {}; + const uniqueObjectInterfaceTypes: Record = {}; + + return { + enter: { + QueryDefinition: (def: QueryDefinition) => { + for (const interfaceDef of def.interfaces) { + uniqueQueryInterfaceTypes[interfaceDef.type] = true; + } + return def; + }, + ObjectDefinition: (def: ObjectDefinition) => { + for (const interfaceDef of def.interfaces) { + uniqueObjectInterfaceTypes[interfaceDef.type] = true; + } + return def; + }, + }, + leave: { + TypeInfo: (typeInfo: TypeInfo) => { + for (const interfaceType of Object.keys(uniqueQueryInterfaceTypes)) { + const importedInterface = typeInfo.importedQueryTypes.find( + (importedQuery) => importedQuery.type === interfaceType + ); + + if (importedInterface) { + uniqueInterfaceUris[importedInterface.uri] = true; + } + } + + for (const interfaceType of Object.keys(uniqueObjectInterfaceTypes)) { + const importedInterface = typeInfo.importedObjectTypes.find( + (importedObject) => importedObject.type === interfaceType + ); + + if (importedInterface) { + uniqueInterfaceUris[importedInterface.uri] = true; + } + } + + return { + ...typeInfo, + interfaceUris: Object.keys(uniqueInterfaceUris), + }; + }, + }, + }; +} diff --git a/packages/schema/parse/src/transform/methodParentPointers.ts b/packages/schema/parse/src/transform/methodParentPointers.ts new file mode 100644 index 0000000000..06739d2e83 --- /dev/null +++ b/packages/schema/parse/src/transform/methodParentPointers.ts @@ -0,0 +1,44 @@ +import { TypeInfoTransforms } from "."; +import { + QueryDefinition, + ImportedQueryDefinition, + MethodDefinition, +} from "../typeInfo"; + +export function methodParentPointers(): TypeInfoTransforms { + const visitorStack: (QueryDefinition | ImportedQueryDefinition)[] = []; + + return { + enter: { + QueryDefinition: (def: QueryDefinition) => { + visitorStack.push(def); + return def; + }, + ImportedQueryDefinition: (def: ImportedQueryDefinition) => { + visitorStack.push(def); + return def; + }, + MethodDefinition: (def: MethodDefinition) => { + const parent = + visitorStack.length > 0 + ? visitorStack[visitorStack.length - 1] + : undefined; + + return { + ...def, + parent, + }; + }, + }, + leave: { + QueryDefinition: (def: QueryDefinition) => { + visitorStack.pop(); + return def; + }, + ImportedQueryDefinition: (def: ImportedQueryDefinition) => { + visitorStack.pop(); + return def; + }, + }, + }; +} diff --git a/packages/templates/api/assemblyscript/web3api.build.yaml b/packages/templates/api/assemblyscript/web3api.build.yaml index ff79093235..878a83e8a1 100644 --- a/packages/templates/api/assemblyscript/web3api.build.yaml +++ b/packages/templates/api/assemblyscript/web3api.build.yaml @@ -1,4 +1,4 @@ -format: 0.0.1-prealpha.2 +format: 0.0.1-prealpha.1 docker: name: build-env config: diff --git a/packages/templates/api/assemblyscript/web3api.yaml b/packages/templates/api/assemblyscript/web3api.yaml index cb826f8a63..95ac2aa07c 100644 --- a/packages/templates/api/assemblyscript/web3api.yaml +++ b/packages/templates/api/assemblyscript/web3api.yaml @@ -1,5 +1,5 @@ repository: https://github.com/web3-api/monorepo -format: 0.0.1-prealpha.2 +format: 0.0.1-prealpha.4 language: wasm/assemblyscript build: ./web3api.build.yaml modules: diff --git a/packages/templates/api/interface/web3api.yaml b/packages/templates/api/interface/web3api.yaml index a147deb3f1..0b22996376 100644 --- a/packages/templates/api/interface/web3api.yaml +++ b/packages/templates/api/interface/web3api.yaml @@ -1,6 +1,6 @@ -format: 0.0.1-prealpha.3 +format: 0.0.1-prealpha.4 repository: https://github.com/web3-api/monorepo -interface: true +language: interface modules: query: - schema: ./src/query.graphql + schema: ./query.graphql diff --git a/packages/templates/plugin/typescript/package.json b/packages/templates/plugin/typescript/package.json index 3b7b50b007..1721b1f895 100644 --- a/packages/templates/plugin/typescript/package.json +++ b/packages/templates/plugin/typescript/package.json @@ -6,6 +6,7 @@ "main": "build/index.js", "scripts": { "build": "rimraf ./build && tsc --project tsconfig.json", + "prebuild": "npx w3 plugin codegen", "test": "jest --passWithNoTests --runInBand --verbose", "test:ci": "jest --passWithNoTests --runInBand --verbose", "test:watch": "jest --watch --passWithNoTests --verbose" @@ -16,6 +17,7 @@ "devDependencies": { "@types/jest": "26.0.8", "@web3api/client-js": "0.0.1-prealpha.31", + "@web3api/cli": "0.0.1-prealpha.31", "jest": "26.6.3", "rimraf": "3.0.2", "ts-jest": "26.5.4", diff --git a/packages/templates/plugin/typescript/src/__tests__/e2e.spec.ts b/packages/templates/plugin/typescript/src/__tests__/e2e.spec.ts index d10927caf7..2cc48245de 100644 --- a/packages/templates/plugin/typescript/src/__tests__/e2e.spec.ts +++ b/packages/templates/plugin/typescript/src/__tests__/e2e.spec.ts @@ -9,10 +9,10 @@ describe("e2e", () => { beforeAll(() => { // Add the samplePlugin to the Web3ApiClient client = new Web3ApiClient({ - redirects: [ + plugins: [ { - from: uri, - to: samplePlugin({ defaultValue: "foo bar" }) + uri: uri, + plugin: samplePlugin({ defaultValue: "foo bar" }) } ] }); diff --git a/packages/templates/plugin/typescript/src/index.ts b/packages/templates/plugin/typescript/src/index.ts index 92d9196450..cfc392c521 100644 --- a/packages/templates/plugin/typescript/src/index.ts +++ b/packages/templates/plugin/typescript/src/index.ts @@ -1,10 +1,10 @@ import { mutation, query } from "./resolvers"; -import { manifest } from "./manifest"; +import { manifest } from "./w3"; import { Plugin, PluginFactory, - PluginManifest, + PluginPackageManifest, PluginModules, } from "@web3api/core-js"; @@ -17,7 +17,7 @@ export class SamplePlugin extends Plugin { super(); } - public static manifest(): PluginManifest { + public static manifest(): PluginPackageManifest { return manifest; } diff --git a/packages/templates/plugin/typescript/src/manifest.ts b/packages/templates/plugin/typescript/src/manifest.ts deleted file mode 100644 index ebcc8802cd..0000000000 --- a/packages/templates/plugin/typescript/src/manifest.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { PluginManifest } from "@web3api/core-js"; - -export const manifest: PluginManifest = { - // TODO: use the schema.graphql - // https://github.com/web3-api/monorepo/issues/101 - schema: ` -type Query { - sampleQuery(data: String!): String! -} - -type Mutation { - sampleMutation(data: Bytes!): Boolean! -}`, - implements: [], -}; diff --git a/packages/templates/plugin/typescript/src/resolvers.ts b/packages/templates/plugin/typescript/src/resolvers.ts index fdeb6369fc..ead1554a16 100644 --- a/packages/templates/plugin/typescript/src/resolvers.ts +++ b/packages/templates/plugin/typescript/src/resolvers.ts @@ -1,15 +1,14 @@ import { SamplePlugin } from "."; +import { Query, Mutation } from "./w3"; -import { PluginModule } from "@web3api/core-js"; - -export const query = (plugin: SamplePlugin): PluginModule => ({ - sampleQuery: async (input: { data: string }) => { +export const query = (plugin: SamplePlugin): Query.Module => ({ + sampleQuery: async (input: Query.Input_sampleQuery) => { return await plugin.sampleQuery(input.data); }, }); -export const mutation = (plugin: SamplePlugin): PluginModule => ({ - sampleMutation: (input: { data: Uint8Array }) => { +export const mutation = (plugin: SamplePlugin): Mutation.Module => ({ + sampleMutation: (input: Mutation.Input_sampleMutation ) => { return plugin.sampleMutation(input.data); }, }); diff --git a/packages/templates/plugin/typescript/web3api.plugin.yaml b/packages/templates/plugin/typescript/web3api.plugin.yaml new file mode 100644 index 0000000000..b21359a846 --- /dev/null +++ b/packages/templates/plugin/typescript/web3api.plugin.yaml @@ -0,0 +1,3 @@ +format: 0.0.1-prealpha.1 +language: plugin/typescript +schema: ./schema.graphql diff --git a/packages/test-cases/cases/apis/implementations/test-interface/web3api.yaml b/packages/test-cases/cases/apis/implementations/test-interface/web3api.yaml index 49b631439d..a6a35c1d81 100644 --- a/packages/test-cases/cases/apis/implementations/test-interface/web3api.yaml +++ b/packages/test-cases/cases/apis/implementations/test-interface/web3api.yaml @@ -1,5 +1,5 @@ -format: 0.0.1-prealpha.3 -interface: true +format: 0.0.1-prealpha.4 +language: interface modules: mutation: schema: ./mutation/schema.graphql diff --git a/packages/test-cases/cases/bind/sanity/input/mutation.graphql b/packages/test-cases/cases/bind/sanity/input/mutation.graphql index 6a67c0c5cd..d994666cee 100644 --- a/packages/test-cases/cases/bind/sanity/input/mutation.graphql +++ b/packages/test-cases/cases/bind/sanity/input/mutation.graphql @@ -1,5 +1,5 @@ #import { CustomEnum, AnotherType } from "../imports-local/common.graphql" -#import { Query, Object, AnotherObject, Enum } into TestImport from "testimport.uri.eth" +#import { Query, Mutation, Object, AnotherObject, Enum } into TestImport from "testimport.uri.eth" type Mutation { mutationMethod( diff --git a/packages/test-cases/cases/bind/sanity/output/plugin-ts/index.ts b/packages/test-cases/cases/bind/sanity/output/plugin-ts/index.ts new file mode 100644 index 0000000000..905246e513 --- /dev/null +++ b/packages/test-cases/cases/bind/sanity/output/plugin-ts/index.ts @@ -0,0 +1,5 @@ +export * as Query from "./query"; +export * as Mutation from "./mutation"; +export * from "./types"; +export * from "./schema"; +export * from "./manifest"; diff --git a/packages/test-cases/cases/bind/sanity/output/plugin-ts/manifest.ts b/packages/test-cases/cases/bind/sanity/output/plugin-ts/manifest.ts new file mode 100644 index 0000000000..5e193c285e --- /dev/null +++ b/packages/test-cases/cases/bind/sanity/output/plugin-ts/manifest.ts @@ -0,0 +1,10 @@ +// @ts-noCheck +import { schema } from "./"; + +import { PluginPackageManifest, Uri } from "@web3api/core-js"; + +export const manifest: PluginPackageManifest = { + schema, + implements: [ + ], +} diff --git a/packages/test-cases/cases/bind/sanity/output/plugin-ts/mutation.ts b/packages/test-cases/cases/bind/sanity/output/plugin-ts/mutation.ts new file mode 100644 index 0000000000..57dba3206a --- /dev/null +++ b/packages/test-cases/cases/bind/sanity/output/plugin-ts/mutation.ts @@ -0,0 +1,50 @@ +// @ts-noCheck +import { + UInt, + UInt8, + UInt16, + UInt32, + Int, + Int8, + Int16, + Int32, + Bytes, + BigInt, + String, + Boolean +} from "./types"; +import * as Types from "./types"; + +import { + Client, + PluginModule, + MaybeAsync +} from "@web3api/core-js"; + +export interface Input_mutationMethod extends Record { + str: String; + optStr?: String | undefined; + en: Types.CustomEnum; + optEnum?: Types.CustomEnum | undefined; + enumArray: Array; + optEnumArray?: Array | undefined; +} + +export interface Input_objectMethod extends Record { + object: Types.AnotherType; + optObject?: Types.AnotherType | undefined; + objectArray: Array; + optObjectArray?: Array | undefined; +} + +export interface Module extends PluginModule { + mutationMethod( + input: Input_mutationMethod, + client: Client + ): MaybeAsync; + + objectMethod( + input: Input_objectMethod, + client: Client + ): MaybeAsync; +} diff --git a/packages/test-cases/cases/bind/sanity/output/plugin-ts/query.ts b/packages/test-cases/cases/bind/sanity/output/plugin-ts/query.ts new file mode 100644 index 0000000000..3b44183a0e --- /dev/null +++ b/packages/test-cases/cases/bind/sanity/output/plugin-ts/query.ts @@ -0,0 +1,50 @@ +// @ts-noCheck +import { + UInt, + UInt8, + UInt16, + UInt32, + Int, + Int8, + Int16, + Int32, + Bytes, + BigInt, + String, + Boolean +} from "./types"; +import * as Types from "./types"; + +import { + Client, + PluginModule, + MaybeAsync +} from "@web3api/core-js"; + +export interface Input_queryMethod extends Record { + str: String; + optStr?: String | undefined; + en: Types.CustomEnum; + optEnum?: Types.CustomEnum | undefined; + enumArray: Array; + optEnumArray?: Array | undefined; +} + +export interface Input_objectMethod extends Record { + object: Types.AnotherType; + optObject?: Types.AnotherType | undefined; + objectArray: Array; + optObjectArray?: Array | undefined; +} + +export interface Module extends PluginModule { + queryMethod( + input: Input_queryMethod, + client: Client + ): MaybeAsync; + + objectMethod( + input: Input_objectMethod, + client: Client + ): MaybeAsync; +} diff --git a/packages/test-cases/cases/bind/sanity/output/plugin-ts/schema.ts b/packages/test-cases/cases/bind/sanity/output/plugin-ts/schema.ts new file mode 100644 index 0000000000..3a6a2da395 --- /dev/null +++ b/packages/test-cases/cases/bind/sanity/output/plugin-ts/schema.ts @@ -0,0 +1,202 @@ +export const schema: string = `### Web3API Header START ### +scalar UInt +scalar UInt8 +scalar UInt16 +scalar UInt32 +scalar Int +scalar Int8 +scalar Int16 +scalar Int32 +scalar Bytes +scalar BigInt + +directive @imported( + uri: String! + namespace: String! + nativeType: String! +) on OBJECT | ENUM + +directive @imports( + types: [String!]! +) on OBJECT +### Web3API Header END ### + +type Query @imports( + types: [ + "TestImport_Query", + "TestImport_Object", + "TestImport_AnotherObject", + "TestImport_Enum" + ] +) { + queryMethod( + str: String! + optStr: String + en: CustomEnum! + optEnum: CustomEnum + enumArray: [CustomEnum!]! + optEnumArray: [CustomEnum] + ): Int! + + objectMethod( + object: AnotherType! + optObject: AnotherType + objectArray: [AnotherType!]! + optObjectArray: [AnotherType] + ): AnotherType +} + +type Mutation @imports( + types: [ + "TestImport_Query", + "TestImport_Object", + "TestImport_AnotherObject", + "TestImport_Enum", + "TestImport_Mutation" + ] +) { + mutationMethod( + str: String! + optStr: String + en: CustomEnum! + optEnum: CustomEnum + enumArray: [CustomEnum!]! + optEnumArray: [CustomEnum] + ): Int! + + objectMethod( + object: AnotherType! + optObject: AnotherType + objectArray: [AnotherType!]! + optObjectArray: [AnotherType] + ): AnotherType +} + +type CustomType { + str: String! + optStr: String + u: UInt! + optU: UInt + u8: UInt8! + u16: UInt16! + u32: UInt32! + i: Int! + i8: Int8! + i16: Int16! + i32: Int32! + bigint: BigInt! + optBigint: BigInt + bytes: Bytes! + optBytes: Bytes + boolean: Boolean! + optBoolean: Boolean + uArray: [UInt!]! + uOptArray: [UInt!] + optUOptArray: [UInt] + optStrOptArray: [String] + uArrayArray: [[UInt!]!]! + uOptArrayOptArray: [[UInt32]]! + uArrayOptArrayArray: [[[UInt32!]!]]! + crazyArray: [[[[UInt32!]]!]] + object: AnotherType! + optObject: AnotherType + objectArray: [AnotherType!]! + optObjectArray: [AnotherType] + en: CustomEnum! + optEnum: CustomEnum + enumArray: [CustomEnum!]! + optEnumArray: [CustomEnum] +} + +type AnotherType { + prop: String + circular: CustomType +} + +enum CustomEnum { + STRING + BYTES +} + +### Imported Queries START ### + +type TestImport_Query @imported( + uri: "testimport.uri.eth", + namespace: "TestImport", + nativeType: "Query" +) { + importedMethod( + str: String! + optStr: String + u: UInt! + optU: UInt + uArrayArray: [[UInt]]! + object: TestImport_Object! + optObject: TestImport_Object + objectArray: [TestImport_Object!]! + optObjectArray: [TestImport_Object] + en: TestImport_Enum! + optEnum: TestImport_Enum + enumArray: [TestImport_Enum!]! + optEnumArray: [TestImport_Enum] + ): TestImport_Object + + anotherMethod( + arg: [String!]! + ): Int32! +} + +type TestImport_Mutation @imported( + uri: "testimport.uri.eth", + namespace: "TestImport", + nativeType: "Mutation" +) { + importedMethod( + str: String! + object: TestImport_Object! + objectArray: [TestImport_Object!]! + ): TestImport_Object + + anotherMethod( + arg: [String!]! + ): Int32! +} + +### Imported Queries END ### + +### Imported Objects START ### + +type TestImport_Object @imported( + uri: "testimport.uri.eth", + namespace: "TestImport", + nativeType: "Object" +) { + object: TestImport_AnotherObject! + optObject: TestImport_AnotherObject + objectArray: [TestImport_AnotherObject!]! + optObjectArray: [TestImport_AnotherObject] + en: TestImport_Enum! + optEnum: TestImport_Enum + enumArray: [TestImport_Enum!]! + optEnumArray: [TestImport_Enum] +} + +type TestImport_AnotherObject @imported( + uri: "testimport.uri.eth", + namespace: "TestImport", + nativeType: "AnotherObject" +) { + prop: String! +} + +enum TestImport_Enum @imported( + namespace: "TestImport", + uri: "testimport.uri.eth", + nativeType: "Enum" +) { + STRING + BYTES +} + +### Imported Objects END ### +`; diff --git a/packages/test-cases/cases/bind/sanity/output/plugin-ts/types.ts b/packages/test-cases/cases/bind/sanity/output/plugin-ts/types.ts new file mode 100644 index 0000000000..f4ef849eab --- /dev/null +++ b/packages/test-cases/cases/bind/sanity/output/plugin-ts/types.ts @@ -0,0 +1,185 @@ +// @ts-noCheck +import * as Types from "./"; + +import { + Client, + InvokeApiResult +} from "@web3api/core-js"; + +export type UInt = number; +export type UInt8 = number; +export type UInt16 = number; +export type UInt32 = number; +export type Int = number; +export type Int8 = number; +export type Int16 = number; +export type Int32 = number; +export type Bytes = Uint8Array; +export type BigInt = string; +export type String = string; +export type Boolean = boolean; + +export interface CustomType { + str: String; + optStr?: String | undefined; + u: UInt; + optU?: UInt | undefined; + u8: UInt8; + u16: UInt16; + u32: UInt32; + i: Int; + i8: Int8; + i16: Int16; + i32: Int32; + bigint: BigInt; + optBigint?: BigInt | undefined; + bytes: Bytes; + optBytes?: Bytes | undefined; + boolean: Boolean; + optBoolean?: Boolean | undefined; + uArray: Array; + uOptArray?: Array | undefined; + optUOptArray?: Array | undefined; + optStrOptArray?: Array | undefined; + uArrayArray: Array>; + uOptArrayOptArray: Array | undefined>; + uArrayOptArrayArray: Array> | undefined>; + crazyArray?: Array | undefined>> | undefined> | undefined; + object: Types.AnotherType; + optObject?: Types.AnotherType | undefined; + objectArray: Array; + optObjectArray?: Array | undefined; + en: Types.CustomEnum; + optEnum?: Types.CustomEnum | undefined; + enumArray: Array; + optEnumArray?: Array | undefined; +} + +export interface AnotherType { + prop?: String | undefined; + circular?: Types.CustomType | undefined; +} + +export enum CustomEnum { + STRING, + BYTES, +} + +/// Imported Objects START /// + +/* URI: "testimport.uri.eth" */ +export interface TestImport_Object { + object: Types.TestImport_AnotherObject; + optObject?: Types.TestImport_AnotherObject | undefined; + objectArray: Array; + optObjectArray?: Array | undefined; + en: Types.TestImport_Enum; + optEnum?: Types.TestImport_Enum | undefined; + enumArray: Array; + optEnumArray?: Array | undefined; +} + +/* URI: "testimport.uri.eth" */ +export interface TestImport_AnotherObject { + prop: String; +} + +/* URI: "testimport.uri.eth" */ +export enum TestImport_Enum { + STRING, + BYTES, +} + +/// Imported Objects END /// + +/// Imported Queries START /// + +/* URI: "testimport.uri.eth" */ +interface TestImport_Query_Input_importedMethod extends Record { + str: String; + optStr?: String | undefined; + u: UInt; + optU?: UInt | undefined; + uArrayArray: Array | undefined>; + object: Types.TestImport_Object; + optObject?: Types.TestImport_Object | undefined; + objectArray: Array; + optObjectArray?: Array | undefined; + en: Types.TestImport_Enum; + optEnum?: Types.TestImport_Enum | undefined; + enumArray: Array; + optEnumArray?: Array | undefined; +} + +/* URI: "testimport.uri.eth" */ +interface TestImport_Query_Input_anotherMethod extends Record { + arg: Array; +} + +/* URI: "testimport.uri.eth" */ +export const TestImport_Query = { + importedMethod: async ( + input: TestImport_Query_Input_importedMethod, + client: Client + ): Promise> => { + return client.invoke({ + uri: "testimport.uri.eth", + module: "query", + method: "importedMethod", + input + }); + }, + + anotherMethod: async ( + input: TestImport_Query_Input_anotherMethod, + client: Client + ): Promise> => { + return client.invoke({ + uri: "testimport.uri.eth", + module: "query", + method: "anotherMethod", + input + }); + } +} + +/* URI: "testimport.uri.eth" */ +interface TestImport_Mutation_Input_importedMethod extends Record { + str: String; + object: Types.TestImport_Object; + objectArray: Array; +} + +/* URI: "testimport.uri.eth" */ +interface TestImport_Mutation_Input_anotherMethod extends Record { + arg: Array; +} + +/* URI: "testimport.uri.eth" */ +export const TestImport_Mutation = { + importedMethod: async ( + input: TestImport_Mutation_Input_importedMethod, + client: Client + ): Promise> => { + return client.invoke({ + uri: "testimport.uri.eth", + module: "mutation", + method: "importedMethod", + input + }); + }, + + anotherMethod: async ( + input: TestImport_Mutation_Input_anotherMethod, + client: Client + ): Promise> => { + return client.invoke({ + uri: "testimport.uri.eth", + module: "mutation", + method: "anotherMethod", + input + }); + } +} + +/// Imported Queries END /// diff --git a/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/imported/TestImport_Mutation/index.ts b/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/imported/TestImport_Mutation/index.ts new file mode 100644 index 0000000000..8c3465225b --- /dev/null +++ b/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/imported/TestImport_Mutation/index.ts @@ -0,0 +1,41 @@ +import { + w3_subinvoke, + Nullable, + BigInt +} from "@web3api/wasm-as"; +import { + serializeimportedMethodArgs, + deserializeimportedMethodResult, + Input_importedMethod, + serializeanotherMethodArgs, + deserializeanotherMethodResult, + Input_anotherMethod +} from "./serialization"; +import * as Types from "../.."; + +export class TestImport_Mutation { + + public static uri: string = "testimport.uri.eth"; + + public static importedMethod(input: Input_importedMethod): Types.TestImport_Object | null { + const args = serializeimportedMethodArgs(input); + const result = w3_subinvoke( + "testimport.uri.eth", + "mutation", + "importedMethod", + args + ); + return deserializeimportedMethodResult(result); + } + + public static anotherMethod(input: Input_anotherMethod): i32 { + const args = serializeanotherMethodArgs(input); + const result = w3_subinvoke( + "testimport.uri.eth", + "mutation", + "anotherMethod", + args + ); + return deserializeanotherMethodResult(result); + } +} diff --git a/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/imported/TestImport_Mutation/serialization.ts b/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/imported/TestImport_Mutation/serialization.ts new file mode 100644 index 0000000000..6a7831453f --- /dev/null +++ b/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/imported/TestImport_Mutation/serialization.ts @@ -0,0 +1,102 @@ +import { + Nullable, + Write, + WriteSizer, + WriteEncoder, + ReadDecoder, + BigInt, + Context +} from "@web3api/wasm-as"; +import * as Types from "../.."; + +export class Input_importedMethod { + str: string; + object: Types.TestImport_Object; + objectArray: Array; +} + +export function serializeimportedMethodArgs(input: Input_importedMethod): ArrayBuffer { + const sizerContext: Context = new Context("Serializing (sizing) imported query-type: importedMethod"); + const sizer = new WriteSizer(sizerContext); + writeimportedMethodArgs(sizer, input); + const buffer = new ArrayBuffer(sizer.length); + const encoderContext: Context = new Context("Serializing (encoding) imported query-type: importedMethod"); + const encoder = new WriteEncoder(buffer, encoderContext); + writeimportedMethodArgs(encoder, input); + return buffer; +} + +export function writeimportedMethodArgs( + writer: Write, + input: Input_importedMethod +): void { + writer.writeMapLength(3); + writer.context().push("str", "string", "writing property"); + writer.writeString("str"); + writer.writeString(input.str); + writer.context().pop(); + writer.context().push("object", "Types.TestImport_Object", "writing property"); + writer.writeString("object"); + Types.TestImport_Object.write(writer, input.object); + writer.context().pop(); + writer.context().push("objectArray", "Array", "writing property"); + writer.writeString("objectArray"); + writer.writeArray(input.objectArray, (writer: Write, item: Types.TestImport_Object): void => { + Types.TestImport_Object.write(writer, item); + }); + writer.context().pop(); +} + +export function deserializeimportedMethodResult(buffer: ArrayBuffer): Types.TestImport_Object | null { + const context: Context = new Context("Deserializing imported query-type: importedMethod"); + const reader = new ReadDecoder(buffer, context); + + reader.context().push("importedMethod", "Types.TestImport_Object | null", "reading function output"); + let object: Types.TestImport_Object | null = null; + if (!reader.isNextNil()) { + object = Types.TestImport_Object.read(reader); + } + const res: Types.TestImport_Object | null = object; + reader.context().pop(); + + return res; +} + +export class Input_anotherMethod { + arg: Array; +} + +export function serializeanotherMethodArgs(input: Input_anotherMethod): ArrayBuffer { + const sizerContext: Context = new Context("Serializing (sizing) imported query-type: anotherMethod"); + const sizer = new WriteSizer(sizerContext); + writeanotherMethodArgs(sizer, input); + const buffer = new ArrayBuffer(sizer.length); + const encoderContext: Context = new Context("Serializing (encoding) imported query-type: anotherMethod"); + const encoder = new WriteEncoder(buffer, encoderContext); + writeanotherMethodArgs(encoder, input); + return buffer; +} + +export function writeanotherMethodArgs( + writer: Write, + input: Input_anotherMethod +): void { + writer.writeMapLength(1); + writer.context().push("arg", "Array", "writing property"); + writer.writeString("arg"); + writer.writeArray(input.arg, (writer: Write, item: string): void => { + writer.writeString(item); + }); + writer.context().pop(); +} + +export function deserializeanotherMethodResult(buffer: ArrayBuffer): i32 { + const context: Context = new Context("Deserializing imported query-type: anotherMethod"); + const reader = new ReadDecoder(buffer, context); + + reader.context().push("anotherMethod", "i32", "reading function output"); + const res: i32 = reader.readInt32(); + reader.context().pop(); + + return res; +} diff --git a/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/imported/index.ts b/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/imported/index.ts index 5aa9d402f3..dcb1660624 100644 --- a/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/imported/index.ts +++ b/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/imported/index.ts @@ -1,4 +1,5 @@ export * from "./TestImport_Query"; +export * from "./TestImport_Mutation"; export * from "./TestImport_Object"; export * from "./TestImport_AnotherObject"; export * from "./TestImport_Enum"; diff --git a/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/index.ts b/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/index.ts index f012197920..dde358ab2f 100644 --- a/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/index.ts +++ b/packages/test-cases/cases/bind/sanity/output/wasm-as/mutation/index.ts @@ -18,6 +18,7 @@ export { } from "./CustomEnum"; export { TestImport_Query } from "./imported/TestImport_Query"; +export { TestImport_Mutation } from "./imported/TestImport_Mutation"; export { TestImport_Object } from "./imported/TestImport_Object"; export { TestImport_AnotherObject } from "./imported/TestImport_AnotherObject"; export { diff --git a/yarn.lock b/yarn.lock index 10a2f9fe2a..31f0334013 100644 --- a/yarn.lock +++ b/yarn.lock @@ -410,13 +410,13 @@ "@babel/types" "^7.14.5" "@babel/helpers@^7.14.8", "@babel/helpers@^7.4.4", "@babel/helpers@^7.9.0": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.8.tgz#839f88f463025886cff7f85a35297007e2da1b77" - integrity sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw== + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.3.tgz#c96838b752b95dcd525b4e741ed40bb1dc2a1357" + integrity sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g== dependencies: "@babel/template" "^7.14.5" - "@babel/traverse" "^7.14.8" - "@babel/types" "^7.14.8" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" "@babel/highlight@^7.14.5", "@babel/highlight@^7.8.3": version "7.14.5" @@ -428,9 +428,9 @@ js-tokens "^4.0.0" "@babel/parser@^7.1.0", "@babel/parser@^7.14.5", "@babel/parser@^7.15.0", "@babel/parser@^7.4.3", "@babel/parser@^7.4.4", "@babel/parser@^7.7.0", "@babel/parser@^7.9.0": - version "7.15.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.2.tgz#08d4ffcf90d211bf77e7cc7154c6f02d468d2b1d" - integrity sha512-bMJXql1Ss8lFnvr11TZDH4ArtwlAS5NG9qBmdiFW2UHHm6MVoR+GDc5XE2b9K938cyjc9O6/+vjjcffLDtfuDg== + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.3.tgz#3416d9bea748052cfcb63dbcc27368105b1ed862" + integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA== "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": version "7.14.5" @@ -783,9 +783,9 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-block-scoping@^7.14.5", "@babel/plugin-transform-block-scoping@^7.4.4", "@babel/plugin-transform-block-scoping@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.5.tgz#8cc63e61e50f42e078e6f09be775a75f23ef9939" - integrity sha512-LBYm4ZocNgoCqyxMLoOnwpsmQ18HWTQvql64t3GvMUzLQrNoV1BDG0lNftC8QKYERkZgCCT/7J5xWGObGAyHDw== + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz#94c81a6e2fc230bcce6ef537ac96a1e4d2b3afaf" + integrity sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q== dependencies: "@babel/helper-plugin-utils" "^7.14.5" @@ -1370,9 +1370,9 @@ "@babel/plugin-transform-typescript" "^7.9.0" "@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.12.1": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.14.9.tgz#fb21b1cf11650dcb8fcf4de2e6b3b8cf411da3f3" - integrity sha512-64RiH2ON4/y8qYtoa8rUiyam/tUVyGqRyNYhe+vCRGmjnV4bUlZvY+mwd0RrmLoCpJpdq3RsrNqKb7SJdw/4kw== + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.15.3.tgz#28754263988198f2a928c09733ade2fb4d28089d" + integrity sha512-30A3lP+sRL6ml8uhoJSs+8jwpKzbw8CqBvDc1laeptxPm5FahumJxirigcbD2qTs71Sonvj1cyZB0OKGAmxQ+A== dependencies: core-js-pure "^3.16.0" regenerator-runtime "^0.13.4" @@ -1392,9 +1392,9 @@ regenerator-runtime "^0.13.4" "@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": - version "7.14.8" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446" - integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg== + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b" + integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA== dependencies: regenerator-runtime "^0.13.4" @@ -1407,7 +1407,7 @@ "@babel/parser" "^7.14.5" "@babel/types" "^7.14.5" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.14.8", "@babel/traverse@^7.15.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.4.4", "@babel/traverse@^7.7.0", "@babel/traverse@^7.9.0": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.15.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.4.4", "@babel/traverse@^7.7.0", "@babel/traverse@^7.9.0": version "7.15.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.0.tgz#4cca838fd1b2a03283c1f38e141f639d60b3fc98" integrity sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw== @@ -3165,10 +3165,10 @@ is-plain-object "^5.0.0" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^9.4.0": - version "9.4.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-9.4.0.tgz#31a76fb4c0f2e15af300edd880cedf4f75be212b" - integrity sha512-rKRkXikOJgDNImPl49IJuECLVXjj+t4qOXHhl8SBjMQCGGp1w4m5Ud/0kfdUx+zCpTvBN8vaOUDF4nnboZoOtQ== +"@octokit/openapi-types@^9.5.0": + version "9.7.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-9.7.0.tgz#9897cdefd629cd88af67b8dbe2e5fb19c63426b2" + integrity sha512-TUJ16DJU8mekne6+KVcMV5g6g/rJlrnIKn7aALG9QrNpnEipFc1xjoarh0PKaAWf2Hf+HwthRKYt+9mCm5RsRg== "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" @@ -3214,9 +3214,9 @@ once "^1.4.0" "@octokit/request@^5.2.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.0.tgz#6084861b6e4fa21dc40c8e2a739ec5eff597e672" - integrity sha512-4cPp/N+NqmaGQwbh3vUsYqokQIzt7VjsgTYVXiwpUP2pxd5YiZB2XuTedbb0SPtv9XS7nzAKjAuQxmY8/aZkiA== + version "5.6.1" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.1.tgz#f97aff075c37ab1d427c49082fefeef0dba2d8ce" + integrity sha512-Ls2cfs1OfXaOKzkcxnqw5MR6drMA/zWX/LIS/p8Yjdz7QKTPQLMsB3R+OvoxE6XnXeXEE2X7xe4G4l4X0gRiKQ== dependencies: "@octokit/endpoint" "^6.0.1" "@octokit/request-error" "^2.1.0" @@ -3255,11 +3255,11 @@ "@types/node" ">= 8" "@octokit/types@^6.0.3", "@octokit/types@^6.16.1": - version "6.24.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.24.0.tgz#d7858ceae8ac29256da85dcfcb9acbae28e6ba22" - integrity sha512-MfEimJeQ8AV1T2nI5kOfHqsqPHaAnG0Dw3MVoHSEsEq6iLKx2N91o+k2uAgXhPYeSE76LVBqjgTShnFFgNwe0A== + version "6.25.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.25.0.tgz#c8e37e69dbe7ce55ed98ee63f75054e7e808bf1a" + integrity sha512-bNvyQKfngvAd/08COlYIN54nRgxskmejgywodizQNyiKoXmWRAjKup2/LYwm+T9V0gsKH6tuld1gM0PzmOiB4Q== dependencies: - "@octokit/openapi-types" "^9.4.0" + "@octokit/openapi-types" "^9.5.0" "@opentelemetry/api-metrics@0.20.0": version "0.20.0" @@ -3749,9 +3749,9 @@ form-data "^3.0.0" "@types/node@*", "@types/node@>= 8": - version "16.4.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.13.tgz#7dfd9c14661edc65cccd43a29eb454174642370d" - integrity sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg== + version "16.6.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.1.tgz#aee62c7b966f55fc66c7b6dfa1d58db2a616da61" + integrity sha512-Sr7BhXEAer9xyGuCN3Ek9eg9xPviCF2gfu9kTfuU2HkTVAMYSDeX40fvpmo72n5nansg3nsBjuQBrsS28r+NUw== "@types/node@12.6.9": version "12.6.9" @@ -3829,9 +3829,9 @@ "@types/react" "*" "@types/react@*", "@types/react@>=16.9.0": - version "17.0.16" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.16.tgz#056f40c45645761527baeb7d89d842a6abdf285a" - integrity sha512-3kCUiOOlQTwUUvjNFkbBTWMTxdTGybz/PfjCw9JmaRGcEDBQh+nGMg7/E9P2rklhJuYVd25IYLNcvqgSPCPksg== + version "17.0.18" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.18.tgz#4109cbbd901be9582e5e39e3d77acd7b66bb7fbe" + integrity sha512-YTLgu7oS5zvSqq49X5Iue5oAbVGhgPc5Au29SJC4VeE17V6gASoOxVkUDy9pXFMRFxCWCD9fLeweNFizo3UzOg== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -6003,6 +6003,11 @@ btoa-lite@^1.0.0: resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= +buffer-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" + integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74= + buffer-from@1.x, buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -6290,9 +6295,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001248: - version "1.0.30001249" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001249.tgz#90a330057f8ff75bfe97a94d047d5e14fabb2ee8" - integrity sha512-vcX4U8lwVXPdqzPWi6cAJ3FnQaqXbBqy/GZseKNQzRj37J7qZdGcBtxq/QLFNLLlfsoXLUdHw8Iwenri86Tagw== + version "1.0.30001251" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz#6853a606ec50893115db660f82c094d18f096d85" + integrity sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A== capture-exit@^2.0.0: version "2.0.0" @@ -6724,9 +6729,9 @@ color@^3.0.0: color-string "^1.6.0" colorette@^1.2.1, colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + version "1.3.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af" + integrity sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w== colors@^1.1.2, colors@^1.3.3: version "1.4.0" @@ -7050,17 +7055,17 @@ copyfiles@2.4.1: yargs "^16.1.0" core-js-compat@^3.0.0, core-js-compat@^3.14.0, core-js-compat@^3.16.0, core-js-compat@^3.6.2: - version "3.16.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.16.1.tgz#c44b7caa2dcb94b673a98f27eee1c8312f55bc2d" - integrity sha512-NHXQXvRbd4nxp9TEmooTJLUf94ySUG6+DSsscBpTftN1lQLQ4LjnWvc7AoIo4UjDsFF3hB8Uh5LLCRRdaiT5MQ== + version "3.16.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.16.2.tgz#442ef1d933ca6fc80859bd5a1db7a3ba716aaf56" + integrity sha512-4lUshXtBXsdmp8cDWh6KKiHUg40AjiuPD3bOWkNVsr1xkAhpUqCjaZ8lB1bKx9Gb5fXcbRbFJ4f4qpRIRTuJqQ== dependencies: browserslist "^4.16.7" semver "7.0.0" core-js-pure@^3.16.0: - version "3.16.1" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.16.1.tgz#b997df2669c957a5b29f06e95813a171f993592e" - integrity sha512-TyofCdMzx0KMhi84mVRS8rL1XsRk2SPUNz2azmth53iRN0/08Uim9fdhQTaZTG1LqaXHYVci4RDHka6WrXfnvg== + version "3.16.2" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.16.2.tgz#0ef4b79cabafb251ea86eb7d139b42bd98c533e8" + integrity sha512-oxKe64UH049mJqrKkynWp6Vu0Rlm/BTXO/bJZuN2mmR3RtOFNepLlSWDd1eo16PzHpQAoNG97rLU1V/YxesJjw== core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.5: version "2.6.12" @@ -7068,9 +7073,9 @@ core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.5: integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== core-js@^3.5.0: - version "3.16.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.1.tgz#f4485ce5c9f3c6a7cb18fa80488e08d362097249" - integrity sha512-AAkP8i35EbefU+JddyWi12AWE9f2N/qr/pwnDtWz4nyUIBGMJPX99ANFFRSw6FefM374lDujdtLDyhN2A/btHw== + version "3.16.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.2.tgz#3f485822889c7fc48ef463e35be5cc2a4a01a1f4" + integrity sha512-P0KPukO6OjMpjBtHSceAZEWlDD1M2Cpzpg6dBbrjFqFhBHe/BwhxaP820xKOjRn/lZRQirrCusIpLS/n2sgXLQ== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -7772,6 +7777,14 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dir-compare@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/dir-compare/-/dir-compare-3.3.0.tgz#2c749f973b5c4b5d087f11edaae730db31788416" + integrity sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg== + dependencies: + buffer-equal "^1.0.0" + minimatch "^3.0.4" + dir-glob@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" @@ -8020,9 +8033,9 @@ electron-fetch@^1.7.2: encoding "^0.1.13" electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.47, electron-to-chromium@^1.3.793: - version "1.3.800" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.800.tgz#8efbb11e88b0a072d5c0250e6249123d3a76cb9a" - integrity sha512-qagikPjZJSDWP85uWoxs32oK/xk/y3MhDZELfKRCWI7pBc0ZFlmjnXb+3+aNMaiqboeDJJa0v7CJd5cO1HKwEQ== + version "1.3.808" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.808.tgz#6aa204f56c6de554cd4e90e1eb1a36f3ac3a15d5" + integrity sha512-espnsbWTuUw0a2jMwfabCc09py2ujB+FZZE1hZWn5yYijEmxzEhdhTLKUfZGjynHvdIMQ4X/Pr/t8s4eiyH/QQ== elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3: version "6.5.4" @@ -8356,9 +8369,9 @@ eslint-config-react-app@^5.2.1: confusing-browser-globals "^1.0.9" eslint-import-resolver-node@^0.3.2, eslint-import-resolver-node@^0.3.4: - version "0.3.5" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.5.tgz#939bbb0f74e179e757ca87f7a4a890dabed18ac4" - integrity sha512-XMoPKjSpXbkeJ7ZZ9icLnJMTY5Mc1kZbCakHquaFsXPpyWOwK0TK6CODO+0ca54UoM9LKOxyUNnoVZRl8TeaAg== + version "0.3.6" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== dependencies: debug "^3.2.7" resolve "^1.20.0" @@ -10926,9 +10939,11 @@ is-arrayish@^0.3.1: integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== is-bigint@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.3.tgz#fc9d9e364210480675653ddaea0518528d49a581" - integrity sha512-ZU538ajmYJmzysE5yU4Y7uIrPQ2j704u+hXFiIPQExpqzzUbpe5jCPdTfmz7jXRxZdvjY3KZ3ZNenoXQovX+Dg== + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" is-binary-path@^1.0.0: version "1.0.1" @@ -10987,9 +11002,9 @@ is-color-stop@^1.0.0: rgba-regex "^1.0.0" is-core-module@^2.2.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.5.0.tgz#f754843617c70bfd29b7bd87327400cda5c18491" - integrity sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg== + version "2.6.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19" + integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ== dependencies: has "^1.0.3" @@ -13160,9 +13175,9 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: js-tokens "^3.0.0 || ^4.0.0" lottie-web@^5.1.3: - version "5.7.12" - resolved "https://registry.yarnpkg.com/lottie-web/-/lottie-web-5.7.12.tgz#59771aeec72e6748e6009d0384fce19e07943243" - integrity sha512-aW1gdxDzcwXmlYnYJ4SdtH0ujmHzNnAXf+noyE0otUTCLtwMIkOL/CCXmjNj+pZmEeu9GrrHDOt/pTPWOCzBRQ== + version "5.7.13" + resolved "https://registry.yarnpkg.com/lottie-web/-/lottie-web-5.7.13.tgz#c4087e4742c485fc2c4034adad65d1f3fcd438b0" + integrity sha512-6iy93BGPkdk39b0jRgJ8Zosxi8QqcMP5XcDvg1f0XAvEkke6EMCl6BUO4Lu78dpgvfG2tzut4QJ+0vCrfbrldQ== loud-rejection@^1.0.0: version "1.6.0" @@ -13830,9 +13845,9 @@ multibase@^3.0.0, multibase@^3.1.0: web-encoding "^1.0.6" multibase@^4.0.1: - version "4.0.4" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-4.0.4.tgz#55ef53e6acce223c5a09341a8a3a3d973871a577" - integrity sha512-8/JmrdSGzlw6KTgAJCOqUBSGd1V6186i/X8dDCGy/lbCKrQ+1QB6f3HE+wPr7Tpdj4U3gutaj9jG2rNX6UpiJg== + version "4.0.5" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-4.0.5.tgz#620293b524e01f504b750cef585c2bdc6ee1c64c" + integrity sha512-oqFkOYXdUkakxT8MqGyn5sE1KYeVt1zataOTvg688skQp6TVBv9XnouCcVO86XKFzh/UTiCGmEImTx6ZnPZ0qQ== dependencies: "@multiformats/base-x" "^4.0.1" @@ -13930,9 +13945,9 @@ multihashes@^4.0.1: varint "^5.0.2" multihashing-async@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/multihashing-async/-/multihashing-async-2.1.2.tgz#9ed68f183bde70e0416b166bbc59a0c0623a0ede" - integrity sha512-FTPNnWWxwIK5dXXmTFhySSF8Fkdqf7vzqpV09+RWsmfUhrsL/b3Arg3+bRrBnXTtjxm3JRGI3wSAtQHL0QCxhQ== + version "2.1.3" + resolved "https://registry.yarnpkg.com/multihashing-async/-/multihashing-async-2.1.3.tgz#8b6a33a754dc02327a19adfaf1f1054625b1c470" + integrity sha512-z4dlnTgZLn4D8daBdMGn601aS3GLOMnW5+EKoaevLwa3Fu4FK64ofn9PdJ3s0bDkhGK2fdwSjrG/S8mWlW9bzQ== dependencies: blakejs "^1.1.0" err-code "^3.0.0" @@ -14002,9 +14017,9 @@ nano-json-stream-parser@^0.1.2: integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18= nanoid@^3.1.12, nanoid@^3.1.3: - version "3.1.23" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" - integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== + version "3.1.25" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" + integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== nanomatch@^1.2.9: version "1.2.13" @@ -14219,9 +14234,9 @@ node-notifier@^8.0.0: which "^2.0.2" node-releases@^1.1.52, node-releases@^1.1.73: - version "1.1.73" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20" - integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg== + version "1.1.74" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.74.tgz#e5866488080ebaa70a93b91144ccde06f3c3463e" + integrity sha512-caJBVempXZPepZoZAPCWRTNxYQ+xtG/KAi4ozTA5A+nJ7IU+kLQCbqaUjb5Rwy14M9upBWiQ4NutcmW04LJSRw== noms@0.0.0: version "0.0.0" @@ -16058,9 +16073,9 @@ proto-list@~1.2.1: integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= protocol-buffers-schema@^3.3.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.5.1.tgz#8388e768d383ac8cbea23e1280dfadb79f4122ad" - integrity sha512-YVCvdhxWNDP8/nJDyXLuM+UFsuPk4+1PB7WGPVDzm3HTHbzFLxQYeW2iZpS4mmnXrQJGBzt230t/BbEb7PrQaw== + version "3.5.2" + resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.5.2.tgz#38ad35ba768607a5ed2375f8db4c2ecc5ea293c8" + integrity sha512-LPzSaBYp/TcbuSlpGwqT5jR9kvJ3Zp5ic2N5c2ybx6XB/lSfEHq2D7ja8AgoxHoMD91wXFALJoXsvshKPuXyew== protocols@^1.1.0, protocols@^1.4.0: version "1.4.8" @@ -16075,9 +16090,9 @@ protoduck@^5.0.1: genfun "^5.0.0" protons@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/protons/-/protons-2.0.1.tgz#bfee5123c100001dcf56ab8f71b1b36f2e8289f1" - integrity sha512-FlmPorLEeCEDPu+uIn0Qardgiy5XqVA4IyNTz9wb9c0e2U7BEXdRcIbx64r09o4Abtf+4B7mkTtMbsIXMxZzKw== + version "2.0.2" + resolved "https://registry.yarnpkg.com/protons/-/protons-2.0.2.tgz#f55ee68f6d183a7efaa80b4bee58e52444f7f1f7" + integrity sha512-EIPoT9ftVirJ9QJ3oFoueYUiBhmPqE1AoSBPypLSqbbvHvx+OcUeK9z84YIsk6jda+N3FL58dU1LcWmfGCZGHA== dependencies: protocol-buffers-schema "^3.3.1" signed-varint "^2.0.1" @@ -17321,7 +17336,7 @@ semver@7.3.4: dependencies: lru-cache "^6.0.0" -semver@7.x, semver@^7.0.0, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: +semver@7.3.5, semver@7.x, semver@^7.0.0, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -18312,9 +18327,9 @@ tapable@^1.0.0, tapable@^1.1.3: integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== tar@^4.0.2, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: - version "4.4.16" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.16.tgz#4a48b3c025e77d9d0c788f038a09b91c594d326d" - integrity sha512-gOVUT/KWPkGFZQmCRDVFNUWBl7niIo/PRR7lzrIqtZpit+st54lGROuVjc6zEQM9FhH+dJfQIl+9F0k8GNXg5g== + version "4.4.17" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.17.tgz#44be5e3fa8353ee1d11db3b1401561223a5c3985" + integrity sha512-q7OwXq6NTdcYIa+k58nEMV3j1euhDhGCs/VRw9ymx/PbH0jtIM2+VTgDE/BW3rbLkrBUXs5fzEKgic5oUciu7g== dependencies: chownr "^1.1.4" fs-minipass "^1.2.7" @@ -18751,9 +18766,9 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" - integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== tsutils@^3.17.1: version "3.21.0" @@ -19603,9 +19618,9 @@ web3-utils@1.2.11: utf8 "3.0.0" web3-utils@^1.0.0-beta.31: - version "1.5.1" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.5.1.tgz#d82087b43c0c0777dec5c44d375afcf1424417f4" - integrity sha512-U8ULaMBwjkp9Rn+kRLjUmgAUHwPqDrM5/Q9tPKgvuDKtMWUggTLC33/KF8RY+PyAhSAlnD+lmNGfZnbjmVKBxQ== + version "1.5.2" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.5.2.tgz#150982dcb1918ffc54eba87528e28f009ebc03aa" + integrity sha512-quTtTeQJHYSxAwIBOCGEcQtqdVcFWX6mCFNoqnp+mRbq+Hxbs8CGgO/6oqfBx4OvxIOfCpgJWYVHswRXnbEu9Q== dependencies: bn.js "^4.11.9" eth-lib "0.2.8"