|
|
|
@ -9,7 +9,7 @@ import { |
|
|
|
|
Source, SourceWithTarget, MessageFromWorker, CompilerState, CompilationResult, |
|
|
|
|
visitContractsCallbackParam, visitContractsCallbackInterface, CompilationError, |
|
|
|
|
gatherImportsCallbackInterface, |
|
|
|
|
isFunctionDescription |
|
|
|
|
isFunctionDescription, CompilerRetriggerMode |
|
|
|
|
} from './types' |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
@ -19,7 +19,7 @@ export class Compiler { |
|
|
|
|
event |
|
|
|
|
state: CompilerState |
|
|
|
|
|
|
|
|
|
constructor (public handleImportCall?: (fileurl: string, cb) => void) { |
|
|
|
|
constructor(public handleImportCall?: (fileurl: string, cb) => void) { |
|
|
|
|
this.event = new EventManager() |
|
|
|
|
this.state = { |
|
|
|
|
compileJSON: null, |
|
|
|
@ -33,6 +33,7 @@ export class Compiler { |
|
|
|
|
target: null, |
|
|
|
|
useFileConfiguration: false, |
|
|
|
|
configFileContent: '', |
|
|
|
|
compilerRetriggerMode: CompilerRetriggerMode.none, |
|
|
|
|
lastCompilationResult: { |
|
|
|
|
data: null, |
|
|
|
|
source: null |
|
|
|
@ -47,7 +48,6 @@ export class Compiler { |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
this.event.register('compilationStarted', () => { |
|
|
|
|
this.state.compilationStartTime = new Date().getTime() |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -57,7 +57,7 @@ export class Compiler { |
|
|
|
|
* @param value value of key in CompilerState |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
set <K extends keyof CompilerState> (key: K, value: CompilerState[K]): void { |
|
|
|
|
set<K extends keyof CompilerState>(key: K, value: CompilerState[K]): void { |
|
|
|
|
this.state[key] = value |
|
|
|
|
if (key === 'runs') this.state['runs'] = parseInt(value) |
|
|
|
|
} |
|
|
|
@ -68,7 +68,7 @@ export class Compiler { |
|
|
|
|
* @param missingInputs missing import file path list |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
internalCompile (files: Source, missingInputs?: string[]): void { |
|
|
|
|
internalCompile(files: Source, missingInputs?: string[]): void { |
|
|
|
|
this.gatherImports(files, missingInputs, (error, input) => { |
|
|
|
|
if (error) { |
|
|
|
|
this.state.lastCompilationResult = null |
|
|
|
@ -83,8 +83,9 @@ export class Compiler { |
|
|
|
|
* @param target target file name (This is passed as it is to IDE) |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
compile (files: Source, target: string): void { |
|
|
|
|
compile(files: Source, target: string): void { |
|
|
|
|
this.state.target = target |
|
|
|
|
this.state.compilationStartTime = new Date().getTime() |
|
|
|
|
this.event.trigger('compilationStarted', []) |
|
|
|
|
this.internalCompile(files) |
|
|
|
|
} |
|
|
|
@ -94,7 +95,7 @@ export class Compiler { |
|
|
|
|
* @param version compiler version |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
onCompilerLoaded (version: string): void { |
|
|
|
|
onCompilerLoaded(version: string): void { |
|
|
|
|
this.state.currentVersion = version |
|
|
|
|
this.event.trigger('compilerLoaded', [version]) |
|
|
|
|
} |
|
|
|
@ -103,7 +104,7 @@ export class Compiler { |
|
|
|
|
* @dev Called when compiler is loaded internally (without worker) |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
onInternalCompilerLoaded (): void { |
|
|
|
|
onInternalCompilerLoaded(): void { |
|
|
|
|
if (this.state.worker === null) { |
|
|
|
|
const compiler: any = typeof (window) !== 'undefined' && window['Module'] ? require('solc/wrapper')(window['Module']) : require('solc') // eslint-disable-line
|
|
|
|
|
this.state.compileJSON = (source: SourceWithTarget) => { |
|
|
|
@ -142,7 +143,7 @@ export class Compiler { |
|
|
|
|
* @param source Source |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
onCompilationFinished (data: CompilationResult, missingInputs?: string[], source?: SourceWithTarget, input?: string, version?: string): void { |
|
|
|
|
onCompilationFinished(data: CompilationResult, missingInputs?: string[], source?: SourceWithTarget, input?: string, version?: string): void { |
|
|
|
|
let noFatalErrors = true // ie warnings are ok
|
|
|
|
|
|
|
|
|
|
const checkIfFatalError = (error: CompilationError) => { |
|
|
|
@ -177,7 +178,7 @@ export class Compiler { |
|
|
|
|
* @param version compiler version |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
loadRemoteVersion (version: string): void { |
|
|
|
|
loadRemoteVersion(version: string): void { |
|
|
|
|
console.log(`Loading remote solc version ${version} ...`) |
|
|
|
|
const compiler: any = require('solc') // eslint-disable-line
|
|
|
|
|
compiler.loadRemoteVersion(version, (err, remoteCompiler) => { |
|
|
|
@ -220,7 +221,7 @@ export class Compiler { |
|
|
|
|
* @param url URL to load compiler from |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
loadVersion (usingWorker: boolean, url: string): void { |
|
|
|
|
loadVersion(usingWorker: boolean, url: string): void { |
|
|
|
|
console.log('Loading ' + url + ' ' + (usingWorker ? 'with worker' : 'without worker')) |
|
|
|
|
this.event.trigger('loadingCompiler', [url, usingWorker]) |
|
|
|
|
if (this.state.worker) { |
|
|
|
@ -239,7 +240,7 @@ export class Compiler { |
|
|
|
|
* @param url URL to load compiler from |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
loadInternal (url: string): void { |
|
|
|
|
loadInternal(url: string): void { |
|
|
|
|
delete window['Module'] |
|
|
|
|
// NOTE: workaround some browsers?
|
|
|
|
|
window['Module'] = undefined |
|
|
|
@ -265,38 +266,41 @@ export class Compiler { |
|
|
|
|
* @param url URL to load compiler from |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
loadWorker (url: string): void { |
|
|
|
|
loadWorker(url: string): void { |
|
|
|
|
this.state.worker = webworkify(require.resolve('./compiler-worker')) |
|
|
|
|
const jobs: Record<'sources', SourceWithTarget> [] = [] |
|
|
|
|
const jobs: Record<'sources', SourceWithTarget>[] = [] |
|
|
|
|
|
|
|
|
|
this.state.worker.addEventListener('message', (msg: Record <'data', MessageFromWorker>) => { |
|
|
|
|
this.state.worker.addEventListener('message', (msg: Record<'data', MessageFromWorker>) => { |
|
|
|
|
const data: MessageFromWorker = msg.data |
|
|
|
|
if (this.state.compilerRetriggerMode == CompilerRetriggerMode.retrigger && data.timestamp !== this.state.compilationStartTime) { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
switch (data.cmd) { |
|
|
|
|
case 'versionLoaded': |
|
|
|
|
if (data.data) this.onCompilerLoaded(data.data) |
|
|
|
|
break |
|
|
|
|
case 'compiled': |
|
|
|
|
{ |
|
|
|
|
let result: CompilationResult |
|
|
|
|
if (data.data && data.job !== undefined && data.job >= 0) { |
|
|
|
|
try { |
|
|
|
|
result = JSON.parse(data.data) |
|
|
|
|
} catch (exception) { |
|
|
|
|
result = { error: { formattedMessage: 'Invalid JSON output from the compiler: ' + exception } } |
|
|
|
|
} |
|
|
|
|
let sources: SourceWithTarget = {} |
|
|
|
|
if (data.job in jobs !== undefined) { |
|
|
|
|
sources = jobs[data.job].sources |
|
|
|
|
delete jobs[data.job] |
|
|
|
|
{ |
|
|
|
|
let result: CompilationResult |
|
|
|
|
if (data.data && data.job !== undefined && data.job >= 0) { |
|
|
|
|
try { |
|
|
|
|
result = JSON.parse(data.data) |
|
|
|
|
} catch (exception) { |
|
|
|
|
result = { error: { formattedMessage: 'Invalid JSON output from the compiler: ' + exception } } |
|
|
|
|
} |
|
|
|
|
let sources: SourceWithTarget = {} |
|
|
|
|
if (data.job in jobs !== undefined) { |
|
|
|
|
sources = jobs[data.job].sources |
|
|
|
|
delete jobs[data.job] |
|
|
|
|
} |
|
|
|
|
this.onCompilationFinished(result, data.missingInputs, sources, data.input, this.state.currentVersion) |
|
|
|
|
} |
|
|
|
|
this.onCompilationFinished(result, data.missingInputs, sources, data.input, this.state.currentVersion) |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
this.state.worker.addEventListener('error', (msg: Record <'data', MessageFromWorker>) => { |
|
|
|
|
this.state.worker.addEventListener('error', (msg: Record<'data', MessageFromWorker>) => { |
|
|
|
|
const formattedMessage = `Worker error: ${msg.data && msg.data !== undefined ? msg.data : msg['message']}` |
|
|
|
|
this.onCompilationFinished({ error: { formattedMessage } }) |
|
|
|
|
}) |
|
|
|
@ -322,7 +326,8 @@ export class Compiler { |
|
|
|
|
this.state.worker.postMessage({ |
|
|
|
|
cmd: 'compile', |
|
|
|
|
job: jobs.length - 1, |
|
|
|
|
input: input |
|
|
|
|
input: input, |
|
|
|
|
timestamp: this.state.compilationStartTime |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -340,7 +345,7 @@ export class Compiler { |
|
|
|
|
* @param cb callback |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
gatherImports (files: Source, importHints?: string[], cb?: gatherImportsCallbackInterface): void { |
|
|
|
|
gatherImports(files: Source, importHints?: string[], cb?: gatherImportsCallbackInterface): void { |
|
|
|
|
importHints = importHints || [] |
|
|
|
|
// FIXME: This will only match imports if the file begins with one '.'
|
|
|
|
|
// It should tokenize by lines and check each.
|
|
|
|
@ -379,7 +384,7 @@ export class Compiler { |
|
|
|
|
* @param version version |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
truncateVersion (version: string): string { |
|
|
|
|
truncateVersion(version: string): string { |
|
|
|
|
const tmp: RegExpExecArray | null = /^(\d+.\d+.\d+)/.exec(version) |
|
|
|
|
return tmp ? tmp[1] : version |
|
|
|
|
} |
|
|
|
@ -389,8 +394,8 @@ export class Compiler { |
|
|
|
|
* @param data Compilation result |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
updateInterface (data: CompilationResult) : CompilationResult { |
|
|
|
|
txHelper.visitContracts(data.contracts, (contract : visitContractsCallbackParam) => { |
|
|
|
|
updateInterface(data: CompilationResult): CompilationResult { |
|
|
|
|
txHelper.visitContracts(data.contracts, (contract: visitContractsCallbackParam) => { |
|
|
|
|
if (!contract.object.abi) contract.object.abi = [] |
|
|
|
|
if (this.state.language === 'Yul' && contract.object.abi.length === 0) { |
|
|
|
|
// yul compiler does not return any abi,
|
|
|
|
@ -422,7 +427,7 @@ export class Compiler { |
|
|
|
|
* @param name contract name |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
getContract (name: string): Record<string, any> | null { |
|
|
|
|
getContract(name: string): Record<string, any> | null { |
|
|
|
|
if (this.state.lastCompilationResult && this.state.lastCompilationResult.data && this.state.lastCompilationResult.data.contracts) { |
|
|
|
|
return txHelper.getContract(name, this.state.lastCompilationResult.data.contracts) |
|
|
|
|
} |
|
|
|
@ -434,7 +439,7 @@ export class Compiler { |
|
|
|
|
* @param cb callback |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
visitContracts (cb: visitContractsCallbackInterface) : void | null { |
|
|
|
|
visitContracts(cb: visitContractsCallbackInterface): void | null { |
|
|
|
|
if (this.state.lastCompilationResult && this.state.lastCompilationResult.data && this.state.lastCompilationResult.data.contracts) { |
|
|
|
|
return txHelper.visitContracts(this.state.lastCompilationResult.data.contracts, cb) |
|
|
|
|
} |
|
|
|
@ -445,7 +450,7 @@ export class Compiler { |
|
|
|
|
* @dev Get the compiled contracts data from last compilation result |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
getContracts () : CompilationResult['contracts'] | null { |
|
|
|
|
getContracts(): CompilationResult['contracts'] | null { |
|
|
|
|
if (this.state.lastCompilationResult && this.state.lastCompilationResult.data && this.state.lastCompilationResult.data.contracts) { |
|
|
|
|
return this.state.lastCompilationResult.data.contracts |
|
|
|
|
} |
|
|
|
@ -456,7 +461,7 @@ export class Compiler { |
|
|
|
|
* @dev Get sources from last compilation result |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
getSources () : Source | null | undefined { |
|
|
|
|
getSources(): Source | null | undefined { |
|
|
|
|
if (this.state.lastCompilationResult && this.state.lastCompilationResult.source) { |
|
|
|
|
return this.state.lastCompilationResult.source.sources |
|
|
|
|
} |
|
|
|
@ -468,7 +473,7 @@ export class Compiler { |
|
|
|
|
* @param fileName file name |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
getSource (fileName: string) : Source['filename'] | null { |
|
|
|
|
getSource(fileName: string): Source['filename'] | null { |
|
|
|
|
if (this.state.lastCompilationResult && this.state.lastCompilationResult.source && this.state.lastCompilationResult.source.sources) { |
|
|
|
|
return this.state.lastCompilationResult.source.sources[fileName] |
|
|
|
|
} |
|
|
|
@ -480,7 +485,7 @@ export class Compiler { |
|
|
|
|
* @param index - index of the source |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
getSourceName (index: number): string | null { |
|
|
|
|
getSourceName(index: number): string | null { |
|
|
|
|
if (this.state.lastCompilationResult && this.state.lastCompilationResult.data && this.state.lastCompilationResult.data.sources) { |
|
|
|
|
return Object.keys(this.state.lastCompilationResult.data.sources)[index] |
|
|
|
|
} |
|
|
|
|