UNPKG

hardhat-output-validator

Version:

Zero-config Hardhat plugin to check the build output of Solidity contracts

134 lines 8.22 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getFullBuildInfo = exports.getDefaultSeverity = exports.getConfig = void 0; /* eslint-disable guard-for-in, max-len, no-await-in-loop, no-restricted-syntax */ const config_1 = require("hardhat/config"); const task_names_1 = require("hardhat/builtin-tasks/task-names"); const chalk_1 = __importDefault(require("chalk")); require("./type-extensions"); const checks_1 = require("./checks"); const _1compWarnings_1 = require("./checks/1compWarnings"); (0, config_1.extendConfig)((config, userConfig) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1; const errorMode = ((_a = userConfig.outputValidator) === null || _a === void 0 ? void 0 : _a.errorMode) || false; const defaultValue = errorMode ? 'error' : 'warning'; config.outputValidator = { errorMode, strict: ((_b = userConfig.outputValidator) === null || _b === void 0 ? void 0 : _b.strict) || false, checks: Object.assign(Object.assign({ title: defaultValue, details: defaultValue, compilationWarnings: defaultValue, missingUserDoc: defaultValue, missingDevDoc: defaultValue, events: false, functions: defaultValue, variables: false, ctor: false, params: defaultValue, returns: defaultValue }, (((_c = userConfig.outputValidator) === null || _c === void 0 ? void 0 : _c.checks) || {})), { userDoc: Object.assign({ events: ((_e = (_d = userConfig.outputValidator) === null || _d === void 0 ? void 0 : _d.checks) === null || _e === void 0 ? void 0 : _e.events) || defaultValue, functions: ((_g = (_f = userConfig.outputValidator) === null || _f === void 0 ? void 0 : _f.checks) === null || _g === void 0 ? void 0 : _g.functions) || defaultValue, variables: ((_j = (_h = userConfig.outputValidator) === null || _h === void 0 ? void 0 : _h.checks) === null || _j === void 0 ? void 0 : _j.variables) || defaultValue, ctor: ((_l = (_k = userConfig.outputValidator) === null || _k === void 0 ? void 0 : _k.checks) === null || _l === void 0 ? void 0 : _l.ctor) || defaultValue }, (((_o = (_m = userConfig.outputValidator) === null || _m === void 0 ? void 0 : _m.checks) === null || _o === void 0 ? void 0 : _o.userDoc) || {})), devDoc: Object.assign({ events: ((_q = (_p = userConfig.outputValidator) === null || _p === void 0 ? void 0 : _p.checks) === null || _q === void 0 ? void 0 : _q.events) || defaultValue, functions: ((_s = (_r = userConfig.outputValidator) === null || _r === void 0 ? void 0 : _r.checks) === null || _s === void 0 ? void 0 : _s.functions) || defaultValue, variables: ((_u = (_t = userConfig.outputValidator) === null || _t === void 0 ? void 0 : _t.checks) === null || _u === void 0 ? void 0 : _u.variables) || defaultValue, ctor: ((_w = (_v = userConfig.outputValidator) === null || _v === void 0 ? void 0 : _v.checks) === null || _w === void 0 ? void 0 : _w.ctor) || defaultValue }, (((_y = (_x = userConfig.outputValidator) === null || _x === void 0 ? void 0 : _x.checks) === null || _y === void 0 ? void 0 : _y.devDoc) || {})) }), include: ((_z = userConfig.outputValidator) === null || _z === void 0 ? void 0 : _z.include) || [], exclude: ((_0 = userConfig.outputValidator) === null || _0 === void 0 ? void 0 : _0.exclude) || [], runOnCompile: ((_1 = userConfig.outputValidator) === null || _1 === void 0 ? void 0 : _1.runOnCompile) || false, }; }); (0, config_1.task)(task_names_1.TASK_COMPILE, async (args, hre, runSuper) => { const config = hre.config.outputValidator; // Updates the compiler settings for (const compiler of hre.config.solidity.compilers) { compiler.settings.outputSelection['*']['*'].push('devdoc'); compiler.settings.outputSelection['*']['*'].push('userdoc'); } // Calls the actual COMPILE task await runSuper(); if (!config.runOnCompile) { return; } await run(hre); }); (0, config_1.task)('validateOutput', async (args, hre) => { console.log('<<< Validating Output for Natspec >>>'); await run(hre); }); let getConfig = () => ({}); exports.getConfig = getConfig; let getDefaultSeverity = () => 'warning'; exports.getDefaultSeverity = getDefaultSeverity; let getFullBuildInfo = () => []; exports.getFullBuildInfo = getFullBuildInfo; const run = async (hre) => { const config = hre.config.outputValidator; exports.getConfig = () => config; exports.getDefaultSeverity = () => (config.errorMode ? 'error' : 'warning'); const getBuildInfo = async (qualifiedName) => hre.artifacts.getBuildInfo(qualifiedName); // Loops through all the qualified names to get all the compiled contracts const getContractBuildInfo = async (qualifiedName) => { const [source, name] = qualifiedName.split(':'); const build = await getBuildInfo(qualifiedName); const info = build === null || build === void 0 ? void 0 : build.output.contracts[source][name]; return Object.assign(Object.assign({}, info), { filePath: source, fileName: name }); }; // ====== Start ====== console.log('<<< Starting Output Checks >>> '); // Apply filters const allContracts = await hre.artifacts.getAllFullyQualifiedNames(); const qualifiedNames = allContracts .filter((str) => str.startsWith('contracts')) .filter((path) => { // Checks if this contact is included const includesPath = config.include.some((str) => path.includes(str)); const excludesPath = config.exclude.some((str) => path.includes(str)); return (config.include.length === 0 || includesPath) && !excludesPath; }); console.log('qualifiedNames', qualifiedNames); // ============ 1.Setup ============ // (*0) Full Build Info const buildInfo = (await Promise.all(qualifiedNames.map(getBuildInfo))).filter((inf) => inf !== undefined); exports.getFullBuildInfo = () => buildInfo; // (*1) Subset - build.output.contracts[name] const contractBuildInfo = (await Promise.all(qualifiedNames.map(getContractBuildInfo))).filter((inf) => inf !== undefined); // ============ 2.Checks ============ // (*0) checks console.log('<<< Checking for Errors >>> '); const errors = contractBuildInfo.reduce((foundErrors, info) => { const docErrors = (0, checks_1.checkForErrors)(info); if (docErrors && docErrors.length > 0) { const key = info.filePath + ':' + info.fileName; foundErrors[key] = docErrors; } return foundErrors; }, {}); // (*1) checks // compilationWarnings if (config.checks.compilationWarnings) { const compErros = (0, _1compWarnings_1.checkForCompilationWarnings)(buildInfo, config.checks.compilationWarnings); Object.keys(compErros).forEach((fi) => { if (!errors[fi]) { errors[fi] = []; } errors[fi].push(...compErros[fi]); }); } // ============ 3.Act ============ const printErrors = () => { let printedErrors = false; Object.keys(errors).forEach((file) => { const errorsInfo = errors[file]; if (errorsInfo && errorsInfo.length > 0) { errorsInfo.forEach((erIn) => { if (erIn.severityLevel === 'error') { console.error(chalk_1.default.red(erIn.text)); if (!printedErrors) { printedErrors = true; } } else { console.warn(chalk_1.default.yellow(erIn.text)); } }); } }); return printedErrors; }; if (Object.keys(errors).length > 0) { const printedErrors = printErrors(); if (printedErrors) { throw new Error('Missing Natspec Comments - Found Errors.'); } } console.log('✅ All Contracts have been checked for missing Natspec comments'); // ====== END ====== }; //# sourceMappingURL=index.js.map