├── docs ├── 0.png ├── 1-1.png ├── 2-1.png ├── 2-2.png ├── 2-3.png ├── 2-4.png ├── 3-1.png ├── 3-2.png ├── 4-1.png ├── 4-2.png ├── 4-3.png ├── 4-4.png ├── 5-2.png ├── 5-3.png ├── 5-1-0.png ├── 5-1-1.png └── features.md ├── screenshot.png ├── resources ├── icon.png ├── playground.png ├── add.svg ├── runTask.svg ├── add-black.svg ├── runTask-black.svg ├── apps.svg ├── apps-black.svg ├── play-black.svg ├── play.svg ├── stopProcess.svg ├── purgeChain.svg ├── stopProcess-black.svg ├── purgeChain-black.svg ├── check-black.svg ├── check.svg ├── home.svg ├── home-black.svg ├── book.svg ├── book-black.svg ├── startNode.svg ├── startNode-black.svg ├── compileStartNode.svg ├── compileStartNode-black.svg ├── gear.svg ├── gear-black.svg ├── substrate.svg ├── github.svg ├── github-black.svg └── playground.png.base64 ├── .gitignore ├── src ├── constants.ts ├── views │ ├── marketplace │ │ ├── types.ts │ │ ├── substrateDeps.ts │ │ ├── fetchCategories.ts │ │ └── MarketplaceProvider.ts │ ├── processes │ │ └── ProcessesProvider.ts │ ├── nodes │ │ └── NodesProvider.ts │ ├── accounts │ │ └── AccountsProvider.ts │ └── contracts │ │ └── ContractsProvider.ts ├── common │ ├── TreeDataProvider.ts │ └── Substrate.ts ├── runtimes │ ├── parseDepsFromFile.ts │ └── Runtime.ts ├── processes │ └── Processes.ts ├── extension.ts ├── util.ts └── nodes │ └── Nodes.ts ├── .vscode ├── extensions.json ├── tasks.json ├── settings.json └── launch.json ├── .vscodeignore ├── .eslintrc.json ├── tsconfig.json ├── README.md ├── .github └── workflows │ └── release.yml ├── CHANGELOG.md ├── package.json └── yarn.lock /docs/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/0.png -------------------------------------------------------------------------------- /docs/1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/1-1.png -------------------------------------------------------------------------------- /docs/2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/2-1.png -------------------------------------------------------------------------------- /docs/2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/2-2.png -------------------------------------------------------------------------------- /docs/2-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/2-3.png -------------------------------------------------------------------------------- /docs/2-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/2-4.png -------------------------------------------------------------------------------- /docs/3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/3-1.png -------------------------------------------------------------------------------- /docs/3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/3-2.png -------------------------------------------------------------------------------- /docs/4-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/4-1.png -------------------------------------------------------------------------------- /docs/4-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/4-2.png -------------------------------------------------------------------------------- /docs/4-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/4-3.png -------------------------------------------------------------------------------- /docs/4-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/4-4.png -------------------------------------------------------------------------------- /docs/5-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/5-2.png -------------------------------------------------------------------------------- /docs/5-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/5-3.png -------------------------------------------------------------------------------- /docs/5-1-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/5-1-0.png -------------------------------------------------------------------------------- /docs/5-1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/docs/5-1-1.png -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/screenshot.png -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/resources/icon.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | scratchpad 2 | out 3 | node_modules 4 | .vscode-test/ 5 | *.vsix 6 | vsc-extension-quickstart.md -------------------------------------------------------------------------------- /resources/playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/vscode-substrate/HEAD/resources/playground.png -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | // Source for the marketplace treeview 2 | export const GRAPHQL_API_ENDPOINT = 'https://marketplace-api-staging.substrate.dev/graphql'; -------------------------------------------------------------------------------- /resources/add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/runTask.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/add-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/runTask-black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | src/** 5 | .gitignore 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts 11 | scratchpad 12 | *.vsix -------------------------------------------------------------------------------- /resources/apps.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/apps-black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/play-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/stopProcess.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/purgeChain.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/stopProcess-black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/purgeChain-black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/check-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/views/marketplace/types.ts: -------------------------------------------------------------------------------- 1 | export interface Category { 2 | category: string; 3 | pallets: Pallet[]; 4 | } 5 | 6 | export interface Pallet { 7 | id: number; 8 | name: string; 9 | description: string; 10 | homepage: string; 11 | github: string; 12 | documentation: string; 13 | icon: string; 14 | version: string; 15 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/class-name-casing": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/home-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/book.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/book-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/common/TreeDataProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | export abstract class TreeDataProvider implements vscode.TreeDataProvider { 4 | protected _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 5 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 6 | 7 | public refresh(): void { 8 | this._onDidChangeTreeData.fire(); 9 | } 10 | 11 | public getTreeItem(element: T): vscode.TreeItem { 12 | return element; 13 | } 14 | 15 | abstract getChildren(element?: T): Thenable; 16 | } 17 | -------------------------------------------------------------------------------- /resources/startNode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/runtimes/parseDepsFromFile.ts: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const uniq = require('lodash/fp/uniq'); 3 | const matchAll = require('string.prototype.matchall') 4 | 5 | /** 6 | * Given the contents of a Cargo.toml, extract the list of pallet names. 7 | */ 8 | function parseDeps(text: string) : string[] { 9 | return uniq(Array.from(matchAll(text, /(pallet-[a-z-A-Z0-9-]+)/g)).map((match: any) => match[1])); 10 | } 11 | 12 | /** 13 | * Given a path to a Cargo.toml, extract the list of pallet names. 14 | */ 15 | export default function parseDepsFromFile(file: string) { 16 | return parseDeps(fs.readFileSync(file).toString()); 17 | } -------------------------------------------------------------------------------- /resources/startNode-black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/compileStartNode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/compileStartNode-black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/gear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/gear-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es2019" 8 | ], 9 | "esModuleInterop": true, 10 | "sourceMap": true, 11 | "rootDir": "src", 12 | "strict": true /* enable all strict type-checking options */ 13 | /* Additional Checks */ 14 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 15 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 16 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 17 | }, 18 | "exclude": [ 19 | "node_modules", 20 | ".vscode-test" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/processes/Processes.ts: -------------------------------------------------------------------------------- 1 | import { BehaviorSubject} from 'rxjs'; 2 | import * as vscode from 'vscode'; 3 | 4 | export type Process = {nodePath: string; term: vscode.Terminal; command: string; termCloseHandlerDispose: any;} 5 | 6 | // Manages Substrate processes spawned through the extension 7 | export default class Processes { 8 | 9 | processes$: BehaviorSubject = new BehaviorSubject([] as Process[]); 10 | 11 | new(process: Process) { 12 | this.processes$.next(this.processes$.getValue().concat([process])); 13 | process.termCloseHandlerDispose = vscode.window.onDidCloseTerminal(t => { 14 | if (t === process.term) { 15 | process.termCloseHandlerDispose.dispose(); 16 | console.log('Terminal closed; removing process.'); 17 | this.del(process); 18 | } 19 | }); 20 | } 21 | 22 | del(process: Process) { 23 | this.processes$.next(this.processes$.getValue().filter(p => p != process)); 24 | } 25 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ], 19 | "preLaunchTask": "${defaultBuildTask}" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "--extensionDevelopmentPath=${workspaceFolder}", 28 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 29 | ], 30 | "outFiles": [ 31 | "${workspaceFolder}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "${defaultBuildTask}" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import 'array-flat-polyfill'; 2 | import * as vscode from 'vscode'; 3 | import { Substrate } from './common/Substrate'; 4 | import Nodes from './nodes/Nodes'; 5 | import Processes from './processes/Processes'; 6 | import { setupAccountsTreeView } from './views/accounts/AccountsProvider'; 7 | import { setupContractsTreeView } from './views/contracts/ContractsProvider'; 8 | import { setUpMarketplaceTreeView } from './views/marketplace/MarketplaceProvider'; 9 | import { setUpNodesTreeView } from './views/nodes/NodesProvider'; 10 | import { setupProcessesTreeView } from './views/processes/ProcessesProvider'; 11 | 12 | export async function activate(context: vscode.ExtensionContext) { 13 | const substrate = new Substrate(context) 14 | 15 | const nodes = new Nodes(); 16 | const processes = new Processes(); 17 | 18 | // Set up runtimes 19 | const { selectedNode$ } = setUpNodesTreeView(nodes, processes); 20 | 21 | // Set up marketplace 22 | setUpMarketplaceTreeView(nodes, selectedNode$); 23 | 24 | // Set up processes 25 | const selectedProcess$ = setupProcessesTreeView(substrate, processes); 26 | 27 | // Set up accounts 28 | setupAccountsTreeView(substrate, context); 29 | 30 | // Set up contracts 31 | setupContractsTreeView(substrate, selectedProcess$, context); 32 | } 33 | 34 | export function deactivate() { } -------------------------------------------------------------------------------- /src/runtimes/Runtime.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import parseDepsFromFile from './parseDepsFromFile'; 3 | import { BehaviorSubject } from 'rxjs'; 4 | import { startWith, distinctUntilChanged, map } from 'rxjs/operators'; 5 | import { vscToObservable } from '../util'; 6 | const isEqual = require('lodash/fp/isEqual'); 7 | const path = require('path'); 8 | 9 | // Manages the auto-detection of a runtime's dependencies 10 | export default class Runtime { 11 | 12 | deps$: BehaviorSubject; 13 | 14 | _watcher: vscode.FileSystemWatcher; 15 | 16 | constructor(public runtimePath: string) { 17 | this._watcher = vscode.workspace.createFileSystemWatcher( 18 | path.join(runtimePath,'Cargo.toml'), true, false, true 19 | ); 20 | // Note that moving Cargo.toml around (e.g. removing/adding) will mess up the events. 21 | // TODO listen to all three events? Probably sounder. 22 | const fileChange$ = vscToObservable(this._watcher.onDidChange.bind(this._watcher)); 23 | 24 | this.deps$ = new BehaviorSubject([] as string[]); 25 | fileChange$ 26 | .pipe( 27 | startWith(null), 28 | map(() => parseDepsFromFile(path.join(runtimePath,'Cargo.toml'))), 29 | distinctUntilChanged(isEqual) 30 | ).subscribe(this.deps$); 31 | } 32 | 33 | dispose() { 34 | this._watcher.dispose(); // can Runtime still be garbage collected? 35 | // todo use setinterval unref to check if old runtime gets gc'd 36 | } 37 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## DEPRECATION NOTICE 2 | 3 | This repo is not supported anymore. There are no replacement. 4 | 5 | # Substrate - VSCode extension 6 | 7 | Manage your node, runtime, browse and install pallets, manage your accounts and your smart contracts within VSCode. 8 | 9 | A complete list of features and walkthrough is available in [this document](./docs/features.md). 10 | 11 | Visit the extension's page on Visual Studio Marketplace: https://marketplace.visualstudio.com/items?itemName=paritytech.vscode-substrate 12 | 13 | ![Screenshot](./screenshot.png) 14 | 15 | This extension is work in progress and is in active development. Please [report](https://github.com/paritytech/vscode-substrate/issues/new) any issues you encounter. 16 | 17 | ## Installation 18 | 19 | Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter. 20 | 21 | ``` 22 | ext install paritytech.vscode-substrate 23 | ``` 24 | 25 | Alternatively, search for "VSCode Substrate" in the extension marketplace. 26 | 27 | ## Development 28 | 29 | Clone, run `yarn` to install the dependencies, open the folder in VSCode, run the command "Debug: Start Debugging" to launch a new VSCode instance with the extension running. 30 | 31 | ## Publish 32 | 33 | Bump the version in `package.json`, tag your commit with the version number (`vX.X.X`) and push. This will trigger the GitHub Action and publish the new version on VSCode Marketplace as well as create a new release on GitHub. Release information can be edited manually and added to CHANGELOG.md 34 | -------------------------------------------------------------------------------- /src/views/marketplace/substrateDeps.ts: -------------------------------------------------------------------------------- 1 | 2 | const child_process = require('child_process'); 3 | import * as vscode from 'vscode'; 4 | import { resolveWhenTerminalClosed } from '../../util'; 5 | 6 | /** 7 | * Ensures that substrate-deps is installed; installs it otherwise. 8 | * 9 | * @return A promise that always resolves; either with true in case substrate-deps 10 | * is or got installed; false otherwise. 11 | */ 12 | export async function substrateDepsInstalled(): Promise { 13 | try { 14 | child_process.execSync('substrate-deps --version'); 15 | return true; 16 | } catch (e) { 17 | const clicked = await vscode.window.showWarningMessage( 18 | `substrate-deps is required for this extension to work but doesn't seem to be installed. Install it? This will run the following command: 'cargo install substrate-deps'`, 19 | { modal: true }, 20 | 'Yes' 21 | ); 22 | 23 | if (clicked !== 'Yes') { 24 | return false; 25 | } 26 | 27 | const term = vscode.window.createTerminal('Installing substrate-deps'); 28 | term.sendText('cargo install substrate-deps && exit'); 29 | term.show(); 30 | 31 | await resolveWhenTerminalClosed(term); 32 | 33 | if (term.exitStatus?.code === 0) { 34 | vscode.window.showInformationMessage(`substrate-deps was successfully installed.`); 35 | return substrateDepsInstalled(); 36 | } else { 37 | console.error('Terminal is closed; should have exit status; qed.') 38 | return false; 39 | } 40 | 41 | // TODO if users runs this function again with a terminal already running, we have two listeners, this is bad. 42 | } 43 | } -------------------------------------------------------------------------------- /resources/substrate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | # Sequence of patterns matched against refs/tags 4 | tags: 5 | - 'v[0-9]+.[0-9]+.[0-9]+' 6 | 7 | name: Upload Release Asset 8 | 9 | jobs: 10 | build: 11 | name: Upload Release Asset 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v2 16 | - name: Use Node.js 12.8.1 17 | uses: actions/setup-node@v1 18 | with: 19 | node-version: '12.8.1' 20 | - name: Build extension package 21 | run: | 22 | npm install 23 | npx vsce package -o vscode-substrate.vsix 24 | - name: Publish Extension to Visual Studio Marketplace 25 | run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ./vscode-substrate.vsix 26 | - name: Create GitHub Release 27 | id: create_release 28 | uses: actions/create-release@v1 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | with: 32 | tag_name: ${{ github.ref }} 33 | release_name: ${{ github.ref }} 34 | draft: false 35 | prerelease: false 36 | - name: Upload Release Asset 37 | id: upload-release-asset 38 | uses: actions/upload-release-asset@v1 39 | env: 40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 41 | with: 42 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing its ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 43 | asset_path: ./vscode-substrate.vsix 44 | asset_name: vscode-substrate.vsix 45 | asset_content_type: application/vsix -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { Observable } from 'rxjs'; 3 | 4 | const path = require('path'); 5 | 6 | export function resolveWhenTerminalClosed(term: vscode.Terminal): Promise { 7 | return new Promise((resolve, reject) => { 8 | const disp = vscode.window.onDidCloseTerminal(t => { 9 | if (t === term) { 10 | disp.dispose(); 11 | resolve(); 12 | } 13 | }); 14 | }); 15 | } 16 | 17 | export function vscToObservable(fn: (arg0: ((x: T) => any)) => any): Observable { 18 | return new Observable((subscriber) => { 19 | return fn((x: T) => subscriber.next(x)); 20 | }); 21 | } 22 | 23 | // Convert a full path to a human-friendly shorter path to display 24 | export function tryShortname(fullPath: string) { 25 | const fsPaths = vscode.workspace.workspaceFolders?.map((x) => x.uri.fsPath) || []; 26 | if (fsPaths.length !== 1) return fullPath; 27 | return path.relative(fsPaths[0], fullPath); 28 | } 29 | 30 | export async function showInputBoxValidate(options: vscode.InputBoxOptions, validateFn: (x: any) => Promise) { 31 | do { 32 | const a = await vscode.window.showInputBox(options); 33 | if (a === undefined) 34 | return a; 35 | else { 36 | let err = await validateFn(a); 37 | if (err !== '') 38 | vscode.window.showErrorMessage(err); 39 | else 40 | return a; 41 | } 42 | } while (true); 43 | } 44 | 45 | const INSTANCE = process.env.SUBSTRATE_PLAYGROUND_INSTANCE; 46 | const HOST = process.env.SUBSTRATE_PLAYGROUND_HOSTNAME; 47 | 48 | export function wsEndpointFromCommand(command: string) { 49 | const port = command.match(/--ws-port[ =]\d+/)?.[0] || '9944'; 50 | const wsEndpoint = INSTANCE ? `wss://${INSTANCE}.${HOST}${port !== '9944' ? `:${port}` : ''}/wss` : `ws://127.0.0.1:${port}/`; 51 | return wsEndpoint; 52 | } -------------------------------------------------------------------------------- /src/views/marketplace/fetchCategories.ts: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | const flow = require('lodash/fp/flow'); 3 | const get = require('lodash/fp/get'); 4 | const invoke = require('lodash/fp/invoke'); 5 | const isEqual = require('lodash/fp/isEqual'); 6 | const map = require('lodash/fp/map'); 7 | const remove = require('lodash/fp/remove'); 8 | 9 | import { Category, Pallet } from './types'; 10 | import { GRAPHQL_API_ENDPOINT } from '../../constants'; 11 | 12 | /** 13 | * Executes the given GraphQL query on the Marketplace endpoint, returns 14 | * the deserialized response value 15 | * 16 | * @returns {Promise} A resolved promise with the deserialized response in 17 | * case of success; a rejected promise with the error message in case the 18 | * request failed or the response payload indicates an error. 19 | */ 20 | const gq = (query: string) => (variables?: object): Promise => 21 | fetch( 22 | GRAPHQL_API_ENDPOINT, 23 | { 24 | method: 'POST', 25 | headers: { 26 | 'Accept': 'application/json', 27 | 'Content-Type': 'application/json' 28 | }, 29 | body: JSON.stringify({ 30 | query, 31 | variables 32 | }) 33 | } 34 | ) 35 | .then(invoke('json')) 36 | .then((d: any) => d.data || Promise.reject(map('message')(d.errors))); 37 | 38 | /** 39 | * Fetches all the pallets for a given Marketplace category. 40 | */ 41 | const fetchPallets = (category: string): Promise => 42 | gq(`query($category: String!){ 43 | search(type: PALLET query: "" category: $category) { 44 | results { 45 | ...on Pallet { 46 | id 47 | name 48 | description 49 | documentation 50 | homepage 51 | github: repository 52 | icon 53 | version 54 | repository 55 | } 56 | } 57 | } 58 | }`)({ category }) 59 | .then( 60 | get('search.results'), 61 | ); 62 | 63 | /** 64 | * Fetches a category with all its pallets. 65 | */ 66 | const fetchCategory = (category: string): Promise => 67 | fetchPallets(category).then((pallets: Pallet[]) => ({ category, pallets })) 68 | 69 | /** 70 | * Fetches the list of all categories and their pallets. 71 | */ 72 | const fetchCategories = (): Promise => 73 | gq('{ marketplaceCategories(type:PALLET) {name} }')() 74 | .then(flow( 75 | get('marketplaceCategories'), 76 | map('name'), 77 | remove(isEqual('tutorial')), 78 | map(fetchCategory), 79 | Promise.all.bind(Promise) 80 | )); 81 | export default fetchCategories; -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## v0.5.1 4 | * Remove Getting Started (Substrate Playground) 5 | * Remove Tasks 6 | * Remove built-in default process 7 | 8 | ## v0.5.0 9 | * Smart contracts and accounts support 10 | 11 | ## v0.4.11 12 | * "Purge chain" will run the binary directly (instead of potentially recompiling); same for "Start node". 13 | * Add command "Compile & start node" that behaves like "Start node" previously, i.e. using "cargo run". 14 | 15 | ## v0.4.10 16 | * Playground: Fix ws endpoint for apps 17 | 18 | ## v0.4.9 19 | * Add "Getting started" command 20 | 21 | ## v0.4.8 22 | * Fix icons for light theme 23 | * Always show marketplace treeview, even when no node is selected 24 | * Playground: don't show Getting Started when a file is already opened 25 | 26 | ## v0.4.7 27 | * Playground: fix for Workspace tasks. 28 | 29 | ## v0.4.6 30 | * Workspace tasks (tasks defined by the template) are now listed in a treeview 31 | 32 | ## v0.4.5 33 | * Playground: add Polkadot Apps link 34 | * Ask user for flags when launching node 35 | 36 | ## v0.4.4 37 | * List running nodes 38 | 39 | ## v0.4.3 40 | * The start node command now compiles in release mode. 41 | 42 | ## v0.4.2 43 | * Retain Getting started view in cache when the tab loses focus 44 | 45 | ## v0.4.1 46 | * Lint 47 | 48 | ## v0.4.0 49 | * Reorganized UI : now shows the list of nodes in the workspace. The marketplace is based on the runtime of the selected node. 50 | * Node commands accessible in the Command Palette. 51 | 52 | ## v0.3.4 53 | * Fix commands "Start node" and "Purge chain" 54 | * Remove playground-specific commands 55 | 56 | ## v0.3.2 57 | * Fix Playground detection 58 | * Fix pallets GitHub target 59 | 60 | ## v0.3.1 61 | * Marketplace is now loaded on startup 62 | * Selected runtime now highlighted 63 | * Fix parsing runtime pallets 64 | 65 | ## v0.3.0 66 | * Support multiple nodes 67 | * Execute operations on the selected node 68 | * Runtime is selected by user and isn't based on the active editor's path any longer. 69 | 70 | ## v0.2.0 71 | * Support multiple runtimes in the same workspace. Your active editor will determine the runtime used by the extension. 72 | * Display installed pallets. 73 | * Removed setting `substrateMarketplace.runtimeManifestPath` & removed Substrate Playground hardcoded path. Runtimes are now detected and updated automatically. 74 | 75 | ## v0.1.1 76 | * Your project's runtime manifest location can now be provided using the `substrateMarketplace.runtimeManifestPath` setting. 77 | * If this setting is not provided, the extension will try to use `./runtime/Cargo.toml` or `./Cargo.toml`. -------------------------------------------------------------------------------- /src/nodes/Nodes.ts: -------------------------------------------------------------------------------- 1 | import { BehaviorSubject, merge, of } from 'rxjs'; 2 | import { map, tap, throttleTime } from 'rxjs/operators'; 3 | import * as vscode from 'vscode'; 4 | import parseDepsFromFile from '../runtimes/parseDepsFromFile'; 5 | import { vscToObservable } from '../util'; 6 | 7 | const path = require('path'); 8 | const fs = require('fs'); 9 | const glob = require('glob'); 10 | 11 | /** 12 | * Given a folder path, return a list of substrate nodes contained inside. 13 | */ 14 | const findNodesInFolder = (roots: string): string[] => { 15 | // TODO use vscode.workspace.findFiles instead 16 | return glob.sync(path.join(roots, '**/Cargo.toml'), { ignore: '**/node_modules/**' }).filter((b: string) => { 17 | return fs.readFileSync(b).toString().includes('[[bin]]') 18 | }).map((nodeRs: string) => path.dirname(nodeRs)); // (todo transducers) 19 | } 20 | 21 | const findNodesInWorkspace = () => { 22 | return vscode.workspace.workspaceFolders?.map((x) => x.uri.fsPath).map(root => { 23 | return findNodesInFolder(root); 24 | }).flat() || []; 25 | } 26 | 27 | export type Node = {nodePath: string; runtimePath?: string; deps?: any[]} 28 | 29 | // Manages the auto-detection of nodes in the current workspace 30 | export default class Nodes { 31 | 32 | nodes$: BehaviorSubject; 33 | 34 | constructor() { 35 | // TODO add to the deactivate function of extension.ts? Not sure if vscode 36 | // does this automatically. Evtl add a dispose() function to the class. 37 | const watcher = vscode.workspace.createFileSystemWatcher('**/Cargo.toml'); 38 | 39 | const nodesPath$ = merge( 40 | // Scan on startup 41 | of(null), 42 | // Scan on file changes involving build.rs 43 | merge( 44 | vscToObservable(watcher.onDidChange.bind(watcher)), 45 | vscToObservable(watcher.onDidCreate.bind(watcher)), 46 | vscToObservable(watcher.onDidDelete.bind(watcher)) 47 | ).pipe(throttleTime(100)) // e.g. in case of renaming folders, we receive a delete + added event. 48 | ).pipe 49 | ( 50 | map(() => findNodesInWorkspace()), 51 | // tap(r => console.log('Found nodes',r)) 52 | ); // TODO have a rescan button 53 | 54 | this.nodes$ = new BehaviorSubject([]); 55 | 56 | nodesPath$.pipe( 57 | map(nodePaths => { 58 | return nodePaths.map(nodePath => { 59 | try{ 60 | const cargoToml = fs.readFileSync(path.join(nodePath, 'Cargo.toml')).toString(); // TODO ASYNC 61 | const matches = cargoToml.match(/^(?:[^#].*)?path ?= ?"([a-zA-Z./-]*runtime[a-zA-Z./-]*)"|^(?:[^#].*)?path ?= ?'([a-zA-Z./-]*runtime[a-zA-Z./-]*)'/m) 62 | if (matches === null) 63 | return {nodePath} as Node; 64 | else { 65 | // Important that this be called on any dep change (Cargo.toml) 66 | const runtimePath = path.join(nodePath, matches[1] || matches[2]); 67 | 68 | return { 69 | nodePath, 70 | runtimePath: runtimePath, 71 | deps: parseDepsFromFile(path.join(runtimePath, 'Cargo.toml')) 72 | } as Node; 73 | } 74 | } catch (e) { console.error('error',e); return {nodePath: ''} } 75 | }); 76 | }), 77 | // tap(r => console.log('Found nodes infos', r)) 78 | ).subscribe(this.nodes$); 79 | this.nodes$.subscribe(x => {}); 80 | } 81 | } -------------------------------------------------------------------------------- /resources/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /resources/github-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/views/processes/ProcessesProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { BehaviorSubject, of, combineLatest } from 'rxjs'; 3 | import { tryShortname, wsEndpointFromCommand } from '../../util'; 4 | import { switchMap, tap, distinctUntilChanged } from 'rxjs/operators'; 5 | import Nodes, {Node} from '../../nodes/Nodes'; 6 | import Processes, { Process } from '../../processes/Processes'; 7 | import { Substrate } from '../../common/Substrate'; 8 | 9 | export class ProcessesProvider implements vscode.TreeDataProvider { 10 | ProcessTreeItems: ProcessTreeItem[] = []; 11 | 12 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 13 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 14 | 15 | constructor(processes: Processes) { 16 | processes.processes$.subscribe((processes: Process[]) => { 17 | this.ProcessTreeItems = processes.map((process: Process) => { 18 | return new ProcessTreeItem(process); 19 | }); 20 | 21 | this._onDidChangeTreeData.fire(); 22 | }); 23 | } 24 | 25 | getTreeItem(element: ProcessTreeItem): ProcessTreeItem | Thenable { 26 | return element; 27 | } 28 | 29 | getChildren(element?: ProcessTreeItem | undefined): vscode.ProviderResult { 30 | if (element === undefined) { 31 | return this.ProcessTreeItems; 32 | } 33 | return element.children; 34 | } 35 | } 36 | 37 | const isTheia = process.env.SUBSTRATE_PLAYGROUND !== undefined; 38 | 39 | export class ProcessTreeItem extends vscode.TreeItem { 40 | children: undefined; 41 | process: Process; 42 | 43 | constructor(process: Process) { 44 | const { nodePath, command } = process; 45 | super( 46 | tryShortname(nodePath) + ' • ' + command, 47 | vscode.TreeItemCollapsibleState.None); 48 | this.process = process; 49 | this.command = { 50 | command: "substrate.selectProcess", 51 | title: "Select Process", 52 | arguments: [this] 53 | }; 54 | 55 | this.contextValue = isTheia ? 'theia' : 'vscode' 56 | } 57 | } 58 | 59 | 60 | async function quickPickProcesses(_processes: Processes) { 61 | let processes = _processes.processes$.getValue(); 62 | 63 | if (processes.length === 1) 64 | return processes[0]; 65 | 66 | if (processes.length === 0) { 67 | vscode.window.showErrorMessage('No node was found in the workspace.'); 68 | return Promise.reject(); 69 | } 70 | 71 | const processesReadable = processes.map(n => tryShortname(n.nodePath)); 72 | 73 | const pick = await vscode.window.showQuickPick(processesReadable, { placeHolder: "Please choose a node." }); 74 | if (pick === undefined) 75 | return Promise.reject(); 76 | 77 | return processes[processesReadable.findIndex(x => x === pick)]; 78 | } 79 | 80 | const INSTANCE = process.env.SUBSTRATE_PLAYGROUND_INSTANCE; 81 | const HOST = process.env.SUBSTRATE_PLAYGROUND_HOSTNAME; 82 | 83 | export function setupProcessesTreeView(substrate: Substrate, processes: Processes) { 84 | 85 | vscode.commands.registerCommand("substrate.polkadotApps", async (processTreeItem?: ProcessTreeItem) => { 86 | const process = processTreeItem?.process || await quickPickProcesses(processes); 87 | 88 | const port = process.command.match(/--ws-port[ =]\d+/)?.[0] || '9944'; 89 | const wsEndpoint = `wss://${INSTANCE}.${HOST}${port !== '9944' ? `:${port}` : ''}/wss`; 90 | const apps = `https://polkadot.js.org/apps/?rpc=${wsEndpoint}`; 91 | vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(apps)); 92 | }); 93 | 94 | const selectedProcess$ = new BehaviorSubject(null); 95 | vscode.commands.registerCommand("substrate.selectProcess", async (processTreeItem: ProcessTreeItem) => { 96 | selectedProcess$.next((processTreeItem as any).process || null); 97 | processTreeItem.process.term.show(); 98 | }); 99 | 100 | vscode.commands.registerCommand("substrate.stopProcess", async (processTreeItem?: ProcessTreeItem) => { 101 | const process = processTreeItem?.process || await quickPickProcesses(processes); 102 | processes.del(process); 103 | process.term.sendText('\x03'); 104 | process.term.sendText('exit 0'); 105 | }); 106 | 107 | const treeDataProvider = new ProcessesProvider(processes); 108 | const treeView = vscode.window.createTreeView('substrateProcesses', { treeDataProvider }); 109 | 110 | processes.processes$.subscribe((processes: Process[]) => { 111 | if (processes.length === 0 && isTheia) 112 | treeView.message = `No node is currently running.`; 113 | else 114 | treeView.message = undefined; 115 | 116 | if (!processes.find(process => process === selectedProcess$.getValue())) 117 | selectedProcess$.next(null); 118 | 119 | 120 | }); 121 | 122 | selectedProcess$.pipe(distinctUntilChanged()).subscribe(process => { 123 | if (!process) 124 | substrate.disconnect(); 125 | else { 126 | substrate.connectTo(wsEndpointFromCommand(process.command)); 127 | } 128 | }); 129 | 130 | return selectedProcess$; 131 | } -------------------------------------------------------------------------------- /docs/features.md: -------------------------------------------------------------------------------- 1 | # Features 2 | 3 | - [Features](#features) 4 | * [1. Workspace actions](#1-workspace-actions) 5 | + [1.1 Run workspace actions](#11-run-workspace-actions) 6 | * [2. Node actions](#2-node-actions) 7 | + [2.1 Compile & run a node](#21-compile---run-a-node) 8 | + [2.2 Run an already compiled node](#22-run-an-already-compiled-node) 9 | + [2.3 Kill a process](#23-kill-a-process) 10 | + [2.4 Purge a node's chain](#24-purge-a-node-s-chain) 11 | * [3. Runtime actions](#3-runtime-actions) 12 | + [3.1 Get information on installed pallets](#31-get-information-on-installed-pallets) 13 | + [3.2 Add a new pallet](#32-add-a-new-pallet) 14 | * [4. Account management](#4-account-management) 15 | + [4.1 Import an account](#41-import-an-account) 16 | + [4.2 Import an account from JSON](#42-import-an-account-from-json) 17 | + [4.3 Generate a new account](#43-generate-a-new-account) 18 | + [4.4 Rename, copy address, export, remove account](#44-rename--copy-address--export--remove-account) 19 | * [5. Contracts](#5-contracts) 20 | + [5.1 Compile & deploy a contract](#51-compile---deploy-a-contract) 21 | + [5.2 Call a contract method](#52-call-a-contract-method) 22 | + [5.3 Copy hash, forget contract](#53-copy-hash--forget-contract) 23 | 24 | Access the extension's features by clicking the "Substrate" icon to the left. 25 | 26 | ![Screenshot](./0.png) 27 | 28 | ## 1. Workspace actions 29 | ### 1.1 Run workspace actions 30 | The extension will detect all VSCode actions provided in your workspace folders and list them under the "Actions" panel. Hover over an action and click the "Execute" icon to the right to run it. 31 | 32 | ![Screenshot](./1-1.png) 33 | 34 | ## 2. Node actions 35 | ### 2.1 Compile & run a node 36 | The extension will detect all nodes (binary Rust projects) in the workspace and list them in the "Nodes" panel. To compile and run a node, hover over the node in the list and click the corresponding icon. The new process will be listed under "Processes" and a new terminal will be opened with the process's ouput. 37 | 38 | ![Screenshot](./2-1.png) 39 | 40 | ### 2.2 Run an already compiled node 41 | If you have already compiled the node and which to run it again without compiling the new changes, click the "Start node" button. The new process will be listed under "Processes" and a new terminal will be opened with the process's ouput. 42 | 43 | ![Screenshot](./2-2.png) 44 | 45 | ### 2.3 Kill a process 46 | Once a node is running, you can exit it by clicking the "Stop process" icon. 47 | 48 | ![Screenshot](./2-3.png) 49 | 50 | ### 2.4 Purge a node's chain 51 | You can purge the chain of an already compiled node by clicking the "Purge chain" icon. 52 | 53 | ![Screenshot](./2-4.png) 54 | 55 | ## 3. Runtime actions 56 | 57 | ### 3.1 Get information on installed pallets 58 | First, select a node. 59 | 60 | ![Screenshot](./3-1.png) 61 | 62 | The runtime used by this node will be automatically detected and displayed in the "Marketplace" panel. The "Marketplace" panel will then list all pallets available, and add a checkmark next to those that are used by the runtime of the selected node. Hover over each pallet to get access to their homepage, documentation page and GitHub page. 63 | 64 | ### 3.2 Add a new pallet 65 | To add a pallet as a dependency of the runtime, click the "Add pallet" icon. This will install the pallet using the tool `substrate-deps`, installing it if necessary. 66 | 67 | ![Screenshot](./3-2.png) 68 | 69 | ## 4. Account management 70 | Please note that this extension's account management features are meant to be used for testing/development purposes only. The accounts are persisted across restarts. 71 | 72 | ### 4.1 Import an account 73 | To add an account, hover over the "Accounts" bar and click the "+" icon. You will then be asked for a human-friendly name, cryptographic type and the key to the account. 74 | 75 | ![Screenshot](./4-1.png) 76 | 77 | ### 4.2 Import an account from JSON 78 | You can also import an account from a JSON file by clicking on the "Next actions" icon next to the "+" icon, then choosing "Import account from JSON." 79 | 80 | ![Screenshot](./4-2.png) 81 | 82 | ### 4.3 Generate a new account 83 | You can also generate a new account with a random seed by clicking "Generate new account". 84 | 85 | ![Screenshot](./4-3.png) 86 | 87 | ### 4.4 Rename, copy address, export, remove account 88 | By right-clicking an account, you can rename it, copy its address, export it as a JSON file, or remove the account from the list. 89 | 90 | ![Screenshot](./4-4.png) 91 | 92 | ## 5. Contracts 93 | Contracts are persisted across restarts and are linked to a WebSocket endpoint (host and port). You need to have added an account in the extension in order to be able to deploy a contract. 94 | 95 | ### 5.1 Compile & deploy a contract 96 | Select a running process. This will list the contracts you already added to this endpoint in the extension (if any). 97 | 98 | ![Screenshot](./5-1-0.png) 99 | 100 | You can compile an __ink!__ project, upload its WASM code and instantiate the contract with one click by clicking the "..." icon after hovering over "Contracts", and then selecting "Compile & deploy contract". You will then be asked for the location of your __ink!__ project, a human-friendly name for the contract, the account (see section 4) with which to upload the WASM & deploy the contract, its password, the constructor to use when instantiating the contract, if necessary its arguments, the endowment and maximum amount of gas for the deployment. The contract will then be listed in the "Contracts" panel. 101 | 102 | ![Screenshot](./5-1-1.png) 103 | 104 | ### 5.2 Call a contract method 105 | Right-click a contract and click "Call contract method". You will then be asked various information and be informed of the progress of the transaction. 106 | 107 | ![Screenshot](./5-2.png) 108 | 109 | ### 5.3 Copy hash, forget contract 110 | By right-clicking a contract, you can also copy its hash or remove the contract from the list. 111 | 112 | ![Screenshot](./5-3.png) -------------------------------------------------------------------------------- /src/common/Substrate.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { Keyring } from '@polkadot/keyring'; 3 | import { KeyringPair$Json } from '@polkadot/keyring/types'; 4 | import { KeypairType } from '@polkadot/util-crypto/types'; 5 | import { ApiPromise, WsProvider } from '@polkadot/api'; 6 | const fs = require('fs'); 7 | 8 | export type Contracts = { [index: string]: Contract[] }; 9 | 10 | export type Contract = { name: string, address: string, abiJson: any }; 11 | 12 | // Manages API connection and extension storage (accounts, contracts) 13 | export class Substrate { 14 | private keyring = new Keyring({ type: 'sr25519' }); 15 | private api?: ApiPromise; 16 | private wsEndpoint?: string; 17 | 18 | getConnection(): ApiPromise | undefined { 19 | return this.api; 20 | } 21 | 22 | constructor( 23 | // Necessary to access the extension's persistent storage 24 | private context: vscode.ExtensionContext 25 | ) { } 26 | 27 | async connectTo(wsEndpoint: string) { 28 | this.disconnect(); 29 | this.wsEndpoint = wsEndpoint; 30 | const api = new ApiPromise({provider: new WsProvider(wsEndpoint)}); 31 | await api.isReady; 32 | this.api = api; 33 | } 34 | 35 | async disconnect() { 36 | if (this.api) { 37 | this.api!.disconnect(); 38 | } 39 | this.wsEndpoint = undefined; 40 | this.api = undefined; 41 | } 42 | 43 | getAccounts(): KeyringPair$Json[] { 44 | const accounts = this.context.globalState.get('accounts'); 45 | if (!accounts) { 46 | return []; 47 | } 48 | return JSON.parse(accounts); 49 | } 50 | 51 | getKeyring(): Keyring { 52 | return this.keyring; 53 | } 54 | 55 | // Verify if an account with the given name exists 56 | isAccountExists(name: string): boolean { 57 | const result = this.getAccounts(); 58 | const exKey = result.find((val) => val.meta.name === name); 59 | if (!exKey) { 60 | return false; 61 | } 62 | return true; 63 | } 64 | 65 | // Replace all accounts with new accounts list 66 | async updateAccounts(accounts: KeyringPair$Json[]) { 67 | await this.context.globalState.update('accounts', JSON.stringify(accounts)); 68 | } 69 | 70 | async createKeyringPair(key: string, name: string, type: KeypairType) { 71 | const pair = this.keyring.addFromUri(key, { name }, type); 72 | const accounts = this.getAccounts(); 73 | accounts.push(pair.toJson()); 74 | await this.updateAccounts(accounts); 75 | } 76 | 77 | async createKeyringPairWithPassword(key: string, name: string, type: KeypairType, pass: string) { 78 | const pair = this.keyring.addFromUri(key, { name }, type); 79 | 80 | const json = pair.toJson(pass); 81 | json.meta.whenEdited = Date.now(); 82 | 83 | const accounts = this.getAccounts(); 84 | accounts.push(json); 85 | await this.updateAccounts(accounts); 86 | } 87 | 88 | // Forget an account 89 | async removeAccount(name: string) { 90 | const accounts = this.getAccounts(); 91 | const index = accounts.findIndex((val) => val.meta['name'] === name); 92 | accounts.splice(index, 1); 93 | await this.updateAccounts(accounts); 94 | } 95 | 96 | async renameAccount(oldName: string, newName: string) { 97 | const accounts = this.getAccounts(); 98 | for (const account of accounts) { 99 | if (account.meta['name'] === oldName) { 100 | account.meta['name'] = newName; 101 | break; 102 | } 103 | } 104 | await this.updateAccounts(accounts); 105 | } 106 | 107 | // Import a new keyring pair globally 108 | // @TODO Keyring pairs are currently global, maybe scope them? 109 | async importKeyringPair(path: string) { 110 | const rawdata = fs.readFileSync(path); 111 | const pair: KeyringPair$Json = JSON.parse(rawdata.toString()); 112 | if (this.isAccountExists(pair.meta['name'] as string)) { 113 | vscode.window.showWarningMessage('Account with same key already exists. Account not added'); 114 | return; 115 | } 116 | const accounts = this.getAccounts(); 117 | accounts.push(pair); 118 | await this.updateAccounts(accounts); 119 | } 120 | 121 | // Get the list of contracts for the current endpoint 122 | getConnectionContracts() : any[] { 123 | if (!this.wsEndpoint) return []; 124 | const contractCodes = this.getContracts(); 125 | // @TODO Contracts are currently scoped to a websocket endpoint 126 | // We could use better heuristics instead 127 | const nodeContractCodes = contractCodes[this.wsEndpoint] || []; 128 | return nodeContractCodes; 129 | } 130 | 131 | // Get the list of all contracts for all endpoints 132 | getContracts() { 133 | const contractsString = this.context.globalState.get('contracts'); 134 | if (!contractsString) { 135 | return {}; 136 | } 137 | return JSON.parse(contractsString); 138 | } 139 | 140 | // Add a new contract for the current endpoint 141 | async saveContract(contractName: string, contractAddress: string, abiJson: any) { 142 | const contracts = this.getConnectionContracts(); 143 | const existingContract = contracts.find( 144 | contract => contract.name === contractName || contract.address === contractAddress 145 | ); 146 | if (existingContract) { 147 | existingContract.name = contractName; 148 | existingContract.address = contractAddress; 149 | existingContract.abiJson = abiJson; 150 | } else { 151 | contracts.push({ 152 | name: contractName, 153 | address: contractAddress, 154 | abiJson: abiJson, 155 | }); 156 | } 157 | await this.updateConnectionContracts(contracts); 158 | } 159 | 160 | // Update contracts for the current endpoint 161 | async updateConnectionContracts(codes: Contract[]) { 162 | const connectedNode = this.wsEndpoint; 163 | if (!connectedNode) { 164 | throw Error('Not connected to node'); 165 | } 166 | const contracts = this.getContracts(); 167 | contracts[connectedNode] = codes; 168 | await this.updateContracts(contracts); 169 | } 170 | 171 | async updateContracts(codes: Contracts) { 172 | await this.context.globalState.update('contracts', JSON.stringify(codes)); 173 | await vscode.commands.executeCommand('substrate.refreshContracts'); // Refresh TreeView 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/views/marketplace/MarketplaceProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { BehaviorSubject } from 'rxjs'; 3 | import fetchCategories from './fetchCategories'; 4 | import { substrateDepsInstalled } from './substrateDeps'; 5 | import { Category, Pallet } from './types'; 6 | import Nodes, { Node } from '../../nodes/Nodes'; 7 | import { tryShortname } from '../../util'; 8 | 9 | const path = require('path'); 10 | 11 | type TreeItem = TreePallet | TreeCategory; 12 | 13 | export class TreeDataProvider implements vscode.TreeDataProvider { 14 | treeCategories: TreeCategory[]; 15 | 16 | private _selectedNode$: any; 17 | 18 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 19 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 20 | 21 | constructor(data: any, selectedNode$: BehaviorSubject) { 22 | this.treeCategories = data.map((category: any) => { 23 | return new TreeCategory(category, category.pallets.map(TreePallet.create.bind(TreePallet))); 24 | }); 25 | 26 | this._selectedNode$ = selectedNode$; 27 | 28 | // TODO Reinstantiating all pallets would be cleaner (shared logic when instantiating) 29 | selectedNode$.subscribe((node) => { 30 | this.treeCategories.forEach(treeCategory => { 31 | treeCategory.children?.forEach(treePallet => { 32 | treePallet.contextValue = node && node.deps && node.deps.includes(treePallet.name) 33 | ? 'palletInstalled' // TODO work from a single source of truth and have a clear mapping instead (see above comment); pure functions 34 | : node ? 'pallet' : 'palletNoNode'; 35 | treePallet.iconPath = treePallet.contextValue === 'palletInstalled' ? path.join(__filename, '..', '..', '..', '..', 'resources', 'check.svg') : false; 36 | }); 37 | }); 38 | this._onDidChangeTreeData.fire(); 39 | }); 40 | } 41 | 42 | getTreeItem(element: TreeCategory): TreeCategory | Thenable { 43 | return element; 44 | } 45 | 46 | getChildren(element?: TreeItem | undefined): vscode.ProviderResult { 47 | if (element === undefined) { 48 | return this.treeCategories; 49 | } 50 | return element.children; 51 | } 52 | } 53 | 54 | export class TreeCategory extends vscode.TreeItem { 55 | children: TreePallet[] | undefined; 56 | 57 | constructor(info: Category, children?: TreePallet[]) { 58 | const { category: label } = info; 59 | super( 60 | label, 61 | children === undefined ? vscode.TreeItemCollapsibleState.None : 62 | vscode.TreeItemCollapsibleState.Expanded); 63 | this.children = children; 64 | this.contextValue = 'category'; 65 | } 66 | } 67 | 68 | export class TreePallet extends vscode.TreeItem { 69 | children: TreeItem[] | undefined; 70 | name: string; 71 | github: string; 72 | documentation: string; 73 | homepage: string; 74 | 75 | static create(info: Pallet) { 76 | return new this(info); 77 | } 78 | 79 | constructor(info: Pallet) { 80 | const { name, description, github, documentation, homepage } = info; 81 | super( 82 | name, 83 | vscode.TreeItemCollapsibleState.None); 84 | this.name = name; 85 | this.description = description; 86 | this.tooltip = `${name} - ${description}`; 87 | this.contextValue = 'palletNoNode'; 88 | this.github = github; 89 | this.documentation = documentation; 90 | this.homepage = homepage; 91 | } 92 | } 93 | 94 | type NodePath = string | null; 95 | export function setUpMarketplaceTreeView(nodes: Nodes, selectedNode$: BehaviorSubject) { 96 | fetchCategories().then((categories: Category[]) => { 97 | const treeView = vscode.window.createTreeView('substrateMarketplace', { treeDataProvider: new TreeDataProvider(categories, selectedNode$) }); 98 | selectedNode$.subscribe((node) => { 99 | if (node && node.runtimePath) 100 | treeView.message = `Runtime: ${tryShortname(node.runtimePath)}`; 101 | else 102 | treeView.message = `No node selected`; 103 | }); 104 | 105 | // Set up commands: documentation, github, homepage 106 | ([ 107 | { command: 'substrateMarketplace.palletDocumentation', name: 'Documentation', property: 'documentation' }, 108 | { command: 'substrateMarketplace.palletGithub', name: 'GitHub page', property: 'github' }, 109 | { command: 'substrateMarketplace.palletHomepage', name: 'Homepage', property: 'homepage' } 110 | ] as const).forEach(({ command, name, property }) => { 111 | vscode.commands.registerCommand(command, (item: TreePallet) => { 112 | if (!item[property].startsWith('http')) { // Also acts as a safeguard 113 | vscode.window.showErrorMessage(`${name} is unavailable for this pallet.`); 114 | return; 115 | } 116 | vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(item[property])); 117 | }); 118 | }); 119 | 120 | // Set up command: install 121 | vscode.commands.registerCommand("substrateMarketplace.installPallet", async (item: vscode.TreeItem) => { 122 | // Install substrate-deps if needed 123 | if (!await substrateDepsInstalled()) { 124 | return; 125 | } 126 | 127 | // Verify pallet name to prevent shell injection & derive alias 128 | const palletName = item.label as string; 129 | if (!/^[a-z-]+$/.test(palletName)) { 130 | vscode.window.showErrorMessage('Pallet name is invalid.'); 131 | return; 132 | } 133 | const alias = (alias => alias === palletName ? null : alias)(palletName.replace(/^pallet-/, '')); 134 | 135 | // Ask for user confirmation 136 | // TODO Indicate current runtime in the message in case we have more than 137 | // one runtime in the workspace. 138 | const clicked = await vscode.window.showInformationMessage(`Install the pallet ${palletName}?`, { modal: true }, 'Yes'); 139 | if (clicked !== 'Yes') { 140 | return; 141 | } 142 | 143 | // Get manifest path 144 | let manifestPath: string; 145 | try { 146 | let selectedNodeRuntimePath = selectedNode$.getValue()?.runtimePath; 147 | if (!selectedNodeRuntimePath) { 148 | vscode.window.showErrorMessage('Please first select a node.'); 149 | return; 150 | } 151 | manifestPath = path.join(selectedNodeRuntimePath, 'Cargo.toml'); 152 | } catch (e) { 153 | return; 154 | } 155 | 156 | // Prepare command 157 | const termCommand = [ 158 | 'substrate-deps', 159 | `add ${palletName}`, 160 | ...alias ? [`--alias ${alias}`] : [], 161 | `--manifest-path '${manifestPath.replace(/'/, `'\\''`)}'`, // Allow spaces in path, prevent command injection (TODO Windows?) 162 | `&& echo '${palletName} was successfully added to the project${alias ? ` as '${alias}'` : ''}.'` 163 | ].join(' '); 164 | 165 | // Create terminal and run command 166 | const term = vscode.window.createTerminal({ name: `Installing ${palletName}` }); 167 | term.sendText(termCommand); 168 | term.show(); 169 | 170 | }); 171 | }, (async r => { // Offer to retry in case fetching the categories failed 172 | const clicked = await vscode.window.showErrorMessage(`An error occured when fetching the list of pallets from the Substrate Marketplace: ${r}`, 'Try again'); 173 | if (clicked === 'Try again') { 174 | return setUpMarketplaceTreeView(nodes, selectedNode$); 175 | } 176 | })); 177 | 178 | } -------------------------------------------------------------------------------- /src/views/nodes/NodesProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { BehaviorSubject, of, combineLatest } from 'rxjs'; 3 | import { tryShortname } from '../../util'; 4 | import { switchMap, tap } from 'rxjs/operators'; 5 | import Nodes, {Node} from '../../nodes/Nodes'; 6 | 7 | const path = require('path'); 8 | const fs = require('fs'); 9 | 10 | export class NodesProvider implements vscode.TreeDataProvider { 11 | nodeTreeItems: NodeTreeItem[] = []; 12 | 13 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 14 | readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; 15 | 16 | constructor(nodes: Nodes, selectedNode$: BehaviorSubject) { 17 | nodes.nodes$.subscribe((nodes: Node[]) => { 18 | 19 | this.nodeTreeItems = nodes.map((node: Node) => { 20 | return new NodeTreeItem(node); 21 | }); 22 | 23 | this.changeSelected(selectedNode$.getValue()?.nodePath || null); 24 | this._onDidChangeTreeData.fire(); 25 | }); 26 | 27 | selectedNode$.subscribe(node => { 28 | this.changeSelected(node?.nodePath || null); 29 | }); 30 | } 31 | 32 | changeSelected(selectedNodePath: string | null) { 33 | this.nodeTreeItems.forEach((nodeTreeItem) => { 34 | if (nodeTreeItem.nodePath === selectedNodePath) 35 | nodeTreeItem.select(); 36 | else 37 | nodeTreeItem.unselect(); 38 | }); 39 | this._onDidChangeTreeData.fire(); 40 | 41 | } 42 | 43 | getTreeItem(element: NodeTreeItem): NodeTreeItem | Thenable { 44 | return element; 45 | } 46 | 47 | getChildren(element?: NodeTreeItem | undefined): vscode.ProviderResult { 48 | if (element === undefined) { 49 | return this.nodeTreeItems; 50 | } 51 | return element.children; 52 | } 53 | } 54 | 55 | export class NodeTreeItem extends vscode.TreeItem { 56 | children: undefined; 57 | nodePath: string; 58 | 59 | static create(info: Node) { 60 | return new this(info); 61 | } 62 | 63 | constructor(node: Node) { 64 | const { nodePath } = node; 65 | super( 66 | tryShortname(nodePath), 67 | vscode.TreeItemCollapsibleState.None); 68 | this.nodePath = nodePath; 69 | this.command = { 70 | command: "substrateNodes.selectNode", 71 | title: "Select Node", 72 | arguments: [this] 73 | }; 74 | } 75 | 76 | select() { 77 | this.label = '▶️ ' + tryShortname(this.nodePath); 78 | } 79 | 80 | unselect() { 81 | this.label = tryShortname(this.nodePath); 82 | } 83 | } 84 | 85 | // Prompt the user to select a node among a list 86 | async function quickPickNodePath(nodes: Nodes) { 87 | let nodePaths = nodes.nodes$.getValue().map((node: Node) => node.nodePath); 88 | 89 | if (nodePaths.length === 1) 90 | return nodePaths[0]; 91 | 92 | if (nodePaths.length === 0) { 93 | vscode.window.showErrorMessage('No node was found in the workspace.'); 94 | return Promise.reject(); 95 | } 96 | 97 | const nodesReadable = nodePaths.map(n => tryShortname(n)); 98 | 99 | const pick = await vscode.window.showQuickPick(nodesReadable, { placeHolder: "Please choose a node." }); 100 | if (pick === undefined) 101 | return Promise.reject(); 102 | 103 | return nodePaths[nodesReadable.findIndex(x => x === pick)]; 104 | } 105 | 106 | function getCargoName(directory: string) { 107 | const toml = fs.readFileSync(path.join(directory,'Cargo.toml')).toString(); 108 | const ap = toml.match(/name ?= ?'(.+)'/); 109 | if (ap) 110 | return ap[1]; 111 | else return toml.match(/name ?= ?"(.+)"/)[1]; 112 | } 113 | 114 | function getWorkspaceRoot(directory: string) { 115 | let currDir = directory; 116 | do { 117 | if (fs.existsSync(path.join(currDir, 'Cargo.lock'))) 118 | return currDir; 119 | currDir = path.join(currDir, '..'); 120 | } while (currDir.split(path.sep).length > 0) 121 | throw new Error('No workspace root was found'); 122 | } 123 | 124 | export function setUpNodesTreeView(nodes: Nodes, processes: any) { 125 | 126 | // Can be called by the NodesProvider, in which case a NodeTreeItem is provided; 127 | // or remotely (across iframe in Substrate Playground), in which case we provide 128 | // the path of the node to run, and optional additional flags. 129 | vscode.commands.registerCommand("substrate.startNode", async (nodePathLike?: string | NodeTreeItem, _flags?: string | string[], options: any = {compile: false}) => { 130 | try { 131 | let nodePath = nodePathLike instanceof NodeTreeItem ? nodePathLike.nodePath : nodePathLike; 132 | if (nodePath) { 133 | selectedNodePath$.next(nodePath); // select the item we launch the command on 134 | } 135 | const defNodePath = nodePath || await quickPickNodePath(nodes); // e.g. When run through Command Palette 136 | const term = vscode.window.createTerminal({ name: 'Start node ' + tryShortname(defNodePath), cwd: defNodePath }); 137 | 138 | const flags = _flags ? (Array.isArray(_flags) ? _flags.join(' ') : _flags) : await vscode.window.showInputBox({ 139 | value: '--dev --ws-external', 140 | prompt: 'Flags to run Substrate with', 141 | ignoreFocusOut: true 142 | }); 143 | if (!flags) return; // user cancelled 144 | 145 | // todo use ws port to use polkadot apps 146 | // does it make sense to have two different polkadot apps endpoints ? two processes, one polkadot app endpoint ? 147 | 148 | if (options.compile) { 149 | term.sendText(`cargo run --release -- ${flags}`); 150 | } else { 151 | term.sendText(path.join(getWorkspaceRoot(defNodePath),`target/release/${getCargoName(defNodePath)}`) + ' ' + flags); 152 | } 153 | term.show(); 154 | 155 | processes.new({nodePath: defNodePath, command: flags, term: term}); 156 | } catch (e) { 157 | vscode.window.showErrorMessage(e); 158 | console.error(e); 159 | } 160 | }); 161 | 162 | vscode.commands.registerCommand("substrate.compileStartNode", async (nodePathLike?: string | NodeTreeItem, _flags?: string | string[]) => { 163 | vscode.commands.executeCommand("substrate.startNode", nodePathLike, _flags, {compile: true}); 164 | }); 165 | 166 | vscode.commands.registerCommand("substrate.purgeChain", async (nodePathLike?: string | NodeTreeItem) => { 167 | let nodePath = nodePathLike instanceof NodeTreeItem ? nodePathLike.nodePath : nodePathLike; 168 | if (nodePath) { 169 | selectedNodePath$.next(nodePath); // select the item we launch the command on 170 | } 171 | const defoNodePath = nodePath || await quickPickNodePath(nodes); 172 | const term = vscode.window.createTerminal({ name: 'Purge chain', cwd: defoNodePath }); 173 | 174 | term.sendText(path.join(getWorkspaceRoot(defoNodePath), `target/release/${getCargoName(defoNodePath)}`) + ' purge-chain --dev'); // TODO s 175 | term.show(); 176 | }); 177 | 178 | const selectedNodePath$ = new BehaviorSubject(null); // TODO NULL ON UNSELECT 179 | const selectedNode$ = new BehaviorSubject(null); 180 | 181 | combineLatest(selectedNodePath$, nodes.nodes$) 182 | .pipe( 183 | switchMap(([nodePath, nodes]: [string | null, Node[]]) => { 184 | if (!nodePath) return of(null); 185 | const selectedNode = nodes.find(node => node.nodePath === nodePath); 186 | if (selectedNode === undefined) { 187 | console.error("Selected node but doesn't match any."); 188 | return of(null); 189 | } 190 | return of(selectedNode); 191 | }), 192 | // tap(r => console.log('Selected node \'changes\' fired with', r)) 193 | ).subscribe(selectedNode$); 194 | 195 | const treeDataProvider = new NodesProvider(nodes, selectedNode$); 196 | vscode.window.createTreeView('substrateNodes', { treeDataProvider }); 197 | vscode.commands.registerCommand("substrateNodes.selectNode", (item: vscode.TreeItem) => { 198 | selectedNodePath$.next((item as any).nodePath || null); 199 | }); 200 | 201 | return { selectedNode$ }; 202 | } -------------------------------------------------------------------------------- /src/views/accounts/AccountsProvider.ts: -------------------------------------------------------------------------------- 1 | import { u8aToHex } from '@polkadot/util'; 2 | import { mnemonicGenerate, randomAsU8a } from '@polkadot/util-crypto'; 3 | import * as clipboard from 'clipboardy'; 4 | import * as vscode from 'vscode'; 5 | import { Substrate } from '../../common/Substrate'; 6 | import { TreeDataProvider } from '../../common/TreeDataProvider'; 7 | import { showInputBoxValidate } from '../../util'; 8 | 9 | const fs = require('fs'); 10 | 11 | type Account = any; 12 | 13 | export class AccountsProvider extends TreeDataProvider { 14 | substrate: Substrate; 15 | 16 | constructor(substrate: Substrate) { 17 | super(); 18 | this.substrate = substrate; 19 | } 20 | 21 | getChildren(element?: AccountTreeItem): Thenable { 22 | if (element === undefined) { 23 | return Promise.resolve(this.substrate.getAccounts().map(a => new AccountTreeItem(a))); 24 | } 25 | return Promise.resolve(element.children); 26 | } 27 | } 28 | 29 | export class AccountTreeItem extends vscode.TreeItem { 30 | children: [] = []; 31 | account: Account; 32 | 33 | constructor(account: Account) { 34 | super( 35 | account.meta.name, 36 | vscode.TreeItemCollapsibleState.None); 37 | this.description = account.address; 38 | this.account = account; 39 | } 40 | } 41 | 42 | async function quickPickAccount(substrate: Substrate, placeholder: string) { 43 | const quickPickItem = await vscode.window.showQuickPick(substrate.getAccounts().map(pair => ({ 44 | label: pair.address, 45 | decription: pair.meta.name, 46 | account: pair 47 | }),{placeHolder: placeholder})); 48 | return quickPickItem?.account; 49 | } 50 | 51 | export async function setupAccountsTreeView(substrate: Substrate, context: vscode.ExtensionContext) { 52 | const treeDataProvider = new AccountsProvider(substrate); 53 | vscode.window.createTreeView('substrateAccounts', { treeDataProvider }); 54 | 55 | // Add an existing account 56 | vscode.commands.registerCommand("substrate.addAccount", async () => { 57 | const name: string | undefined = await showInputBoxValidate({ 58 | ignoreFocusOut: true, 59 | prompt: 'Account name', 60 | placeHolder: 'ex. Alice' 61 | }, async (value: any) => { 62 | if (!value || !value.trim()) { 63 | return 'Name is required'; 64 | } 65 | if (substrate.isAccountExists(value)) { 66 | return 'Account with same name already exists'; 67 | } 68 | return ''; 69 | }); 70 | if (!name) return; 71 | 72 | const type: 'ed25519' | 'sr25519' | undefined = await vscode.window.showQuickPick(['ed25519', 'sr25519']) as 'ed25519' | 'sr25519' | undefined; 73 | if (!type) return; 74 | 75 | const key: string | undefined = await showInputBoxValidate({ 76 | ignoreFocusOut: true, 77 | prompt: 'The key to the account', 78 | placeHolder: 'ex. //Alice' 79 | }, async (value: any) => { 80 | if (!value || !value.trim()) { 81 | return 'Key is required'; 82 | } 83 | return ''; 84 | }); 85 | if (!key) return; 86 | 87 | await substrate.createKeyringPair(key, name, type); 88 | 89 | treeDataProvider.refresh(); 90 | }); 91 | 92 | // Generate a new account 93 | vscode.commands.registerCommand("substrate.createAccount", async () => { 94 | const name: string | undefined = await showInputBoxValidate({ 95 | ignoreFocusOut: true, 96 | prompt: 'Account name', 97 | placeHolder: 'ex. Alice' 98 | }, async (value: any) => { 99 | if (!value || !value.trim()) { 100 | return 'Name is required'; 101 | } 102 | if (substrate.isAccountExists(value)) { 103 | return 'Account with same name already exists'; 104 | } 105 | return ''; 106 | }); 107 | if (!name) return; 108 | 109 | const cryptoType: 'ed25519' | 'sr25519' | undefined = await vscode.window.showQuickPick(['ed25519', 'sr25519']) as 'ed25519' | 'sr25519' | undefined; 110 | if (!cryptoType) return; 111 | 112 | const keyTypeR: 'Raw seed' | 'Mnemonic seed' | undefined = await vscode.window.showQuickPick(['Raw seed', 'Mnemonic seed']) as 'Raw seed' | 'Mnemonic seed' | undefined; 113 | if (!keyTypeR) return; 114 | const keyType = keyTypeR === 'Raw seed' ? 'seed' : 'mnemonic'; 115 | 116 | const placeholder = keyType !== 'seed' ? 117 | 'crunch aspect strong flavor enable final display general shy debate stable final' 118 | : 'ex. 0x89abd2b6b79f4e2df7e89cb6b44c7f02d416719f6970b17d6ad34178423fa922'; 119 | const seed = keyType !== 'seed' ? 120 | mnemonicGenerate() 121 | : u8aToHex(randomAsU8a()); 122 | const key: string | undefined = await showInputBoxValidate({ 123 | ignoreFocusOut: true, 124 | prompt: 'The key to the account', 125 | placeHolder: placeholder, 126 | value: seed 127 | }, async (value: any) => { 128 | if (!value || !value.trim()) { 129 | return 'Key is required'; 130 | } 131 | return ''; 132 | }); 133 | if (!key) return; 134 | 135 | const password: string | undefined = await vscode.window.showInputBox({ 136 | ignoreFocusOut: true, 137 | prompt: 'Account password', 138 | placeHolder: 'ex. StrongPassword', 139 | password: true, 140 | value: '', 141 | }); 142 | if (typeof password === 'undefined') return; 143 | 144 | substrate.createKeyringPairWithPassword(key, name, cryptoType, password); 145 | 146 | treeDataProvider.refresh(); 147 | }); 148 | 149 | // Rename the selected account in the TreeView 150 | vscode.commands.registerCommand("substrate.renameAccount", async (item?: AccountTreeItem) => { 151 | let itemAccount = item?.account || await quickPickAccount(substrate, 'Please pick the account you want to rename'); 152 | if (!itemAccount) return; 153 | const name: string | undefined = await showInputBoxValidate({ 154 | ignoreFocusOut: true, 155 | prompt: 'Account name', 156 | value: itemAccount.meta.name, 157 | placeHolder: 'ex. Alice' 158 | }, async (value: any) => { 159 | if (!value || !value.trim()) { 160 | return 'Name is required'; 161 | } 162 | if (substrate.isAccountExists(value) && value !== itemAccount.meta.name) { 163 | return 'Account with same name already exists'; 164 | } 165 | return ''; 166 | }); 167 | if (!name) return; 168 | 169 | await substrate.renameAccount(itemAccount.meta.name, name); 170 | 171 | treeDataProvider.refresh(); 172 | }); 173 | 174 | // Remove the selected account in the TreeView 175 | vscode.commands.registerCommand("substrate.removeAccount", async (item?: AccountTreeItem) => { 176 | let itemAccount = item?.account || await quickPickAccount(substrate, 'Please pick the account you want to remove'); 177 | if (!itemAccount) return; 178 | await substrate.removeAccount(itemAccount.meta.name); 179 | treeDataProvider.refresh(); 180 | }); 181 | 182 | // Copy the address of the selected account in the TreeView 183 | vscode.commands.registerCommand("substrate.copyAddress", async (item?: AccountTreeItem) => { 184 | let itemAccount = item?.account || await quickPickAccount(substrate, 'Please pick the account whose address you want to copy'); 185 | if (!itemAccount) return; 186 | try { 187 | await clipboard.write(itemAccount.address); 188 | vscode.window.showInformationMessage(`Address copied to clipboard.`); 189 | } catch (err) { 190 | vscode.window.showErrorMessage(`Failed to copy address to clipboard: ${err.message}`); 191 | } 192 | }); 193 | 194 | // Import a new account 195 | vscode.commands.registerCommand("substrate.importAccount", async () => { 196 | const res = await vscode.window.showOpenDialog({ 197 | openLabel: 'Import', 198 | canSelectFiles: true, 199 | canSelectFolders: false, 200 | canSelectMany: false, 201 | filters: { 202 | 'JSON': ['json'], 203 | }, 204 | }); 205 | if (!res) return; 206 | await substrate.importKeyringPair(res[0].path); 207 | 208 | treeDataProvider.refresh(); 209 | }); 210 | 211 | // Export the selected account in the TreeView 212 | vscode.commands.registerCommand("substrate.exportAccount", async (item?: AccountTreeItem) => { 213 | let itemAccount = item?.account || await quickPickAccount(substrate,'Please pick an account to export'); 214 | if (!itemAccount) return; 215 | 216 | const result = await vscode.window.showSaveDialog({}); 217 | if (!result) return; 218 | 219 | fs.writeFileSync(result.fsPath, JSON.stringify(itemAccount), 'utf8'); 220 | }); 221 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-substrate", 3 | "displayName": "VSCode Substrate", 4 | "description": "Manage your Substrate node and add pallets from the Marketplace to your runtime", 5 | "version": "0.5.2", 6 | "publisher": "paritytech", 7 | "icon": "resources/icon.png", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/paritytech/vscode-substrate.git" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/paritytech/vscode-substrate/issues" 14 | }, 15 | "homepage": "https://github.com/paritytech/vscode-substrate/blob/master/README.md", 16 | "engines": { 17 | "vscode": "^1.42.0" 18 | }, 19 | "keywords": [ 20 | "pallets", 21 | "polkadot", 22 | "parity", 23 | "web3" 24 | ], 25 | "categories": [ 26 | "Other" 27 | ], 28 | "activationEvents": [ 29 | "*" 30 | ], 31 | "main": "./out/extension.js", 32 | "contributes": { 33 | "viewsWelcome": [ 34 | { 35 | "view": "substrateAccounts", 36 | "contents": "No accounts found." 37 | }, 38 | { 39 | "view": "substrateProcesses", 40 | "contents": "No node is currently running." 41 | }, 42 | { 43 | "view": "substrateNodes", 44 | "contents": "No node was found in your current workspace.\n[Open folder](command:vscode.openFolder)" 45 | } 46 | ], 47 | "viewsContainers": { 48 | "activitybar": [ 49 | { 50 | "id": "substrate", 51 | "title": "Substrate", 52 | "icon": "resources/substrate.svg" 53 | } 54 | ] 55 | }, 56 | "views": { 57 | "substrate": [ 58 | { 59 | "id": "substrateProcesses", 60 | "name": "Processes", 61 | "group": "@1" 62 | }, 63 | { 64 | "id": "substrateNodes", 65 | "name": "Nodes", 66 | "group": "@2" 67 | }, 68 | { 69 | "id": "substrateMarketplace", 70 | "name": "Marketplace", 71 | "group": "@3" 72 | }, 73 | { 74 | "id": "substrateAccounts", 75 | "name": "Accounts", 76 | "group": "@4" 77 | }, 78 | { 79 | "id": "substrateContracts", 80 | "name": "Contracts", 81 | "group": "@5" 82 | } 83 | ] 84 | }, 85 | "commands": [ 86 | { 87 | "command": "substrate.stopProcess", 88 | "title": "Substrate: Stop process", 89 | "icon": { 90 | "dark": "resources/stopProcess.svg", 91 | "light": "resources/stopProcess-black.svg" 92 | } 93 | }, 94 | { 95 | "command": "substrate.polkadotApps", 96 | "title": "Substrate: Polkadot Apps", 97 | "icon": { 98 | "dark": "resources/apps.svg", 99 | "light": "resources/apps-black.svg" 100 | } 101 | }, 102 | { 103 | "command": "substrate.purgeChain", 104 | "title": "Substrate: Purge chain", 105 | "icon": { 106 | "dark": "resources/purgeChain.svg", 107 | "light": "resources/purgeChain-black.svg" 108 | } 109 | }, 110 | { 111 | "command": "substrate.startNode", 112 | "title": "Substrate: Start node", 113 | "icon": { 114 | "dark": "resources/startNode.svg", 115 | "light": "resources/startNode-black.svg" 116 | } 117 | }, 118 | { 119 | "command": "substrate.compileStartNode", 120 | "title": "Substrate: Compile & start node", 121 | "icon": { 122 | "dark": "resources/compileStartNode.svg", 123 | "light": "resources/compileStartNode-black.svg" 124 | } 125 | }, 126 | { 127 | "command": "substrateMarketplace.palletHomepage", 128 | "title": "Homepage", 129 | "icon": { 130 | "dark": "resources/home.svg", 131 | "light": "resources/home-black.svg" 132 | } 133 | }, 134 | { 135 | "command": "substrateMarketplace.palletGithub", 136 | "title": "GitHub", 137 | "icon": { 138 | "dark": "resources/github.svg", 139 | "light": "resources/github-black.svg" 140 | } 141 | }, 142 | { 143 | "command": "substrateMarketplace.palletDocumentation", 144 | "title": "Documentation", 145 | "icon": { 146 | "dark": "resources/book.svg", 147 | "light": "resources/book-black.svg" 148 | } 149 | }, 150 | { 151 | "command": "substrateMarketplace.installPallet", 152 | "title": "Add pallet to runtime", 153 | "icon": { 154 | "dark": "resources/add.svg", 155 | "light": "resources/add-black.svg" 156 | } 157 | }, 158 | { 159 | "command": "substrate.addAccount", 160 | "title": "Substrate: Add account", 161 | "icon": { 162 | "dark": "resources/add.svg", 163 | "light": "resources/add-black.svg" 164 | } 165 | }, 166 | { 167 | "command": "substrate.createAccount", 168 | "title": "Generate new account" 169 | }, 170 | { 171 | "command": "substrate.importAccount", 172 | "title": "Import account from JSON" 173 | }, 174 | { 175 | "command": "substrate.removeAccount", 176 | "title": "Remove" 177 | }, 178 | { 179 | "command": "substrate.exportAccount", 180 | "title": "Export" 181 | }, 182 | { 183 | "command": "substrate.renameAccount", 184 | "title": "Change name" 185 | }, 186 | { 187 | "command": "substrate.copyAddress", 188 | "title": "Copy address" 189 | }, 190 | { 191 | "command": "substrate.compileAndDeploy", 192 | "title": "Compile & deploy contract" 193 | }, 194 | { 195 | "command": "substrate.forgetContract", 196 | "title": "Forget contract" 197 | }, 198 | { 199 | "command": "substrate.copyContractHash", 200 | "title": "Copy hash" 201 | }, 202 | { 203 | "command": "substrate.callContractMethod", 204 | "title": "Call a contract method" 205 | }, 206 | { 207 | "command": "substrate.refreshContracts", 208 | "title": "Refresh contracts list" 209 | } 210 | ], 211 | "menus": { 212 | "commandPalette": [ 213 | { 214 | "command": "substrateMarketplace.palletHomepage", 215 | "when": "false" 216 | }, 217 | { 218 | "command": "substrateMarketplace.palletGithub", 219 | "when": "false" 220 | }, 221 | { 222 | "command": "substrateMarketplace.palletDocumentation", 223 | "when": "false" 224 | }, 225 | { 226 | "command": "substrateMarketplace.installPallet", 227 | "when": "false" 228 | } 229 | ], 230 | "view/title": [ 231 | { 232 | "command": "substrate.addAccount", 233 | "when": "view == substrateAccounts", 234 | "group": "navigation" 235 | }, 236 | { 237 | "command": "substrate.createAccount", 238 | "when": "view == substrateAccounts" 239 | }, 240 | { 241 | "command": "substrate.importAccount", 242 | "when": "view == substrateAccounts" 243 | }, 244 | { 245 | "command": "substrate.compileAndDeploy", 246 | "when": "view == substrateContracts", 247 | "group": "section-1" 248 | } 249 | ], 250 | "view/item/context": [ 251 | { 252 | "command": "substrate.polkadotApps", 253 | "when": "view == substrateProcesses && viewItem == theia", 254 | "group": "inline@0" 255 | }, 256 | { 257 | "command": "substrate.stopProcess", 258 | "when": "view == substrateProcesses", 259 | "group": "inline@1" 260 | }, 261 | { 262 | "command": "substrate.purgeChain", 263 | "when": "view == substrateNodes", 264 | "group": "inline@0" 265 | }, 266 | { 267 | "command": "substrate.startNode", 268 | "when": "view == substrateNodes", 269 | "group": "inline@1" 270 | }, 271 | { 272 | "command": "substrate.compileStartNode", 273 | "when": "view == substrateNodes", 274 | "group": "inline@2" 275 | }, 276 | { 277 | "command": "substrateMarketplace.palletHomepage", 278 | "when": "view == substrateMarketplace && viewItem == pallet || view == substrateMarketplace && viewItem == palletInstalled || view == substrateMarketplace && viewItem == palletNoNode", 279 | "group": "inline@0" 280 | }, 281 | { 282 | "command": "substrateMarketplace.palletGithub", 283 | "when": "view == substrateMarketplace && viewItem == pallet || view == substrateMarketplace && viewItem == palletInstalled || view == substrateMarketplace && viewItem == palletNoNode", 284 | "group": "inline@1" 285 | }, 286 | { 287 | "command": "substrateMarketplace.palletDocumentation", 288 | "when": "view == substrateMarketplace && viewItem == pallet || view == substrateMarketplace && viewItem == palletInstalled || view == substrateMarketplace && viewItem == palletNoNode", 289 | "group": "inline@2" 290 | }, 291 | { 292 | "command": "substrateMarketplace.installPallet", 293 | "when": "view == substrateMarketplace && viewItem == pallet", 294 | "group": "inline@3" 295 | }, 296 | { 297 | "command": "substrate.removeAccount", 298 | "when": "view == substrateAccounts" 299 | }, 300 | { 301 | "command": "substrate.exportAccount", 302 | "when": "view == substrateAccounts" 303 | }, 304 | { 305 | "command": "substrate.renameAccount", 306 | "when": "view == substrateAccounts" 307 | }, 308 | { 309 | "command": "substrate.copyAddress", 310 | "when": "view == substrateAccounts" 311 | }, 312 | { 313 | "command": "substrate.callContractMethod", 314 | "when": "view == substrateContracts", 315 | "group": "section-1" 316 | }, 317 | { 318 | "command": "substrate.copyContractHash", 319 | "when": "view == substrateContracts", 320 | "group": "section-1" 321 | }, 322 | { 323 | "command": "substrate.forgetContract", 324 | "when": "view == substrateContracts", 325 | "group": "section-2" 326 | } 327 | ] 328 | } 329 | }, 330 | "scripts": { 331 | "vscode:prepublish": "yarn run compile", 332 | "compile": "tsc -p ./", 333 | "watch": "tsc -watch -p ./" 334 | }, 335 | "devDependencies": { 336 | "@types/node": "^10.12.21", 337 | "@types/vscode": "^1.42.0", 338 | "tslint": "^5.12.1", 339 | "typescript": "^3.5.1" 340 | }, 341 | "dependencies": { 342 | "@polkadot/api": "^1.27.1", 343 | "@polkadot/api-contract": "^1.27.1", 344 | "@types/lodash": "^4.14.149", 345 | "@types/node-fetch": "^2.5.5", 346 | "array-flat-polyfill": "^1.0.1", 347 | "clipboardy": "^2.3.0", 348 | "glob": "^7.1.6", 349 | "lodash": "^4.17.19", 350 | "node-fetch": "^2.6.1", 351 | "rxjs": "^6.5.5", 352 | "string.prototype.matchall": "^4.0.2" 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /src/views/contracts/ContractsProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import { tryShortname, resolveWhenTerminalClosed, showInputBoxValidate, wsEndpointFromCommand } from '../../util'; 3 | import { Abi } from '@polkadot/api-contract'; 4 | import { compactAddLength } from '@polkadot/util'; 5 | 6 | import * as clipboard from 'clipboardy'; 7 | import { TreeDataProvider } from '../../common/TreeDataProvider'; 8 | import { Substrate, Contract } from '../../common/Substrate'; 9 | import { Process } from '../../processes/Processes'; 10 | 11 | const fs = require('fs'); 12 | const path = require('path'); 13 | 14 | export class ContractsProvider extends TreeDataProvider { 15 | substrate: Substrate; 16 | 17 | constructor(substrate: Substrate) { 18 | super(); 19 | this.substrate = substrate; 20 | } 21 | 22 | getChildren(element?: ContractTreeItem): Thenable { 23 | if (element === undefined) { 24 | return Promise.resolve(this.substrate.getConnectionContracts().map(a => new ContractTreeItem(a))); 25 | } 26 | return Promise.resolve(element.children); 27 | } 28 | } 29 | 30 | export class ContractTreeItem extends vscode.TreeItem { 31 | children: [] = []; 32 | contract: Contract; 33 | 34 | constructor(contract: Contract) { 35 | super( 36 | contract.name, 37 | vscode.TreeItemCollapsibleState.None); 38 | this.description = contract.address; 39 | this.contract = contract; 40 | } 41 | } 42 | 43 | export async function setupContractsTreeView(substrate: Substrate, selectedProcess$: any, context: vscode.ExtensionContext) { 44 | const treeDataProvider = new ContractsProvider(substrate); 45 | const treeView = vscode.window.createTreeView('substrateContracts', { treeDataProvider }); 46 | 47 | selectedProcess$.subscribe((process: Process) => { 48 | if (process) 49 | treeView.message = `Connected to: ${wsEndpointFromCommand(process.command)} (${tryShortname(process.nodePath) + ' • ' + process.command})`; 50 | else 51 | treeView.message = `Not connected to any node.`; 52 | vscode.commands.executeCommand('substrate.refreshContracts'); 53 | }); 54 | 55 | vscode.commands.registerCommand("substrate.refreshContracts", async (contractItem: ContractTreeItem) => { 56 | treeDataProvider.refresh(); 57 | }); 58 | 59 | vscode.commands.registerCommand("substrate.callContractMethod", async (contractItem: ContractTreeItem) => { 60 | try { 61 | const api = substrate.getConnection(); 62 | if (!api) { 63 | vscode.window.showErrorMessage(`Not connected to a node.`); 64 | return; 65 | } 66 | 67 | const abi = new Abi(api.registry, contractItem.contract.abiJson); 68 | 69 | const methods = abi.abi.contract.messages; 70 | const items = methods.map(method => { 71 | const args = method.args.map((arg) => `${arg.name}: ${arg.type}`); 72 | const retDisplayName = method.returnType && method.returnType.displayName; 73 | return { 74 | label: `🧭 ${method.name}(${args.join(', ')})${retDisplayName ? `: ${retDisplayName}` : ''}`, 75 | description: method.mutates ? 'will mutate storage' : 'won\'t mutate storage', 76 | detail: `Method selector: ${method.selector}`, 77 | method 78 | }; 79 | }); 80 | const pickedMessage = await vscode.window.showQuickPick(items, { placeHolder: 'ex. get(): bool' }); 81 | if (!pickedMessage) return; 82 | const method = pickedMessage.method; 83 | 84 | const valueTo: string | undefined = await showInputBoxValidate({ 85 | ignoreFocusOut: true, 86 | prompt: 'The allotted value for this contract, i.e. the amount transferred to the contract as part of this call', 87 | value: '1000000000000000', 88 | placeHolder: 'ex. 1000000000000000' 89 | }, async (value: any) => { 90 | if (!value || !value.trim()) { 91 | return 'Value is required'; 92 | } 93 | if (!value.match(/^-{0,1}\d+$/)) { 94 | return 'The value specified is not a number'; 95 | } 96 | return ''; 97 | }); 98 | if (!valueTo) return; 99 | 100 | const maxGas: string | undefined = await showInputBoxValidate({ 101 | ignoreFocusOut: true, 102 | prompt: 'The maximum amount of gas that can be used by this call', 103 | value: '1000000000000', // too much? 104 | placeHolder: 'ex. 1000000000000' 105 | }, async (value: any) => { 106 | if (!value || !value.trim()) { 107 | return 'A value is required'; 108 | } 109 | if (!value.match(/^-{0,1}\d+$/)) { 110 | return 'The maximum gas specified is not a number'; 111 | } 112 | return ''; 113 | }); 114 | if (!maxGas) return; 115 | 116 | const argsVals = []; 117 | const argsDefs = pickedMessage.method.args; 118 | 119 | while (argsDefs.length > argsVals.length) { 120 | const i: number = argsVals.length; 121 | const prompt = `${argsDefs[i].name}: ${argsDefs[i].type.displayName}`; 122 | 123 | const vale = await showInputBoxValidate({ 124 | ignoreFocusOut: true, 125 | prompt 126 | }, async (value: any) => { 127 | return '' 128 | }); 129 | if (vale === undefined) return; // User cancelled 130 | argsVals.push(vale); 131 | } 132 | 133 | const accounts = substrate.getAccounts(); 134 | const _account = await vscode.window.showQuickPick(substrate.getAccounts().map((x: any) => x.meta.name)); 135 | if (!_account) return; 136 | const accountJson = accounts.find(a => a.meta.name === _account)!; 137 | 138 | const keyring = substrate.getKeyring(); 139 | const account = keyring.addFromJson(accountJson); 140 | 141 | const password: string | undefined = await showInputBoxValidate({ 142 | ignoreFocusOut: true, 143 | prompt: 'Account password', 144 | placeHolder: 'ex. StrongPassword', 145 | password: true, 146 | value: '', 147 | }, async (value: any) => { 148 | try { 149 | account.decodePkcs8(value); 150 | if (account.isLocked) { 151 | return 'Failed to decode account'; 152 | } 153 | } catch (e) { 154 | return 'Failed to decode account'; 155 | } 156 | return ''; 157 | }); 158 | if (typeof password === 'undefined') return; 159 | 160 | // METHOD CALL 161 | 162 | vscode.window.showInformationMessage('Calling contract method...'); 163 | 164 | try { 165 | const { nonce } = await api.query.system.account(account.address); 166 | const contractApi = api.tx.contracts ? api.tx['contracts'] : api.tx['contract']; 167 | 168 | const methodExec = abi.messages[method.name]; 169 | const unsignedTransaction = contractApi.call( 170 | contractItem.description, 171 | valueTo, 172 | maxGas, 173 | methodExec(...argsVals), 174 | ); 175 | 176 | const cb = await unsignedTransaction.sign(account, { nonce: nonce as any }).send(({ events = [], status }: any) => { 177 | if (status.isFinalized) { 178 | const finalized = status.asFinalized.toHex(); 179 | console.log(`Completed at block hash: ${finalized}`); 180 | 181 | console.log(`Events:`); 182 | let error: string = ''; 183 | events.forEach(({ phase, event: { data, method, section } }: any) => { 184 | const res = `\t ${phase.toString()} : ${section}.${method} ${data.toString()}`; 185 | if (res.indexOf('Failed') !== -1) { 186 | error += res; 187 | } 188 | console.log(res); 189 | }); 190 | if (error !== '') { 191 | // Todo: Get error 192 | vscode.window.showErrorMessage(`Failed on block "${finalized}" with error: ${error}`); 193 | return; 194 | } 195 | vscode.window.showInformationMessage(`Completed on block ${finalized}`); 196 | } 197 | }); 198 | // TODO Get results from contract 199 | } catch (err) { 200 | vscode.window.showErrorMessage(`Error on put code: ${err.message}`); 201 | } 202 | } 203 | catch (err) { 204 | console.error(err); 205 | vscode.window.showErrorMessage(err); 206 | } 207 | }); 208 | 209 | vscode.commands.registerCommand("substrate.forgetContract", async (contractItem: ContractTreeItem) => { 210 | try { 211 | const contracts = substrate.getConnectionContracts(); 212 | for (let i = 0; i < contracts.length; i++) { 213 | const contract = contracts[i]; 214 | if (contract.name === contractItem.label || contract.address === contractItem.description) { 215 | contracts.splice(i, 1); 216 | } 217 | } 218 | await substrate.updateConnectionContracts(contracts); 219 | } catch (err) { 220 | vscode.window.showErrorMessage('You are not connected to a node'); 221 | } 222 | await vscode.commands.executeCommand('substrate.refreshContracts'); 223 | vscode.window.showInformationMessage(`Successfully removed contract "${contractItem.label}"`); 224 | }); 225 | 226 | vscode.commands.registerCommand("substrate.copyContractHash", async (contractItem: ContractTreeItem) => { 227 | try { 228 | await clipboard.write((contractItem as any).description); 229 | vscode.window.showInformationMessage('Hash copied to clipboard'); 230 | } catch (err) { 231 | vscode.window.showErrorMessage(`Failed to copy hash to clipboard: ${err.message}`); 232 | } 233 | }); 234 | 235 | vscode.commands.registerCommand("substrate.compileAndDeploy", async () => { 236 | try { 237 | const api = substrate.getConnection(); 238 | if (!api) { 239 | vscode.window.showErrorMessage('Please connect to a node first.'); 240 | return; 241 | } 242 | if (!api.tx.contracts && !api.tx.contract) { 243 | vscode.window.showErrorMessage('The selected process doesn\'t support smart contracts.'); 244 | return; 245 | } 246 | 247 | const folders = await vscode.window.showOpenDialog({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, openLabel: 'Select contract folder' }) 248 | if (folders === undefined) return; 249 | 250 | const term = vscode.window.createTerminal({ name: 'Compiling contract', cwd: folders[0] }); 251 | term.sendText('cargo +nightly contract build && cargo +nightly contract generate-metadata && exit'); 252 | term.show(); 253 | 254 | await resolveWhenTerminalClosed(term); 255 | 256 | const wasmPath = path.join(folders[0].fsPath, 'target', path.basename(folders[0].fsPath) + '.wasm'); 257 | const abiPath = path.join(folders[0].fsPath, 'target', 'metadata.json'); 258 | const wasm: Uint8Array = await fs.promises.readFile(wasmPath); 259 | const isWasmValid = wasm.subarray(0, 4).join(',') === '0,97,115,109'; // '\0asm' 260 | if (!isWasmValid) { 261 | console.error('Invalid code'); 262 | throw Error('Invalid code'); 263 | } 264 | const compiledContract = compactAddLength(wasm); 265 | 266 | const name: string | undefined = await showInputBoxValidate({ 267 | ignoreFocusOut: true, 268 | prompt: 'Contract name', 269 | placeHolder: 'ex. Flipper contract', 270 | value: 'flip' 271 | }, async (value: any) => { 272 | if (!value || !value.trim()) { 273 | return 'A name is required'; 274 | } 275 | return ''; 276 | }); 277 | if (!name) return; 278 | 279 | const accounts = substrate.getAccounts(); 280 | const _account = await vscode.window.showQuickPick(substrate.getAccounts().map((x: any) => x.meta.name)); 281 | if (!_account) return; 282 | const accountJson = accounts.find(a => a.meta.name === _account)!; 283 | 284 | const keyring = substrate.getKeyring(); 285 | const account = keyring.addFromJson(accountJson); 286 | 287 | const password: string | undefined = await showInputBoxValidate({ 288 | ignoreFocusOut: true, 289 | prompt: 'Account password', 290 | placeHolder: 'ex. StrongPassword', 291 | password: true, 292 | value: '', 293 | }, async (value: any) => { 294 | try { 295 | account.decodePkcs8(value); 296 | if (account.isLocked) { 297 | return 'Failed to decode account'; 298 | } 299 | } catch (e) { 300 | return 'Failed to decode account'; 301 | } 302 | return ''; 303 | }); 304 | if (typeof password === 'undefined') return; 305 | 306 | const abiBytes: Uint8Array = await fs.promises.readFile(abiPath); 307 | const abiJson = JSON.parse(abiBytes.toString()); 308 | const abi = new Abi(api.registry, abiJson); 309 | const constructors = abi.abi.contract.constructors; 310 | const _constructor = await vscode.window.showQuickPick(constructors.map((x: any) => x.name), { placeHolder: 'Choose constructor' }); 311 | if (!_constructor) return; 312 | const constructorI = constructors.findIndex(x => x.name === _constructor)!; 313 | const constructor = constructors.find(x => x.name === _constructor)!; 314 | const args = constructor.args 315 | 316 | const constructorParams: any[] = []; 317 | while (args.length > constructorParams.length) { 318 | const i = constructorParams.length; 319 | const prompt = `${args[i].name}: ${args[i].type.displayName}`; 320 | 321 | constructorParams.push(await showInputBoxValidate({ 322 | ignoreFocusOut: true, 323 | prompt 324 | }, async (value: any) => { 325 | return '' 326 | })); 327 | } 328 | 329 | const endowment: string | undefined = await showInputBoxValidate({ 330 | ignoreFocusOut: true, 331 | prompt: 'The allotted endowment for this contract, i.e. the amount transferred to the contract upon instantiation.', 332 | value: '1000000000000000', 333 | placeHolder: 'ex. 1000000000000000' 334 | }, async (value: any) => { 335 | if (!value || !value.trim()) { 336 | return 'Endowment is required'; 337 | } 338 | if (!value.match(/^-{0,1}\d+$/)) { 339 | return 'The endowment specified is not a number'; 340 | } 341 | return ''; 342 | }); 343 | if (!endowment) return; 344 | 345 | const maxGasDeployment: string | undefined = await showInputBoxValidate({ 346 | ignoreFocusOut: true, 347 | prompt: 'The maximum amount of gas that can be used for the deployment', 348 | value: '1000000000000', 349 | placeHolder: 'ex. 1000000000000' 350 | }, async (value: any) => { 351 | if (!value || !value.trim()) { 352 | return 'A value is required'; 353 | } 354 | if (!value.match(/^-{0,1}\d+$/)) { 355 | return 'The maximum gas specified is not a number'; 356 | } 357 | return ''; 358 | }); 359 | if (!maxGasDeployment) return; 360 | 361 | // PUT CODE 362 | 363 | vscode.window.showInformationMessage('Uploading WASM...'); 364 | 365 | try { 366 | const { nonce } = await api.query.system.account(account.address); 367 | const contractApi = api.tx.contracts ? api.tx['contracts'] : api.tx['contract']; 368 | const unsignedTransaction = contractApi.putCode(compiledContract); 369 | 370 | let code_hash = ''; 371 | unsignedTransaction.sign(account, { nonce: nonce as any }).send(async ({ events = [], status }: any) => { 372 | if (status.isFinalized) { 373 | const finalized = status.asFinalized.toHex(); 374 | console.log(`Completed at block hash: ${finalized}`); 375 | 376 | console.log('Events:'); 377 | let error: string = ''; 378 | let resultHash: string = ''; 379 | events.forEach(({ phase, event: { data, method, section } }: any) => { 380 | const res = `\t ${phase.toString()} : ${section}.${method} ${data.toString()}`; 381 | if (res.indexOf('Failed') !== -1) { 382 | error += res; 383 | } 384 | if (res.indexOf('contracts.CodeStored') !== -1) { 385 | resultHash = res.substring( 386 | res.lastIndexOf('["') + 2, 387 | res.lastIndexOf('"]'), 388 | ); 389 | } 390 | console.log(res); 391 | }); 392 | if (error !== '') { 393 | // Todo: Get error 394 | vscode.window.showErrorMessage(`Failed on block "${finalized}" with error: ${error}`); 395 | return; 396 | } 397 | if (resultHash === '') { 398 | vscode.window.showErrorMessage(`Completed on block "${finalized}" but failed to get event result`); 399 | return; 400 | } 401 | console.log(`Completed on block ${finalized} with code hash ${resultHash}`); 402 | code_hash = resultHash; 403 | 404 | // Deploying contract 405 | 406 | vscode.window.showInformationMessage('Instantiating contract...'); 407 | 408 | // DEPLOY CONTRACT 409 | try { 410 | const { nonce } = await api.query.system.account(account.address); 411 | const unsignedTransaction = contractApi.instantiate( 412 | endowment, // +3 more 0's 413 | maxGasDeployment, 414 | code_hash, 415 | abi.constructors[constructorI](...constructorParams) // TODO test when passing parameters 416 | ); 417 | await unsignedTransaction.sign(account, { nonce: nonce as any }).send(({ events = [], status }: any) => { 418 | if (status.isFinalized) { 419 | const finalized = status.asFinalized.toHex(); 420 | console.log(`Completed at block hash: ${finalized}`); 421 | 422 | console.log('Events:'); 423 | let error: string = ''; 424 | let resultHash: string = ''; 425 | events.forEach(({ phase, event: { data, method, section } }: any) => { 426 | const res = `\t ${phase.toString()} : ${section}.${method} ${data.toString()}`; 427 | if (res.indexOf('Failed') !== -1) { 428 | error += res; 429 | } 430 | if (res.indexOf('contracts.Instantiated') !== -1) { 431 | resultHash = res.substring( 432 | res.lastIndexOf('["') + 2, 433 | res.lastIndexOf('",'), 434 | ); 435 | } 436 | console.log(res); 437 | }); 438 | if (error !== '') { 439 | vscode.window.showErrorMessage(`Failed on block "${finalized}" with error: ${error}`); 440 | return; 441 | } 442 | if (resultHash === '') { 443 | vscode.window.showWarningMessage(`Completed on block "${finalized}" but failed to get event result`); 444 | return; 445 | } 446 | substrate.saveContract(name, resultHash, abiJson).catch(err => { 447 | vscode.window.showErrorMessage(`Failed to store contract: ${err.message}`); 448 | }); 449 | vscode.window.showInformationMessage(`Completed on block ${finalized} with code hash ${resultHash}`); 450 | } 451 | }); 452 | } catch (err) { 453 | vscode.window.showErrorMessage(`Error on deploy contract: ${err.message}`); 454 | } 455 | } 456 | }); 457 | } catch (err) { 458 | vscode.window.showErrorMessage(`Error on put code: ${err.message}`); 459 | } 460 | } catch (surerr) { 461 | vscode.window.showErrorMessage(surerr); 462 | } 463 | }); 464 | } -------------------------------------------------------------------------------- /resources/playground.png.base64: -------------------------------------------------------------------------------- 1 | data:image/png;base64,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 -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.8.3" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" 8 | integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== 9 | dependencies: 10 | "@babel/highlight" "^7.8.3" 11 | 12 | "@babel/highlight@^7.8.3": 13 | version "7.8.3" 14 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" 15 | integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== 16 | dependencies: 17 | chalk "^2.0.0" 18 | esutils "^2.0.2" 19 | js-tokens "^4.0.0" 20 | 21 | "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.0": 22 | version "7.11.2" 23 | resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" 24 | integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== 25 | dependencies: 26 | regenerator-runtime "^0.13.4" 27 | 28 | "@polkadot/api-contract@^1.27.1": 29 | version "1.27.1" 30 | resolved "https://registry.yarnpkg.com/@polkadot/api-contract/-/api-contract-1.27.1.tgz#52b45b7de8ce35b0d278f4c37eafdcd0b0b7b8c7" 31 | integrity sha512-4Md0LXysEctONz38u7TG9EEFHL2rd9s25nzskGOuFm3FoLomFrvUHGsheIr0zM6wDg8yScRh9zvdkc8EvG4sWQ== 32 | dependencies: 33 | "@babel/runtime" "^7.11.0" 34 | "@polkadot/api" "1.27.1" 35 | "@polkadot/rpc-core" "1.27.1" 36 | "@polkadot/types" "1.27.1" 37 | "@polkadot/util" "^3.0.1" 38 | bn.js "^5.1.2" 39 | rxjs "^6.6.2" 40 | 41 | "@polkadot/api-derive@1.27.1": 42 | version "1.27.1" 43 | resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-1.27.1.tgz#5001f19cb29ea4d7924412950b41e46fcca45d81" 44 | integrity sha512-WPZEZ9THeYOkkGzDDsCGSTrWJuWu6qegmWLo52pqD7enmP3dADDoKqPzszHVbEAfc+wYtc5Ye4EogUAiK30iMg== 45 | dependencies: 46 | "@babel/runtime" "^7.11.0" 47 | "@polkadot/api" "1.27.1" 48 | "@polkadot/rpc-core" "1.27.1" 49 | "@polkadot/rpc-provider" "1.27.1" 50 | "@polkadot/types" "1.27.1" 51 | "@polkadot/util" "^3.0.1" 52 | "@polkadot/util-crypto" "^3.0.1" 53 | bn.js "^5.1.2" 54 | memoizee "^0.4.14" 55 | rxjs "^6.6.2" 56 | 57 | "@polkadot/api@1.27.1", "@polkadot/api@^1.27.1": 58 | version "1.27.1" 59 | resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-1.27.1.tgz#dcd3ae5d8699ea5555369b9594888eb1008dd7fe" 60 | integrity sha512-ANMLmNR1PfXLoQ7Ysep9sM/2U3oh3fjFI+9P4Yy9Pv+XMvCROaGAcvxoG+hHfWFz6OAT7ABwyiocV93PuOpAww== 61 | dependencies: 62 | "@babel/runtime" "^7.11.0" 63 | "@polkadot/api-derive" "1.27.1" 64 | "@polkadot/keyring" "^3.0.1" 65 | "@polkadot/metadata" "1.27.1" 66 | "@polkadot/rpc-core" "1.27.1" 67 | "@polkadot/rpc-provider" "1.27.1" 68 | "@polkadot/types" "1.27.1" 69 | "@polkadot/types-known" "1.27.1" 70 | "@polkadot/util" "^3.0.1" 71 | "@polkadot/util-crypto" "^3.0.1" 72 | bn.js "^5.1.2" 73 | eventemitter3 "^4.0.4" 74 | rxjs "^6.6.2" 75 | 76 | "@polkadot/keyring@^3.0.1": 77 | version "3.0.1" 78 | resolved "https://registry.yarnpkg.com/@polkadot/keyring/-/keyring-3.0.1.tgz#3944079697c15b2af81e1f57b1c4aeab703a4fef" 79 | integrity sha512-vAHSBnisiDYHsBbEzAgIpuwQp3vIDN2uWQ/1wAE2BrKzXCBQM7RrF3LRcLFySk0xzQoDs7AP1TlPoakxJ/C/Qw== 80 | dependencies: 81 | "@babel/runtime" "^7.10.5" 82 | "@polkadot/util" "3.0.1" 83 | "@polkadot/util-crypto" "3.0.1" 84 | 85 | "@polkadot/metadata@1.27.1": 86 | version "1.27.1" 87 | resolved "https://registry.yarnpkg.com/@polkadot/metadata/-/metadata-1.27.1.tgz#40b8e26f9eee30df5b6790aaab406dae1e6d3152" 88 | integrity sha512-jOsWvpGNFkV3NGSGVTzyir0PKinxoa97CYEQj8tJTU7iHDPnSs5R/BEmI0+1hg4ZM/47n+YU8d0lLktD6wbMOA== 89 | dependencies: 90 | "@babel/runtime" "^7.11.0" 91 | "@polkadot/types" "1.27.1" 92 | "@polkadot/types-known" "1.27.1" 93 | "@polkadot/util" "^3.0.1" 94 | "@polkadot/util-crypto" "^3.0.1" 95 | bn.js "^5.1.2" 96 | 97 | "@polkadot/rpc-core@1.27.1": 98 | version "1.27.1" 99 | resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-1.27.1.tgz#afe7d1890c779eaf2bec9bb1336b5ba2ff1ba15b" 100 | integrity sha512-HxLHHdV3bDqTltsEedCRGiZeTGmeahnk6OEGyysFOW3PFIrygwwuYa0Mo10lS93dwy9xZw4oE3h9qZqox2mGmQ== 101 | dependencies: 102 | "@babel/runtime" "^7.11.0" 103 | "@polkadot/metadata" "1.27.1" 104 | "@polkadot/rpc-provider" "1.27.1" 105 | "@polkadot/types" "1.27.1" 106 | "@polkadot/util" "^3.0.1" 107 | memoizee "^0.4.14" 108 | rxjs "^6.6.2" 109 | 110 | "@polkadot/rpc-provider@1.27.1": 111 | version "1.27.1" 112 | resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-1.27.1.tgz#c0307a9e9c658f4072ad94ac6e98e2bd78bb1ee6" 113 | integrity sha512-12lpsmHNYLZ3p0X0h643U+sw+WE/kzVB9Q0Y0RA9Recq794cBGiEgK/nmVjT5hrTEk+2+qdtu+CqficWt2FeQw== 114 | dependencies: 115 | "@babel/runtime" "^7.11.0" 116 | "@polkadot/metadata" "1.27.1" 117 | "@polkadot/types" "1.27.1" 118 | "@polkadot/util" "^3.0.1" 119 | "@polkadot/util-crypto" "^3.0.1" 120 | bn.js "^5.1.2" 121 | eventemitter3 "^4.0.4" 122 | isomorphic-fetch "^2.2.1" 123 | websocket "^1.0.31" 124 | 125 | "@polkadot/types-known@1.27.1": 126 | version "1.27.1" 127 | resolved "https://registry.yarnpkg.com/@polkadot/types-known/-/types-known-1.27.1.tgz#d6c48c7b075cd0a9772fcc5df8d98f77b0da35f3" 128 | integrity sha512-9HzHJXznuuG0EQPR3XN931smIzA5usOP2D4Te/uyjiqHgXGUv1EU/vPYaacYYRrjLNdytNcF3HbW97fxu+fC6w== 129 | dependencies: 130 | "@babel/runtime" "^7.11.0" 131 | "@polkadot/types" "1.27.1" 132 | "@polkadot/util" "^3.0.1" 133 | bn.js "^5.1.2" 134 | 135 | "@polkadot/types@1.27.1": 136 | version "1.27.1" 137 | resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-1.27.1.tgz#243f796178f9308a8e58f13fa13d0f3ed1fd2bc8" 138 | integrity sha512-6sX+0/cBUEd/Pt6Y4JSjUI44nqH6qyuRcs6bte2OsEsm06XTEMoIqICPHoOS36Sd/ux7IA/gTZgEj39C9mJWBQ== 139 | dependencies: 140 | "@babel/runtime" "^7.11.0" 141 | "@polkadot/metadata" "1.27.1" 142 | "@polkadot/util" "^3.0.1" 143 | "@polkadot/util-crypto" "^3.0.1" 144 | "@types/bn.js" "^4.11.6" 145 | bn.js "^5.1.2" 146 | memoizee "^0.4.14" 147 | rxjs "^6.6.2" 148 | 149 | "@polkadot/util-crypto@3.0.1", "@polkadot/util-crypto@^3.0.1": 150 | version "3.0.1" 151 | resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-3.0.1.tgz#800746a39a00e5aa7dc7b901bbde0f5e3e0be60b" 152 | integrity sha512-4G5kzNfqa/nQGuTtoFsy3DESApc8BTgTHbAvLwSkxzM3j8YsvC5ayJ3AFYvM2UT2PDwXmrFx4cwRnYsYZvhC9A== 153 | dependencies: 154 | "@babel/runtime" "^7.10.5" 155 | "@polkadot/util" "3.0.1" 156 | "@polkadot/wasm-crypto" "^1.2.1" 157 | base-x "^3.0.8" 158 | bip39 "^3.0.2" 159 | blakejs "^1.1.0" 160 | bn.js "^5.1.2" 161 | elliptic "^6.5.3" 162 | js-sha3 "^0.8.0" 163 | pbkdf2 "^3.1.1" 164 | scryptsy "^2.1.0" 165 | tweetnacl "^1.0.3" 166 | xxhashjs "^0.2.2" 167 | 168 | "@polkadot/util@3.0.1", "@polkadot/util@^3.0.1": 169 | version "3.0.1" 170 | resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-3.0.1.tgz#f7ed9d81d745136aa6d6ad57277ee05c88f32784" 171 | integrity sha512-WvH+seT03YQ+6dWJqo285uYHsDvMEGzgYQILEclzQo8xExeCYLIX6GptpW0vGycVxdZmmCdDmUFbcQSRsFawYA== 172 | dependencies: 173 | "@babel/runtime" "^7.10.5" 174 | "@types/bn.js" "^4.11.6" 175 | bn.js "^5.1.2" 176 | camelcase "^5.3.1" 177 | chalk "^4.1.0" 178 | ip-regex "^4.1.0" 179 | 180 | "@polkadot/wasm-crypto@^1.2.1": 181 | version "1.2.1" 182 | resolved "https://registry.yarnpkg.com/@polkadot/wasm-crypto/-/wasm-crypto-1.2.1.tgz#2189702447acd28d763886359576c87562241767" 183 | integrity sha512-nckIoZBV4nBZdeKwFwH5t7skS7L7GO5EFUl5B1F6uCjUfdNpDz3DtqbYQHcLdCZNmG4TDLg6w/1J+rkl2SiUZw== 184 | 185 | "@types/bn.js@^4.11.6": 186 | version "4.11.6" 187 | resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" 188 | integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== 189 | dependencies: 190 | "@types/node" "*" 191 | 192 | "@types/color-name@^1.1.1": 193 | version "1.1.1" 194 | resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" 195 | integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== 196 | 197 | "@types/lodash@^4.14.149": 198 | version "4.14.149" 199 | resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" 200 | integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== 201 | 202 | "@types/node-fetch@^2.5.5": 203 | version "2.5.5" 204 | resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.5.tgz#cd264e20a81f4600a6c52864d38e7fef72485e92" 205 | integrity sha512-IWwjsyYjGw+em3xTvWVQi5MgYKbRs0du57klfTaZkv/B24AEQ/p/IopNeqIYNy3EsfHOpg8ieQSDomPcsYMHpA== 206 | dependencies: 207 | "@types/node" "*" 208 | form-data "^3.0.0" 209 | 210 | "@types/node@*": 211 | version "13.9.1" 212 | resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.1.tgz#96f606f8cd67fb018847d9b61e93997dabdefc72" 213 | integrity sha512-E6M6N0blf/jiZx8Q3nb0vNaswQeEyn0XlupO+xN6DtJ6r6IT4nXrTry7zhIfYvFCl3/8Cu6WIysmUBKiqV0bqQ== 214 | 215 | "@types/node@11.11.6": 216 | version "11.11.6" 217 | resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" 218 | integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== 219 | 220 | "@types/node@^10.12.21": 221 | version "10.17.18" 222 | resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.18.tgz#ae364d97382aacdebf583fa4e7132af2dfe56a0c" 223 | integrity sha512-DQ2hl/Jl3g33KuAUOcMrcAOtsbzb+y/ufakzAdeK9z/H/xsvkpbETZZbPNMIiQuk24f5ZRMCcZIViAwyFIiKmg== 224 | 225 | "@types/vscode@^1.42.0": 226 | version "1.43.0" 227 | resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.43.0.tgz#22276e60034c693b33117f1068ffaac0e89522db" 228 | integrity sha512-kIaR9qzd80rJOxePKpCB/mdy00mz8Apt2QA5Y6rdrKFn13QNFNeP3Hzmsf37Bwh/3cS7QjtAeGSK7wSqAU0sYQ== 229 | 230 | ansi-styles@^3.2.1: 231 | version "3.2.1" 232 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 233 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 234 | dependencies: 235 | color-convert "^1.9.0" 236 | 237 | ansi-styles@^4.1.0: 238 | version "4.2.1" 239 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" 240 | integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== 241 | dependencies: 242 | "@types/color-name" "^1.1.1" 243 | color-convert "^2.0.1" 244 | 245 | arch@^2.1.1: 246 | version "2.1.2" 247 | resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.2.tgz#0c52bbe7344bb4fa260c443d2cbad9c00ff2f0bf" 248 | integrity sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ== 249 | 250 | argparse@^1.0.7: 251 | version "1.0.10" 252 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 253 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 254 | dependencies: 255 | sprintf-js "~1.0.2" 256 | 257 | array-flat-polyfill@^1.0.1: 258 | version "1.0.1" 259 | resolved "https://registry.yarnpkg.com/array-flat-polyfill/-/array-flat-polyfill-1.0.1.tgz#1e3a4255be619dfbffbfd1d635c1cf357cd034e7" 260 | integrity sha512-hfJmKupmQN0lwi0xG6FQ5U8Rd97RnIERplymOv/qpq8AoNKPPAnxJadjFA23FNWm88wykh9HmpLJUUwUtNU/iw== 261 | 262 | asynckit@^0.4.0: 263 | version "0.4.0" 264 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 265 | integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= 266 | 267 | balanced-match@^1.0.0: 268 | version "1.0.0" 269 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 270 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 271 | 272 | base-x@^3.0.8: 273 | version "3.0.8" 274 | resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d" 275 | integrity sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA== 276 | dependencies: 277 | safe-buffer "^5.0.1" 278 | 279 | bip39@^3.0.2: 280 | version "3.0.2" 281 | resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.2.tgz#2baf42ff3071fc9ddd5103de92e8f80d9257ee32" 282 | integrity sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ== 283 | dependencies: 284 | "@types/node" "11.11.6" 285 | create-hash "^1.1.0" 286 | pbkdf2 "^3.0.9" 287 | randombytes "^2.0.1" 288 | 289 | blakejs@^1.1.0: 290 | version "1.1.0" 291 | resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" 292 | integrity sha1-ad+S75U6qIylGjLfarHFShVfx6U= 293 | 294 | bn.js@^4.4.0: 295 | version "4.11.9" 296 | resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" 297 | integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== 298 | 299 | bn.js@^5.1.2: 300 | version "5.1.2" 301 | resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0" 302 | integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA== 303 | 304 | brace-expansion@^1.1.7: 305 | version "1.1.11" 306 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 307 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 308 | dependencies: 309 | balanced-match "^1.0.0" 310 | concat-map "0.0.1" 311 | 312 | brorand@^1.0.1: 313 | version "1.1.0" 314 | resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" 315 | integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= 316 | 317 | builtin-modules@^1.1.1: 318 | version "1.1.1" 319 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 320 | integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= 321 | 322 | camelcase@^5.3.1: 323 | version "5.3.1" 324 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 325 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 326 | 327 | chalk@^2.0.0, chalk@^2.3.0: 328 | version "2.4.2" 329 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 330 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 331 | dependencies: 332 | ansi-styles "^3.2.1" 333 | escape-string-regexp "^1.0.5" 334 | supports-color "^5.3.0" 335 | 336 | chalk@^4.1.0: 337 | version "4.1.0" 338 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" 339 | integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== 340 | dependencies: 341 | ansi-styles "^4.1.0" 342 | supports-color "^7.1.0" 343 | 344 | cipher-base@^1.0.1, cipher-base@^1.0.3: 345 | version "1.0.4" 346 | resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" 347 | integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== 348 | dependencies: 349 | inherits "^2.0.1" 350 | safe-buffer "^5.0.1" 351 | 352 | clipboardy@^2.3.0: 353 | version "2.3.0" 354 | resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-2.3.0.tgz#3c2903650c68e46a91b388985bc2774287dba290" 355 | integrity sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ== 356 | dependencies: 357 | arch "^2.1.1" 358 | execa "^1.0.0" 359 | is-wsl "^2.1.1" 360 | 361 | color-convert@^1.9.0: 362 | version "1.9.3" 363 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 364 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 365 | dependencies: 366 | color-name "1.1.3" 367 | 368 | color-convert@^2.0.1: 369 | version "2.0.1" 370 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 371 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 372 | dependencies: 373 | color-name "~1.1.4" 374 | 375 | color-name@1.1.3: 376 | version "1.1.3" 377 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 378 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 379 | 380 | color-name@~1.1.4: 381 | version "1.1.4" 382 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 383 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 384 | 385 | combined-stream@^1.0.8: 386 | version "1.0.8" 387 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 388 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 389 | dependencies: 390 | delayed-stream "~1.0.0" 391 | 392 | commander@^2.12.1: 393 | version "2.20.3" 394 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 395 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 396 | 397 | concat-map@0.0.1: 398 | version "0.0.1" 399 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 400 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 401 | 402 | create-hash@^1.1.0, create-hash@^1.1.2: 403 | version "1.2.0" 404 | resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" 405 | integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== 406 | dependencies: 407 | cipher-base "^1.0.1" 408 | inherits "^2.0.1" 409 | md5.js "^1.3.4" 410 | ripemd160 "^2.0.1" 411 | sha.js "^2.4.0" 412 | 413 | create-hmac@^1.1.4: 414 | version "1.1.7" 415 | resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" 416 | integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== 417 | dependencies: 418 | cipher-base "^1.0.3" 419 | create-hash "^1.1.0" 420 | inherits "^2.0.1" 421 | ripemd160 "^2.0.0" 422 | safe-buffer "^5.0.1" 423 | sha.js "^2.4.8" 424 | 425 | cross-spawn@^6.0.0: 426 | version "6.0.5" 427 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" 428 | integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== 429 | dependencies: 430 | nice-try "^1.0.4" 431 | path-key "^2.0.1" 432 | semver "^5.5.0" 433 | shebang-command "^1.2.0" 434 | which "^1.2.9" 435 | 436 | cuint@^0.2.2: 437 | version "0.2.2" 438 | resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" 439 | integrity sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs= 440 | 441 | d@1, d@^1.0.1: 442 | version "1.0.1" 443 | resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" 444 | integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== 445 | dependencies: 446 | es5-ext "^0.10.50" 447 | type "^1.0.1" 448 | 449 | debug@^2.2.0: 450 | version "2.6.9" 451 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 452 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 453 | dependencies: 454 | ms "2.0.0" 455 | 456 | define-properties@^1.1.2, define-properties@^1.1.3: 457 | version "1.1.3" 458 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 459 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== 460 | dependencies: 461 | object-keys "^1.0.12" 462 | 463 | delayed-stream@~1.0.0: 464 | version "1.0.0" 465 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 466 | integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= 467 | 468 | diff@^4.0.1: 469 | version "4.0.2" 470 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" 471 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 472 | 473 | elliptic@^6.5.3: 474 | version "6.5.3" 475 | resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" 476 | integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw== 477 | dependencies: 478 | bn.js "^4.4.0" 479 | brorand "^1.0.1" 480 | hash.js "^1.0.0" 481 | hmac-drbg "^1.0.0" 482 | inherits "^2.0.1" 483 | minimalistic-assert "^1.0.0" 484 | minimalistic-crypto-utils "^1.0.0" 485 | 486 | encoding@^0.1.11: 487 | version "0.1.12" 488 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" 489 | integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= 490 | dependencies: 491 | iconv-lite "~0.4.13" 492 | 493 | end-of-stream@^1.1.0: 494 | version "1.4.4" 495 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 496 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 497 | dependencies: 498 | once "^1.4.0" 499 | 500 | es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: 501 | version "1.17.5" 502 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" 503 | integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== 504 | dependencies: 505 | es-to-primitive "^1.2.1" 506 | function-bind "^1.1.1" 507 | has "^1.0.3" 508 | has-symbols "^1.0.1" 509 | is-callable "^1.1.5" 510 | is-regex "^1.0.5" 511 | object-inspect "^1.7.0" 512 | object-keys "^1.1.1" 513 | object.assign "^4.1.0" 514 | string.prototype.trimleft "^2.1.1" 515 | string.prototype.trimright "^2.1.1" 516 | 517 | es-to-primitive@^1.2.1: 518 | version "1.2.1" 519 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" 520 | integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== 521 | dependencies: 522 | is-callable "^1.1.4" 523 | is-date-object "^1.0.1" 524 | is-symbol "^1.0.2" 525 | 526 | es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: 527 | version "0.10.53" 528 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" 529 | integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== 530 | dependencies: 531 | es6-iterator "~2.0.3" 532 | es6-symbol "~3.1.3" 533 | next-tick "~1.0.0" 534 | 535 | es6-iterator@^2.0.3, es6-iterator@~2.0.3: 536 | version "2.0.3" 537 | resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" 538 | integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= 539 | dependencies: 540 | d "1" 541 | es5-ext "^0.10.35" 542 | es6-symbol "^3.1.1" 543 | 544 | es6-symbol@^3.1.1, es6-symbol@~3.1.3: 545 | version "3.1.3" 546 | resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" 547 | integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== 548 | dependencies: 549 | d "^1.0.1" 550 | ext "^1.1.2" 551 | 552 | es6-weak-map@^2.0.2: 553 | version "2.0.3" 554 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" 555 | integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== 556 | dependencies: 557 | d "1" 558 | es5-ext "^0.10.46" 559 | es6-iterator "^2.0.3" 560 | es6-symbol "^3.1.1" 561 | 562 | escape-string-regexp@^1.0.5: 563 | version "1.0.5" 564 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 565 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 566 | 567 | esprima@^4.0.0: 568 | version "4.0.1" 569 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 570 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 571 | 572 | esutils@^2.0.2: 573 | version "2.0.3" 574 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 575 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 576 | 577 | event-emitter@^0.3.5: 578 | version "0.3.5" 579 | resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" 580 | integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= 581 | dependencies: 582 | d "1" 583 | es5-ext "~0.10.14" 584 | 585 | eventemitter3@^4.0.4: 586 | version "4.0.4" 587 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" 588 | integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== 589 | 590 | execa@^1.0.0: 591 | version "1.0.0" 592 | resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" 593 | integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== 594 | dependencies: 595 | cross-spawn "^6.0.0" 596 | get-stream "^4.0.0" 597 | is-stream "^1.1.0" 598 | npm-run-path "^2.0.0" 599 | p-finally "^1.0.0" 600 | signal-exit "^3.0.0" 601 | strip-eof "^1.0.0" 602 | 603 | ext@^1.1.2: 604 | version "1.4.0" 605 | resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" 606 | integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== 607 | dependencies: 608 | type "^2.0.0" 609 | 610 | form-data@^3.0.0: 611 | version "3.0.0" 612 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" 613 | integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== 614 | dependencies: 615 | asynckit "^0.4.0" 616 | combined-stream "^1.0.8" 617 | mime-types "^2.1.12" 618 | 619 | fs.realpath@^1.0.0: 620 | version "1.0.0" 621 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 622 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 623 | 624 | function-bind@^1.1.1: 625 | version "1.1.1" 626 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 627 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 628 | 629 | get-stream@^4.0.0: 630 | version "4.1.0" 631 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" 632 | integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== 633 | dependencies: 634 | pump "^3.0.0" 635 | 636 | glob@^7.1.1, glob@^7.1.6: 637 | version "7.1.6" 638 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 639 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 640 | dependencies: 641 | fs.realpath "^1.0.0" 642 | inflight "^1.0.4" 643 | inherits "2" 644 | minimatch "^3.0.4" 645 | once "^1.3.0" 646 | path-is-absolute "^1.0.0" 647 | 648 | has-flag@^3.0.0: 649 | version "3.0.0" 650 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 651 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 652 | 653 | has-flag@^4.0.0: 654 | version "4.0.0" 655 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 656 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 657 | 658 | has-symbols@^1.0.0, has-symbols@^1.0.1: 659 | version "1.0.1" 660 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" 661 | integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== 662 | 663 | has@^1.0.3: 664 | version "1.0.3" 665 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 666 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 667 | dependencies: 668 | function-bind "^1.1.1" 669 | 670 | hash-base@^3.0.0: 671 | version "3.1.0" 672 | resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" 673 | integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== 674 | dependencies: 675 | inherits "^2.0.4" 676 | readable-stream "^3.6.0" 677 | safe-buffer "^5.2.0" 678 | 679 | hash.js@^1.0.0, hash.js@^1.0.3: 680 | version "1.1.7" 681 | resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" 682 | integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== 683 | dependencies: 684 | inherits "^2.0.3" 685 | minimalistic-assert "^1.0.1" 686 | 687 | hmac-drbg@^1.0.0: 688 | version "1.0.1" 689 | resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" 690 | integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= 691 | dependencies: 692 | hash.js "^1.0.3" 693 | minimalistic-assert "^1.0.0" 694 | minimalistic-crypto-utils "^1.0.1" 695 | 696 | iconv-lite@~0.4.13: 697 | version "0.4.24" 698 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 699 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 700 | dependencies: 701 | safer-buffer ">= 2.1.2 < 3" 702 | 703 | inflight@^1.0.4: 704 | version "1.0.6" 705 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 706 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 707 | dependencies: 708 | once "^1.3.0" 709 | wrappy "1" 710 | 711 | inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: 712 | version "2.0.4" 713 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 714 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 715 | 716 | internal-slot@^1.0.2: 717 | version "1.0.2" 718 | resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.2.tgz#9c2e9fb3cd8e5e4256c6f45fe310067fcfa378a3" 719 | integrity sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g== 720 | dependencies: 721 | es-abstract "^1.17.0-next.1" 722 | has "^1.0.3" 723 | side-channel "^1.0.2" 724 | 725 | ip-regex@^4.1.0: 726 | version "4.1.0" 727 | resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.1.0.tgz#5ad62f685a14edb421abebc2fff8db94df67b455" 728 | integrity sha512-pKnZpbgCTfH/1NLIlOduP/V+WRXzC2MOz3Qo8xmxk8C5GudJLgK5QyLVXOSWy3ParAH7Eemurl3xjv/WXYFvMA== 729 | 730 | is-callable@^1.1.4, is-callable@^1.1.5: 731 | version "1.1.5" 732 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" 733 | integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== 734 | 735 | is-date-object@^1.0.1: 736 | version "1.0.2" 737 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" 738 | integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== 739 | 740 | is-docker@^2.0.0: 741 | version "2.0.0" 742 | resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b" 743 | integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ== 744 | 745 | is-promise@^2.1: 746 | version "2.2.2" 747 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" 748 | integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== 749 | 750 | is-regex@^1.0.5: 751 | version "1.0.5" 752 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" 753 | integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== 754 | dependencies: 755 | has "^1.0.3" 756 | 757 | is-stream@^1.0.1, is-stream@^1.1.0: 758 | version "1.1.0" 759 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 760 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= 761 | 762 | is-symbol@^1.0.2: 763 | version "1.0.3" 764 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" 765 | integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== 766 | dependencies: 767 | has-symbols "^1.0.1" 768 | 769 | is-typedarray@^1.0.0: 770 | version "1.0.0" 771 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 772 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= 773 | 774 | is-wsl@^2.1.1: 775 | version "2.2.0" 776 | resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" 777 | integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== 778 | dependencies: 779 | is-docker "^2.0.0" 780 | 781 | isexe@^2.0.0: 782 | version "2.0.0" 783 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 784 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 785 | 786 | isomorphic-fetch@^2.2.1: 787 | version "2.2.1" 788 | resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" 789 | integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= 790 | dependencies: 791 | node-fetch "^1.0.1" 792 | whatwg-fetch ">=0.10.0" 793 | 794 | js-sha3@^0.8.0: 795 | version "0.8.0" 796 | resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" 797 | integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== 798 | 799 | js-tokens@^4.0.0: 800 | version "4.0.0" 801 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 802 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 803 | 804 | js-yaml@^3.13.1: 805 | version "3.13.1" 806 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 807 | integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== 808 | dependencies: 809 | argparse "^1.0.7" 810 | esprima "^4.0.0" 811 | 812 | lodash@^4.17.19: 813 | version "4.17.19" 814 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" 815 | integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== 816 | 817 | lru-queue@0.1: 818 | version "0.1.0" 819 | resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" 820 | integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM= 821 | dependencies: 822 | es5-ext "~0.10.2" 823 | 824 | md5.js@^1.3.4: 825 | version "1.3.5" 826 | resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" 827 | integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== 828 | dependencies: 829 | hash-base "^3.0.0" 830 | inherits "^2.0.1" 831 | safe-buffer "^5.1.2" 832 | 833 | memoizee@^0.4.14: 834 | version "0.4.14" 835 | resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.14.tgz#07a00f204699f9a95c2d9e77218271c7cd610d57" 836 | integrity sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg== 837 | dependencies: 838 | d "1" 839 | es5-ext "^0.10.45" 840 | es6-weak-map "^2.0.2" 841 | event-emitter "^0.3.5" 842 | is-promise "^2.1" 843 | lru-queue "0.1" 844 | next-tick "1" 845 | timers-ext "^0.1.5" 846 | 847 | mime-db@1.43.0: 848 | version "1.43.0" 849 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" 850 | integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== 851 | 852 | mime-types@^2.1.12: 853 | version "2.1.26" 854 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" 855 | integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== 856 | dependencies: 857 | mime-db "1.43.0" 858 | 859 | minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: 860 | version "1.0.1" 861 | resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" 862 | integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== 863 | 864 | minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: 865 | version "1.0.1" 866 | resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" 867 | integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= 868 | 869 | minimatch@^3.0.4: 870 | version "3.0.4" 871 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 872 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 873 | dependencies: 874 | brace-expansion "^1.1.7" 875 | 876 | minimist@0.0.8: 877 | version "0.0.8" 878 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 879 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 880 | 881 | mkdirp@^0.5.1: 882 | version "0.5.1" 883 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 884 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 885 | dependencies: 886 | minimist "0.0.8" 887 | 888 | ms@2.0.0: 889 | version "2.0.0" 890 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 891 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 892 | 893 | nan@^2.14.0: 894 | version "2.14.1" 895 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" 896 | integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== 897 | 898 | next-tick@1: 899 | version "1.1.0" 900 | resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" 901 | integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== 902 | 903 | next-tick@~1.0.0: 904 | version "1.0.0" 905 | resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" 906 | integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= 907 | 908 | nice-try@^1.0.4: 909 | version "1.0.5" 910 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" 911 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== 912 | 913 | node-fetch@^1.0.1: 914 | version "1.7.3" 915 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" 916 | integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== 917 | dependencies: 918 | encoding "^0.1.11" 919 | is-stream "^1.0.1" 920 | 921 | node-fetch@^2.6.1: 922 | version "2.6.1" 923 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" 924 | integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== 925 | 926 | npm-run-path@^2.0.0: 927 | version "2.0.2" 928 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" 929 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= 930 | dependencies: 931 | path-key "^2.0.0" 932 | 933 | object-inspect@^1.7.0: 934 | version "1.7.0" 935 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" 936 | integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== 937 | 938 | object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: 939 | version "1.1.1" 940 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 941 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 942 | 943 | object.assign@^4.1.0: 944 | version "4.1.0" 945 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" 946 | integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== 947 | dependencies: 948 | define-properties "^1.1.2" 949 | function-bind "^1.1.1" 950 | has-symbols "^1.0.0" 951 | object-keys "^1.0.11" 952 | 953 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 954 | version "1.4.0" 955 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 956 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 957 | dependencies: 958 | wrappy "1" 959 | 960 | p-finally@^1.0.0: 961 | version "1.0.0" 962 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" 963 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= 964 | 965 | path-is-absolute@^1.0.0: 966 | version "1.0.1" 967 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 968 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 969 | 970 | path-key@^2.0.0, path-key@^2.0.1: 971 | version "2.0.1" 972 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" 973 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= 974 | 975 | path-parse@^1.0.6: 976 | version "1.0.6" 977 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 978 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== 979 | 980 | pbkdf2@^3.0.9, pbkdf2@^3.1.1: 981 | version "3.1.1" 982 | resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" 983 | integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg== 984 | dependencies: 985 | create-hash "^1.1.2" 986 | create-hmac "^1.1.4" 987 | ripemd160 "^2.0.1" 988 | safe-buffer "^5.0.1" 989 | sha.js "^2.4.8" 990 | 991 | pump@^3.0.0: 992 | version "3.0.0" 993 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 994 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 995 | dependencies: 996 | end-of-stream "^1.1.0" 997 | once "^1.3.1" 998 | 999 | randombytes@^2.0.1: 1000 | version "2.1.0" 1001 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" 1002 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 1003 | dependencies: 1004 | safe-buffer "^5.1.0" 1005 | 1006 | readable-stream@^3.6.0: 1007 | version "3.6.0" 1008 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" 1009 | integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== 1010 | dependencies: 1011 | inherits "^2.0.3" 1012 | string_decoder "^1.1.1" 1013 | util-deprecate "^1.0.1" 1014 | 1015 | regenerator-runtime@^0.13.4: 1016 | version "0.13.5" 1017 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" 1018 | integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== 1019 | 1020 | regexp.prototype.flags@^1.3.0: 1021 | version "1.3.0" 1022 | resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" 1023 | integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== 1024 | dependencies: 1025 | define-properties "^1.1.3" 1026 | es-abstract "^1.17.0-next.1" 1027 | 1028 | resolve@^1.3.2: 1029 | version "1.15.1" 1030 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" 1031 | integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== 1032 | dependencies: 1033 | path-parse "^1.0.6" 1034 | 1035 | ripemd160@^2.0.0, ripemd160@^2.0.1: 1036 | version "2.0.2" 1037 | resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" 1038 | integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== 1039 | dependencies: 1040 | hash-base "^3.0.0" 1041 | inherits "^2.0.1" 1042 | 1043 | rxjs@^6.5.5: 1044 | version "6.5.5" 1045 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec" 1046 | integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ== 1047 | dependencies: 1048 | tslib "^1.9.0" 1049 | 1050 | rxjs@^6.6.2: 1051 | version "6.6.2" 1052 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2" 1053 | integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg== 1054 | dependencies: 1055 | tslib "^1.9.0" 1056 | 1057 | safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: 1058 | version "5.2.1" 1059 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 1060 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1061 | 1062 | "safer-buffer@>= 2.1.2 < 3": 1063 | version "2.1.2" 1064 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 1065 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 1066 | 1067 | scryptsy@^2.1.0: 1068 | version "2.1.0" 1069 | resolved "https://registry.yarnpkg.com/scryptsy/-/scryptsy-2.1.0.tgz#8d1e8d0c025b58fdd25b6fa9a0dc905ee8faa790" 1070 | integrity sha512-1CdSqHQowJBnMAFyPEBRfqag/YP9OF394FV+4YREIJX4ljD7OxvQRDayyoyyCk+senRjSkP6VnUNQmVQqB6g7w== 1071 | 1072 | semver@^5.3.0, semver@^5.5.0: 1073 | version "5.7.1" 1074 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1075 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1076 | 1077 | sha.js@^2.4.0, sha.js@^2.4.8: 1078 | version "2.4.11" 1079 | resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" 1080 | integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== 1081 | dependencies: 1082 | inherits "^2.0.1" 1083 | safe-buffer "^5.0.1" 1084 | 1085 | shebang-command@^1.2.0: 1086 | version "1.2.0" 1087 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 1088 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= 1089 | dependencies: 1090 | shebang-regex "^1.0.0" 1091 | 1092 | shebang-regex@^1.0.0: 1093 | version "1.0.0" 1094 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 1095 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= 1096 | 1097 | side-channel@^1.0.2: 1098 | version "1.0.2" 1099 | resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.2.tgz#df5d1abadb4e4bf4af1cd8852bf132d2f7876947" 1100 | integrity sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA== 1101 | dependencies: 1102 | es-abstract "^1.17.0-next.1" 1103 | object-inspect "^1.7.0" 1104 | 1105 | signal-exit@^3.0.0: 1106 | version "3.0.3" 1107 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" 1108 | integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== 1109 | 1110 | sprintf-js@~1.0.2: 1111 | version "1.0.3" 1112 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1113 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 1114 | 1115 | string.prototype.matchall@^4.0.2: 1116 | version "4.0.2" 1117 | resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz#48bb510326fb9fdeb6a33ceaa81a6ea04ef7648e" 1118 | integrity sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg== 1119 | dependencies: 1120 | define-properties "^1.1.3" 1121 | es-abstract "^1.17.0" 1122 | has-symbols "^1.0.1" 1123 | internal-slot "^1.0.2" 1124 | regexp.prototype.flags "^1.3.0" 1125 | side-channel "^1.0.2" 1126 | 1127 | string.prototype.trimend@^1.0.0: 1128 | version "1.0.1" 1129 | resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" 1130 | integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== 1131 | dependencies: 1132 | define-properties "^1.1.3" 1133 | es-abstract "^1.17.5" 1134 | 1135 | string.prototype.trimleft@^2.1.1: 1136 | version "2.1.2" 1137 | resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" 1138 | integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== 1139 | dependencies: 1140 | define-properties "^1.1.3" 1141 | es-abstract "^1.17.5" 1142 | string.prototype.trimstart "^1.0.0" 1143 | 1144 | string.prototype.trimright@^2.1.1: 1145 | version "2.1.2" 1146 | resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" 1147 | integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== 1148 | dependencies: 1149 | define-properties "^1.1.3" 1150 | es-abstract "^1.17.5" 1151 | string.prototype.trimend "^1.0.0" 1152 | 1153 | string.prototype.trimstart@^1.0.0: 1154 | version "1.0.1" 1155 | resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" 1156 | integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== 1157 | dependencies: 1158 | define-properties "^1.1.3" 1159 | es-abstract "^1.17.5" 1160 | 1161 | string_decoder@^1.1.1: 1162 | version "1.3.0" 1163 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" 1164 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== 1165 | dependencies: 1166 | safe-buffer "~5.2.0" 1167 | 1168 | strip-eof@^1.0.0: 1169 | version "1.0.0" 1170 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" 1171 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= 1172 | 1173 | supports-color@^5.3.0: 1174 | version "5.5.0" 1175 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1176 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1177 | dependencies: 1178 | has-flag "^3.0.0" 1179 | 1180 | supports-color@^7.1.0: 1181 | version "7.1.0" 1182 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" 1183 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== 1184 | dependencies: 1185 | has-flag "^4.0.0" 1186 | 1187 | timers-ext@^0.1.5: 1188 | version "0.1.7" 1189 | resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" 1190 | integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== 1191 | dependencies: 1192 | es5-ext "~0.10.46" 1193 | next-tick "1" 1194 | 1195 | tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: 1196 | version "1.11.1" 1197 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" 1198 | integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== 1199 | 1200 | tslint@^5.12.1: 1201 | version "5.20.1" 1202 | resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d" 1203 | integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg== 1204 | dependencies: 1205 | "@babel/code-frame" "^7.0.0" 1206 | builtin-modules "^1.1.1" 1207 | chalk "^2.3.0" 1208 | commander "^2.12.1" 1209 | diff "^4.0.1" 1210 | glob "^7.1.1" 1211 | js-yaml "^3.13.1" 1212 | minimatch "^3.0.4" 1213 | mkdirp "^0.5.1" 1214 | resolve "^1.3.2" 1215 | semver "^5.3.0" 1216 | tslib "^1.8.0" 1217 | tsutils "^2.29.0" 1218 | 1219 | tsutils@^2.29.0: 1220 | version "2.29.0" 1221 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" 1222 | integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== 1223 | dependencies: 1224 | tslib "^1.8.1" 1225 | 1226 | tweetnacl@^1.0.3: 1227 | version "1.0.3" 1228 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" 1229 | integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== 1230 | 1231 | type@^1.0.1: 1232 | version "1.2.0" 1233 | resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" 1234 | integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== 1235 | 1236 | type@^2.0.0: 1237 | version "2.0.0" 1238 | resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3" 1239 | integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow== 1240 | 1241 | typedarray-to-buffer@^3.1.5: 1242 | version "3.1.5" 1243 | resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" 1244 | integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== 1245 | dependencies: 1246 | is-typedarray "^1.0.0" 1247 | 1248 | typescript@^3.5.1: 1249 | version "3.8.3" 1250 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" 1251 | integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== 1252 | 1253 | util-deprecate@^1.0.1: 1254 | version "1.0.2" 1255 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1256 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1257 | 1258 | websocket@^1.0.31: 1259 | version "1.0.31" 1260 | resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.31.tgz#e5d0f16c3340ed87670e489ecae6144c79358730" 1261 | integrity sha512-VAouplvGKPiKFDTeCCO65vYHsyay8DqoBSlzIO3fayrfOgU94lQN5a1uWVnFrMLceTJw/+fQXR5PGbUVRaHshQ== 1262 | dependencies: 1263 | debug "^2.2.0" 1264 | es5-ext "^0.10.50" 1265 | nan "^2.14.0" 1266 | typedarray-to-buffer "^3.1.5" 1267 | yaeti "^0.0.6" 1268 | 1269 | whatwg-fetch@>=0.10.0: 1270 | version "3.1.0" 1271 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.1.0.tgz#49d630cdfa308dba7f2819d49d09364f540dbcc6" 1272 | integrity sha512-pgmbsVWKpH9GxLXZmtdowDIqtb/rvPyjjQv3z9wLcmgWKFHilKnZD3ldgrOlwJoPGOUluQsRPWd52yVkPfmI1A== 1273 | 1274 | which@^1.2.9: 1275 | version "1.3.1" 1276 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 1277 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 1278 | dependencies: 1279 | isexe "^2.0.0" 1280 | 1281 | wrappy@1: 1282 | version "1.0.2" 1283 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1284 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1285 | 1286 | xxhashjs@^0.2.2: 1287 | version "0.2.2" 1288 | resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8" 1289 | integrity sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw== 1290 | dependencies: 1291 | cuint "^0.2.2" 1292 | 1293 | yaeti@^0.0.6: 1294 | version "0.0.6" 1295 | resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" 1296 | integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= 1297 | --------------------------------------------------------------------------------