diff --git a/.prettierrc.json b/.prettierrc.json index f6ca428..fa51da2 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -2,5 +2,5 @@ "trailingComma": "es5", "tabWidth": 2, "semi": false, - "singleQuote": false + "singleQuote": true } diff --git a/crates/solidity/src/tests/cli-tests/src/entities.ts b/crates/solidity/src/tests/cli-tests/src/entities.ts index 4189c93..d2f9f45 100644 --- a/crates/solidity/src/tests/cli-tests/src/entities.ts +++ b/crates/solidity/src/tests/cli-tests/src/entities.ts @@ -1,19 +1,33 @@ -import * as path from 'path'; +import * as path from 'path' -const outputDir = 'artifacts'; -const binExtension = ':C.pvm'; -const asmExtension = ':C.pvmasm'; -const llvmExtension = '.ll'; -const contractSolFilename = 'contract.sol'; -const contractYulFilename = 'contract.yul'; -const contractOptimizedLLVMFilename = contractSolFilename + '.C.optimized'; -const contractUnoptimizedLLVMFilename = contractSolFilename + '.C.unoptimized'; -const pathToOutputDir = path.join(__dirname, '..', outputDir); -const pathToContracts = path.join(__dirname, '..', 'src', 'contracts'); -const pathToBasicYulContract = path.join(pathToContracts, 'yul', contractYulFilename); -const pathToBasicSolContract = path.join(pathToContracts, 'solidity', contractSolFilename); -const pathToSolBinOutputFile = path.join(pathToOutputDir, contractSolFilename + binExtension); -const pathToSolAsmOutputFile = path.join(pathToOutputDir, contractSolFilename + asmExtension); +const outputDir = 'artifacts' +const binExtension = ':C.pvm' +const asmExtension = ':C.pvmasm' +const llvmExtension = '.ll' +const contractSolFilename = 'contract.sol' +const contractYulFilename = 'contract.yul' +const contractOptimizedLLVMFilename = contractSolFilename + '.C.optimized' +const contractUnoptimizedLLVMFilename = contractSolFilename + '.C.unoptimized' +const pathToOutputDir = path.join(__dirname, '..', outputDir) +const pathToContracts = path.join(__dirname, '..', 'src', 'contracts') +const pathToBasicYulContract = path.join( + pathToContracts, + 'yul', + contractYulFilename +) +const pathToBasicSolContract = path.join( + pathToContracts, + 'solidity', + contractSolFilename +) +const pathToSolBinOutputFile = path.join( + pathToOutputDir, + contractSolFilename + binExtension +) +const pathToSolAsmOutputFile = path.join( + pathToOutputDir, + contractSolFilename + asmExtension +) export const paths = { outputDir: outputDir, @@ -30,4 +44,4 @@ export const paths = { pathToBasicYulContract: pathToBasicYulContract, pathToSolBinOutputFile: pathToSolBinOutputFile, pathToSolAsmOutputFile: pathToSolAsmOutputFile, -}; +} diff --git a/crates/solidity/src/tests/cli-tests/src/helper.ts b/crates/solidity/src/tests/cli-tests/src/helper.ts index e1f7332..d237d8d 100644 --- a/crates/solidity/src/tests/cli-tests/src/helper.ts +++ b/crates/solidity/src/tests/cli-tests/src/helper.ts @@ -1,44 +1,51 @@ -import * as shell from 'shelljs'; -import * as fs from 'fs'; -import { spawnSync } from 'child_process'; +import * as shell from 'shelljs' +import * as fs from 'fs' +import { spawnSync } from 'child_process' interface CommandResult { - output: string; - exitCode: number; + output: string + exitCode: number } -export const executeCommand = (command: string, stdin?: string): CommandResult => { - if (stdin) { - const process = spawnSync(command, [], { - input: stdin, - shell: true, - encoding: 'utf8', - maxBuffer: 30 * 1024 * 1024 - }); +export const executeCommand = ( + command: string, + stdin?: string +): CommandResult => { + if (stdin) { + const process = spawnSync(command, [], { + input: stdin, + shell: true, + encoding: 'utf8', + maxBuffer: 30 * 1024 * 1024, + }) - return { - exitCode: process.status || 0, - output: (process.stdout || process.stderr || '').toString() - }; - } - - const result = shell.exec(command, { silent: true, async: false }); return { - exitCode: result.code, - output: result.stdout || result.stderr || '' - }; -}; + exitCode: process.status || 0, + output: (process.stdout || process.stderr || '').toString(), + } + } + + const result = shell.exec(command, { silent: true, async: false }) + return { + exitCode: result.code, + output: result.stdout || result.stderr || '', + } +} export const isFolderExist = (folder: string): boolean => { - return shell.test('-d', folder); -}; + return shell.test('-d', folder) +} -export const isFileExist = (pathToFileDir: string, fileName: string, fileExtension: string): boolean => { - return shell.ls(pathToFileDir).stdout.includes(fileName + fileExtension); -}; +export const isFileExist = ( + pathToFileDir: string, + fileName: string, + fileExtension: string +): boolean => { + return shell.ls(pathToFileDir).stdout.includes(fileName + fileExtension) +} export const isFileEmpty = (file: string): boolean => { - if (fs.existsSync(file)) { - return (fs.readFileSync(file).length === 0); - } -}; + if (fs.existsSync(file)) { + return fs.readFileSync(file).length === 0 + } +} diff --git a/crates/solidity/src/tests/cli-tests/tests/asm.test.ts b/crates/solidity/src/tests/cli-tests/tests/asm.test.ts index 6c178d6..c068274 100644 --- a/crates/solidity/src/tests/cli-tests/tests/asm.test.ts +++ b/crates/solidity/src/tests/cli-tests/tests/asm.test.ts @@ -1,43 +1,44 @@ -import {executeCommand} from "../src/helper"; -import { paths } from '../src/entities'; - +import { executeCommand } from '../src/helper' +import { paths } from '../src/entities' //id1746 -describe("Run with --asm by default", () => { - const command = `resolc ${paths.pathToBasicSolContract} --asm`; - const result = executeCommand(command); - const commandInvalid = 'resolc --asm'; - const resultInvalid = executeCommand(commandInvalid); +describe('Run with --asm by default', () => { + const command = `resolc ${paths.pathToBasicSolContract} --asm` + const result = executeCommand(command) + const commandInvalid = 'resolc --asm' + const resultInvalid = executeCommand(commandInvalid) - it("Valid command exit code = 0", () => { - expect(result.exitCode).toBe(0); - }); + it('Valid command exit code = 0', () => { + expect(result.exitCode).toBe(0) + }) - it("--asm output is presented", () => { - const expectedPatterns = [/(deploy)/i, /(call)/i, /(seal_return)/i]; + it('--asm output is presented', () => { + const expectedPatterns = [/(deploy)/i, /(call)/i, /(seal_return)/i] for (const pattern of expectedPatterns) { - expect(result.output).toMatch(pattern); + expect(result.output).toMatch(pattern) } - }); + }) - it("solc exit code == resolc exit code", () => { - const command = `solc ${paths.pathToBasicSolContract} --asm`; - const solcResult = executeCommand(command); - expect(solcResult.exitCode).toBe(result.exitCode); - }); + it('solc exit code == resolc exit code', () => { + const command = `solc ${paths.pathToBasicSolContract} --asm` + const solcResult = executeCommand(command) + expect(solcResult.exitCode).toBe(result.exitCode) + }) - it("run invalid: resolc --asm", () => { - expect(resultInvalid.output).toMatch(/(No input sources specified|Compilation aborted)/i); - }); - - it("Invalid command exit code = 1", () => { - expect(resultInvalid.exitCode).toBe(1); - }); + it('run invalid: resolc --asm', () => { + expect(resultInvalid.output).toMatch( + /(No input sources specified|Compilation aborted)/i + ) + }) - it("Invalid solc exit code == Invalid resolc exit code", () => { - const command = 'solc --asm'; - const solcResult = executeCommand(command); - expect(solcResult.exitCode).toBe(resultInvalid.exitCode); - }); -}); \ No newline at end of file + it('Invalid command exit code = 1', () => { + expect(resultInvalid.exitCode).toBe(1) + }) + + it('Invalid solc exit code == Invalid resolc exit code', () => { + const command = 'solc --asm' + const solcResult = executeCommand(command) + expect(solcResult.exitCode).toBe(resultInvalid.exitCode) + }) +}) diff --git a/crates/solidity/src/tests/cli-tests/tests/common.test.ts b/crates/solidity/src/tests/cli-tests/tests/common.test.ts index 0ed795f..c3ab4d2 100644 --- a/crates/solidity/src/tests/cli-tests/tests/common.test.ts +++ b/crates/solidity/src/tests/cli-tests/tests/common.test.ts @@ -1,191 +1,241 @@ -import { executeCommand, isFolderExist, isFileExist, isFileEmpty } from "../src/helper"; -import { paths } from '../src/entities'; -import * as shell from 'shelljs'; -import * as path from 'path'; - +import { + executeCommand, + isFolderExist, + isFileExist, + isFileEmpty, +} from '../src/helper' +import { paths } from '../src/entities' +import * as shell from 'shelljs' +import * as path from 'path' //id1762 -describe("Run resolc without any options", () => { - const command = 'resolc'; - const result = executeCommand(command); +describe('Run resolc without any options', () => { + const command = 'resolc' + const result = executeCommand(command) - it("Info with help is presented", () => { - expect(result.output).toMatch(/(Usage: resolc)/i); - }); + it('Info with help is presented', () => { + expect(result.output).toMatch(/(Usage: resolc)/i) + }) - it("Exit code = 1", () => { - expect(result.exitCode).toBe(1); - }); - - it("solc exit code == resolc exit code", () => { - const command = 'solc'; - const solcResult = executeCommand(command); - expect(solcResult.exitCode).toBe(result.exitCode); - }); -}); + it('Exit code = 1', () => { + expect(result.exitCode).toBe(1) + }) + it('solc exit code == resolc exit code', () => { + const command = 'solc' + const solcResult = executeCommand(command) + expect(solcResult.exitCode).toBe(result.exitCode) + }) +}) //#1713 -describe("Default run a command from the help", () => { +describe('Default run a command from the help', () => { + const command = `resolc ${paths.pathToBasicSolContract} --overwrite -O3 --bin --output-dir "${paths.pathToOutputDir}"` // potential issue on resolc with full path on Windows cmd + const result = executeCommand(command) - const command = `resolc ${paths.pathToBasicSolContract} --overwrite -O3 --bin --output-dir "${paths.pathToOutputDir}"`; // potential issue on resolc with full path on Windows cmd - const result = executeCommand(command); - - it("Compiler run successful", () => { - expect(result.output).toMatch(/(Compiler run successful.)/i); - }); - it("Exit code = 0", () => { - expect(result.exitCode).toBe(0); - }); - it("Output dir is created", () => { - expect(isFolderExist(paths.pathToOutputDir)).toBe(true); - }); - xit("Output file is created", () => { // a bug on windows - expect(isFileExist(paths.pathToOutputDir, paths.contractSolFilename, paths.binExtension)).toBe(true); - }); - it("the output file is not empty", () => { - expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false); - }); - it("No 'Error'/'Warning'/'Fail' in the output", () => { - expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i); - }); -}); + it('Compiler run successful', () => { + expect(result.output).toMatch(/(Compiler run successful.)/i) + }) + it('Exit code = 0', () => { + expect(result.exitCode).toBe(0) + }) + it('Output dir is created', () => { + expect(isFolderExist(paths.pathToOutputDir)).toBe(true) + }) + xit('Output file is created', () => { + // a bug on windows + expect( + isFileExist( + paths.pathToOutputDir, + paths.contractSolFilename, + paths.binExtension + ) + ).toBe(true) + }) + it('the output file is not empty', () => { + expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false) + }) + it("No 'Error'/'Warning'/'Fail' in the output", () => { + expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i) + }) +}) //#1818 -describe("Default run a command from the help", () => { +describe('Default run a command from the help', () => { + const command = `resolc ${paths.pathToBasicSolContract} --overwrite -O3 --bin --asm --output-dir "${paths.pathToOutputDir}"` // potential issue on resolc with full path on Windows cmd + const result = executeCommand(command) - const command = `resolc ${paths.pathToBasicSolContract} --overwrite -O3 --bin --asm --output-dir "${paths.pathToOutputDir}"`; // potential issue on resolc with full path on Windows cmd - const result = executeCommand(command); + it('Compiler run successful', () => { + expect(result.output).toMatch(/(Compiler run successful.)/i) + }) + it('Exit code = 0', () => { + expect(result.exitCode).toBe(0) + }) + it('Output dir is created', () => { + expect(isFolderExist(paths.pathToOutputDir)).toBe(true) + }) + xit('Output files are created', () => { + // a bug on windows + expect( + isFileExist( + paths.pathToOutputDir, + paths.contractSolFilename, + paths.binExtension + ) + ).toBe(true) + expect( + isFileExist( + paths.pathToOutputDir, + paths.contractSolFilename, + paths.asmExtension + ) + ).toBe(true) + }) + it('the output files are not empty', () => { + expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false) + expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false) + }) + it("No 'Error'/'Warning'/'Fail' in the output", () => { + expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i) + }) +}) - it("Compiler run successful", () => { - expect(result.output).toMatch(/(Compiler run successful.)/i); - }); - it("Exit code = 0", () => { - expect(result.exitCode).toBe(0); - }); - it("Output dir is created", () => { - expect(isFolderExist(paths.pathToOutputDir)).toBe(true); - }); - xit("Output files are created", () => { // a bug on windows - expect(isFileExist(paths.pathToOutputDir, paths.contractSolFilename, paths.binExtension)).toBe(true); - expect(isFileExist(paths.pathToOutputDir, paths.contractSolFilename, paths.asmExtension)).toBe(true); - }); - it("the output files are not empty", () => { - expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false); - expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false); - }); - it("No 'Error'/'Warning'/'Fail' in the output", () => { - expect(result.output).not.toMatch(/([Ee]rror|[Ww]arning|[Ff]ail)/i); - }); -}); +describe('Run resolc with source debug information', () => { + const commands = [ + `resolc -g ${paths.pathToBasicSolContract} --overwrite --bin --asm --output-dir "${paths.pathToOutputDir}"`, + `resolc --disable-solc-optimizer -g ${paths.pathToBasicSolContract} --overwrite --bin --asm --output-dir "${paths.pathToOutputDir}"`, + ] // potential issue on resolc with full path on Windows cmd`; -describe("Run resolc with source debug information", () => { - const commands = [ - `resolc -g ${paths.pathToBasicSolContract} --overwrite --bin --asm --output-dir "${paths.pathToOutputDir}"`, - `resolc --disable-solc-optimizer -g ${paths.pathToBasicSolContract} --overwrite --bin --asm --output-dir "${paths.pathToOutputDir}"` - ]; // potential issue on resolc with full path on Windows cmd`; + for (var idx in commands) { + const command = commands[idx] + const result = executeCommand(command) - for (var idx in commands) { - const command = commands[idx]; - const result = executeCommand(command); + it('Compiler run successful', () => { + expect(result.output).toMatch(/(Compiler run successful.)/i) + }) + it('Exit code = 0', () => { + expect(result.exitCode).toBe(0) + }) + it('Output dir is created', () => { + expect(isFolderExist(paths.pathToOutputDir)).toBe(true) + }) + it('Output files are created', () => { + // a bug on windows + expect( + isFileExist( + paths.pathToOutputDir, + paths.contractSolFilename, + paths.binExtension + ) + ).toBe(true) + expect( + isFileExist( + paths.pathToOutputDir, + paths.contractSolFilename, + paths.asmExtension + ) + ).toBe(true) + }) + it('the output files are not empty', () => { + expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false) + expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false) + }) + it("No 'Error'/'Fail' in the output", () => { + expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i) + }) + } +}) - it("Compiler run successful", () => { - expect(result.output).toMatch(/(Compiler run successful.)/i); - }); - it("Exit code = 0", () => { - expect(result.exitCode).toBe(0); - }); - it("Output dir is created", () => { - expect(isFolderExist(paths.pathToOutputDir)).toBe(true); - }); - it("Output files are created", () => { // a bug on windows - expect(isFileExist(paths.pathToOutputDir, paths.contractSolFilename, paths.binExtension)).toBe(true); - expect(isFileExist(paths.pathToOutputDir, paths.contractSolFilename, paths.asmExtension)).toBe(true); - }); - it("the output files are not empty", () => { - expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false); - expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false); - }); - it("No 'Error'/'Fail' in the output", () => { - expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i); - }); - } -}); +describe('Run resolc with source debug information, check LLVM debug-info', () => { + const commands = [ + `resolc -g ${paths.pathToBasicSolContract} --overwrite --debug-output-dir="${paths.pathToOutputDir}"`, + `resolc -g --disable-solc-optimizer ${paths.pathToBasicSolContract} --overwrite --debug-output-dir="${paths.pathToOutputDir}"`, + ] // potential issue on resolc with full path on Windows cmd`; -describe("Run resolc with source debug information, check LLVM debug-info", () => { - const commands = [ - `resolc -g ${paths.pathToBasicSolContract} --overwrite --debug-output-dir="${paths.pathToOutputDir}"`, - `resolc -g --disable-solc-optimizer ${paths.pathToBasicSolContract} --overwrite --debug-output-dir="${paths.pathToOutputDir}"` - ]; // potential issue on resolc with full path on Windows cmd`; + for (var idx in commands) { + const command = commands[idx] + const result = executeCommand(command) - for (var idx in commands) { - const command = commands[idx]; - const result = executeCommand(command); + it('Compiler run successful', () => { + expect(result.output).toMatch(/(Compiler run successful.)/i) + }) + it('Exit code = 0', () => { + expect(result.exitCode).toBe(0) + }) + it('Output dir is created', () => { + expect(isFolderExist(paths.pathToOutputDir)).toBe(true) + }) + it('Output files are created', () => { + // a bug on windows + expect( + isFileExist( + paths.pathToOutputDir, + paths.contractOptimizedLLVMFilename, + paths.llvmExtension + ) + ).toBe(true) + expect( + isFileExist( + paths.pathToOutputDir, + paths.contractUnoptimizedLLVMFilename, + paths.llvmExtension + ) + ).toBe(true) + }) + it('the output files are not empty', () => { + expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false) + expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false) + }) + it("No 'Error'/'Fail' in the output", () => { + expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i) + }) + } +}) - it("Compiler run successful", () => { - expect(result.output).toMatch(/(Compiler run successful.)/i); - }); - it("Exit code = 0", () => { - expect(result.exitCode).toBe(0); - }); - it("Output dir is created", () => { - expect(isFolderExist(paths.pathToOutputDir)).toBe(true); - }); - it("Output files are created", () => { // a bug on windows - expect(isFileExist(paths.pathToOutputDir, paths.contractOptimizedLLVMFilename, paths.llvmExtension)).toBe(true); - expect(isFileExist(paths.pathToOutputDir, paths.contractUnoptimizedLLVMFilename, paths.llvmExtension)).toBe(true); - }); - it("the output files are not empty", () => { - expect(isFileEmpty(paths.pathToSolBinOutputFile)).toBe(false); - expect(isFileEmpty(paths.pathToSolAsmOutputFile)).toBe(false); - }); - it("No 'Error'/'Fail' in the output", () => { - expect(result.output).not.toMatch(/([Ee]rror|[Ff]ail)/i); - }); - } -}); +describe('Standard JSON compilation with path options', () => { + const contractsDir = path.join(shell.tempdir(), 'contracts-test') + const inputFile = path.join(__dirname, '..', 'src/contracts/compiled/1.json') + beforeAll(() => { + shell.mkdir('-p', contractsDir) + const input = JSON.parse(shell.cat(inputFile).toString()) -describe("Standard JSON compilation with path options", () => { - const contractsDir = path.join(shell.tempdir(), 'contracts-test'); - const inputFile = path.join(__dirname, '..', 'src/contracts/compiled/1.json'); + Object.entries(input.sources).forEach( + ([sourcePath, source]: [string, any]) => { + const filePath = path.join(contractsDir, sourcePath) + shell.mkdir('-p', path.dirname(filePath)) + shell.ShellString(source.content).to(filePath) + } + ) + }) + + afterAll(() => { + shell.rm('-rf', contractsDir) + }) + + describe('Output with all path options', () => { + let result: { exitCode: number; output: string } beforeAll(() => { - shell.mkdir('-p', contractsDir); + const tempInputFile = path.join(contractsDir, 'temp-input.json') + shell.cp(inputFile, tempInputFile) + const inputContent = shell.cat(inputFile).toString() - const input = JSON.parse(shell.cat(inputFile).toString()); + const command = `resolc --standard-json --base-path "${contractsDir}" --include-path "${contractsDir}" --allow-paths "${contractsDir}"` - Object.entries(input.sources).forEach(([sourcePath, source]: [string, any]) => { - const filePath = path.join(contractsDir, sourcePath); - shell.mkdir('-p', path.dirname(filePath)); - shell.ShellString(source.content).to(filePath); - }); - }); + result = executeCommand(command, inputContent) - afterAll(() => { - shell.rm('-rf', contractsDir); - }); + shell.rm(tempInputFile) + }) - describe("Output with all path options", () => { - let result: { exitCode: number; output: string }; - - beforeAll(() => { - const tempInputFile = path.join(contractsDir, 'temp-input.json'); - shell.cp(inputFile, tempInputFile); - const inputContent = shell.cat(inputFile).toString(); - - const command = `resolc --standard-json --base-path "${contractsDir}" --include-path "${contractsDir}" --allow-paths "${contractsDir}"`; - - result = executeCommand(command, inputContent); - - shell.rm(tempInputFile); - - }); - - it("Compiler run successful without emiting warnings", () => { - const parsedResults = JSON.parse(result.output) - expect(parsedResults.errors.filter((error: { type: string; }) => error.type != 'Warning')).toEqual([]); - }); - }); -}); \ No newline at end of file + it('Compiler run successful without emiting warnings', () => { + const parsedResults = JSON.parse(result.output) + expect( + parsedResults.errors.filter( + (error: { type: string }) => error.type != 'Warning' + ) + ).toEqual([]) + }) + }) +}) diff --git a/crates/solidity/src/tests/cli-tests/tests/yul.test.ts b/crates/solidity/src/tests/cli-tests/tests/yul.test.ts index 79700b3..b3d866b 100644 --- a/crates/solidity/src/tests/cli-tests/tests/yul.test.ts +++ b/crates/solidity/src/tests/cli-tests/tests/yul.test.ts @@ -1,40 +1,39 @@ -import {executeCommand} from "../src/helper"; -import { paths } from '../src/entities'; - +import { executeCommand } from '../src/helper' +import { paths } from '../src/entities' //id1743 -describe("Run with --yul by default", () => { - const command = `resolc ${paths.pathToBasicYulContract} --yul`; - const result = executeCommand(command); - const commandInvalid = 'resolc --yul'; - const resultInvalid = executeCommand(commandInvalid); +describe('Run with --yul by default', () => { + const command = `resolc ${paths.pathToBasicYulContract} --yul` + const result = executeCommand(command) + const commandInvalid = 'resolc --yul' + const resultInvalid = executeCommand(commandInvalid) - it("Valid command exit code = 0", () => { - expect(result.exitCode).toBe(0); - }); + it('Valid command exit code = 0', () => { + expect(result.exitCode).toBe(0) + }) - it("--yul output is presented", () => { - expect(result.output).toMatch(/(Compiler run successful)/i); - expect(result.output).toMatch(/(No output requested)/i); - }); + it('--yul output is presented', () => { + expect(result.output).toMatch(/(Compiler run successful)/i) + expect(result.output).toMatch(/(No output requested)/i) + }) + xit('solc exit code == resolc exit code', () => { + // unknown solc issue for datatype of the contract + const command = `solc ${paths.pathToBasicSolContract} --yul` + const solcResult = executeCommand(command) + expect(solcResult.exitCode).toBe(result.exitCode) + }) - xit("solc exit code == resolc exit code", () => { // unknown solc issue for datatype of the contract - const command = `solc ${paths.pathToBasicSolContract} --yul`; - const solcResult = executeCommand(command); - expect(solcResult.exitCode).toBe(result.exitCode); - }); + it('run invalid: resolc --yul', () => { + expect(resultInvalid.output).toMatch(/(The input file is missing)/i) + }) + it('Invalid command exit code = 1', () => { + expect(resultInvalid.exitCode).toBe(1) + }) - it("run invalid: resolc --yul", () => { - expect(resultInvalid.output).toMatch(/(The input file is missing)/i); - }); - it("Invalid command exit code = 1", () => { - expect(resultInvalid.exitCode).toBe(1); - }); - - it("Invalid solc exit code == Invalid resolc exit code", () => { - const command = 'solc --yul'; - const solcResult = executeCommand(command); - expect(solcResult.exitCode).toBe(resultInvalid.exitCode); - }); -}); + it('Invalid solc exit code == Invalid resolc exit code', () => { + const command = 'solc --yul' + const solcResult = executeCommand(command) + expect(solcResult.exitCode).toBe(resultInvalid.exitCode) + }) +}) diff --git a/crates/solidity/src/tests/combined-json.tests.ts b/crates/solidity/src/tests/combined-json.tests.ts index 6dc1b25..d417c32 100644 --- a/crates/solidity/src/tests/combined-json.tests.ts +++ b/crates/solidity/src/tests/combined-json.tests.ts @@ -1,153 +1,188 @@ -import { executeCommand } from "../src/helper"; -import { paths } from '../src/entities'; +import { executeCommand } from '../src/helper' +import { paths } from '../src/entities' +describe('Set of --combined-json tests', () => { + const zksolcCommand = 'zksolc' + const solcCommand = 'solc' + const json_args: string[] = [ + `abi`, + `hashes`, + `metadata`, + `devdoc`, + `userdoc`, + `storage-layout`, + `ast`, + `asm`, + `bin`, + `bin-runtime`, + ] -describe("Set of --combined-json tests", () => { - const zksolcCommand = 'zksolc'; - const solcCommand = 'solc'; - const json_args: string[] = [`abi`, `hashes`, `metadata`, `devdoc`, `userdoc`, `storage-layout`, `ast`, `asm`, `bin`, `bin-runtime`]; + //id1742:I + describe(`Run ${zksolcCommand} with just --combined-json`, () => { + const args = [`--combined-json`] + const result = executeCommand(zksolcCommand, args) - //id1742:I - describe(`Run ${zksolcCommand} with just --combined-json`, () => { - const args = [`--combined-json`]; - const result = executeCommand(zksolcCommand, args); + it('Valid command exit code = 1', () => { + expect(result.exitCode).toBe(1) + }) - it("Valid command exit code = 1", () => { - expect(result.exitCode).toBe(1); - }); + it('--combined-json error is presented', () => { + expect(result.output).toMatch(/(requires a value but none was supplied)/i) + }) - it("--combined-json error is presented", () => { - expect(result.output).toMatch(/(requires a value but none was supplied)/i); - }); + it('solc exit code == zksolc exit code', () => { + const solcResult = executeCommand(solcCommand, args) + expect(solcResult.exitCode).toBe(result.exitCode) + }) + }) - it("solc exit code == zksolc exit code", () => { - const solcResult = executeCommand(solcCommand, args); - expect(solcResult.exitCode).toBe(result.exitCode); - }); - }); + //id1742:II + describe(`Run ${zksolcCommand} with Sol contract and --combined-json`, () => { + const args = [`${paths.pathToBasicSolContract}`, `--combined-json`] + const result = executeCommand(zksolcCommand, args) - //id1742:II - describe(`Run ${zksolcCommand} with Sol contract and --combined-json`, () => { - const args = [`${paths.pathToBasicSolContract}`, `--combined-json`]; - const result = executeCommand(zksolcCommand, args); + it('Valid command exit code = 1', () => { + expect(result.exitCode).toBe(1) + }) - it("Valid command exit code = 1", () => { - expect(result.exitCode).toBe(1); - }); + it('--combined-json error is presented', () => { + expect(result.output).toMatch(/(requires a value but none was supplied)/i) + }) - it("--combined-json error is presented", () => { - expect(result.output).toMatch(/(requires a value but none was supplied)/i); - }); + it('solc exit code == zksolc exit code', () => { + const solcResult = executeCommand(solcCommand, args) + expect(solcResult.exitCode).toBe(result.exitCode) + }) + }) - it("solc exit code == zksolc exit code", () => { - const solcResult = executeCommand(solcCommand, args); - expect(solcResult.exitCode).toBe(result.exitCode); - }); - }); + //id1742:III + for (let i = 0; i < json_args.length; i++) { + describe(`Run ${zksolcCommand} with Sol, --combined-json and ARG: ${json_args[i]}`, () => { + const args = [ + `${paths.pathToBasicSolContract}`, + `--combined-json`, + `${json_args[i]}`, + ] + const result = executeCommand(zksolcCommand, args) - //id1742:III - for (let i = 0; i < json_args.length; i++) { - describe(`Run ${zksolcCommand} with Sol, --combined-json and ARG: ${json_args[i]}`, () => { - const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `${json_args[i]}`]; - const result = executeCommand(zksolcCommand, args); + it('Valid command exit code = 0', () => { + expect(result.exitCode).toBe(0) + }) - it("Valid command exit code = 0", () => { - expect(result.exitCode).toBe(0); - }); + it('--combined-json error is presented', () => { + expect(result.output).toMatch(/(contracts)/i) + }) - it("--combined-json error is presented", () => { - expect(result.output).toMatch(/(contracts)/i); - }); + it('solc exit code == zksolc exit code', () => { + const solcResult = executeCommand(solcCommand, args) + expect(solcResult.exitCode).toBe(result.exitCode) + }) + }) + } - it("solc exit code == zksolc exit code", () => { - const solcResult = executeCommand(solcCommand, args); - expect(solcResult.exitCode).toBe(result.exitCode); - }); - }); - } + //id1829:I + for (let i = 0; i < json_args.length; i++) { + describe(`Run ${zksolcCommand} with Sol, --combined-json and wrong ARG: --${json_args[i]}`, () => { + const args = [ + `${paths.pathToBasicSolContract}`, + `--combined-json`, + `--${json_args[i]}`, + ] + const result = executeCommand(zksolcCommand, args) - //id1829:I - for (let i = 0; i < json_args.length; i++) { - describe(`Run ${zksolcCommand} with Sol, --combined-json and wrong ARG: --${json_args[i]}`, () => { - const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `--${json_args[i]}`]; - const result = executeCommand(zksolcCommand, args); + it('Valid command exit code = 1', () => { + expect(result.exitCode).toBe(1) + }) - it("Valid command exit code = 1", () => { - expect(result.exitCode).toBe(1); - }); + it('--combined-json error is presented', () => { + expect(result.output).toMatch(/(Invalid option|error)/i) + }) - it("--combined-json error is presented", () => { - expect(result.output).toMatch(/(Invalid option|error)/i); - }); + it('solc exit code == zksolc exit code', () => { + const solcResult = executeCommand(solcCommand, args) + expect(solcResult.exitCode).toBe(result.exitCode) + }) + }) + } - it("solc exit code == zksolc exit code", () => { - const solcResult = executeCommand(solcCommand, args); - expect(solcResult.exitCode).toBe(result.exitCode); - }); - }); - } + //id1829:II + for (let i = 0; i < json_args.length; i++) { + describe(`Run ${zksolcCommand} with Sol, --combined-json and multiple ARG: ${json_args[i]} ${json_args[i]}`, () => { + const args = [ + `${paths.pathToBasicSolContract}`, + `--combined-json`, + `${json_args[i]}`, + `${json_args[i]}`, + ] + const result = executeCommand(zksolcCommand, args) - //id1829:II - for (let i = 0; i < json_args.length; i++) { - describe(`Run ${zksolcCommand} with Sol, --combined-json and multiple ARG: ${json_args[i]} ${json_args[i]}`, () => { - const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `${json_args[i]}`, `${json_args[i]}`]; - const result = executeCommand(zksolcCommand, args); + xit('Valid command exit code = 1', () => { + expect(result.exitCode).toBe(1) + }) - xit("Valid command exit code = 1", () => { - expect(result.exitCode).toBe(1); - }); + it('--combined-json error is presented', () => { + expect(result.output).toMatch( + /(No such file or directory|cannot find the file specified)/i + ) // Hopefully we should have more precise message here! + }) - it("--combined-json error is presented", () => { - expect(result.output).toMatch(/(No such file or directory|cannot find the file specified)/i); // Hopefully we should have more precise message here! - }); + xit('solc exit code == zksolc exit code', () => { + const solcResult = executeCommand(solcCommand, args) + expect(solcResult.exitCode).toBe(result.exitCode) + }) + }) + } - xit("solc exit code == zksolc exit code", () => { - const solcResult = executeCommand(solcCommand, args); - expect(solcResult.exitCode).toBe(result.exitCode); - }); - }); - } + //id1829:III + for (let i = 0; i < json_args.length; i++) { + describe(`Run ${zksolcCommand} with Sol, and multiple (--combined-json ${json_args[i]})`, () => { + const args = [ + `${paths.pathToBasicSolContract}`, + `--combined-json`, + `${json_args[i]}`, + `--combined-json`, + `${json_args[i]}`, + ] + const result = executeCommand(zksolcCommand, args) - //id1829:III - for (let i = 0; i < json_args.length; i++) { - describe(`Run ${zksolcCommand} with Sol, and multiple (--combined-json ${json_args[i]})`, () => { - const args = [`${paths.pathToBasicSolContract}`, `--combined-json`, `${json_args[i]}`, `--combined-json`, `${json_args[i]}`]; - const result = executeCommand(zksolcCommand, args); + it('Valid command exit code = 1', () => { + expect(result.exitCode).toBe(1) + }) - it("Valid command exit code = 1", () => { - expect(result.exitCode).toBe(1); - }); + it('--combined-json error is presented', () => { + expect(result.output).toMatch(/(cannot be used multiple times)/i) + }) - it("--combined-json error is presented", () => { - expect(result.output).toMatch(/(cannot be used multiple times)/i); - }); + it('solc exit code == zksolc exit code', () => { + const solcResult = executeCommand(solcCommand, args) + expect(solcResult.exitCode).toBe(result.exitCode) + }) + }) + } - it("solc exit code == zksolc exit code", () => { - const solcResult = executeCommand(solcCommand, args); - expect(solcResult.exitCode).toBe(result.exitCode); - }); - }); - } + //id1830 + for (let i = 0; i < json_args.length; i++) { + describe(`Run ${zksolcCommand} with Yul, and --combined-json ${json_args[i]}`, () => { + const args = [ + `${paths.pathToBasicYulContract}`, + `--combined-json`, + `${json_args[i]}`, + ] + const result = executeCommand(zksolcCommand, args) - //id1830 - for (let i = 0; i < json_args.length; i++) { - describe(`Run ${zksolcCommand} with Yul, and --combined-json ${json_args[i]}`, () => { - const args = [`${paths.pathToBasicYulContract}`, `--combined-json`, `${json_args[i]}`]; - const result = executeCommand(zksolcCommand, args); + it('Valid command exit code = 1', () => { + expect(result.exitCode).toBe(1) + }) - it("Valid command exit code = 1", () => { - expect(result.exitCode).toBe(1); - }); + it('--combined-json error is presented', () => { + expect(result.output).toMatch(/(ParserError: Expected identifier)/i) + }) + asd - it("--combined-json error is presented", () => { - expect(result.output).toMatch(/(ParserError: Expected identifier)/i); - }); - asd - - it("solc exit code == zksolc exit code", () => { - const solcResult = executeCommand(solcCommand, args); - expect(solcResult.exitCode).toBe(result.exitCode); - }); - }); - } -}); + it('solc exit code == zksolc exit code', () => { + const solcResult = executeCommand(solcCommand, args) + expect(solcResult.exitCode).toBe(result.exitCode) + }) + }) + } +}) diff --git a/eslint.config.mjs b/eslint.config.mjs index 2db5ff9..b2e494b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -4,8 +4,8 @@ import tseslint from 'typescript-eslint' /** @type {import('eslint').Linter.Config[]} */ export default [ - { files: ['**/*.{mjs,ts}'] }, - { languageOptions: { globals: globals.browser } }, - pluginJs.configs.recommended, - ...tseslint.configs.recommended, + { files: ['**/*.{mjs,ts}'] }, + { languageOptions: { globals: globals.browser } }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, ] diff --git a/js/emscripten/tests/node.test.mjs b/js/emscripten/tests/node.test.mjs index ad3f9e5..cb6f56e 100644 --- a/js/emscripten/tests/node.test.mjs +++ b/js/emscripten/tests/node.test.mjs @@ -1,142 +1,138 @@ -import { expect } from "chai"; -import { compile } from "../examples/node/revive.js"; -import { fileURLToPath } from "url"; -import path from "path"; -import fs from "fs"; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); +import { expect } from 'chai' +import { compile } from '../examples/node/revive.js' +import { fileURLToPath } from 'url' +import path from 'path' +import fs from 'fs' +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) function loadFixture(fixture) { - const fixturePath = path.resolve(__dirname, `../fixtures/${fixture}`); - return JSON.parse(fs.readFileSync(fixturePath, "utf-8")); + const fixturePath = path.resolve(__dirname, `../fixtures/${fixture}`) + return JSON.parse(fs.readFileSync(fixturePath, 'utf-8')) } -describe("Compile Function Tests", function () { - it("should successfully compile valid Solidity code", async function () { - const standardInput = loadFixture("storage.json"); +describe('Compile Function Tests', function () { + it('should successfully compile valid Solidity code', async function () { + const standardInput = loadFixture('storage.json') - const result = await compile(standardInput); - expect(result).to.be.a("string"); - const output = JSON.parse(result); - expect(output).to.have.property("contracts"); - expect(output.contracts["fixtures/storage.sol"]).to.have.property( - "Storage", - ); - expect(output.contracts["fixtures/storage.sol"].Storage).to.have.property( - "abi", - ); - expect(output.contracts["fixtures/storage.sol"].Storage).to.have.property( - "evm", - ); + const result = await compile(standardInput) + expect(result).to.be.a('string') + const output = JSON.parse(result) + expect(output).to.have.property('contracts') + expect(output.contracts['fixtures/storage.sol']).to.have.property('Storage') + expect(output.contracts['fixtures/storage.sol'].Storage).to.have.property( + 'abi' + ) + expect(output.contracts['fixtures/storage.sol'].Storage).to.have.property( + 'evm' + ) expect( - output.contracts["fixtures/storage.sol"].Storage.evm, - ).to.have.property("bytecode"); - }); + output.contracts['fixtures/storage.sol'].Storage.evm + ).to.have.property('bytecode') + }) - if (typeof globalThis.Bun == "undefined") { + if (typeof globalThis.Bun == 'undefined') { // Running this test with Bun on a Linux host causes: // RuntimeError: Out of bounds memory access (evaluating 'getWasmTableEntry(index)(a1, a2, a3, a4, a5)') // Once this issue is resolved, the test will be re-enabled. - it("should successfully compile large Solidity code", async function () { - const standardInput = loadFixture("token.json"); + it('should successfully compile large Solidity code', async function () { + const standardInput = loadFixture('token.json') - const result = await compile(standardInput); - expect(result).to.be.a("string"); - const output = JSON.parse(result); - expect(output).to.have.property("contracts"); - expect(output.contracts["fixtures/token.sol"]).to.have.property( - "MyToken", - ); - expect(output.contracts["fixtures/token.sol"].MyToken).to.have.property( - "abi", - ); - expect(output.contracts["fixtures/token.sol"].MyToken).to.have.property( - "evm", - ); + const result = await compile(standardInput) + expect(result).to.be.a('string') + const output = JSON.parse(result) + expect(output).to.have.property('contracts') + expect(output.contracts['fixtures/token.sol']).to.have.property('MyToken') + expect(output.contracts['fixtures/token.sol'].MyToken).to.have.property( + 'abi' + ) + expect(output.contracts['fixtures/token.sol'].MyToken).to.have.property( + 'evm' + ) expect( - output.contracts["fixtures/token.sol"].MyToken.evm, - ).to.have.property("bytecode"); - }); + output.contracts['fixtures/token.sol'].MyToken.evm + ).to.have.property('bytecode') + }) - it("should successfully compile a valid Solidity contract that instantiates the token contracts", async function () { - const standardInput = loadFixture("instantiate_tokens.json"); + it('should successfully compile a valid Solidity contract that instantiates the token contracts', async function () { + const standardInput = loadFixture('instantiate_tokens.json') - const result = await compile(standardInput); - expect(result).to.be.a("string"); - const output = JSON.parse(result); - expect(output).to.have.property("contracts"); + const result = await compile(standardInput) + expect(result).to.be.a('string') + const output = JSON.parse(result) + expect(output).to.have.property('contracts') expect( - output.contracts["fixtures/instantiate_tokens.sol"], - ).to.have.property("TokensFactory"); + output.contracts['fixtures/instantiate_tokens.sol'] + ).to.have.property('TokensFactory') expect( - output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory, - ).to.have.property("abi"); + output.contracts['fixtures/instantiate_tokens.sol'].TokensFactory + ).to.have.property('abi') expect( - output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory, - ).to.have.property("evm"); + output.contracts['fixtures/instantiate_tokens.sol'].TokensFactory + ).to.have.property('evm') expect( - output.contracts["fixtures/instantiate_tokens.sol"].TokensFactory.evm, - ).to.have.property("bytecode"); - }); + output.contracts['fixtures/instantiate_tokens.sol'].TokensFactory.evm + ).to.have.property('bytecode') + }) } - it("should throw an error for invalid Solidity code", async function () { - const standardInput = loadFixture("invalid_contract_content.json"); + it('should throw an error for invalid Solidity code', async function () { + const standardInput = loadFixture('invalid_contract_content.json') - const result = await compile(standardInput); - expect(result).to.be.a("string"); - const output = JSON.parse(result); - expect(output).to.have.property("errors"); - expect(output.errors).to.be.an("array"); - expect(output.errors.length).to.be.greaterThan(0); - expect(output.errors[0].type).to.exist; - expect(output.errors[0].type).to.contain("ParserError"); - }); + const result = await compile(standardInput) + expect(result).to.be.a('string') + const output = JSON.parse(result) + expect(output).to.have.property('errors') + expect(output.errors).to.be.an('array') + expect(output.errors.length).to.be.greaterThan(0) + expect(output.errors[0].type).to.exist + expect(output.errors[0].type).to.contain('ParserError') + }) - it("should return not found error for missing imports", async function () { - const standardInput = loadFixture("missing_import.json"); + it('should return not found error for missing imports', async function () { + const standardInput = loadFixture('missing_import.json') - const result = await compile(standardInput); - const output = JSON.parse(result); - expect(output).to.have.property("errors"); - expect(output.errors).to.be.an("array"); - expect(output.errors.length).to.be.greaterThan(0); - expect(output.errors[0].message).to.exist; + const result = await compile(standardInput) + const output = JSON.parse(result) + expect(output).to.have.property('errors') + expect(output.errors).to.be.an('array') + expect(output.errors.length).to.be.greaterThan(0) + expect(output.errors[0].message).to.exist expect(output.errors[0].message).to.include( - 'Source "nonexistent/console.sol" not found', - ); - }); + 'Source "nonexistent/console.sol" not found' + ) + }) - it("should successfully compile a valid Solidity contract that instantiates another contract", async function () { - const standardInput = loadFixture("instantiate.json"); + it('should successfully compile a valid Solidity contract that instantiates another contract', async function () { + const standardInput = loadFixture('instantiate.json') - const result = await compile(standardInput); - expect(result).to.be.a("string"); - const output = JSON.parse(result); - expect(output).to.have.property("contracts"); - expect(output.contracts["fixtures/instantiate.sol"]).to.have.property( - "ChildContract", - ); + const result = await compile(standardInput) + expect(result).to.be.a('string') + const output = JSON.parse(result) + expect(output).to.have.property('contracts') + expect(output.contracts['fixtures/instantiate.sol']).to.have.property( + 'ChildContract' + ) expect( - output.contracts["fixtures/instantiate.sol"].ChildContract, - ).to.have.property("abi"); + output.contracts['fixtures/instantiate.sol'].ChildContract + ).to.have.property('abi') expect( - output.contracts["fixtures/instantiate.sol"].ChildContract, - ).to.have.property("evm"); + output.contracts['fixtures/instantiate.sol'].ChildContract + ).to.have.property('evm') expect( - output.contracts["fixtures/instantiate.sol"].ChildContract.evm, - ).to.have.property("bytecode"); - expect(output.contracts["fixtures/instantiate.sol"]).to.have.property( - "MainContract", - ); + output.contracts['fixtures/instantiate.sol'].ChildContract.evm + ).to.have.property('bytecode') + expect(output.contracts['fixtures/instantiate.sol']).to.have.property( + 'MainContract' + ) expect( - output.contracts["fixtures/instantiate.sol"].MainContract, - ).to.have.property("abi"); + output.contracts['fixtures/instantiate.sol'].MainContract + ).to.have.property('abi') expect( - output.contracts["fixtures/instantiate.sol"].MainContract, - ).to.have.property("evm"); + output.contracts['fixtures/instantiate.sol'].MainContract + ).to.have.property('evm') expect( - output.contracts["fixtures/instantiate.sol"].MainContract.evm, - ).to.have.property("bytecode"); - }); -}); + output.contracts['fixtures/instantiate.sol'].MainContract.evm + ).to.have.property('bytecode') + }) +}) diff --git a/js/resolc/src/bin.ts b/js/resolc/src/bin.ts index 21f432d..a607ad3 100755 --- a/js/resolc/src/bin.ts +++ b/js/resolc/src/bin.ts @@ -8,196 +8,193 @@ import * as resolc from '.' import { SolcInput } from '.' async function main() { - // hold on to any exception handlers that existed prior to this script running, we'll be adding them back at the end - const originalUncaughtExceptionListeners = - process.listeners('uncaughtException') - // FIXME: remove annoying exception catcher of Emscripten - // see https://github.com/chriseth/browser-solidity/issues/167 - process.removeAllListeners('uncaughtException') + // hold on to any exception handlers that existed prior to this script running, we'll be adding them back at the end + const originalUncaughtExceptionListeners = + process.listeners('uncaughtException') + // FIXME: remove annoying exception catcher of Emscripten + // see https://github.com/chriseth/browser-solidity/issues/167 + process.removeAllListeners('uncaughtException') - const program = new commander.Command() + const program = new commander.Command() - program.name('solcjs') - program.version(resolc.version()) - program - .option('--bin', 'Binary of the contracts in hex.') - .option('--abi', 'ABI of the contracts.') - .option( - '--base-path ', - 'Root of the project source tree. ' + - 'The import callback will attempt to interpret all import paths as relative to this directory.' - ) - .option( - '--include-path ', - 'Extra source directories available to the import callback. ' + - 'When using a package manager to install libraries, use this option to specify directories where packages are installed. ' + - 'Can be used multiple times to provide multiple locations.' - ) - .option( - '-o, --output-dir ', - 'Output directory for the contracts.' - ) - .option('-p, --pretty-json', 'Pretty-print all JSON output.', false) - .option('-v, --verbose', 'More detailed console output.', false) - .argument('') + program.name('solcjs') + program.version(resolc.version()) + program + .option('--bin', 'Binary of the contracts in hex.') + .option('--abi', 'ABI of the contracts.') + .option( + '--base-path ', + 'Root of the project source tree. ' + + 'The import callback will attempt to interpret all import paths as relative to this directory.' + ) + .option( + '--include-path ', + 'Extra source directories available to the import callback. ' + + 'When using a package manager to install libraries, use this option to specify directories where packages are installed. ' + + 'Can be used multiple times to provide multiple locations.' + ) + .option( + '-o, --output-dir ', + 'Output directory for the contracts.' + ) + .option('-p, --pretty-json', 'Pretty-print all JSON output.', false) + .option('-v, --verbose', 'More detailed console output.', false) + .argument('') - program.parse(process.argv) - const options = program.opts<{ - verbose: boolean - abi: boolean - bin: boolean - outputDir?: string - prettyJson: boolean - basePath?: string - includePath?: string[] - }>() - const files: string[] = program.args - const destination = options.outputDir ?? '.' + program.parse(process.argv) + const options = program.opts<{ + verbose: boolean + abi: boolean + bin: boolean + outputDir?: string + prettyJson: boolean + basePath?: string + includePath?: string[] + }>() + const files: string[] = program.args + const destination = options.outputDir ?? '.' - function abort(msg: string) { - console.error(msg || 'Error occurred') - process.exit(1) + function abort(msg: string) { + console.error(msg || 'Error occurred') + process.exit(1) + } + + function withUnixPathSeparators(filePath: string) { + // On UNIX-like systems forward slashes in paths are just a part of the file name. + if (os.platform() !== 'win32') { + return filePath } - function withUnixPathSeparators(filePath: string) { - // On UNIX-like systems forward slashes in paths are just a part of the file name. - if (os.platform() !== 'win32') { - return filePath - } + return filePath.replace(/\\/g, '/') + } - return filePath.replace(/\\/g, '/') - } - - function makeSourcePathRelativeIfPossible(sourcePath: string) { - const absoluteBasePath = options.basePath - ? path.resolve(options.basePath) - : path.resolve('.') - const absoluteIncludePaths = options.includePath - ? options.includePath.map((prefix: string) => { - return path.resolve(prefix) - }) - : [] - - // Compared to base path stripping logic in solc this is much simpler because path.resolve() - // handles symlinks correctly (does not resolve them except in work dir) and strips .. segments - // from paths going beyond root (e.g. `/../../a/b/c` -> `/a/b/c/`). It's simpler also because it - // ignores less important corner cases: drive letters are not stripped from absolute paths on - // Windows and UNC paths are not handled in a special way (at least on Linux). Finally, it has - // very little test coverage so there might be more differences that we are just not aware of. - const absoluteSourcePath = path.resolve(sourcePath) - - for (const absolutePrefix of [absoluteBasePath].concat( - absoluteIncludePaths - )) { - const relativeSourcePath = path.relative( - absolutePrefix, - absoluteSourcePath - ) - - if (!relativeSourcePath.startsWith('../')) { - return withUnixPathSeparators(relativeSourcePath) - } - } - - // File is not located inside base path or include paths so use its absolute path. - return withUnixPathSeparators(absoluteSourcePath) - } - - function toFormattedJson(input: T) { - return JSON.stringify(input, null, options.prettyJson ? 4 : 0) - } - - if (files.length === 0) { - console.error('Must provide a file') - process.exit(1) - } - - if (!(options.bin || options.abi)) { - abort('Invalid option selected, must specify either --bin or --abi') - } - - const sources: SolcInput = {} - - for (let i = 0; i < files.length; i++) { - try { - sources[makeSourcePathRelativeIfPossible(files[i])] = { - content: fs.readFileSync(files[i]).toString(), - } - } catch (e) { - abort('Error reading ' + files[i] + ': ' + e) - } - } - - if (options.verbose) { - console.log('>>> Compiling:\n' + toFormattedJson(sources) + '\n') - } - - const output = await resolc.compile(sources) - let hasError = false - - if (!output) { - abort('No output from compiler') - } else if (output.errors) { - for (const error in output.errors) { - const message = output.errors[error] - if (message.severity === 'warning') { - console.log(message.formattedMessage) - } else { - console.error(message.formattedMessage) - hasError = true - } - } - } - - fs.mkdirSync(destination, { recursive: true }) - - function writeFile(file: string, content: Buffer | string) { - file = path.join(destination, file) - fs.writeFile(file, content, function (err) { - if (err) { - console.error('Failed to write ' + file + ': ' + err) - } + function makeSourcePathRelativeIfPossible(sourcePath: string) { + const absoluteBasePath = options.basePath + ? path.resolve(options.basePath) + : path.resolve('.') + const absoluteIncludePaths = options.includePath + ? options.includePath.map((prefix: string) => { + return path.resolve(prefix) }) + : [] + + // Compared to base path stripping logic in solc this is much simpler because path.resolve() + // handles symlinks correctly (does not resolve them except in work dir) and strips .. segments + // from paths going beyond root (e.g. `/../../a/b/c` -> `/a/b/c/`). It's simpler also because it + // ignores less important corner cases: drive letters are not stripped from absolute paths on + // Windows and UNC paths are not handled in a special way (at least on Linux). Finally, it has + // very little test coverage so there might be more differences that we are just not aware of. + const absoluteSourcePath = path.resolve(sourcePath) + + for (const absolutePrefix of [absoluteBasePath].concat( + absoluteIncludePaths + )) { + const relativeSourcePath = path.relative( + absolutePrefix, + absoluteSourcePath + ) + + if (!relativeSourcePath.startsWith('../')) { + return withUnixPathSeparators(relativeSourcePath) + } } - for (const fileName in output.contracts) { - for (const contractName in output.contracts[fileName]) { - let contractFileName = fileName + ':' + contractName - contractFileName = contractFileName.replace(/[:./\\]/g, '_') + // File is not located inside base path or include paths so use its absolute path. + return withUnixPathSeparators(absoluteSourcePath) + } - if (options.bin) { - writeFile( - contractFileName + '.polkavm', - Buffer.from( - output.contracts[fileName][contractName].evm.bytecode - .object, - 'hex' - ) - ) - } + function toFormattedJson(input: T) { + return JSON.stringify(input, null, options.prettyJson ? 4 : 0) + } - if (options.abi) { - writeFile( - contractFileName + '.abi', - toFormattedJson( - output.contracts[fileName][contractName].abi - ) - ) - } - } + if (files.length === 0) { + console.error('Must provide a file') + process.exit(1) + } + + if (!(options.bin || options.abi)) { + abort('Invalid option selected, must specify either --bin or --abi') + } + + const sources: SolcInput = {} + + for (let i = 0; i < files.length; i++) { + try { + sources[makeSourcePathRelativeIfPossible(files[i])] = { + content: fs.readFileSync(files[i]).toString(), + } + } catch (e) { + abort('Error reading ' + files[i] + ': ' + e) } + } - // Put back original exception handlers. - originalUncaughtExceptionListeners.forEach(function (listener) { - process.addListener('uncaughtException', listener) + if (options.verbose) { + console.log('>>> Compiling:\n' + toFormattedJson(sources) + '\n') + } + + const output = await resolc.compile(sources) + let hasError = false + + if (!output) { + abort('No output from compiler') + } else if (output.errors) { + for (const error in output.errors) { + const message = output.errors[error] + if (message.severity === 'warning') { + console.log(message.formattedMessage) + } else { + console.error(message.formattedMessage) + hasError = true + } + } + } + + fs.mkdirSync(destination, { recursive: true }) + + function writeFile(file: string, content: Buffer | string) { + file = path.join(destination, file) + fs.writeFile(file, content, function (err) { + if (err) { + console.error('Failed to write ' + file + ': ' + err) + } }) + } - if (hasError) { - process.exit(1) + for (const fileName in output.contracts) { + for (const contractName in output.contracts[fileName]) { + let contractFileName = fileName + ':' + contractName + contractFileName = contractFileName.replace(/[:./\\]/g, '_') + + if (options.bin) { + writeFile( + contractFileName + '.polkavm', + Buffer.from( + output.contracts[fileName][contractName].evm.bytecode.object, + 'hex' + ) + ) + } + + if (options.abi) { + writeFile( + contractFileName + '.abi', + toFormattedJson(output.contracts[fileName][contractName].abi) + ) + } } + } + + // Put back original exception handlers. + originalUncaughtExceptionListeners.forEach(function (listener) { + process.addListener('uncaughtException', listener) + }) + + if (hasError) { + process.exit(1) + } } main().catch((err) => { - console.error('Error:', err) - process.exit(1) + console.error('Error:', err) + process.exit(1) }) diff --git a/js/resolc/src/index.test.ts b/js/resolc/src/index.test.ts index 8ea3910..9559321 100644 --- a/js/resolc/src/index.test.ts +++ b/js/resolc/src/index.test.ts @@ -4,112 +4,113 @@ import assert from 'node:assert' import { compile, tryResolveImport } from '.' import { resolve } from 'node:path' - const compileOptions = [{}] if (existsSync('../../target/release/resolc')) { - compileOptions.push({ bin: '../../target/release/resolc' }) + compileOptions.push({ bin: '../../target/release/resolc' }) } for (const options of compileOptions) { - test(`check Ok output with option ${JSON.stringify(options)}`, async () => { - const contract = 'fixtures/token.sol' - const sources = { - [contract]: { - content: readFileSync('fixtures/storage.sol', 'utf8'), - }, - } + test(`check Ok output with option ${JSON.stringify(options)}`, async () => { + const contract = 'fixtures/token.sol' + const sources = { + [contract]: { + content: readFileSync('fixtures/storage.sol', 'utf8'), + }, + } - const out = await compile(sources, options) - assert(out.contracts[contract].Storage.abi != null) - assert(out.contracts[contract].Storage.evm.bytecode != null) - }) + const out = await compile(sources, options) + assert(out.contracts[contract].Storage.abi != null) + assert(out.contracts[contract].Storage.evm.bytecode != null) + }) } test('check Err output', async () => { - const sources = { - bad: { - content: readFileSync('fixtures/storage_bad.sol', 'utf8'), - }, - } + const sources = { + bad: { + content: readFileSync('fixtures/storage_bad.sol', 'utf8'), + }, + } - const out = await compile(sources) - assert( - out?.errors?.[0].message.includes( - 'SPDX license identifier not provided in source file' - ) + const out = await compile(sources) + assert( + out?.errors?.[0].message.includes( + 'SPDX license identifier not provided in source file' ) - assert( - out?.errors?.[1].message.includes( - 'Source file does not specify required compiler version' - ) + ) + assert( + out?.errors?.[1].message.includes( + 'Source file does not specify required compiler version' ) + ) }) test('check Err from stderr', async () => { - const sources = { - bad: { - content: readFileSync('fixtures/bad_pragma.sol', 'utf8'), - }, - } + const sources = { + bad: { + content: readFileSync('fixtures/bad_pragma.sol', 'utf8'), + }, + } - try { - await compile(sources) - assert(false, 'Expected error') - } catch (error) { - assert( - String(error).includes( - 'Source file requires different compiler version' - ) - ) - } + try { + await compile(sources) + assert(false, 'Expected error') + } catch (error) { + assert( + String(error).includes('Source file requires different compiler version') + ) + } }) test('resolve import', () => { - const cases = [ - // local - { - file: './fixtures/storage.sol', - expected: resolve('fixtures/storage.sol'), - }, - // scopped module with version - { - file: '@openzeppelin/contracts@5.1.0/token/ERC20/ERC20.sol', - expected: require.resolve('@openzeppelin/contracts/token/ERC20/ERC20.sol'), - }, - // scopped module without version - { - file: '@openzeppelin/contracts/token/ERC20/ERC20.sol', - expected: require.resolve('@openzeppelin/contracts/token/ERC20/ERC20.sol'), - }, - // scopped module with wrong version - { - file: '@openzeppelin/contracts@4.8.3/token/ERC20/ERC20.sol', - expected: `Error: Version mismatch: Specified @openzeppelin/contracts@4.8.3, but installed version is 5.1.0`, - }, - // module without version - { - file: '@openzeppelin/contracts/package.json', - expected: require.resolve('@openzeppelin/contracts/package.json'), - }, - // scopped module with version - { - file: '@openzeppelin/contracts@5.1.0/package.json', - expected: require.resolve('@openzeppelin/contracts/package.json'), - }, - ] + const cases = [ + // local + { + file: './fixtures/storage.sol', + expected: resolve('fixtures/storage.sol'), + }, + // scopped module with version + { + file: '@openzeppelin/contracts@5.1.0/token/ERC20/ERC20.sol', + expected: require.resolve( + '@openzeppelin/contracts/token/ERC20/ERC20.sol' + ), + }, + // scopped module without version + { + file: '@openzeppelin/contracts/token/ERC20/ERC20.sol', + expected: require.resolve( + '@openzeppelin/contracts/token/ERC20/ERC20.sol' + ), + }, + // scopped module with wrong version + { + file: '@openzeppelin/contracts@4.8.3/token/ERC20/ERC20.sol', + expected: `Error: Version mismatch: Specified @openzeppelin/contracts@4.8.3, but installed version is 5.1.0`, + }, + // module without version + { + file: '@openzeppelin/contracts/package.json', + expected: require.resolve('@openzeppelin/contracts/package.json'), + }, + // scopped module with version + { + file: '@openzeppelin/contracts@5.1.0/package.json', + expected: require.resolve('@openzeppelin/contracts/package.json'), + }, + ] - for (const { file, expected } of cases) { - try { - const resolved = tryResolveImport(file) - assert( - resolved === expected, - `\nGot:\n${resolved}\nExpected:\n${expected}` - ) - } catch (error) { - assert( - String(error) == expected, - `\nGot:\n${String(error)}\nExpected:\n${expected}` - ) - } + for (const { file, expected } of cases) { + try { + const resolved = tryResolveImport(file) + assert( + resolved === expected, + `\nGot:\n${resolved}\nExpected:\n${expected}` + ) + } catch (error) { + assert( + String(error) == expected, + `\nGot:\n${String(error)}\nExpected:\n${expected}` + ) } + } }) diff --git a/js/resolc/src/index.ts b/js/resolc/src/index.ts index 7d17684..e1ee372 100644 --- a/js/resolc/src/index.ts +++ b/js/resolc/src/index.ts @@ -5,114 +5,114 @@ import path from 'path' import { existsSync, readFileSync } from 'fs' export type SolcInput = { - [contractName: string]: { - content: string - } + [contractName: string]: { + content: string + } } export type SolcError = { - component: string - errorCode: string - formattedMessage: string - message: string - severity: string - sourceLocation?: { - file: string - start: number - end: number - } - type: string + component: string + errorCode: string + formattedMessage: string + message: string + severity: string + sourceLocation?: { + file: string + start: number + end: number + } + type: string } export type SolcOutput = { - contracts: { - [contractPath: string]: { - [contractName: string]: { - abi: Array<{ - name: string - inputs: Array<{ name: string; type: string }> - outputs: Array<{ name: string; type: string }> - stateMutability: string - type: string - }> - evm: { - bytecode: { object: string } - } - } + contracts: { + [contractPath: string]: { + [contractName: string]: { + abi: Array<{ + name: string + inputs: Array<{ name: string; type: string }> + outputs: Array<{ name: string; type: string }> + stateMutability: string + type: string + }> + evm: { + bytecode: { object: string } } + } } - errors?: Array + } + errors?: Array } export function resolveInputs(sources: SolcInput): SolcInput { - const input = { - language: 'Solidity', - sources, - settings: { - outputSelection: { - '*': { - '*': ['evm.bytecode.object'], - }, - }, + const input = { + language: 'Solidity', + sources, + settings: { + outputSelection: { + '*': { + '*': ['evm.bytecode.object'], }, - } + }, + }, + } - const out = solc.compile(JSON.stringify(input), { - import: (path: string) => { - return { - contents: readFileSync(tryResolveImport(path), 'utf8'), - } + const out = solc.compile(JSON.stringify(input), { + import: (path: string) => { + return { + contents: readFileSync(tryResolveImport(path), 'utf8'), + } + }, + }) + + const output = JSON.parse(out) as { + sources: { [fileName: string]: { id: number } } + errors: Array + } + + if (output.errors && Object.keys(output.sources).length === 0) { + throw new Error(output.errors[0].formattedMessage) + } + + return Object.fromEntries( + Object.keys(output.sources).map((fileName) => { + return [ + fileName, + sources[fileName] ?? { + content: readFileSync(tryResolveImport(fileName), 'utf8'), }, + ] }) - - const output = JSON.parse(out) as { - sources: { [fileName: string]: { id: number } } - errors: Array - } - - if (output.errors && Object.keys(output.sources).length === 0) { - throw new Error(output.errors[0].formattedMessage) - } - - return Object.fromEntries( - Object.keys(output.sources).map((fileName) => { - return [ - fileName, - sources[fileName] ?? { - content: readFileSync(tryResolveImport(fileName), 'utf8'), - }, - ] - }) - ) + ) } export function version(): string { - const v = resolcVersion() - return v.split(' ').pop() ?? v + const v = resolcVersion() + return v.split(' ').pop() ?? v } export async function compile( - sources: SolcInput, - option: { bin?: string } = {} + sources: SolcInput, + option: { bin?: string } = {} ): Promise { - const input = JSON.stringify({ - language: 'Solidity', - sources: resolveInputs(sources), - settings: { - optimizer: { enabled: true, runs: 200 }, - outputSelection: { - '*': { - '*': ['abi'], - }, - }, + const input = JSON.stringify({ + language: 'Solidity', + sources: resolveInputs(sources), + settings: { + optimizer: { enabled: true, runs: 200 }, + outputSelection: { + '*': { + '*': ['abi'], }, - }) + }, + }, + }) - if (option.bin) { - return compileWithBin(input, option.bin) - } + if (option.bin) { + return compileWithBin(input, option.bin) + } - return resolc(input) + return resolc(input) } /** @@ -120,83 +120,81 @@ export async function compile( * @param importPath - The import path to resolve. */ export function tryResolveImport(importPath: string) { - // resolve local path - if (existsSync(importPath)) { - return path.resolve(importPath) + // resolve local path + if (existsSync(importPath)) { + return path.resolve(importPath) + } + + const importRegex = /^(@?[^@/]+(?:\/[^@/]+)?)(?:@([^/]+))?(\/.+)$/ + const match = importPath.match(importRegex) + + if (!match) { + throw new Error('Invalid import path format.') + } + + const basePackage = match[1] // "foo", "@scope/foo" + const specifiedVersion = match[2] // "1.2.3" (optional) + const relativePath = match[3] // "/path/to/file.sol" + + let packageJsonPath + try { + packageJsonPath = require.resolve(path.join(basePackage, 'package.json')) + } catch { + throw new Error(`Could not resolve package ${basePackage}`) + } + + // Check if a version was specified and compare with the installed version + if (specifiedVersion) { + const installedVersion = JSON.parse( + readFileSync(packageJsonPath, 'utf-8') + ).version + + if (installedVersion !== specifiedVersion) { + throw new Error( + `Version mismatch: Specified ${basePackage}@${specifiedVersion}, but installed version is ${installedVersion}` + ) } + } - const importRegex = /^(@?[^@/]+(?:\/[^@/]+)?)(?:@([^/]+))?(\/.+)$/ - const match = importPath.match(importRegex) + const packageRoot = path.dirname(packageJsonPath) - if (!match) { - throw new Error('Invalid import path format.') - } - - const basePackage = match[1] // "foo", "@scope/foo" - const specifiedVersion = match[2] // "1.2.3" (optional) - const relativePath = match[3] // "/path/to/file.sol" - - let packageJsonPath - try { - packageJsonPath = require.resolve( - path.join(basePackage, 'package.json') - ) - } catch { - throw new Error(`Could not resolve package ${basePackage}`) - } - - // Check if a version was specified and compare with the installed version - if (specifiedVersion) { - const installedVersion = JSON.parse( - readFileSync(packageJsonPath, 'utf-8') - ).version - - if (installedVersion !== specifiedVersion) { - throw new Error( - `Version mismatch: Specified ${basePackage}@${specifiedVersion}, but installed version is ${installedVersion}` - ) - } - } - - const packageRoot = path.dirname(packageJsonPath) - - // Construct full path to the requested file - const resolvedPath = path.join(packageRoot, relativePath) - if (existsSync(resolvedPath)) { - return resolvedPath - } else { - throw new Error(`Resolved path ${resolvedPath} does not exist.`) - } + // Construct full path to the requested file + const resolvedPath = path.join(packageRoot, relativePath) + if (existsSync(resolvedPath)) { + return resolvedPath + } else { + throw new Error(`Resolved path ${resolvedPath} does not exist.`) + } } function compileWithBin(input: string, bin: string): PromiseLike { - return new Promise((resolve, reject) => { - const process = spawn(bin, ['--standard-json']) + return new Promise((resolve, reject) => { + const process = spawn(bin, ['--standard-json']) - let output = '' - let error = '' + let output = '' + let error = '' - process.stdin.write(input) - process.stdin.end() + process.stdin.write(input) + process.stdin.end() - process.stdout.on('data', (data) => { - output += data.toString() - }) - - process.stderr.on('data', (data) => { - error += data.toString() - }) - - process.on('close', (code) => { - if (code === 0) { - try { - const result: SolcOutput = JSON.parse(output) - resolve(result) - } catch { - reject(new Error(`Failed to parse output`)) - } - } else { - reject(new Error(`Process exited with code ${code}: ${error}`)) - } - }) + process.stdout.on('data', (data) => { + output += data.toString() }) + + process.stderr.on('data', (data) => { + error += data.toString() + }) + + process.on('close', (code) => { + if (code === 0) { + try { + const result: SolcOutput = JSON.parse(output) + resolve(result) + } catch { + reject(new Error(`Failed to parse output`)) + } + } else { + reject(new Error(`Process exited with code ${code}: ${error}`)) + } + }) + }) } diff --git a/js/resolc/src/resolc.ts b/js/resolc/src/resolc.ts index 737cc15..583f663 100644 --- a/js/resolc/src/resolc.ts +++ b/js/resolc/src/resolc.ts @@ -3,28 +3,28 @@ import Resolc from './resolc/resolc' import type { SolcOutput } from '.' export function resolc(input: string): SolcOutput { - const m = Resolc() as any // eslint-disable-line @typescript-eslint/no-explicit-any - m.soljson = soljson - m.writeToStdin(input) - m.callMain(['--standard-json']) - const err = m.readFromStderr() + const m = Resolc() as any // eslint-disable-line @typescript-eslint/no-explicit-any + m.soljson = soljson + m.writeToStdin(input) + m.callMain(['--standard-json']) + const err = m.readFromStderr() - if (err) { - throw new Error(err) - } + if (err) { + throw new Error(err) + } - return JSON.parse(m.readFromStdout()) as SolcOutput + return JSON.parse(m.readFromStdout()) as SolcOutput } export function version(): string { - const m = Resolc() as any // eslint-disable-line @typescript-eslint/no-explicit-any - m.soljson = soljson - m.callMain(['--version']) - const err = m.readFromStderr() + const m = Resolc() as any // eslint-disable-line @typescript-eslint/no-explicit-any + m.soljson = soljson + m.callMain(['--version']) + const err = m.readFromStderr() - if (err) { - throw new Error(err) - } + if (err) { + throw new Error(err) + } - return m.readFromStdout() + return m.readFromStdout() } diff --git a/js/resolc/src/solc.d.ts b/js/resolc/src/solc.d.ts index 04b47c8..d195971 100644 --- a/js/resolc/src/solc.d.ts +++ b/js/resolc/src/solc.d.ts @@ -1,95 +1,95 @@ declare module 'solc/soljson' {} declare module 'solc' { - // Basic types for input/output handling - export interface CompileInput { - language: string - sources: { - [fileName: string]: { - content: string - } + // Basic types for input/output handling + export interface CompileInput { + language: string + sources: { + [fileName: string]: { + content: string + } + } + settings?: { + optimizer?: { + enabled: boolean + runs: number + } + outputSelection: { + [fileName: string]: { + [contractName: string]: string[] } - settings?: { - optimizer?: { - enabled: boolean - runs: number - } - outputSelection: { + } + } + } + + export interface CompileOutput { + errors?: Array<{ + component: string + errorCode: string + formattedMessage: string + message: string + severity: string + sourceLocation?: { + file: string + start: number + end: number + } + type: string + }> + sources?: { + [fileName: string]: { + id: number + ast: object + } + } + contracts?: { + [fileName: string]: { + [contractName: string]: { + abi: object[] + evm: { + bytecode: { + object: string + sourceMap: string + linkReferences: { [fileName: string]: { - [contractName: string]: string[] + [libraryName: string]: Array<{ + start: number + length: number + }> } + } } - } - } - - export interface CompileOutput { - errors?: Array<{ - component: string - errorCode: string - formattedMessage: string - message: string - severity: string - sourceLocation?: { - file: string - start: number - end: number - } - type: string - }> - sources?: { - [fileName: string]: { - id: number - ast: object - } - } - contracts?: { - [fileName: string]: { - [contractName: string]: { - abi: object[] - evm: { - bytecode: { - object: string - sourceMap: string - linkReferences: { - [fileName: string]: { - [libraryName: string]: Array<{ - start: number - length: number - }> - } - } - } - deployedBytecode: { - object: string - sourceMap: string - linkReferences: { - [fileName: string]: { - [libraryName: string]: Array<{ - start: number - length: number - }> - } - } - } - } + deployedBytecode: { + object: string + sourceMap: string + linkReferences: { + [fileName: string]: { + [libraryName: string]: Array<{ + start: number + length: number + }> } + } } + } } + } } + } - // Main exported functions - export function compile( - input: string | CompileInput, - options?: { - import: (path: string) => - | { - contents: string - error?: undefined - } - | { - error: string - contents?: undefined - } - } - ): string + // Main exported functions + export function compile( + input: string | CompileInput, + options?: { + import: (path: string) => + | { + contents: string + error?: undefined + } + | { + error: string + contents?: undefined + } + } + ): string }