Merge pull request #3311 from ethereum/resolve_with_package

resolver use package-lock.json or yarn lock
pull/5370/head
Aniket 2 years ago committed by GitHub
commit 7abc0428e1
  1. 56
      libs/remix-core-plugin/src/lib/compiler-content-imports.ts
  2. 79
      libs/remix-url-resolver/src/resolve.ts

@ -16,12 +16,50 @@ export type ResolvedImport = {
} }
export class CompilerImports extends Plugin { export class CompilerImports extends Plugin {
previouslyHandled: Record<string, ResolvedImport>
urlResolver: any urlResolver: any
constructor () { constructor () {
super(profile) super(profile)
this.urlResolver = new RemixURLResolver() this.urlResolver = new RemixURLResolver(async () => {
this.previouslyHandled = {} // cache import so we don't make the request at each compilation. try {
let yarnLock
if (await this.call('fileManager', 'exists', './yarn.lock')) {
yarnLock = await this.call('fileManager', 'readFile', './yarn.lock')
}
let packageLock
if (await this.call('fileManager', 'exists', './package-lock.json')) {
packageLock = await this.call('fileManager', 'readFile', './package-lock.json')
packageLock = JSON.parse(packageLock)
}
if (await this.call('fileManager', 'exists', './package.json')) {
const content = await this.call('fileManager', 'readFile', './package.json')
const pkg = JSON.parse(content)
return { deps: { ...pkg['dependencies'], ...pkg['devDependencies'] }, yarnLock, packageLock }
} else {
return {}
}
} catch (e) {
console.error(e)
return {}
}
})
}
onActivation(): void {
const packageFiles = ['package.json', 'package-lock.json', 'yarn.lock']
this.on('filePanel', 'setWorkspace', () => this.urlResolver.clearCache())
this.on('fileManager', 'fileRemoved', (file: string) => {
if (packageFiles.includes(file)) {
this.urlResolver.clearCache()
}
})
this.on('fileManager', 'fileChanged', (file: string) => {
if (packageFiles.includes(file)) {
this.urlResolver.clearCache()
}
})
} }
async setToken () { async setToken () {
@ -71,22 +109,12 @@ export class CompilerImports extends Plugin {
if (!cb) cb = () => {} if (!cb) cb = () => {}
const self = this const self = this
if (force) delete this.previouslyHandled[url]
const imported = this.previouslyHandled[url]
if (imported) {
return cb(null, imported.content, imported.cleanUrl, imported.type, url)
}
let resolved let resolved
try { try {
await this.setToken() await this.setToken()
resolved = await this.urlResolver.resolve(url) resolved = await this.urlResolver.resolve(url, [], force)
const { content, cleanUrl, type } = resolved const { content, cleanUrl, type } = resolved
self.previouslyHandled[url] = {
content,
cleanUrl,
type
}
cb(null, content, cleanUrl, type, url) cb(null, content, cleanUrl, type, url)
} catch (e) { } catch (e) {
return cb(new Error('not found ' + url)) return cb(new Error('not found ' + url))

@ -23,13 +23,17 @@ interface HandlerResponse {
cleanUrl: string cleanUrl: string
} }
export type getPackages = () => Promise<{ [name: string]: string }>
export class RemixURLResolver { export class RemixURLResolver {
private previouslyHandled: PreviouslyHandledImports private previouslyHandled: PreviouslyHandledImports
gistAccessToken: string gistAccessToken: string
protocol: string protocol: string
getDependencies: getPackages
constructor (gistToken?: string, protocol = 'http:') { constructor (getDependencies?: getPackages, gistToken?: string, protocol = 'http:') {
this.previouslyHandled = {} this.previouslyHandled = {}
this.getDependencies = getDependencies
this.setGistToken(gistToken, protocol) this.setGistToken(gistToken, protocol)
} }
@ -38,12 +42,16 @@ export class RemixURLResolver {
this.protocol = protocol this.protocol = protocol
} }
clearCache () {
this.previouslyHandled = {}
}
/** /**
* Handle an import statement based on github * Handle an import statement based on github
* @param root The root of the github import statement * @param root The root of the github import statement
* @param filePath path of the file in github * @param filePath path of the file in github
*/ */
async handleGithubCall (root: string, filePath: string): Promise<HandlerResponse> { async handleGithubCall(root: string, filePath: string): Promise<HandlerResponse> {
const regex = filePath.match(/blob\/([^/]+)\/(.*)/) const regex = filePath.match(/blob\/([^/]+)\/(.*)/)
let reference = 'master' let reference = 'master'
if (regex) { if (regex) {
@ -67,7 +75,7 @@ export class RemixURLResolver {
* @param url The url of the import statement * @param url The url of the import statement
* @param cleanUrl * @param cleanUrl
*/ */
async handleHttp (url: string, cleanUrl: string): Promise<HandlerResponse> { async handleHttp(url: string, cleanUrl: string): Promise<HandlerResponse> {
// eslint-disable-next-line no-useless-catch // eslint-disable-next-line no-useless-catch
try { try {
const response: AxiosResponse = await axios.get(url, { transformResponse: [] }) const response: AxiosResponse = await axios.get(url, { transformResponse: [] })
@ -82,7 +90,7 @@ export class RemixURLResolver {
* @param url The url of the import statement * @param url The url of the import statement
* @param cleanUrl * @param cleanUrl
*/ */
async handleHttps (url: string, cleanUrl: string): Promise<HandlerResponse> { async handleHttps(url: string, cleanUrl: string): Promise<HandlerResponse> {
// eslint-disable-next-line no-useless-catch // eslint-disable-next-line no-useless-catch
try { try {
const response: AxiosResponse = await axios.get(url, { transformResponse: [] }) const response: AxiosResponse = await axios.get(url, { transformResponse: [] })
@ -92,7 +100,7 @@ export class RemixURLResolver {
} }
} }
async handleSwarm (url: string, cleanUrl: string): Promise<HandlerResponse> { async handleSwarm(url: string, cleanUrl: string): Promise<HandlerResponse> {
// eslint-disable-next-line no-useless-catch // eslint-disable-next-line no-useless-catch
try { try {
const bzz = new Bzz({ url: this.protocol + '//swarm-gateways.net' }) const bzz = new Bzz({ url: this.protocol + '//swarm-gateways.net' })
@ -108,7 +116,7 @@ export class RemixURLResolver {
* Handle an import statement based on IPFS * Handle an import statement based on IPFS
* @param url The url of the IPFS import statement * @param url The url of the IPFS import statement
*/ */
async handleIPFS (url: string): Promise<HandlerResponse> { async handleIPFS(url: string): Promise<HandlerResponse> {
// replace ipfs:// with /ipfs/ // replace ipfs:// with /ipfs/
url = url.replace(/^ipfs:\/\/?/, 'ipfs/') url = url.replace(/^ipfs:\/\/?/, 'ipfs/')
// eslint-disable-next-line no-useless-catch // eslint-disable-next-line no-useless-catch
@ -127,26 +135,69 @@ export class RemixURLResolver {
* Handle an import statement based on NPM * Handle an import statement based on NPM
* @param url The url of the NPM import statement * @param url The url of the NPM import statement
*/ */
async handleNpmImport (url: string): Promise<HandlerResponse> {
const urls = ["https://cdn.jsdelivr.net/npm/", "https://unpkg.com/"] async handleNpmImport(url: string): Promise<HandlerResponse> {
process && process.env && process.env['NPM_URL'] && urls.unshift(process.env['NPM_URL']) if (this.getDependencies) {
try {
const { deps, yarnLock, packageLock } = await this.getDependencies()
let matchLength = 0
let pkg
if (deps) {
Object.keys(deps).map((dep) => {
const reg = new RegExp(dep, 'g')
const match = url.match(reg)
if (match && match.length > 0 && matchLength < match[0].length) {
matchLength = match[0].length
pkg = dep
}
})
if (pkg) {
let version
if (yarnLock) {
// yarn.lock
const regex = new RegExp(`"${pkg}@(.*)"`, 'g')
const yarnVersion = regex.exec(yarnLock)
if (yarnVersion && yarnVersion.length > 1) {
version = yarnVersion[1]
}
}
if (!version && packageLock && packageLock['dependencies'] && packageLock['dependencies'][pkg] && packageLock['dependencies'][pkg]['version']) {
// package-lock.json
version = packageLock['dependencies'][pkg]['version']
}
if (!version) {
// package.json
version = deps[pkg]
}
if (version) url = url.replace(pkg, `${pkg}@${version}`)
}
}
} catch (e) {
console.log(e)
}
}
const npm_urls = ["https://cdn.jsdelivr.net/npm/", "https://unpkg.com/"]
process && process.env && process.env['NPM_URL'] && npm_urls.unshift(process.env['NPM_URL'])
let content = null let content = null
// get response from all urls // get response from all urls
for (let i = 0; i < urls.length; i++) { for (let i = 0; i < npm_urls.length; i++) {
try { try {
const req = urls[i] + url const req = npm_urls[i] + url
const response: AxiosResponse = await axios.get(req, { transformResponse: [] }) const response: AxiosResponse = await axios.get(req, { transformResponse: [] })
content = response.data content = response.data
break break
} catch (e) { } catch (e) {
// try next url // try next url
} }
} }
if (!content) throw new Error('Unable to load ' + url) if (!content) throw new Error('Unable to load ' + url)
return { content, cleanUrl: url } return { content, cleanUrl: url }
} }
getHandlers (): Handler[] { getHandlers (): Handler[] {
return [ return [
{ {
@ -182,9 +233,9 @@ export class RemixURLResolver {
] ]
} }
public async resolve (filePath: string, customHandlers?: Handler[]): Promise<Imported> { public async resolve (filePath: string, customHandlers?: Handler[], force?: boolean): Promise<Imported> {
let imported: Imported = this.previouslyHandled[filePath] let imported: Imported = this.previouslyHandled[filePath]
if (imported) { if (!force && imported) {
return imported return imported
} }
const builtinHandlers: Handler[] = this.getHandlers() const builtinHandlers: Handler[] = this.getHandlers()

Loading…
Cancel
Save