diff --git a/apps/remix-ide/src/app/editor/editor.js b/apps/remix-ide/src/app/editor/editor.js index e2db22943d..e0df3b7d0b 100644 --- a/apps/remix-ide/src/app/editor/editor.js +++ b/apps/remix-ide/src/app/editor/editor.js @@ -145,54 +145,6 @@ class Editor extends Plugin { this.currentThemeType = theme.quality this.renderComponent() }) - this.on('fileManager', 'currentFileChanged', async (name) => { - if (name.endsWith('.ts')) { - // extract the import, resolve their content - // and add the imported files to Monaco through the `addModel` - // so Monaco can provide auto completion - let content = await this.call('fileManager', 'readFile', name) - const paths = name.split('/') - paths.pop() - const fromPath = paths.join('/') // get current execution context path - for (const match of content.matchAll(/import\s+.*\s+from\s+(?:"(.*?)"|'(.*?)')/g)) { - let path = match[2] - if (path.startsWith('./') || path.startsWith('../')) path = resolve(fromPath, path) - if (path.startsWith('/')) path = path.substring(1) - if (!path.endsWith('.ts')) path = path + '.ts' - if (await this.call('fileManager', 'exists', path)) { - content = await this.call('fileManager', 'readFile', path) - this.emit('addModel', content, 'typescript', path, false) - } - } - } - }) - - this.on('fileManager', 'noFileSelected', async () => { - this.currentFile = null - this.renderComponent() - }) - this.on('fileManager', 'currentFileChanged', async (name) => { - if (name.endsWith('.ts')) { - // extract the import, resolve their content - // and add the imported files to Monaco through the `addModel` - // so Monaco can provide auto completion - let content = await this.call('fileManager', 'readFile', name) - const paths = name.split('/') - paths.pop() - const fromPath = paths.join('/') // get current execution context path - for (const match of content.matchAll(/import\s+.*\s+from\s+(?:"(.*?)"|'(.*?)')/g)) { - let path = match[2] - if (path.startsWith('./') || path.startsWith('../')) path = resolve(fromPath, path) - if (path.startsWith('/')) path = path.substring(1) - if (!path.endsWith('.ts')) path = path + '.ts' - if (await this.call('fileManager', 'exists', path)) { - content = await this.call('fileManager', 'readFile', path) - this.emit('addModel', content, 'typescript', path, false) - } - } - } - }) - this.on('fileManager', 'noFileSelected', async () => { this.currentFile = null this.renderComponent() @@ -267,8 +219,33 @@ class Editor extends Plugin { * @param {string} content Content of the file to open * @param {string} mode Mode for this file [Default is `text`] */ - _createSession (path, content, mode) { + async _createSession (path, content, mode) { if (!this.activated) return + + if (path.endsWith('.ts')) { + try { + // extract the import, resolve their content + // and add the imported files to Monaco through the `addModel` + // so Monaco can provide auto completion + let content = await this.call('fileManager', 'readFile', path) + const paths = path.split('/') + paths.pop() + const fromPath = paths.join('/') // get current execution context path + for (const match of content.matchAll(/import\s+.*\s+from\s+(?:"(.*?)"|'(.*?)')/g)) { + let path = match[2] + if (path.startsWith('./') || path.startsWith('../')) path = resolve(fromPath, path) + if (path.startsWith('/')) path = path.substring(1) + if (!path.endsWith('.ts')) path = path + '.ts' + if (await this.call('fileManager', 'exists', path)) { + content = await this.call('fileManager', 'readFile', path) + this.emit('addModel', content, 'typescript', path, false) + } + } + } catch (e) { + console.log('unable to resolve dependency of', path, e) + } + } + this.emit('addModel', content, mode, path, false) return { path, @@ -321,7 +298,7 @@ class Editor extends Plugin { * @param {string} path Path of the session to open. * @param {string} content Content of the document or update. */ - open (path, content) { + async open (path, content) { /* we have the following cases: - URL prepended with "localhost" @@ -329,7 +306,7 @@ class Editor extends Plugin { - URL not prepended with the file explorer. We assume (as it is in the whole app, that this is a "browser" URL */ if (!this.sessions[path]) { - const session = this._createSession(path, content, this._getMode(path)) + const session = await this._createSession(path, content, this._getMode(path)) this.sessions[path] = session this.readOnlySessions[path] = false } else if (this.sessions[path].getValue() !== content) { @@ -343,9 +320,9 @@ class Editor extends Plugin { * @param {string} path Path of the session to open. * @param {string} content Content of the document or update. */ - openReadOnly (path, content) { + async openReadOnly (path, content) { if (!this.sessions[path]) { - const session = this._createSession(path, content, this._getMode(path)) + const session = await this._createSession(path, content, this._getMode(path)) this.sessions[path] = session this.readOnlySessions[path] = true } diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts index f2da619a05..8070762119 100644 --- a/apps/remix-ide/src/app/files/fileManager.ts +++ b/apps/remix-ide/src/app/files/fileManager.ts @@ -633,9 +633,9 @@ class FileManager extends Plugin { throw error } if (provider.isReadOnly(file)) { - this.editor.openReadOnly(file, content) + await this.editor.openReadOnly(file, content) } else { - this.editor.open(file, content) + await this.editor.open(file, content) } // TODO: Only keep `this.emit` (issue#2210) this.emit('currentFileChanged', file) diff --git a/libs/remix-ui/editor/src/lib/hardhat-ethers-extension.ts b/libs/remix-ui/editor/src/lib/hardhat-ethers-extension.ts new file mode 100644 index 0000000000..13cfaf0066 --- /dev/null +++ b/libs/remix-ui/editor/src/lib/hardhat-ethers-extension.ts @@ -0,0 +1,34 @@ +export const hardhatEthersExtension = +` +interface Libraries { + [libraryName: string]: string; +} + +interface FactoryOptions { + signer?: Signer; + libraries?: Libraries; +} + +export declare function getContractFactory(name: string, signer?: Signer): Promise; + +export declare function getContractFactory(name: string, factoryOptions: FactoryOptions): Promise; + +export declare function getContractFactory(abi: any[], bytecode: utils.BytesLike, signer?: Signer): Promise; + +export declare function getContractAt(name: string, address: string, signer?: Signer): Promise; + +export declare function getContractAt(abi: any[], address: string, signer?: Signer): Promise; + +export declare function getSigners() => Promise; + +export declare function getSigner(address: string) => Promise; + +export declare function getImpersonatedSigner(address: string) => Promise; + +export declare function getContractFactoryFromArtifact(artifact: Artifact, signer?: Signer): Promise; + +export declare function getContractFactoryFromArtifact(artifact: Artifact, factoryOptions: FactoryOptions): Promise; + +export declare function getContractAtFromArtifact(artifact: Artifact, address: string, signer?: Signer): Promise; +` + diff --git a/libs/remix-ui/editor/src/lib/web-types.ts b/libs/remix-ui/editor/src/lib/web-types.ts index c4fe61933c..757c183330 100644 --- a/libs/remix-ui/editor/src/lib/web-types.ts +++ b/libs/remix-ui/editor/src/lib/web-types.ts @@ -1,4 +1,5 @@ import { remixTypes } from './remix-plugin-types' +import { hardhatEthersExtension } from './hardhat-ethers-extension' export const loadTypes = async (monaco) => { // ethers.js @@ -169,6 +170,7 @@ export const loadTypes = async (monaco) => { ethers.default = ethers.default.replace(/.\/_version/g, '_version-ethers-lib') ethers.default = ethers.default.replace(/.\/ethers/g, 'ethers-lib') ethers.default = ethers.default.replace(/@ethersproject\//g, '@ethersproject_') + ethers.default = ethers.default + '\n' + hardhatEthersExtension monaco.languages.typescript.typescriptDefaults.addExtraLib(ethers.default, `file:///node_modules/@types/ethers-lib/index.d.ts`) // @ts-ignore @@ -222,4 +224,12 @@ export const loadTypes = async (monaco) => { } ` monaco.languages.typescript.typescriptDefaults.addExtraLib(indexRemixApi) + + // @ts-ignore + const chaiType = await import('raw-loader!@types/chai/index.d.ts') + monaco.languages.typescript.typescriptDefaults.addExtraLib(chaiType.default) + + // @ts-ignore + const mochaType = await import('raw-loader!@types/mocha/index.d.ts') + monaco.languages.typescript.typescriptDefaults.addExtraLib(mochaType.default) } \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index 81ff776435..2d2ce7dd28 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -383,4 +383,4 @@ export function Workspace () { ) } -export default Workspace \ No newline at end of file +export default Workspace diff --git a/package.json b/package.json index eb5b0bbe94..75570a8e3c 100644 --- a/package.json +++ b/package.json @@ -242,12 +242,12 @@ "@nrwl/workspace": "12.3.6", "@testing-library/react": "10.4.1", "@types/axios": "^0.14.0", - "@types/chai": "^4.2.11", + "@types/chai": "^4.3.3", "@types/fs-extra": "^9.0.1", "@types/isomorphic-git__lightning-fs": "^4.4.2", "@types/jest": "^27.0.2", "@types/lodash": "^4.14.172", - "@types/mocha": "^7.0.2", + "@types/mocha": "^9.1.1", "@types/node": "~8.9.4", "@types/react": "^17.0.24", "@types/react-beautiful-dnd": "^13.1.2", diff --git a/yarn.lock b/yarn.lock index 126971157e..e36042dda0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4331,10 +4331,10 @@ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.1.tgz#e2c6e73e0bdeb2521d00756d099218e9f5d90a04" integrity sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ== -"@types/chai@^4.2.11": - version "4.2.22" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.22.tgz#47020d7e4cf19194d43b5202f35f75bd2ad35ce7" - integrity sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ== +"@types/chai@^4.3.3": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.3.tgz#3c90752792660c4b562ad73b3fbd68bf3bc7ae07" + integrity sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g== "@types/estree@*", "@types/estree@0.0.39": version "0.0.39" @@ -4481,10 +4481,10 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== -"@types/mocha@^7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.2.tgz#b17f16cf933597e10d6d78eae3251e692ce8b0ce" - integrity sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w== +"@types/mocha@^9.1.1": + version "9.1.1" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" + integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== "@types/nightwatch@^2.3.1": version "2.3.1"