solidity-docgen
Version:
Documentation generator for Solidity smart contracts.
139 lines (116 loc) • 4.84 kB
text/typescript
import { EnumDefinition, ErrorDefinition, EventDefinition, FunctionDefinition, ModifierDefinition, ParameterList, StructDefinition, UserDefinedValueTypeDefinition, VariableDeclaration } from 'solidity-ast';
import { findAll, isNodeType } from 'solidity-ast/utils';
import { NatSpec, parseNatspec } from '../utils/natspec';
import { DocItemContext, DOC_ITEM_CONTEXT } from '../site';
import { mapValues } from '../utils/map-values';
import { DocItem, docItemTypes } from '../doc-item';
import { formatVariable } from './helpers';
import { PropertyGetter } from '../templates';
import { itemType } from '../utils/item-type';
type TypeDefinition = StructDefinition | EnumDefinition | UserDefinedValueTypeDefinition;
export function type({ item }: DocItemContext): string {
return itemType(item);
}
export function natspec({ item }: DocItemContext): NatSpec {
return parseNatspec(item);
}
export function name({ item }: DocItemContext, original?: unknown): string {
if (item.nodeType === 'FunctionDefinition') {
return typeof(original) === 'string' && original !== '' ? original : item.kind;
} else {
return original as string;
}
}
export function fullName({ item, contract }: DocItemContext): string {
if (contract) {
return `${contract.name}.${item.name}`;
} else {
return `${item.name}`;
}
}
export function signature({ item }: DocItemContext): string | undefined {
switch (item.nodeType) {
case 'ContractDefinition':
return undefined;
case 'FunctionDefinition': {
const { kind, name } = item;
const params = item.parameters.parameters;
const returns = item.returnParameters.parameters;
const head = (kind === 'function' || kind === 'freeFunction') ? `function ${name}` : kind;
let res = [
`${head}(${params.map(formatVariable).join(', ')})`,
item.visibility,
];
if (item.stateMutability !== 'nonpayable') {
res.push(item.stateMutability);
}
if (item.virtual) {
res.push('virtual');
}
if (returns.length > 0) {
res.push(`returns (${returns.map(formatVariable).join(', ')})`);
}
return res.join(' ');
}
case 'EventDefinition': {
const params = item.parameters.parameters;
return `event ${item.name}(${params.map(formatVariable).join(', ')})`;
}
case 'ErrorDefinition': {
const params = item.parameters.parameters;
return `error ${item.name}(${params.map(formatVariable).join(', ')})`;
}
case 'ModifierDefinition': {
const params = item.parameters.parameters;
return `modifier ${item.name}(${params.map(formatVariable).join(', ')})`;
}
case 'VariableDeclaration':
return formatVariable(item);
}
}
interface Param extends VariableDeclaration {
type: string;
natspec?: string;
};
function getParams(params: ParameterList, natspec: NatSpec['params'] | NatSpec['returns']): Param[] {
return params.parameters.map((p, i) => ({
...p,
type: p.typeDescriptions.typeString!,
natspec: natspec?.find((q, j) => q.name === undefined ? i === j : p.name === q.name)?.description,
}));
}
export function params({ item }: DocItemContext): Param[] | undefined {
if ('parameters' in item) {
return getParams(item.parameters, natspec(item[DOC_ITEM_CONTEXT]).params);
}
}
export function returns({ item }: DocItemContext): Param[] | undefined {
if ('returnParameters' in item) {
return getParams(item.returnParameters, natspec(item[DOC_ITEM_CONTEXT]).returns);
}
}
export function items({ item }: DocItemContext): DocItem[] | undefined {
return (item.nodeType === 'ContractDefinition')
? item.nodes.filter(isNodeType(docItemTypes)).filter(n => !('visibility' in n) || n.visibility !== 'private')
: undefined;
}
export function functions({ item }: DocItemContext): FunctionDefinition[] | undefined {
return [...findAll('FunctionDefinition', item)].filter(f => f.visibility !== 'private');
}
export function events({ item }: DocItemContext): EventDefinition[] | undefined {
return [...findAll('EventDefinition', item)];
}
export function modifiers({ item }: DocItemContext): ModifierDefinition[] | undefined {
return [...findAll('ModifierDefinition', item)];
}
export function errors({ item }: DocItemContext): ErrorDefinition[] | undefined {
return [...findAll('ErrorDefinition', item)];
}
export function variables({ item }: DocItemContext): VariableDeclaration[] | undefined {
return (item.nodeType === 'ContractDefinition')
? item.nodes.filter(isNodeType('VariableDeclaration')).filter(v => v.stateVariable && v.visibility !== 'private')
: undefined;
}
export function types({ item }: DocItemContext): TypeDefinition[] | undefined {
return [...findAll(['StructDefinition', 'EnumDefinition', 'UserDefinedValueTypeDefinition'], item)];
}