bufan-hardhat-strip-comments
Version:
Hardhat plugin to strip comments from contracts during verification with custom Dubai ASCII art headers
246 lines (244 loc) • 10.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const config_1 = require("hardhat/config");
const strip_comments_1 = __importDefault(require("strip-comments"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
// 默认作者信息
const DEFAULT_AUTHOR_INFO = {
author: "VeloraChain",
createdDate: "2025-05-11",
purpose: "VeloraChain Blockchain Technology Token",
description: "This is no ordinary code — it carries ambition, and marks a legend on-chain."
};
// 设置默认配置
(0, config_1.extendConfig)((config, userConfig) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
// 处理 authorInfo
const authorInfo = ((_a = userConfig.stripComments) === null || _a === void 0 ? void 0 : _a.authorInfo) || {};
config.stripComments = {
enabled: (_c = (_b = userConfig.stripComments) === null || _b === void 0 ? void 0 : _b.enabled) !== null && _c !== void 0 ? _c : true,
customHeader: (_e = (_d = userConfig.stripComments) === null || _d === void 0 ? void 0 : _d.customHeader) !== null && _e !== void 0 ? _e : "// SPDX-License-Identifier: MIT",
excludedFiles: (_g = (_f = userConfig.stripComments) === null || _f === void 0 ? void 0 : _f.excludedFiles) !== null && _g !== void 0 ? _g : [],
preserveLicense: (_j = (_h = userConfig.stripComments) === null || _h === void 0 ? void 0 : _h.preserveLicense) !== null && _j !== void 0 ? _j : true,
authorInfo: {
author: (_k = authorInfo.author) !== null && _k !== void 0 ? _k : DEFAULT_AUTHOR_INFO.author,
createdDate: (_l = authorInfo.createdDate) !== null && _l !== void 0 ? _l : DEFAULT_AUTHOR_INFO.createdDate,
purpose: (_m = authorInfo.purpose) !== null && _m !== void 0 ? _m : DEFAULT_AUTHOR_INFO.purpose,
description: (_o = authorInfo.description) !== null && _o !== void 0 ? _o : DEFAULT_AUTHOR_INFO.description,
},
headerStyle: (_q = (_p = userConfig.stripComments) === null || _p === void 0 ? void 0 : _p.headerStyle) !== null && _q !== void 0 ? _q : "dubai"
};
});
// 创建一个新任务,用于处理合约文件并去除注释
(0, config_1.task)("strip-comments", "Strips comments from contract files")
.addOptionalParam("input", "Input directory or file path", "contracts")
.addOptionalParam("output", "Output directory", "stripped-contracts")
.setAction(async (taskArgs, { config }) => {
const { input, output } = taskArgs;
const stripCommentsConfig = config.stripComments;
if (!stripCommentsConfig.enabled) {
console.log("Strip comments plugin is disabled. Skipping...");
return;
}
// 确保输出目录存在
const outputDir = path.resolve(process.cwd(), output);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const inputPath = path.resolve(process.cwd(), input);
const stats = fs.statSync(inputPath);
if (stats.isFile()) {
// 处理单个文件
processFile(inputPath, outputDir, stripCommentsConfig);
}
else if (stats.isDirectory()) {
// 处理目录
processDirectory(inputPath, outputDir, stripCommentsConfig);
}
else {
console.error(`Invalid input path: ${inputPath}`);
}
console.log(`Processed files saved to ${outputDir}`);
});
// 重写verify任务,使其在验证前去除注释
(0, config_1.task)("verify", "Verifies contract on the block explorer")
.setAction(async (taskArgs, hre, runSuper) => {
const config = hre.config.stripComments;
if (config.enabled) {
console.log("Stripping comments before verification...");
// 检查要验证的合约文件
let contractFile = "";
if (taskArgs.contract) {
const parts = taskArgs.contract.split(":");
if (parts.length > 1) {
contractFile = parts[1];
}
}
// 如果找到合约文件,处理它
if (contractFile) {
const contractsDir = path.resolve(process.cwd(), "contracts");
const outputDir = path.resolve(process.cwd(), "stripped-contracts");
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const filePath = path.resolve(contractsDir, contractFile);
if (fs.existsSync(filePath)) {
const newFilePath = processFile(filePath, outputDir, config);
// 修改任务参数以使用处理后的文件
if (newFilePath) {
const relativePath = path.relative(process.cwd(), newFilePath);
taskArgs.contract = taskArgs.contract.replace(contractFile, relativePath);
}
}
}
}
// 继续执行原始的verify任务
return runSuper(taskArgs);
});
// 提取合约名称
function extractContractName(source) {
const contractMatch = source.match(/contract\s+([a-zA-Z0-9_]+)/);
if (contractMatch && contractMatch[1]) {
return contractMatch[1];
}
return "Contract";
}
// 生成迪拜风格的头部
function generateDubaiHeader(contractName, config) {
return `// SPDX-License-Identifier: MIT
/*
🌴🏜️ 𓆃 DUBAI SMART CONTRACT 𓆃 🏜️🌴
────────────────────────────────
"Built beneath the sun, coded
for fortune, destined for legend."
Contract Name : ${contractName}
Author : ${config.authorInfo.author}
Created Date : ${config.authorInfo.createdDate}
Purpose : ${config.authorInfo.purpose}
Description : ${config.authorInfo.description}
*/`;
}
// 生成标准风格的头部
function generateStandardHeader(contractName, config) {
return `// SPDX-License-Identifier: MIT
/*
___ _ _ _
| _ \\__ _ _| |_ (_)_ _ __ _ ___ __| |___
| _/ _\` | | ' \\| | ' \\/ _\` / -_)/ _\` (_-<
|_| \\__,_|_|_||_|_|_||_\\__, \\___|\\_\\_,/__/
|___/
Contract Name : ${contractName}
Author : ${config.authorInfo.author}
Created Date : ${config.authorInfo.createdDate}
Purpose : ${config.authorInfo.purpose}
Description : ${config.authorInfo.description}
*/`;
}
// 处理单个文件
function processFile(filePath, outputDir, config) {
const filename = path.basename(filePath);
// 检查是否在排除列表中
if (config.excludedFiles.includes(filename)) {
console.log(`Skipping excluded file: ${filename}`);
return null;
}
try {
let content = fs.readFileSync(filePath, "utf8");
// 保存许可证注释
let licenseComment = "";
if (config.preserveLicense) {
const licenseMatch = content.match(/\/\/\s*SPDX-License-Identifier:.*?\n/);
if (licenseMatch) {
licenseComment = licenseMatch[0];
}
}
// 提取合约名称
const contractName = extractContractName(content);
// 去除所有注释
content = (0, strip_comments_1.default)(content);
// 添加自定义头部
let result = "";
if (config.headerStyle === "dubai") {
result = generateDubaiHeader(contractName, config) + "\n\n" + content;
}
else if (config.headerStyle === "standard") {
result = generateStandardHeader(contractName, config) + "\n\n" + content;
}
else if (config.customHeader) {
result = config.customHeader + "\n" + content;
}
else if (config.preserveLicense && licenseComment) {
result = licenseComment + content;
}
else {
result = content;
}
// 写入输出文件
const outputPath = path.join(outputDir, filename);
fs.writeFileSync(outputPath, result);
console.log(`Processed: ${filename}`);
return outputPath;
}
catch (error) {
console.error(`Error processing file ${filename}:`, error);
return null;
}
}
// 递归处理目录
function processDirectory(dirPath, outputDir, config) {
const items = fs.readdirSync(dirPath);
for (const item of items) {
const itemPath = path.join(dirPath, item);
const stats = fs.statSync(itemPath);
if (stats.isFile() && item.endsWith(".sol")) {
// 为输出目录创建相对路径结构
const relativePath = path.relative(process.cwd(), dirPath);
const targetDir = path.join(outputDir, relativePath);
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
}
processFile(itemPath, targetDir, config);
}
else if (stats.isDirectory()) {
processDirectory(itemPath, outputDir, config);
}
}
}
//# sourceMappingURL=index.js.map