UNPKG

solidity-docgen

Version:

Solidity API documentation automatic generator.

255 lines 7.88 kB
"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