solidity-docgen
Version:
Solidity API documentation automatic generator.
172 lines • 6.96 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__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 });
exports.SolcAdapter = exports.compile = exports.outputSelection = void 0;
const lodash_1 = require("lodash");
const fs_1 = __importDefault(require("fs"));
const semver_1 = __importDefault(require("semver"));
exports.outputSelection = {
'*': {
'': [
'ast',
],
},
};
async function compile(filter, solcModule = require.resolve('solc'), solcSettings = { optimizer: { enabled: true, runs: 200 } }) {
const solc = await SolcAdapter.require(solcModule);
const files = await filter.glob('*.sol');
const sources = lodash_1.fromPairs(await Promise.all(files.map(async (file) => [
file,
{ content: await fs_1.default.promises.readFile(file, 'utf8') },
])));
const solcInput = {
language: "Solidity",
sources: sources,
settings: { ...solcSettings, outputSelection: exports.outputSelection },
};
const solcOutput = solc.compile(solcInput);
const { errors: allErrors } = solcOutput;
if (allErrors && allErrors.some(e => e.severity === 'error')) {
const errors = allErrors.filter(e => e.severity === 'error');
const firstError = errors[0].formattedMessage;
const moreErrors = errors.length === 1 ? '' : ` (And ${errors.length - 1} other errors...)`;
throw new Error(`Solidity was unable to compile. ${firstError}${moreErrors}`);
}
return solcOutput;
}
exports.compile = compile;
class SolcAdapter {
constructor(solc) {
this.solc = solc;
}
static async require(solcModule) {
const solc = await Promise.resolve().then(() => __importStar(require(solcModule)));
return new SolcAdapter(solc);
}
compile(input) {
const inputJSON = JSON.stringify(input);
const solcOutputString = semver_1.default.satisfies(this.solc.version(), '>=0.6')
? this.solc.compile(inputJSON, { import: importCallback })
: this.solc.compileStandardWrapper(inputJSON, importCallback);
const solcOutput = JSON.parse(solcOutputString);
if (semver_1.default.satisfies(this.solc.version(), '^0.4')) {
for (const source of Object.values(solcOutput.sources)) {
for (const fileNode of source.ast.nodes) {
if (fileNode.nodeType === 'ContractDefinition') {
for (const contractNode of fileNode.nodes) {
if (contractNode.nodeType === 'FunctionDefinition') {
if (contractNode.isConstructor) {
contractNode.kind = 'constructor';
}
else if (contractNode.name === '') {
contractNode.kind = 'fallback';
}
else {
contractNode.kind = 'function';
}
}
}
}
}
}
;
}
const reader = new ASTReader(input, solcOutput);
const adaptDocumentation = (node) => {
var _a;
if (typeof node.documentation === 'string') {
// fix solc buggy parsing of doc comments
// reverse engineered from solc behavior...
node.documentation = cleanUpDocstringFromSolc(node.documentation);
}
else if (((_a = node.documentation) === null || _a === void 0 ? void 0 : _a.text) !== undefined) {
const source = reader.read(node.documentation);
if (source !== undefined) {
node.documentation = cleanUpDocstringFromSource(source);
}
else {
node.documentation = cleanUpDocstringFromSolc(node.documentation.text);
}
}
};
for (const source of Object.values(solcOutput.sources)) {
for (const fileNode of source.ast.nodes) {
adaptDocumentation(fileNode);
if (fileNode.nodeType === 'ContractDefinition') {
for (const contractNode of fileNode.nodes) {
adaptDocumentation(contractNode);
}
}
}
}
return solcOutput;
}
}
exports.SolcAdapter = SolcAdapter;
function importCallback(path) {
try {
const resolved = require.resolve(path, { paths: ['.'] });
return {
contents: fs_1.default.readFileSync(resolved, 'utf8'),
};
}
catch (e) {
return {
error: e.message,
};
}
}
class ASTReader {
constructor(input, output) {
this.input = input;
this.output = output;
}
read(node) {
var _a;
const { source, start, length } = this.decodeSrc(node.src);
return (_a = this.input.sources[source]) === null || _a === void 0 ? void 0 : _a.content.slice(start, start + length);
}
decodeSrc(src) {
const [start, length, sourceId] = src.split(':').map(s => parseInt(s));
const source = Object.keys(this.output.sources).find(s => this.output.sources[s].id === sourceId);
if (source === undefined) {
throw new Error(`No source with id ${sourceId}`);
}
return { source, start, length };
}
}
function cleanUpDocstringFromSolc(text) {
// fix solc buggy parsing of doc comments
// reverse engineered from solc behavior
return text
.replace(/\n\n?^[ \t]*(?:\*|\/\/\/)/mg, '\n\n')
.replace(/^[ \t]?/mg, '');
}
function cleanUpDocstringFromSource(text) {
return text
.replace(/^\/\*\*(.*)\*\/$/s, '$1')
.trim()
.replace(/^[ \t]*(\*|\/\/\/)[ \t]?/mg, '');
}
//# sourceMappingURL=solc.js.map
;