Skip to content

Commit 07ce650

Browse files
committed
feat: add support for hardhat
1 parent ed97c3e commit 07ce650

File tree

1 file changed

+70
-59
lines changed

1 file changed

+70
-59
lines changed

src/commands/contract-size.js

Lines changed: 70 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
const vscode = require('vscode');
2-
const solc = require('solc');
32
const path = require('path');
43
const fs = require('fs');
54

65
let decorationType;
76
let workspaceRoot;
8-
let remappings = [];
7+
let foundryOutDir = 'out';
8+
let hardhatOutDir = null;
99

1010
function activate(context) {
11-
console.log('contract-size: Activating extension');
11+
console.info('contract-size: Activating extension');
1212
workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '';
13-
console.log('contract-size: Workspace root:', workspaceRoot);
13+
console.info('contract-size: Workspace root:', workspaceRoot);
1414

15-
loadRemappings();
15+
loadConfig();
1616

1717
decorationType = vscode.window.createTextEditorDecorationType({
1818
after: {
@@ -38,29 +38,51 @@ function activate(context) {
3838
updateDecorations(vscode.window.activeTextEditor.document);
3939
}
4040

41-
console.log('contract-size: Activation complete');
41+
console.info('contract-size: Activation complete');
4242
}
4343

44-
function loadRemappings() {
45-
const remappingsPath = path.join(workspaceRoot, 'remappings.txt');
46-
console.log('contract-size: Looking for remappings at:', remappingsPath);
47-
if (fs.existsSync(remappingsPath)) {
48-
const content = fs.readFileSync(remappingsPath, 'utf8');
49-
remappings = content.split('\n')
50-
.filter(line => line.trim() !== '')
51-
.map(line => {
52-
const [from, to] = line.split('=');
53-
return { from: from.trim(), to: to.trim() };
54-
});
55-
console.log('contract-size: Loaded remappings:', remappings);
44+
function loadConfig() {
45+
const foundryConfigPath = path.join(workspaceRoot, 'foundry.toml');
46+
47+
if (fs.existsSync(foundryConfigPath)) {
48+
console.info('contract-size: Foundry configuration detected');
49+
const configContent = fs.readFileSync(foundryConfigPath, 'utf8');
50+
const outDirMatch = configContent.match(/out\s*=\s*['"](.+)['"]/);
51+
if (outDirMatch) {
52+
foundryOutDir = outDirMatch[1];
53+
}
54+
console.info(`contract-size: Using Foundry out directory: ${foundryOutDir}`);
55+
}
56+
57+
// Search for Hardhat artifacts directory
58+
hardhatOutDir = findArtifactsDir(workspaceRoot);
59+
if (hardhatOutDir) {
60+
console.info(`contract-size: Hardhat artifacts directory found: ${hardhatOutDir}`);
5661
} else {
57-
console.log('contract-size: No remappings.txt found');
62+
console.info('contract-size: Hardhat artifacts directory not found');
63+
}
64+
}
65+
66+
function findArtifactsDir(dir) {
67+
const files = fs.readdirSync(dir);
68+
for (const file of files) {
69+
const filePath = path.join(dir, file);
70+
const stat = fs.statSync(filePath);
71+
if (stat.isDirectory()) {
72+
if (file === 'artifacts') {
73+
return filePath;
74+
} else {
75+
const result = findArtifactsDir(filePath);
76+
if (result) return result;
77+
}
78+
}
5879
}
80+
return null;
5981
}
6082

6183
function updateDecorations(document) {
6284
const text = document.getText();
63-
const contractSizes = compileAndGetSizes(document.fileName, text);
85+
const contractSizes = getContractSizes(document.fileName);
6486
const decorations = [];
6587

6688
const contractRegex = /contract\s+(\w+)(?:\s+is\s+[^{]+)?\s*{/g;
@@ -86,54 +108,43 @@ function updateDecorations(document) {
86108
vscode.window.activeTextEditor?.setDecorations(decorationType, decorations);
87109
}
88110

89-
function compileAndGetSizes(fileName, source) {
90-
const input = {
91-
language: 'Solidity',
92-
sources: { [fileName]: { content: source } },
93-
settings: { outputSelection: { '*': { '*': ['evm.bytecode'] } } }
94-
};
95-
96-
try {
97-
const output = JSON.parse(solc.compile(JSON.stringify(input), { import: findImports }));
98-
if (output.errors?.some(error => error.severity === 'error')) {
99-
console.error('contract-size: Compilation errors:', output.errors);
100-
return {};
101-
}
111+
function getContractSizes(fileName) {
112+
const sizes = {};
113+
const contractName = path.basename(fileName, '.sol');
102114

103-
const sizes = {};
104-
for (const [, contracts] of Object.entries(output.contracts)) {
105-
for (const [name, contract] of Object.entries(contracts)) {
106-
sizes[name] = contract.evm.bytecode.object.length / 2;
107-
}
108-
}
109-
return sizes;
110-
} catch (error) {
111-
console.error('contract-size: Compilation failed:', error);
112-
return {};
115+
// Paths for both Foundry and Hardhat
116+
const foundryJsonPath = path.join(workspaceRoot, foundryOutDir, `${path.basename(fileName)}`, `${contractName}.json`);
117+
let hardhatJsonPath = null;
118+
if (hardhatOutDir) {
119+
const relativePath = path.relative(path.join(workspaceRoot, 'contracts'), fileName);
120+
hardhatJsonPath = path.join(hardhatOutDir, relativePath, `${contractName}.json`);
113121
}
114-
}
115122

116-
function findImports(importPath) {
117-
console.log('contract-size: Resolving import:', importPath);
118-
for (const remap of remappings) {
119-
if (importPath.startsWith(remap.from)) {
120-
const remappedPath = importPath.replace(remap.from, remap.to);
121-
const fullPath = path.resolve(workspaceRoot, remappedPath);
122-
if (fs.existsSync(fullPath)) {
123-
console.log('contract-size: Resolved import via remappings:', fullPath);
124-
return { contents: fs.readFileSync(fullPath, 'utf8') };
123+
const jsonPaths = [foundryJsonPath, hardhatJsonPath].filter(Boolean);
124+
125+
for (const jsonPath of jsonPaths) {
126+
try {
127+
if (fs.existsSync(jsonPath)) {
128+
const jsonContent = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
129+
const bytecode = jsonPath === hardhatJsonPath ? jsonContent.deployedBytecode : jsonContent.deployedBytecode.object;
130+
sizes[contractName] = (bytecode.slice(2).length) / 2;
131+
console.info(`contract-size: Size calculated for ${contractName} from ${jsonPath}`);
132+
break; // Stop after finding the first valid file
125133
}
134+
} catch (error) {
135+
console.error(`contract-size: Error reading or parsing JSON for ${contractName} at ${jsonPath}:`, error);
126136
}
127-
else {
128-
console.log('contract-size: Resolved import without remappings:', importPath);
129-
return { contents: fs.readFileSync(importPath, 'utf8') };
130-
}
131137
}
132-
138+
139+
if (!sizes[contractName]) {
140+
console.info(`contract-size: JSON file not found for ${contractName} in any expected location`);
141+
}
142+
143+
return sizes;
133144
}
134145

135146
function formatSize(bytes) {
136-
return `${(bytes / 1024).toFixed(2) / 2} KB`;
147+
return `${(bytes / 1024).toFixed(2)} KB`;
137148
}
138149

139150
function getSizeColor(bytes) {

0 commit comments

Comments
 (0)