types introduced suggested changes and worker types more types more types and code style update fix to run compilation very first time after plugin activationpull/7/head
parent
1f74b65149
commit
355a02ea3b
@ -1,7 +0,0 @@ |
||||
const Compiler = require('./src/compiler/compiler') |
||||
const CompilerInput = require('./src/compiler/compiler-input') |
||||
|
||||
module.exports = { |
||||
Compiler: Compiler, |
||||
CompilerInput: CompilerInput |
||||
} |
@ -0,0 +1,2 @@ |
||||
export { Compiler } from './src/compiler/compiler' |
||||
export { default as CompilerInput} from './src/compiler/compiler-input' |
File diff suppressed because it is too large
Load Diff
@ -1,390 +0,0 @@ |
||||
'use strict' |
||||
|
||||
const solc = require('solc/wrapper') |
||||
const solcABI = require('solc/abi') |
||||
|
||||
const webworkify = require('webworkify') |
||||
|
||||
const compilerInput = require('./compiler-input') |
||||
|
||||
const remixLib = require('remix-lib') |
||||
const EventManager = remixLib.EventManager |
||||
|
||||
const txHelper = require('./txHelper') |
||||
|
||||
/* |
||||
trigger compilationFinished, compilerLoaded, compilationStarted, compilationDuration |
||||
*/ |
||||
function Compiler (handleImportCall) { |
||||
var self = this |
||||
this.event = new EventManager() |
||||
|
||||
let compileJSON |
||||
|
||||
let worker = null |
||||
|
||||
let currentVersion |
||||
|
||||
let optimize = false |
||||
|
||||
let evmVersion = null |
||||
|
||||
let language = 'Solidity' |
||||
|
||||
this.setOptimize = function (_optimize) { |
||||
optimize = _optimize |
||||
} |
||||
|
||||
this.setEvmVersion = function (_evmVersion) { |
||||
evmVersion = _evmVersion |
||||
} |
||||
|
||||
this.setLanguage = function (_language) { |
||||
language = _language |
||||
} |
||||
|
||||
let compilationStartTime = null |
||||
this.event.register('compilationFinished', (success, data, source) => { |
||||
if (success && compilationStartTime) { |
||||
this.event.trigger('compilationDuration', [(new Date().getTime()) - compilationStartTime]) |
||||
} |
||||
compilationStartTime = null |
||||
}) |
||||
|
||||
this.event.register('compilationStarted', () => { |
||||
compilationStartTime = new Date().getTime() |
||||
}) |
||||
|
||||
const internalCompile = (files, target, missingInputs) => { |
||||
gatherImports(files, target, missingInputs, (error, input) => { |
||||
if (error) { |
||||
this.lastCompilationResult = null |
||||
this.event.trigger('compilationFinished', [false, {'error': { formattedMessage: error, severity: 'error' }}, files]) |
||||
} else { |
||||
compileJSON(input) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
const compile = function (files, target) { |
||||
self.event.trigger('compilationStarted', []) |
||||
internalCompile(files, target) |
||||
} |
||||
this.compile = compile |
||||
|
||||
function setCompileJSON (_compileJSON) { |
||||
compileJSON = _compileJSON |
||||
} |
||||
this.setCompileJSON = setCompileJSON // this is exposed for testing
|
||||
|
||||
function onCompilerLoaded (version) { |
||||
currentVersion = version |
||||
self.event.trigger('compilerLoaded', [version]) |
||||
} |
||||
|
||||
function onInternalCompilerLoaded () { |
||||
if (worker === null) { |
||||
let compiler |
||||
if (typeof (window) === 'undefined') { |
||||
compiler = require('solc') |
||||
} else { |
||||
compiler = solc(window.Module) |
||||
} |
||||
|
||||
compileJSON = function (source) { |
||||
const missingInputs = [] |
||||
const missingInputsCallback = function (path) { |
||||
missingInputs.push(path) |
||||
return { error: 'Deferred import' } |
||||
} |
||||
|
||||
let result |
||||
try { |
||||
const input = compilerInput(source.sources, {optimize: optimize, evmVersion: evmVersion, language: language, target: source.target}) |
||||
result = compiler.compile(input, { import: missingInputsCallback }) |
||||
result = JSON.parse(result) |
||||
} catch (exception) { |
||||
result = { error: { formattedMessage: 'Uncaught JavaScript exception:\n' + exception, severity: 'error', mode: 'panic' } } |
||||
} |
||||
|
||||
compilationFinished(result, missingInputs, source) |
||||
} |
||||
onCompilerLoaded(compiler.version()) |
||||
} |
||||
} |
||||
// exposed for use in node
|
||||
this.onInternalCompilerLoaded = onInternalCompilerLoaded |
||||
|
||||
this.lastCompilationResult = { |
||||
data: null, |
||||
source: null |
||||
} |
||||
|
||||
/** |
||||
* return the contract obj of the given @arg name. Uses last compilation result. |
||||
* return null if not found |
||||
* @param {String} name - contract name |
||||
* @returns contract obj and associated file: { contract, file } or null |
||||
*/ |
||||
this.getContract = (name) => { |
||||
if (this.lastCompilationResult.data && this.lastCompilationResult.data.contracts) { |
||||
return txHelper.getContract(name, this.lastCompilationResult.data.contracts) |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* call the given @arg cb (function) for all the contracts. Uses last compilation result |
||||
* @param {Function} cb - callback |
||||
*/ |
||||
this.visitContracts = (cb) => { |
||||
if (this.lastCompilationResult.data && this.lastCompilationResult.data.contracts) { |
||||
return txHelper.visitContracts(this.lastCompilationResult.data.contracts, cb) |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* return the compiled contracts from the last compilation result |
||||
* @return {Object} - contracts |
||||
*/ |
||||
this.getContracts = () => { |
||||
if (this.lastCompilationResult.data && this.lastCompilationResult.data.contracts) { |
||||
return this.lastCompilationResult.data.contracts |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* return the sources from the last compilation result |
||||
* @param {Object} cb - map of sources |
||||
*/ |
||||
this.getSources = () => { |
||||
if (this.lastCompilationResult.source) { |
||||
return this.lastCompilationResult.source.sources |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* return the sources @arg fileName from the last compilation result |
||||
* @param {Object} cb - map of sources |
||||
*/ |
||||
this.getSource = (fileName) => { |
||||
if (this.lastCompilationResult.source) { |
||||
return this.lastCompilationResult.source.sources[fileName] |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* return the source from the last compilation result that has the given index. null if source not found |
||||
* @param {Int} index - index of the source |
||||
*/ |
||||
this.getSourceName = (index) => { |
||||
if (this.lastCompilationResult.data && this.lastCompilationResult.data.sources) { |
||||
return Object.keys(this.lastCompilationResult.data.sources)[index] |
||||
} |
||||
return null |
||||
} |
||||
|
||||
function compilationFinished (data, missingInputs, source) { |
||||
let noFatalErrors = true // ie warnings are ok
|
||||
|
||||
function isValidError (error) { |
||||
// The deferred import is not a real error
|
||||
// FIXME: maybe have a better check?
|
||||
if (/Deferred import/.exec(error.message)) { |
||||
return false |
||||
} |
||||
|
||||
return error.severity !== 'warning' |
||||
} |
||||
|
||||
if (data['error'] !== undefined) { |
||||
// Ignore warnings (and the 'Deferred import' error as those are generated by us as a workaround
|
||||
if (isValidError(data['error'])) { |
||||
noFatalErrors = false |
||||
} |
||||
} |
||||
if (data['errors'] !== undefined) { |
||||
data['errors'].forEach(function (err) { |
||||
// Ignore warnings and the 'Deferred import' error as those are generated by us as a workaround
|
||||
if (isValidError(err)) { |
||||
noFatalErrors = false |
||||
} |
||||
}) |
||||
} |
||||
|
||||
if (!noFatalErrors) { |
||||
// There are fatal errors - abort here
|
||||
self.lastCompilationResult = null |
||||
self.event.trigger('compilationFinished', [false, data, source]) |
||||
} else if (missingInputs !== undefined && missingInputs.length > 0) { |
||||
// try compiling again with the new set of inputs
|
||||
|
||||
internalCompile(source.sources, source.target, missingInputs) |
||||
} else { |
||||
data = updateInterface(data) |
||||
|
||||
self.lastCompilationResult = { |
||||
data: data, |
||||
source: source |
||||
} |
||||
self.event.trigger('compilationFinished', [true, data, source]) |
||||
} |
||||
} |
||||
|
||||
// TODO: needs to be changed to be more node friendly
|
||||
this.loadVersion = (usingWorker, url) => { |
||||
console.log('Loading ' + url + ' ' + (usingWorker ? 'with worker' : 'without worker')) |
||||
this.event.trigger('loadingCompiler', [url, usingWorker]) |
||||
|
||||
if (worker !== null) { |
||||
worker.terminate() |
||||
worker = null |
||||
} |
||||
if (usingWorker) { |
||||
loadWorker(url) |
||||
} else { |
||||
loadInternal(url) |
||||
} |
||||
} |
||||
|
||||
function loadInternal (url) { |
||||
delete window.Module |
||||
// NOTE: workaround some browsers?
|
||||
window.Module = undefined |
||||
|
||||
// Set a safe fallback until the new one is loaded
|
||||
setCompileJSON(function (source) { |
||||
compilationFinished({ error: { formattedMessage: 'Compiler not yet loaded.' } }) |
||||
}) |
||||
|
||||
const newScript = document.createElement('script') |
||||
newScript.type = 'text/javascript' |
||||
newScript.src = url |
||||
document.getElementsByTagName('head')[0].appendChild(newScript) |
||||
const check = window.setInterval(function () { |
||||
if (!window.Module) { |
||||
return |
||||
} |
||||
window.clearInterval(check) |
||||
onInternalCompilerLoaded() |
||||
}, 200) |
||||
} |
||||
|
||||
function loadWorker (url) { |
||||
worker = webworkify(require('./compiler-worker.js')) |
||||
const jobs = [] |
||||
worker.addEventListener('message', function (msg) { |
||||
const data = msg.data |
||||
switch (data.cmd) { |
||||
case 'versionLoaded': |
||||
onCompilerLoaded(data.data) |
||||
break |
||||
case 'compiled': |
||||
let result |
||||
try { |
||||
result = JSON.parse(data.data) |
||||
} catch (exception) { |
||||
result = { 'error': 'Invalid JSON output from the compiler: ' + exception } |
||||
} |
||||
let sources = {} |
||||
if (data.job in jobs !== undefined) { |
||||
sources = jobs[data.job].sources |
||||
delete jobs[data.job] |
||||
} |
||||
compilationFinished(result, data.missingInputs, sources) |
||||
break |
||||
} |
||||
}) |
||||
worker.addEventListener('error', function (msg) { |
||||
compilationFinished({ error: 'Worker error: ' + msg.data }) |
||||
}) |
||||
compileJSON = function (source) { |
||||
jobs.push({sources: source}) |
||||
worker.postMessage({cmd: 'compile', job: jobs.length - 1, input: compilerInput(source.sources, |
||||
{optimize: optimize, evmVersion: evmVersion, language: language, target: source.target})}) |
||||
} |
||||
worker.postMessage({cmd: 'loadVersion', data: url}) |
||||
} |
||||
|
||||
function gatherImports (files, target, importHints, cb) { |
||||
importHints = importHints || [] |
||||
|
||||
// FIXME: This will only match imports if the file begins with one.
|
||||
// It should tokenize by lines and check each.
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
let importRegex = /^\s*import\s*[\'\"]([^\'\"]+)[\'\"];/g |
||||
|
||||
for (var fileName in files) { |
||||
let match |
||||
while ((match = importRegex.exec(files[fileName].content))) { |
||||
let importFilePath = match[1] |
||||
if (importFilePath.startsWith('./')) { |
||||
const path = /(.*\/).*/.exec(fileName) |
||||
if (path !== null) { |
||||
importFilePath = importFilePath.replace('./', path[1]) |
||||
} else { |
||||
importFilePath = importFilePath.slice(2) |
||||
} |
||||
} |
||||
|
||||
// FIXME: should be using includes or sets, but there's also browser compatibility..
|
||||
if (importHints.indexOf(importFilePath) === -1) { |
||||
importHints.push(importFilePath) |
||||
} |
||||
} |
||||
} |
||||
|
||||
while (importHints.length > 0) { |
||||
let m = importHints.pop() |
||||
if (m in files) { |
||||
continue |
||||
} |
||||
|
||||
if (handleImportCall) { |
||||
handleImportCall(m, function (err, content) { |
||||
if (err) { |
||||
cb(err) |
||||
} else { |
||||
files[m] = { content } |
||||
gatherImports(files, target, importHints, cb) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
return |
||||
} |
||||
|
||||
cb(null, { 'sources': files, 'target': target }) |
||||
} |
||||
|
||||
function truncateVersion (version) { |
||||
const tmp = /^(\d+.\d+.\d+)/.exec(version) |
||||
if (tmp) { |
||||
return tmp[1] |
||||
} |
||||
return version |
||||
} |
||||
|
||||
function updateInterface (data) { |
||||
txHelper.visitContracts(data.contracts, (contract) => { |
||||
if (!contract.object.abi) contract.object.abi = [] |
||||
if (language === 'Yul' && contract.object.abi.length === 0) { |
||||
// yul compiler does not return any abi,
|
||||
// we default to accept the fallback function (which expect raw data as argument).
|
||||
contract.object.abi.push({ |
||||
'payable': true, |
||||
'stateMutability': 'payable', |
||||
'type': 'fallback' |
||||
}) |
||||
} |
||||
data.contracts[contract.file][contract.name].abi = solcABI.update(truncateVersion(currentVersion), contract.object.abi) |
||||
}) |
||||
return data |
||||
} |
||||
} |
||||
|
||||
module.exports = Compiler |
@ -0,0 +1,411 @@ |
||||
'use strict' |
||||
|
||||
import { update } from 'solc/abi' |
||||
import webworkify from 'webworkify' |
||||
import compilerInput from './compiler-input' |
||||
import { EventManager } from 'remix-lib' |
||||
import { default as txHelper } from './txHelper'; |
||||
import { Source, SourceWithTarget, MessageFromWorker, CompilerState, CompilationResult,
|
||||
visitContractsCallbackParam, visitContractsCallbackInterface, CompilationError,
|
||||
gatherImportsCallbackInterface } from './types' |
||||
|
||||
/* |
||||
trigger compilationFinished, compilerLoaded, compilationStarted, compilationDuration |
||||
*/ |
||||
export class Compiler { |
||||
event: EventManager |
||||
state: CompilerState |
||||
|
||||
constructor (public handleImportCall: (fileurl: string, cb: Function) => void) { |
||||
this.event = new EventManager() |
||||
this.state = { |
||||
compileJSON: null, |
||||
worker: null, |
||||
currentVersion: null, |
||||
optimize: false, |
||||
evmVersion: null, |
||||
language: 'Solidity', |
||||
compilationStartTime: null, |
||||
lastCompilationResult: { |
||||
data: null, |
||||
source: null |
||||
} |
||||
} |
||||
|
||||
this.event.register('compilationFinished', (success: boolean, data: CompilationResult, source: SourceWithTarget) => { |
||||
if (success && this.state.compilationStartTime) { |
||||
this.event.trigger('compilationDuration', [(new Date().getTime()) - this.state.compilationStartTime]) |
||||
} |
||||
this.state.compilationStartTime = null |
||||
}) |
||||
|
||||
this.event.register('compilationStarted', () => { |
||||
this.state.compilationStartTime = new Date().getTime() |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* @dev Setter function for CompilerState's properties (used by IDE) |
||||
* @param key key |
||||
* @param value value of key in CompilerState |
||||
*/ |
||||
|
||||
set <K extends keyof CompilerState>(key: K, value: CompilerState[K]) { |
||||
this.state[key] = value |
||||
} |
||||
|
||||
/** |
||||
* @dev Internal function to compile the contract after gathering imports |
||||
* @param files source file |
||||
* @param missingInputs missing import file path list |
||||
*/ |
||||
|
||||
internalCompile (files: Source, missingInputs?: string[]): void { |
||||
this.gatherImports(files, missingInputs, (error, input) => { |
||||
if (error) { |
||||
this.state.lastCompilationResult = null |
||||
this.event.trigger('compilationFinished', [false, {'error': { formattedMessage: error, severity: 'error' }}, files]) |
||||
} else if(this.state.compileJSON && input) |
||||
this.state.compileJSON(input) |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* @dev Compile source files (used by IDE) |
||||
* @param files source files |
||||
* @param target target file name (This is passed as it is to IDE) |
||||
*/ |
||||
|
||||
compile (files: Source, target: string): void { |
||||
this.state.target = target |
||||
this.event.trigger('compilationStarted', []) |
||||
this.internalCompile(files, target) |
||||
} |
||||
|
||||
/** |
||||
* @dev Called when compiler is loaded, set current compiler version |
||||
* @param version compiler version |
||||
*/ |
||||
|
||||
onCompilerLoaded (version: string): void { |
||||
this.state.currentVersion = version |
||||
this.event.trigger('compilerLoaded', [version]) |
||||
} |
||||
|
||||
/** |
||||
* @dev Called when compiler is loaded internally (without worker) |
||||
*/ |
||||
|
||||
onInternalCompilerLoaded (): void { |
||||
if (this.state.worker === null) { |
||||
const compiler: any = typeof (window) === 'undefined' ? require('solc') : require('solc/wrapper')(window['Module']) |
||||
this.state.compileJSON = (source: SourceWithTarget) => { |
||||
let missingInputs: string[] = [] |
||||
const missingInputsCallback = (path: string) => { |
||||
missingInputs.push(path) |
||||
return { error: 'Deferred import' } |
||||
} |
||||
let result: CompilationResult = {} |
||||
try { |
||||
if(source && source.sources) { |
||||
const input = compilerInput(source.sources, {optimize: this.state.optimize, evmVersion: this.state.evmVersion, language: this.state.language}) |
||||
result = JSON.parse(compiler.compile(input, { import: missingInputsCallback })) |
||||
} |
||||
} catch (exception) { |
||||
result = { error: { formattedMessage: 'Uncaught JavaScript exception:\n' + exception, severity: 'error', mode: 'panic' } } |
||||
} |
||||
this.onCompilationFinished(result, missingInputs, source) |
||||
} |
||||
this.onCompilerLoaded(compiler.version()) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @dev Called when compilation is finished |
||||
* @param data compilation result data |
||||
* @param missingInputs missing imports |
||||
* @param source Source |
||||
*/ |
||||
|
||||
onCompilationFinished (data: CompilationResult, missingInputs?: string[], source?: SourceWithTarget): void { |
||||
let noFatalErrors: boolean = true // ie warnings are ok
|
||||
|
||||
const checkIfFatalError = (error: CompilationError) => { |
||||
// Ignore warnings and the 'Deferred import' error as those are generated by us as a workaround
|
||||
const isValidError = (error.message && error.message === 'Deferred import') ? false : error.severity !== 'warning' |
||||
if(isValidError) noFatalErrors = false |
||||
} |
||||
if (data.error) checkIfFatalError(data.error) |
||||
if (data.errors) data.errors.forEach((err) => checkIfFatalError(err)) |
||||
if (!noFatalErrors) { |
||||
// There are fatal errors, abort here
|
||||
this.state.lastCompilationResult = null |
||||
this.event.trigger('compilationFinished', [false, data, source]) |
||||
} else if (missingInputs !== undefined && missingInputs.length > 0) { |
||||
// try compiling again with the new set of inputs
|
||||
this.internalCompile(source.sources, missingInputs) |
||||
} else { |
||||
data = this.updateInterface(data) |
||||
if(source) |
||||
{ |
||||
source.target = this.state.target; |
||||
this.state.lastCompilationResult = { |
||||
data: data, |
||||
source: source |
||||
} |
||||
} |
||||
this.event.trigger('compilationFinished', [true, data, source]) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @dev Load compiler using given URL (used by IDE) |
||||
* @param usingWorker if true, load compiler using worker |
||||
* @param url URL to load compiler from |
||||
*/ |
||||
|
||||
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) { |
||||
this.state.worker.terminate() |
||||
this.state.worker = null |
||||
} |
||||
if (usingWorker) { |
||||
this.loadWorker(url) |
||||
} else { |
||||
this.loadInternal(url) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @dev Load compiler using 'script' element (without worker) |
||||
* @param url URL to load compiler from |
||||
*/ |
||||
|
||||
loadInternal (url: string): void { |
||||
delete window['Module'] |
||||
// NOTE: workaround some browsers?
|
||||
window['Module'] = undefined |
||||
// Set a safe fallback until the new one is loaded
|
||||
this.state.compileJSON = (source: SourceWithTarget) => { |
||||
this.onCompilationFinished({ error: { formattedMessage: 'Compiler not yet loaded.' } }) |
||||
} |
||||
let newScript: HTMLScriptElement = document.createElement('script') |
||||
newScript.type = 'text/javascript' |
||||
newScript.src = url |
||||
document.getElementsByTagName('head')[0].appendChild(newScript) |
||||
const check: number = window.setInterval(() => { |
||||
if (!window['Module']) { |
||||
return |
||||
} |
||||
window.clearInterval(check) |
||||
this.onInternalCompilerLoaded() |
||||
}, 200) |
||||
} |
||||
|
||||
/** |
||||
* @dev Load compiler using web worker |
||||
* @param url URL to load compiler from |
||||
*/ |
||||
|
||||
loadWorker (url: string): void { |
||||
this.state.worker = webworkify(require('./compiler-worker.js').default) |
||||
let jobs: Record<'sources', SourceWithTarget> [] = [] |
||||
|
||||
this.state.worker.addEventListener('message', (msg: Record <'data', MessageFromWorker>) => { |
||||
const data: MessageFromWorker = msg.data |
||||
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] |
||||
} |
||||
this.onCompilationFinished(result, data.missingInputs, sources) |
||||
} |
||||
break |
||||
} |
||||
}) |
||||
|
||||
this.state.worker.addEventListener('error', (msg: Record <'data', MessageFromWorker>) => { |
||||
this.onCompilationFinished({ error: { formattedMessage: 'Worker error: ' + msg.data }}) |
||||
}) |
||||
|
||||
this.state.compileJSON = (source: SourceWithTarget) => { |
||||
if(source && source.sources) { |
||||
jobs.push({sources: source}) |
||||
this.state.worker.postMessage({ |
||||
cmd: 'compile',
|
||||
job: jobs.length - 1,
|
||||
input: compilerInput(source.sources, { |
||||
optimize: this.state.optimize,
|
||||
evmVersion: this.state.evmVersion,
|
||||
language: this.state.language |
||||
}) |
||||
}) |
||||
} |
||||
} |
||||
|
||||
this.state.worker.postMessage({ |
||||
cmd: 'loadVersion',
|
||||
data: url |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* @dev Gather imports for compilation |
||||
* @param files file sources |
||||
* @param importHints import file list |
||||
* @param cb callback |
||||
*/ |
||||
|
||||
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.
|
||||
const importRegex: RegExp = /^\s*import\s*[\'\"]([^\'\"]+)[\'\"];/g |
||||
for (const fileName in files) { |
||||
let match: RegExpExecArray | null |
||||
while ((match = importRegex.exec(files[fileName].content))) { |
||||
let importFilePath = match[1] |
||||
if (importFilePath.startsWith('./')) { |
||||
const path: RegExpExecArray | null = /(.*\/).*/.exec(fileName) |
||||
importFilePath = path ? importFilePath.replace('./', path[1]) : importFilePath.slice(2) |
||||
} |
||||
if (!importHints.includes(importFilePath)) importHints.push(importFilePath) |
||||
} |
||||
} |
||||
while (importHints.length > 0) { |
||||
const m: string = importHints.pop() as string |
||||
if (m && m in files) continue |
||||
|
||||
if (this.handleImportCall) { |
||||
this.handleImportCall(m, (err, content: string) => { |
||||
if (err && cb) cb(err) |
||||
else { |
||||
files[m] = { content } |
||||
this.gatherImports(files, importHints, cb) |
||||
} |
||||
}) |
||||
} |
||||
return |
||||
} |
||||
if(cb) |
||||
cb(null, { 'sources': files }) |
||||
} |
||||
|
||||
/** |
||||
* @dev Truncate version string |
||||
* @param version version |
||||
*/ |
||||
|
||||
truncateVersion (version: string): string { |
||||
const tmp: RegExpExecArray | null = /^(\d+.\d+.\d+)/.exec(version) |
||||
return tmp ? tmp[1] : version |
||||
} |
||||
|
||||
/** |
||||
* @dev Update ABI according to current compiler version |
||||
* @param data Compilation result |
||||
*/ |
||||
|
||||
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,
|
||||
// we default to accept the fallback function (which expect raw data as argument).
|
||||
contract.object.abi.push({ |
||||
'payable': true, |
||||
'stateMutability': 'payable', |
||||
'type': 'fallback' |
||||
}) |
||||
} |
||||
if(data && data.contracts && this.state.currentVersion) |
||||
data.contracts[contract.file][contract.name].abi = update(this.truncateVersion(this.state.currentVersion), contract.object.abi) |
||||
}) |
||||
return data |
||||
} |
||||
|
||||
/** |
||||
* @dev Get contract obj of the given contract name from last compilation result. |
||||
* @param name contract name |
||||
*/ |
||||
|
||||
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) |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* @dev Call the given callback for all the contracts from last compilation result |
||||
* @param cb callback |
||||
*/ |
||||
|
||||
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) |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* @dev Get the compiled contracts data from last compilation result |
||||
*/ |
||||
|
||||
getContracts () : CompilationResult['contracts'] | null { |
||||
if (this.state.lastCompilationResult && this.state.lastCompilationResult.data && this.state.lastCompilationResult.data.contracts) { |
||||
return this.state.lastCompilationResult.data.contracts |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* @dev Get sources from last compilation result |
||||
*/ |
||||
|
||||
getSources () : Source | null | undefined { |
||||
if (this.state.lastCompilationResult && this.state.lastCompilationResult.source) { |
||||
return this.state.lastCompilationResult.source.sources |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* @dev Get sources of passed file name from last compilation result |
||||
* @param fileName file name |
||||
*/ |
||||
|
||||
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] |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* @dev Get source name at passed index from last compilation result |
||||
* @param index - index of the source |
||||
*/ |
||||
|
||||
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] |
||||
} |
||||
return null |
||||
} |
||||
} |
||||
|
@ -1,33 +0,0 @@ |
||||
'use strict' |
||||
|
||||
module.exports = { |
||||
|
||||
/** |
||||
* return the contract obj of the given @arg name. Uses last compilation result. |
||||
* return null if not found |
||||
* @param {String} name - contract name |
||||
* @returns contract obj and associated file: { contract, file } or null |
||||
*/ |
||||
getContract: (contractName, contracts) => { |
||||
for (let file in contracts) { |
||||
if (contracts[file][contractName]) { |
||||
return { object: contracts[file][contractName], file: file } |
||||
} |
||||
} |
||||
return null |
||||
}, |
||||
|
||||
/** |
||||
* call the given @arg cb (function) for all the contracts. Uses last compilation result |
||||
* stop visiting when cb return true |
||||
* @param {Function} cb - callback |
||||
*/ |
||||
visitContracts: (contracts, cb) => { |
||||
for (let file in contracts) { |
||||
for (let name in contracts[file]) { |
||||
if (cb({ name: name, object: contracts[file][name], file: file })) return |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,40 @@ |
||||
'use strict' |
||||
|
||||
import { CompilationResult, visitContractsCallbackParam, visitContractsCallbackInterface } from './types' |
||||
export default { |
||||
|
||||
/** |
||||
* @dev Get contract obj of given contract name from last compilation result. |
||||
* @param name contract name |
||||
* @param contracts 'contracts' object from last compilation result |
||||
*/ |
||||
|
||||
getContract: (contractName: string, contracts: CompilationResult["contracts"]) : Record<string, any> | null => { |
||||
for (const file in contracts) { |
||||
if (contracts[file][contractName]) { |
||||
return { object: contracts[file][contractName], file: file } |
||||
} |
||||
} |
||||
return null |
||||
}, |
||||
|
||||
/** |
||||
* @dev call the given callback for all contracts from last compilation result, stop visiting when cb return true |
||||
* @param contracts - 'contracts' object from last compilation result |
||||
* @param cb - callback |
||||
*/ |
||||
|
||||
visitContracts: (contracts: CompilationResult["contracts"], cb: visitContractsCallbackInterface) : void => { |
||||
for (const file in contracts) { |
||||
for (const name in contracts[file]) { |
||||
const param: visitContractsCallbackParam = {
|
||||
name: name,
|
||||
object: contracts[file][name],
|
||||
file: file
|
||||
} |
||||
if (cb(param)) return |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,481 @@ |
||||
export interface CompilerInput { |
||||
// Required: Source code language. Currently supported are "Solidity" and "Yul".
|
||||
language: Language, |
||||
// Required
|
||||
sources: Source, |
||||
// Optional
|
||||
settings: |
||||
{ |
||||
// Optional: Sorted list of remappings
|
||||
remappings?: string[], |
||||
// Optional: Optimizer settings
|
||||
optimizer: { |
||||
// disabled by default
|
||||
enabled: boolean, |
||||
// Optimize for how many times you intend to run the code.
|
||||
// Lower values will optimize more for initial deployment cost, higher
|
||||
// values will optimize more for high-frequency usage.
|
||||
runs: number, |
||||
// Switch optimizer components on or off in detail.
|
||||
// The "enabled" switch above provides two defaults which can be
|
||||
// tweaked here. If "details" is given, "enabled" can be omitted.
|
||||
details?: { |
||||
// The peephole optimizer is always on if no details are given,
|
||||
// use details to switch it off.
|
||||
peephole?: boolean, |
||||
// The unused jumpdest remover is always on if no details are given,
|
||||
// use details to switch it off.
|
||||
jumpdestRemover?: boolean, |
||||
// Sometimes re-orders literals in commutative operations.
|
||||
orderLiterals?: boolean, |
||||
// Removes duplicate code blocks
|
||||
deduplicate?: boolean, |
||||
// Common subexpression elimination, this is the most complicated step but
|
||||
// can also provide the largest gain.
|
||||
cse?: boolean, |
||||
// Optimize representation of literal numbers and strings in code.
|
||||
constantOptimizer?: boolean, |
||||
// The new Yul optimizer. Mostly operates on the code of ABIEncoderV2.
|
||||
// It can only be activated through the details here.
|
||||
yul?: boolean, |
||||
// Tuning options for the Yul optimizer.
|
||||
yulDetails?: { |
||||
// Improve allocation of stack slots for variables, can free up stack slots early.
|
||||
// Activated by default if the Yul optimizer is activated.
|
||||
stackAllocation: boolean |
||||
} |
||||
} |
||||
}, |
||||
// Version of the EVM to compile for.
|
||||
// Affects type checking and code generation.
|
||||
evmVersion?: EVMVersion, |
||||
// Optional: Debugging settings
|
||||
debug?: { |
||||
// How to treat revert (and require) reason strings. Settings are
|
||||
// "default", "strip", "debug" and "verboseDebug".
|
||||
// "default" does not inject compiler-generated revert strings and keeps user-supplied ones.
|
||||
// "strip" removes all revert strings (if possible, i.e. if literals are used) keeping side-effects
|
||||
// "debug" injects strings for compiler-generated internal reverts (not yet implemented)
|
||||
// "verboseDebug" even appends further information to user-supplied revert strings (not yet implemented)
|
||||
revertStrings: 'default' | 'strip' | 'debug' | 'verboseDebug' |
||||
} |
||||
// Metadata settings (optional)
|
||||
metadata?: { |
||||
// Use only literal content and not URLs (false by default)
|
||||
useLiteralContent: boolean, |
||||
// Use the given hash method for the metadata hash that is appended to the bytecode.
|
||||
// The metadata hash can be removed from the bytecode via option "none".
|
||||
// The other options are "ipfs" and "bzzr1".
|
||||
// If the option is omitted, "ipfs" is used by default.
|
||||
bytecodeHash: 'ipfs' | 'bzzr1' | 'none' |
||||
}, |
||||
// Addresses of the libraries. If not all libraries are given here,
|
||||
// it can result in unlinked objects whose output data is different.
|
||||
libraries?: { |
||||
// The top level key is the the name of the source file where the library is used.
|
||||
// If remappings are used, this source file should match the global path
|
||||
// after remappings were applied.
|
||||
// If this key is an empty string, that refers to a global level.
|
||||
[fileName: string]: Record<string, string> |
||||
} |
||||
// The following can be used to select desired outputs based
|
||||
// on file and contract names.
|
||||
// If this field is omitted, then the compiler loads and does type checking,
|
||||
// but will not generate any outputs apart from errors.
|
||||
// The first level key is the file name and the second level key is the contract name.
|
||||
// An empty contract name is used for outputs that are not tied to a contract
|
||||
// but to the whole source file like the AST.
|
||||
// A star as contract name refers to all contracts in the file.
|
||||
// Similarly, a star as a file name matches all files.
|
||||
// To select all outputs the compiler can possibly generate, use
|
||||
// "outputSelection: { "*": { "*": [ "*" ], "": [ "*" ] } }"
|
||||
// but note that this might slow down the compilation process needlessly.
|
||||
//
|
||||
// The available output types are as follows:
|
||||
//
|
||||
// File level (needs empty string as contract name):
|
||||
// ast - AST of all source files
|
||||
// legacyAST - legacy AST of all source files
|
||||
//
|
||||
// Contract level (needs the contract name or "*"):
|
||||
// abi - ABI
|
||||
// devdoc - Developer documentation (natspec)
|
||||
// userdoc - User documentation (natspec)
|
||||
// metadata - Metadata
|
||||
// ir - Yul intermediate representation of the code before optimization
|
||||
// irOptimized - Intermediate representation after optimization
|
||||
// storageLayout - Slots, offsets and types of the contract's state variables.
|
||||
// evm.assembly - New assembly format
|
||||
// evm.legacyAssembly - Old-style assembly format in JSON
|
||||
// evm.bytecode.object - Bytecode object
|
||||
// evm.bytecode.opcodes - Opcodes list
|
||||
// evm.bytecode.sourceMap - Source mapping (useful for debugging)
|
||||
// evm.bytecode.linkReferences - Link references (if unlinked object)
|
||||
// evm.deployedBytecode* - Deployed bytecode (has the same options as evm.bytecode)
|
||||
// evm.methodIdentifiers - The list of function hashes
|
||||
// evm.gasEstimates - Function gas estimates
|
||||
// ewasm.wast - eWASM S-expressions format (not supported at the moment)
|
||||
// ewasm.wasm - eWASM binary format (not supported at the moment)
|
||||
//
|
||||
// Note that using a using `evm`, `evm.bytecode`, `ewasm`, etc. will select every
|
||||
// target part of that output. Additionally, `*` can be used as a wildcard to request everything.
|
||||
//
|
||||
outputSelection?: { |
||||
'*': { |
||||
'': [ 'legacyAST', 'ast' ], |
||||
'*': [ 'abi', 'metadata', 'devdoc', 'userdoc', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates' ] |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
export interface Source { |
||||
[fileName: string]: |
||||
{ |
||||
// Optional: keccak256 hash of the source file
|
||||
keccak256?: string, |
||||
// Required (unless "urls" is used): literal contents of the source file
|
||||
content: string, |
||||
urls?: string[] |
||||
} |
||||
} |
||||
|
||||
export interface CompilerInputOptions { |
||||
optimize: boolean | number, |
||||
libraries?: { |
||||
[fileName: string]: Record<string, string> |
||||
}, |
||||
evmVersion?: EVMVersion, |
||||
language?: Language |
||||
} |
||||
|
||||
export type EVMVersion = 'homestead' | 'tangerineWhistle' | 'spuriousDragon' | 'byzantium' | 'constantinople' | 'petersburg' | 'istanbul' | 'berlin' | null |
||||
|
||||
export type Language = 'Solidity' | 'Yul' |
||||
|
||||
export interface CompilerState { |
||||
compileJSON: ((input: SourceWithTarget) => void) | null, |
||||
worker: any, |
||||
currentVersion: string| null| undefined, |
||||
optimize: boolean, |
||||
evmVersion: EVMVersion| null, |
||||
language: Language, |
||||
compilationStartTime: number| null, |
||||
target: string | null, |
||||
lastCompilationResult: { |
||||
data: CompilationResult | null, |
||||
source: SourceWithTarget | null | undefined |
||||
} | null |
||||
} |
||||
|
||||
export interface SourceWithTarget { |
||||
sources?: Source, |
||||
target?: string | null | undefined |
||||
} |
||||
|
||||
export interface MessageToWorker { |
||||
cmd: string, |
||||
job?: number, |
||||
input?: CompilerInput, |
||||
data?: string |
||||
} |
||||
|
||||
export interface MessageFromWorker { |
||||
cmd: string, |
||||
job?: number, |
||||
missingInputs?: string[], |
||||
data?: string |
||||
} |
||||
|
||||
export interface visitContractsCallbackParam { |
||||
name: string,
|
||||
object: CompiledContract, |
||||
file: string |
||||
} |
||||
|
||||
export interface visitContractsCallbackInterface { |
||||
(param: visitContractsCallbackParam): boolean | void |
||||
} |
||||
|
||||
export interface gatherImportsCallbackInterface { |
||||
(err?: Error | null, result?: SourceWithTarget) : any |
||||
} |
||||
|
||||
export interface CompilationResult { |
||||
error?: CompilationError, |
||||
/** not present if no errors/warnings were encountered */ |
||||
errors?: CompilationError[] |
||||
/** This contains the file-level outputs. In can be limited/filtered by the outputSelection settings */ |
||||
sources?: { |
||||
[contractName: string]: CompilationSource |
||||
} |
||||
/** This contains the contract-level outputs. It can be limited/filtered by the outputSelection settings */ |
||||
contracts?: { |
||||
/** If the language used has no contract names, this field should equal to an empty string. */ |
||||
[fileName: string]: { |
||||
[contract: string]: CompiledContract |
||||
} |
||||
} |
||||
} |
||||
|
||||
///////////
|
||||
// ERROR //
|
||||
///////////
|
||||
|
||||
export interface CompilationError { |
||||
/** Location within the source file */ |
||||
sourceLocation?: { |
||||
file: string |
||||
start: number |
||||
end: number |
||||
} |
||||
/** Error type */ |
||||
type?: CompilationErrorType |
||||
/** Component where the error originated, such as "general", "ewasm", etc. */ |
||||
component?: 'general' | 'ewasm' | string |
||||
severity?: 'error' | 'warning' |
||||
message?: string |
||||
mode?: 'panic' |
||||
/** the message formatted with source location */ |
||||
formattedMessage?: string |
||||
} |
||||
|
||||
type CompilationErrorType = |
||||
| 'JSONError' |
||||
| 'IOError' |
||||
| 'ParserError' |
||||
| 'DocstringParsingError' |
||||
| 'SyntaxError' |
||||
| 'DeclarationError' |
||||
| 'TypeError' |
||||
| 'UnimplementedFeatureError' |
||||
| 'InternalCompilerError' |
||||
| 'Exception' |
||||
| 'CompilerError' |
||||
| 'FatalError' |
||||
| 'Warning' |
||||
|
||||
////////////
|
||||
// SOURCE //
|
||||
////////////
|
||||
export interface CompilationSource { |
||||
/** Identifier of the source (used in source maps) */ |
||||
id: number |
||||
/** The AST object */ |
||||
ast: AstNode |
||||
/** The legacy AST object */ |
||||
legacyAST: AstNodeLegacy |
||||
} |
||||
|
||||
/////////
|
||||
// AST //
|
||||
/////////
|
||||
export interface AstNode { |
||||
absolutePath?: string |
||||
exportedSymbols?: Object |
||||
id: number |
||||
nodeType: string |
||||
nodes?: Array<AstNode> |
||||
src: string |
||||
literals?: Array<string> |
||||
file?: string |
||||
scope?: number |
||||
sourceUnit?: number |
||||
symbolAliases?: Array<string> |
||||
[x: string]: any |
||||
} |
||||
|
||||
export interface AstNodeLegacy { |
||||
id: number |
||||
name: string |
||||
src: string |
||||
children?: Array<AstNodeLegacy> |
||||
attributes?: AstNodeAtt |
||||
} |
||||
|
||||
export interface AstNodeAtt { |
||||
operator?: string |
||||
string?: null |
||||
type?: string |
||||
value?: string |
||||
constant?: boolean |
||||
name?: string |
||||
public?: boolean |
||||
exportedSymbols?: Object |
||||
argumentTypes?: null |
||||
absolutePath?: string |
||||
[x: string]: any |
||||
} |
||||
|
||||
//////////////
|
||||
// CONTRACT //
|
||||
//////////////
|
||||
export interface CompiledContract { |
||||
/** The Ethereum Contract ABI. If empty, it is represented as an empty array. */ |
||||
abi: ABIDescription[] |
||||
// See the Metadata Output documentation (serialised JSON string)
|
||||
metadata: string |
||||
/** User documentation (natural specification) */ |
||||
userdoc: UserDocumentation |
||||
/** Developer documentation (natural specification) */ |
||||
devdoc: DeveloperDocumentation |
||||
/** Intermediate representation (string) */ |
||||
ir: string |
||||
/** EVM-related outputs */ |
||||
evm: { |
||||
assembly: string |
||||
legacyAssembly: {} |
||||
/** Bytecode and related details. */ |
||||
bytecode: BytecodeObject |
||||
deployedBytecode: BytecodeObject |
||||
/** The list of function hashes */ |
||||
methodIdentifiers: { |
||||
[functionIdentifier: string]: string |
||||
} |
||||
// Function gas estimates
|
||||
gasEstimates: { |
||||
creation: { |
||||
codeDepositCost: string |
||||
executionCost: 'infinite' | string |
||||
totalCost: 'infinite' | string |
||||
} |
||||
external: { |
||||
[functionIdentifier: string]: string |
||||
} |
||||
internal: { |
||||
[functionIdentifier: string]: 'infinite' | string |
||||
} |
||||
} |
||||
} |
||||
/** eWASM related outputs */ |
||||
ewasm: { |
||||
/** S-expressions format */ |
||||
wast: string |
||||
/** Binary format (hex string) */ |
||||
wasm: string |
||||
} |
||||
} |
||||
|
||||
/////////
|
||||
// ABI //
|
||||
/////////
|
||||
export type ABIDescription = FunctionDescription | EventDescription |
||||
|
||||
export interface FunctionDescription { |
||||
/** Type of the method. default is 'function' */ |
||||
type?: 'function' | 'constructor' | 'fallback' | 'receive' |
||||
/** The name of the function. Constructor and fallback function never have name */ |
||||
name?: string |
||||
/** List of parameters of the method. Fallback function doesn’t have inputs. */ |
||||
inputs?: ABIParameter[] |
||||
/** List of the outputs parameters for the method, if any */ |
||||
outputs?: ABIParameter[] |
||||
/** State mutability of the method */ |
||||
stateMutability: 'pure' | 'view' | 'nonpayable' | 'payable' |
||||
/** true if function accepts Ether, false otherwise. Default is false */ |
||||
payable?: boolean |
||||
/** true if function is either pure or view, false otherwise. Default is false */ |
||||
constant?: boolean |
||||
} |
||||
|
||||
export interface EventDescription { |
||||
type: 'event' |
||||
name: string |
||||
inputs: ABIParameter & |
||||
{ |
||||
/** true if the field is part of the log’s topics, false if it one of the log’s data segment. */ |
||||
indexed: boolean |
||||
}[] |
||||
/** true if the event was declared as anonymous. */ |
||||
anonymous: boolean |
||||
} |
||||
|
||||
export interface ABIParameter { |
||||
/** The name of the parameter */ |
||||
name: string |
||||
/** The canonical type of the parameter */ |
||||
type: ABITypeParameter |
||||
/** Used for tuple types */ |
||||
components?: ABIParameter[] |
||||
} |
||||
|
||||
export type ABITypeParameter = |
||||
| 'uint' |
||||
| 'uint[]' // TODO : add <M>
|
||||
| 'int' |
||||
| 'int[]' // TODO : add <M>
|
||||
| 'address' |
||||
| 'address[]' |
||||
| 'bool' |
||||
| 'bool[]' |
||||
| 'fixed' |
||||
| 'fixed[]' // TODO : add <M>
|
||||
| 'ufixed' |
||||
| 'ufixed[]' // TODO : add <M>
|
||||
| 'bytes' |
||||
| 'bytes[]' // TODO : add <M>
|
||||
| 'function' |
||||
| 'function[]' |
||||
| 'tuple' |
||||
| 'tuple[]' |
||||
| string // Fallback
|
||||
|
||||
///////////////////////////
|
||||
// NATURAL SPECIFICATION //
|
||||
///////////////////////////
|
||||
|
||||
// Userdoc
|
||||
export interface UserDocumentation { |
||||
methods: UserMethodList |
||||
notice: string |
||||
} |
||||
|
||||
export type UserMethodList = { |
||||
[functionIdentifier: string]: UserMethodDoc |
||||
} & { |
||||
'constructor'?: string |
||||
} |
||||
export interface UserMethodDoc { |
||||
notice: string |
||||
} |
||||
|
||||
// Devdoc
|
||||
export interface DeveloperDocumentation { |
||||
author: string |
||||
title: string |
||||
details: string |
||||
methods: DevMethodList |
||||
} |
||||
|
||||
export interface DevMethodList { |
||||
[functionIdentifier: string]: DevMethodDoc |
||||
} |
||||
|
||||
export interface DevMethodDoc { |
||||
author: string |
||||
details: string |
||||
return: string |
||||
params: { |
||||
[param: string]: string |
||||
} |
||||
} |
||||
|
||||
//////////////
|
||||
// BYTECODE //
|
||||
//////////////
|
||||
export interface BytecodeObject { |
||||
/** The bytecode as a hex string. */ |
||||
object: string |
||||
/** Opcodes list */ |
||||
opcodes: string |
||||
/** The source mapping as a string. See the source mapping definition. */ |
||||
sourceMap: string |
||||
/** If given, this is an unlinked object. */ |
||||
linkReferences?: { |
||||
[contractName: string]: { |
||||
/** Byte offsets into the bytecode. */ |
||||
[library: string]: { start: number; length: number }[] |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
{ |
||||
"include": ["src", "index.ts"], |
||||
"compilerOptions": { |
||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ |
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ |
||||
"lib": ["dom", "es2018"], /* Specify library files to be included in the compilation. */ |
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */ |
||||
"sourceMap": true, /* Generates corresponding '.map' file. */ |
||||
"outDir": "./dist", /* Redirect output structure to the directory. */ |
||||
/* Strict Type-Checking Options */ |
||||
"strict": true, /* Enable all strict type-checking options. */ |
||||
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */ |
||||
/* Module Resolution Options */ |
||||
"baseUrl": "./src", /* Base directory to resolve non-absolute module names. */ |
||||
"paths": { "remix-solidity": ["./"] }, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ |
||||
"typeRoots": [ |
||||
"./@types", |
||||
"./node_modules/@types" |
||||
], |
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ |
||||
/* Experimental Options */ |
||||
"experimentalDecorators": false, /* Enables experimental support for ES7 decorators. */ |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue