@tevm/compiler
Version:
Utilities around compiler
388 lines (379 loc) • 10.2 kB
JavaScript
var resolutions = require('@tevm/resolutions');
var solc = require('@tevm/solc');
var effect = require('effect');
var Effect = require('effect/Effect');
var resolve = require('resolve');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var resolve__default = /*#__PURE__*/_interopDefault(resolve);
// src/compiler/compileContracts.js
// src/utils/invariant.js
function invariant(condition, message) {
if (!condition) {
throw new Error(message);
}
}
var resolveEffect = (filePath, basedir, fao, logger) => {
return effect.Effect.async((resume) => {
resolve__default.default(
filePath,
{
basedir,
readFile: (file, cb) => {
fao.readFile(file, "utf8").then((fileContent) => {
cb(null, fileContent);
}).catch((e) => {
logger.error(e);
logger.error("Error reading file");
cb(e);
});
},
isFile: async (file, cb) => {
try {
cb(null, await fao.exists(file));
} catch (e) {
cb(
/** @type Error */
e
);
logger.error(
/** @type any */
e
);
logger.error(`Error checking if isFile ${file}`);
resume(effect.Effect.fail(
/** @type Error */
e
));
return;
}
}
},
(err, res) => {
if (err) {
logger.error(
/** @type any */
err
);
logger.error(`There was an error resolving ${filePath}`);
resume(effect.Effect.fail(err));
} else {
resume(effect.Effect.succeed(
/** @type string */
res
));
}
}
);
});
};
// src/compiler/compileContracts.js
var compileContract = async (filePath, basedir, config, includeAst, includeBytecode, fao, logger, solc$1) => {
var _a, _b;
const moduleMap = await Effect.runPromise(
resolutions.moduleFactory(
filePath,
await fao.readFile(await effect.Effect.runPromise(resolveEffect(filePath, basedir, fao, logger)), "utf8").then((code) => {
return code;
}),
config.remappings,
config.libs,
fao,
false
)
);
const entryModule = moduleMap.get(filePath);
invariant(entryModule, "Entry module should exist");
const modules = {};
const stack = [entryModule];
while (stack.length !== 0) {
const m = stack.pop();
invariant(m, "Module should exist");
if (m.id in modules) {
continue;
}
modules[m.id] = m;
const resolutions = m.importedIds.map((id) => (
/** @type {import("../types.js").ModuleInfo}*/
moduleMap.get(id)
));
for (const dep of resolutions) {
stack.push(dep);
}
}
const sources = Object.fromEntries(
Object.entries(modules).map(([id, module]) => {
return [
id,
{
content: (
/** @type {string} */
module.code
)
}
];
})
);
const emptyString = "";
const evmBytecode = ["evm.bytecode.object", "evm.deployedBytecode.object"];
const input = {
language: "Solidity",
sources,
settings: {
outputSelection: {
"*": {
"*": ["abi", "userdoc", ...includeBytecode ? evmBytecode : []],
...includeAst ? { [emptyString]: ["ast"] } : {}
}
}
}
};
const output = solc.solcCompile(solc$1, input);
const warnings = (_a = output == null ? void 0 : output.errors) == null ? void 0 : _a.filter(({ type }) => type === "Warning");
const isErrors = (((_b = output == null ? void 0 : output.errors) == null ? void 0 : _b.length) ?? 0) > ((warnings == null ? void 0 : warnings.length) ?? 0);
if (isErrors) {
logger.error("Compilation errors:");
logger.error(
/** @type {any} */
output == null ? void 0 : output.errors
);
throw new Error("Compilation failed");
}
if (warnings == null ? void 0 : warnings.length) {
logger.warn(
/** @type {any} */
warnings
);
logger.warn("Compilation warnings:");
}
if (includeAst) {
const asts = Object.fromEntries(
Object.entries(output.sources).map(([id, source]) => {
return [id, source.ast];
})
);
return {
artifacts: output.contracts[entryModule.id],
modules: (
/** @type {any} */
modules
),
asts: (
/** @type {any} */
asts
),
solcInput: input,
solcOutput: output
};
}
return {
artifacts: output.contracts[entryModule.id],
modules: (
/** @type {any} */
modules
),
asts: (
/** @type {any} */
void 0
),
solcInput: input,
solcOutput: output
};
};
// src/resolveArtifacts.js
var resolveArtifacts = async (solFile, basedir, logger, config, includeAst, includeBytecode, fao, solc) => {
if (!solFile.endsWith(".sol")) {
throw new Error("Not a solidity file");
}
const { artifacts, modules, asts, solcInput, solcOutput } = await compileContract(
solFile,
basedir,
config,
includeAst,
includeBytecode,
fao,
logger,
solc
);
if (!artifacts) {
logger.error(`Compilation failed for ${solFile}`);
throw new Error("Compilation failed");
}
return {
artifacts: Object.fromEntries(
Object.entries(artifacts).map(([contractName, contract]) => {
return [
contractName,
{
contractName,
abi: contract.abi,
userdoc: contract.userdoc,
evm: contract.evm
}
];
})
),
modules,
asts,
solcInput,
solcOutput
};
};
function compileContractSync(filePath, basedir, config, includeAst, includeBytecode, fao, logger, solc$1) {
var _a, _b;
const moduleMap = Effect.runSync(
resolutions.moduleFactory(
filePath,
fao.readFileSync(
resolve__default.default.sync(filePath, {
basedir,
readFileSync: (file) => fao.readFileSync(file, "utf8"),
isFile: fao.existsSync
}),
"utf8"
),
config.remappings,
config.libs,
fao,
true
)
);
const entryModule = moduleMap.get(filePath);
invariant(entryModule, "Entry module should exist");
const modules = {};
const stack = [entryModule];
while (stack.length !== 0) {
const m = stack.pop();
invariant(m, "Module should exist");
if (m.id in modules) {
continue;
}
modules[m.id] = m;
for (const dep of m.importedIds) {
stack.push(
/** @type {import("../types.js").ModuleInfo} */
moduleMap.get(dep)
);
}
}
const sources = Object.fromEntries(
Object.entries(modules).map(([id, module]) => {
const code = (
/** @type {string} */
module.code
);
return [id, { content: code }];
})
);
const evmBytecode = ["evm.bytecode.object", "evm.deployedBytecode.object"];
const solcInput = {
language: "Solidity",
sources,
settings: {
outputSelection: {
"*": {
"*": [
"abi",
"userdoc",
...includeBytecode ? evmBytecode : [],
...includeAst ? (
/** @type {['evm.deployedBytecode.sourceMap', 'evm.bytecode.sourceMap', 'metadata']}*/
[
"evm.deployedBytecode.sourceMap",
// Source map for deployed code
"evm.bytecode.sourceMap",
// Source map for creation code
"metadata"
// Additional metadata for debugging
]
) : []
],
...includeAst ? { "": ["ast"] } : {}
}
}
}
};
const solcOutput = solc.solcCompile(solc$1, solcInput);
const warnings = (_a = solcOutput == null ? void 0 : solcOutput.errors) == null ? void 0 : _a.filter(({ type }) => type === "Warning");
const isErrors = (((_b = solcOutput == null ? void 0 : solcOutput.errors) == null ? void 0 : _b.length) ?? 0) > ((warnings == null ? void 0 : warnings.length) ?? 0);
if (isErrors) {
logger.error(
"Compilation errors:",
/** @type {any}*/
solcOutput == null ? void 0 : solcOutput.errors
);
console.log(solcOutput.errors);
throw new Error("Compilation failed");
}
if (warnings == null ? void 0 : warnings.length) {
logger.warn(
"Compilation warnings:",
/** @type {any}*/
solcOutput == null ? void 0 : solcOutput.errors
);
}
if (includeAst) {
const asts = Object.fromEntries(
Object.entries(solcOutput.sources).map(([id, source]) => {
return [id, source.ast];
})
);
return {
artifacts: solcOutput.contracts[entryModule.id],
modules,
asts,
solcInput,
solcOutput
};
}
return {
artifacts: solcOutput.contracts[entryModule.id],
modules,
asts: void 0,
solcInput,
solcOutput
};
}
// src/resolveArtifactsSync.js
var resolveArtifactsSync = (solFile, basedir, logger, config, includeAst, includeBytecode, fao, solc) => {
if (!solFile.endsWith(".sol")) {
throw new Error("Not a solidity file");
}
const { artifacts, modules, asts, solcInput, solcOutput } = compileContractSync(
solFile,
basedir,
config,
includeAst,
includeBytecode,
fao,
logger,
solc
);
if (!artifacts) {
logger.error(`Compilation failed for ${solFile}`);
throw new Error("Compilation failed");
}
return {
artifacts: Object.fromEntries(
Object.entries(artifacts).map(([contractName, contract]) => {
return [
contractName,
{
contractName,
abi: contract.abi,
userdoc: contract.userdoc,
evm: contract.evm
}
];
})
),
modules,
asts,
solcInput,
solcOutput
};
};
exports.resolveArtifacts = resolveArtifacts;
exports.resolveArtifactsSync = resolveArtifactsSync;
//# sourceMappingURL=index.cjs.map
//# sourceMappingURL=index.cjs.map
;