solidity-docgen
Version:
Solidity API documentation automatic generator.
255 lines • 7.88 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_1 = require("lodash");
const path_1 = __importDefault(require("path"));
const execall_1 = __importDefault(require("execall"));
const handlebars_1 = require("./handlebars");
class SoliditySource {
constructor(contractsDir, solcOutput, contractTemplate) {
this.contractsDir = contractsDir;
this.solcOutput = solcOutput;
this.contractTemplate = contractTemplate;
}
get contracts() {
return lodash_1.flatten(this.files.map(file => file.contracts));
}
get files() {
return Object.keys(this.solcOutput.sources)
.map(fileName => this.file(fileName));
}
file(fileName) {
return new SolidityFile(this, this.solcOutput.sources[fileName].ast, path_1.default.relative(this.contractsDir, fileName));
}
contractById(id) {
const contract = this.contracts.find(c => c.astId === id);
if (contract === undefined) {
throw new Error(`Contract with id ${id} not found`);
}
return contract;
}
}
exports.SoliditySource = SoliditySource;
class SolidityFile {
constructor(source, ast, path) {
this.source = source;
this.ast = ast;
this.path = path;
}
get contracts() {
const astNodes = this.ast.nodes.filter(n => n.nodeType === 'ContractDefinition');
return astNodes.map(node => new SolidityContract(this.source, this, node));
}
}
class SolidityContract {
constructor(source, file, astNode) {
this.source = source;
this.file = file;
this.astNode = astNode;
}
toString() {
return this.source.contractTemplate(this);
}
get name() {
return this.astNode.name;
}
get fullName() {
return this.name;
}
get anchor() {
return this.name;
}
get linkable() {
return [this, ...this.modifiers, ...this.functions, ...this.events];
}
get inheritance() {
return this.astNode.linearizedBaseContracts.map(id => this.source.contractById(id));
}
get functions() {
return lodash_1.uniqBy(lodash_1.flatten(this.inheritance.map(c => c.ownFunctions)), f => f.signature);
}
get ownFunctions() {
return this.astNode.nodes
.filter(isFunctionDefinition)
.filter(n => n.visibility !== 'private')
.map(n => new SolidityFunction(this, n));
}
get events() {
return lodash_1.uniqBy(lodash_1.flatten(this.inheritance.map(c => c.ownEvents)), f => f.signature);
}
get ownEvents() {
return this.astNode.nodes
.filter(isEventDefinition)
.map(n => new SolidityEvent(this, n));
}
get modifiers() {
return lodash_1.uniqBy(lodash_1.flatten(this.inheritance.map(c => c.ownModifiers)), f => f.signature);
}
get ownModifiers() {
return this.astNode.nodes
.filter(isModifierDefinition)
.map(n => new SolidityModifier(this, n));
}
get natspec() {
if (this.astNode.documentation === null) {
return {};
}
return parseNatSpec(this.astNode.documentation);
}
get astId() {
return this.astNode.id;
}
}
exports.SolidityContract = SolidityContract;
class SolidityContractItem {
constructor(contract, astNode) {
this.contract = contract;
}
get name() {
return this.astNode.name;
}
get fullName() {
return `${this.contract.name}.${this.name}`;
}
get anchor() {
return `${this.contract.name}-${handlebars_1.slug(this.signature)}`;
}
get args() {
return SolidityTypedVariableArray.fromParameterList(this.astNode.parameters);
}
get signature() {
return `${this.name}(${this.args.map(a => a.typeName).join(',')})`;
}
get natspec() {
if (this.astNode.documentation === null) {
return {};
}
return parseNatSpec(this.astNode.documentation);
}
}
class SolidityFunction extends SolidityContractItem {
constructor(contract, astNode) {
super(contract, astNode);
this.astNode = astNode;
}
get name() {
const { name, kind } = this.astNode;
const isRegularFunction = kind === 'function';
return isRegularFunction ? name : kind;
}
get outputs() {
return SolidityTypedVariableArray.fromParameterList(this.astNode.returnParameters);
}
get visibility() {
return this.astNode.visibility;
}
}
class SolidityEvent extends SolidityContractItem {
constructor(contract, astNode) {
super(contract, astNode);
this.astNode = astNode;
}
}
class SolidityModifier extends SolidityContractItem {
constructor(contract, astNode) {
super(contract, astNode);
this.astNode = astNode;
}
}
class SolidityTypedVariable {
constructor(type, name) {
this.type = type;
this.name = name;
}
get typeName() {
return this.type.typeDescriptions.typeString;
}
toString() {
if (this.name) {
return [this.typeName, this.name].join(' ');
}
else {
return this.typeName;
}
}
}
class PrettyArray extends Array {
toString() {
return this.map(e => e.toString()).join(', ');
}
}
class SolidityTypedVariableArray extends PrettyArray {
static fromParameterList(parameters) {
return SolidityTypedVariableArray.from(parameters.parameters.map(p => new SolidityTypedVariable(p.typeName, p.name || undefined)));
}
get types() {
return this.map(v => v.typeName);
}
get names() {
return this.map(v => v.name);
}
}
function parseNatSpec(doc) {
const res = {};
// fix solc buggy parsing of doc comments
// reverse engineered from solc behavior...
const raw = doc.replace(/\n\n?^[ \t]*\*[ \t]*/mg, '\n\n');
const untagged = raw.match(/^(?:(?!^@\w+ )[^])+/m);
if (untagged) {
setOrAppend(res, 'userdoc', untagged[0]);
}
const tagMatches = execall_1.default(/^@(\w+) ((?:(?!^@\w+ )[^])*)/gm, raw);
for (const m of tagMatches) {
const [tag, content] = m.subMatches;
if (tag === 'dev') {
setOrAppend(res, 'devdoc', content);
}
if (tag === 'notice') {
setOrAppend(res, 'userdoc', content);
}
if (tag === 'title') {
res.title = content;
}
if (tag === 'param') {
const paramMatches = content.match(/(\w+) ([^]*)/);
if (paramMatches) {
const [, param, description] = paramMatches;
if (res.params === undefined) {
res.params = [];
}
res.params.push({ param, description });
}
}
if (tag === 'return') {
const paramMatches = content.match(/(\w+) ([^]*)/);
if (paramMatches) {
const [, param, description] = paramMatches;
if (res.returns === undefined) {
res.returns = [];
}
res.returns.push({ param, description });
}
}
}
return res;
}
function setOrAppend(obj, key, value) {
if (obj[key] === undefined) {
obj[key] = value;
}
else {
obj[key] += value;
}
}
function isFunctionDefinition(node) {
return node.nodeType === 'FunctionDefinition';
}
function isEventDefinition(node) {
return node.nodeType === 'EventDefinition';
}
function isModifierDefinition(node) {
return node.nodeType === 'ModifierDefinition';
}
//# sourceMappingURL=solidity.js.map