load npm module from unpkg

pull/860/head
yann300 4 years ago
parent c967ba9703
commit 6e3d50e16a
  1. 13
      apps/remix-ide-e2e/src/tests/solidityImport.test.ts
  2. 64
      apps/remix-ide/src/app/compiler/compiler-imports.js
  3. 20
      libs/remix-url-resolver/src/resolve.ts

@ -79,6 +79,16 @@ module.exports = {
browser.assert.ok(content.indexOf('contract ERC20 is Context, IERC20') !== -1, browser.assert.ok(content.indexOf('contract ERC20 is Context, IERC20') !== -1,
'current displayed content should be from the ERC20 source code') 'current displayed content should be from the ERC20 source code')
}) })
},
'Test NPM Import (with unpkg.com)': function (browser: NightwatchBrowser) {
browser
// .setSolidityCompilerVersion('soljson-v0.8.0+commit.c7dfd78e.js')
.clickLaunchIcon('fileExplorers')
.click('li[data-id="treeViewLitreeViewItembrowser/README.txt"')
.addFile('Untitled9.sol', sources[8]['browser/Untitled9.sol'])
.clickLaunchIcon('fileExplorers')
.verifyContracts(['test13', 'ERC20', 'SafeMath'], { wait: 30000 })
.end() .end()
}, },
tearDown: sauce tearDown: sauce
@ -109,5 +119,8 @@ const sources = [
}, },
{ {
'browser/Untitled8.sol': { content: 'import "https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/master/contracts/token/ERC20/ERC20.sol"; contract test12 {}' } 'browser/Untitled8.sol': { content: 'import "https://raw.githubusercontent.com/OpenZeppelin/openzeppelin-contracts/master/contracts/token/ERC20/ERC20.sol"; contract test12 {}' }
},
{
'browser/Untitled9.sol': { content: 'pragma solidity >=0.6.0 <0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract test13 {}' }
} }
] ]

@ -6,7 +6,6 @@ const remixTests = require('@remix-project/remix-tests')
const globalRegistry = require('../../global/registry') const globalRegistry = require('../../global/registry')
const addTooltip = require('../ui/tooltip') const addTooltip = require('../ui/tooltip')
const async = require('async') const async = require('async')
var resolver = require('@resolver-engine/imports').ImportsEngine()
const profile = { const profile = {
name: 'contentImport', name: 'contentImport',
@ -50,7 +49,7 @@ module.exports = class CompilerImports extends Plugin {
}) })
} }
import (url, force, loadingCb, cb) { async import (url, force, loadingCb, cb) {
if (typeof force !== 'boolean') { if (typeof force !== 'boolean') {
const temp = loadingCb const temp = loadingCb
loadingCb = force loadingCb = force
@ -66,44 +65,20 @@ module.exports = class CompilerImports extends Plugin {
if (imported) { if (imported) {
return cb(null, imported.content, imported.cleanUrl, imported.type, url) return cb(null, imported.content, imported.cleanUrl, imported.type, url)
} }
var handlers = this.urlResolver.getHandlers()
var found = false
handlers.forEach(function (handler) {
if (found) return
var match = handler.match(url)
if (match) {
found = true
loadingCb('Loading ' + url + ' ...')
handler.handle(match).then(function (result) {
const { content, cleanUrl } = result
self.previouslyHandled[url] = {
content,
cleanUrl,
type: handler.type
}
cb(null, content, cleanUrl, handler.type, url)
}).catch(function (error) {
cb('Unable to import url : ' + error)
})
}
})
if (found) return
resolver let resolved
.resolve(url) try {
.then(result => { resolved = await this.urlResolver.resolve(url)
return resolver.require(url) const { content, cleanUrl, type } = resolved
}) self.previouslyHandled[url] = {
.then(result => { content,
if (url.indexOf(result.provider + ':') === 0) { cleanUrl,
url = url.substring(result.provider.length + 1) // remove the github prefix type
} }
cb(null, result.source, url, result.provider, result.url) cb(null, content, cleanUrl, type, url)
}) } catch (e) {
.catch(err => { return cb('Unable to import url : ' + e.message)
console.error(err) }
cb('Unable to import "' + url + '": File not found')
})
} }
importExternal (url, targetPath, cb) { importExternal (url, targetPath, cb) {
@ -182,13 +157,12 @@ module.exports = class CompilerImports extends Plugin {
} }
resolve(result) resolve(result)
}) })
} else {
// try to resolve external content
this.importExternal(url, targetPath, (error, content) => {
if (error) return reject(error)
resolve(content)
})
} }
this.importExternal(url, targetPath, (error, content) => {
if (error) return reject(error)
resolve(content)
})
}) })
} }
}) })

@ -121,6 +121,21 @@ export class RemixURLResolver {
} }
} }
/**
* Handle an import statement based on NPM
* @param url The url of the NPM import statement
*/
async handleNpmImport(url: string): Promise<HandlerResponse> {
// eslint-disable-next-line no-useless-catch
try {
const req = 'https://unpkg.com/' + url
const response: AxiosResponse = await axios.get(req)
return { content: response.data, cleanUrl: url }
} catch (e) {
throw e
}
}
getHandlers(): Handler[] { getHandlers(): Handler[] {
return [ return [
{ {
@ -147,6 +162,11 @@ export class RemixURLResolver {
type: 'ipfs', type: 'ipfs',
match: (url) => { return /^(ipfs:\/\/?.+)/.exec(url) }, match: (url) => { return /^(ipfs:\/\/?.+)/.exec(url) },
handle: (match) => this.handleIPFS(match[1]) handle: (match) => this.handleIPFS(match[1])
},
{
type: 'npm',
match: (url) => { return /^[^/][^\n"?:*<>|]*$/g.exec(url) }, // match a typical relative path
handle: (match) => this.handleNpmImport(match[0])
} }
] ]
} }

Loading…
Cancel
Save