Skip to content

Commit

Permalink
feat: 🎸 add analyzerRules to HardhatUserConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
foxgem committed Jan 10, 2023
1 parent 543bb4b commit 4d39ed9
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 76 deletions.
29 changes: 16 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ hre.analyze(hre);

This plugin needs no configuration to run, in this case, it will apply all rules for all the contracts files.

To customize it, you can create a configuration file named `.analyzerRules.json` under the root directory of your hardhat project. The type of the configuration:
To customize it, you can add `analyzerRules` to `HardhatUserConfig` in your hardhat project. The type of the configuration:

```ts
export type AnalyzerConfiguration = {
Expand All @@ -67,7 +67,7 @@ export type AnalyzerConfiguration = {
Where:

- When it is an empty object like `{}`, then all rules will be applied.
- `default` defines the rules for all contracts files. it is an array of strings. And the name must be one of the following names:
- `default` defines the rules for all contracts files. it is an array of strings. Each element must be one of the following names:

```ts
export const ANALYZER_RULES: { [rule: string]: any } = {
Expand Down Expand Up @@ -101,17 +101,20 @@ export const ANALYZER_RULES: { [rule: string]: any } = {

An example of configuration:

```json
{
"default": ["txOrigin", "gasCosts", "thisLocal"],
"sources": {
"contracts/Global.sol": {
"gasCosts": false,
"thisLocal": false,
"blockTimestamp": true
}
}
}
```ts
const config: HardhatUserConfig = {
...,
analyzerRules: {
default: ["txOrigin", "gasCosts", "thisLocal"],
sources: {
"contracts/Global.sol": {
gasCosts: false,
thisLocal: false,
blockTimestamp: true,
},
},
},
};
```

## Usage
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hardhat-remix-analyzer",
"version": "0.0.2",
"version": "0.0.3",
"description": "A plugin using remix analyzer for solidity syntax analysis.",
"repository": "https://github.com/DTeam-Top/hardhat-remix-analyzer",
"readmeFilename": "README.md",
Expand Down
27 changes: 0 additions & 27 deletions src/common.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { ANALYZER_RULES } from "./const";
import fs from "fs";
import { NomicLabsHardhatPluginError } from "hardhat/plugins";

export type AnalyzerConfiguration = {
default?: string[];
Expand All @@ -9,31 +7,6 @@ export type AnalyzerConfiguration = {
};
};

export function loadRulesFromFile(file?: string) {
if (!file || !file.trim() || !fs.existsSync(file)) {
return {};
}

try {
return JSON.parse(fs.readFileSync(file).toString());
} catch (e) {
let message;

if (typeof e === "string") {
message = e;
} else if (e instanceof Error) {
message = e.message;
} else {
message = JSON.stringify(e);
}

throw new NomicLabsHardhatPluginError(
"hardhat-remix-analyzer",
`cannot generate rules, reason: ${e}`
);
}
}

export function calculateRules(source: string, rules: AnalyzerConfiguration) {
const defaultRules = calculateDefaultRules(rules);
if (!rules.sources || !rules.sources[source]) {
Expand Down
9 changes: 8 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { extendEnvironment } from "hardhat/config";
import { extendConfig, extendEnvironment } from "hardhat/config";
import analyze from "./tasks/analyze";
import "./tasks/analyze";
import "./type-extensions";
import { HardhatConfig, HardhatUserConfig } from "hardhat/types";

extendConfig(
(config: HardhatConfig, userConfig: Readonly<HardhatUserConfig>) => {
config.analyzerRules = userConfig.analyzerRules || {};
}
);

extendEnvironment((hre) => {
hre.analyze = analyze;
Expand Down
14 changes: 6 additions & 8 deletions src/tasks/analyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import staticAnalysisRunner from "@remix-project/remix-analyzer/src/solidity-ana
import fs from "fs";
import { createTable } from "@dteam/st2/dist/stringTable";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { calculateRules, loadRulesFromFile } from "../common";
import { calculateRules } from "../common";

const analyze = async (hre: HardhatRuntimeEnvironment) => {
const runner = new staticAnalysisRunner();
Expand All @@ -13,16 +13,14 @@ const analyze = async (hre: HardhatRuntimeEnvironment) => {
console.log("√ compiled contracts.\n");

const compileResults = await hre.artifacts.getBuildInfoPaths();
const rules = loadRulesFromFile(
`${hre.config.paths.root}/.analyzerRules.json`
);

compileResults.forEach((result) => {
const compiled = JSON.parse(fs.readFileSync(result).toString());
const source = Object.keys(compiled.input.sources)[0];
const modules = calculateRules(source, rules).map((Module: any) => {
return { name: new Module().name, mod: new Module() };
});
const modules = calculateRules(source, hre.config.analyzerRules).map(
(Module: any) => {
return { name: new Module().name, mod: new Module() };
}
);
const reports = runner.runWithModuleList(compiled.output, modules);
console.log(`\nanalyzing ${source}...`);
console.log("---");
Expand Down
11 changes: 11 additions & 0 deletions src/type-extensions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import "hardhat/types/config";
import "hardhat/types/runtime";
import { AnalyzerConfiguration } from "./common";

declare module "hardhat/types/config" {
interface HardhatUserConfig {
analyzerRules?: AnalyzerConfiguration;
}

interface HardhatConfig {
analyzerRules: AnalyzerConfiguration;
}
}

declare module "hardhat/types/runtime" {
export interface HardhatRuntimeEnvironment {
Expand Down
28 changes: 2 additions & 26 deletions test/common.test.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,8 @@
// tslint:disable-next-line no-implicit-dependencies
import { assert } from "chai";
import { calculateRules, loadRulesFromFile } from "../src/common";
import { calculateRules } from "../src/common";
import { ANALYZER_RULES } from "../src/const";

const rulesForTesting = {
default: ["txOrigin", "gasCosts", "thisLocal"],
sources: {
"contracts/Global.sol": {
gasCosts: false,
thisLocal: false,
blockTimestamp: true,
},
},
};

describe("loadRulesFromFile", function () {
it("should return empty object for empty string or undefined.", function () {
assert.deepEqual(loadRulesFromFile(), {});
});

it("should return empty object for a nonexistent file.", function () {
assert.deepEqual(loadRulesFromFile("/a/non/existent/file"), {});
});

it("should return an object for a file.", function () {
assert.deepEqual(loadRulesFromFile("test/rules.json"), rulesForTesting);
});
});
import { rulesForTesting } from "./helpers";

describe("calculateRules", function () {
it("should return all rules for an empty rule configuration.", function () {
Expand Down
20 changes: 20 additions & 0 deletions test/fixture-projects/hardhat-project/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { HardhatUserConfig } from "hardhat/types";

import "../../../src/index";

const config: HardhatUserConfig = {
solidity: "0.7.3",
defaultNetwork: "hardhat",
analyzerRules: {
default: ["txOrigin", "gasCosts", "thisLocal"],
sources: {
"contracts/Global.sol": {
gasCosts: false,
thisLocal: false,
blockTimestamp: true,
},
},
},
};

export default config;
32 changes: 32 additions & 0 deletions test/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { resetHardhatContext } from "hardhat/plugins-testing";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import path from "path";

declare module "mocha" {
interface Context {
hre: HardhatRuntimeEnvironment;
}
}

export const rulesForTesting = {
default: ["txOrigin", "gasCosts", "thisLocal"],
sources: {
"contracts/Global.sol": {
gasCosts: false,
thisLocal: false,
blockTimestamp: true,
},
},
};

export function useEnvironment(fixtureProjectName: string) {
beforeEach("Loading hardhat environment", function () {
process.chdir(path.join(__dirname, "fixture-projects", fixtureProjectName));

this.hre = require("hardhat");
});

afterEach("Resetting hardhat", function () {
resetHardhatContext();
});
}
22 changes: 22 additions & 0 deletions test/project.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// tslint:disable-next-line no-implicit-dependencies
import { assert } from "chai";

import { rulesForTesting, useEnvironment } from "./helpers";

describe("Integration tests", function () {
describe("Hardhat Runtime Environment extension", function () {
useEnvironment("hardhat-project");

it("Should add the analyze field", function () {
assert.equal(typeof this.hre.analyze, "function");
});
});

describe("HardhatConfig extension", function () {
useEnvironment("hardhat-project");

it("Should add the analyzerRules to the config", function () {
assert.deepEqual(this.hre.config.analyzerRules, rulesForTesting);
});
});
});

0 comments on commit 4d39ed9

Please sign in to comment.