UNPKG

solidity-docgen

Version:

Documentation generator for Solidity smart contracts.

64 lines (53 loc) 1.98 kB
import { ContractDefinition, SourceUnit } from "solidity-ast"; import { findAll, isNodeType } from "solidity-ast/utils"; import { DocItemWithContext } from "../site"; import { filterValues, mapValues } from './map-values'; import { mapKeys } from './map-keys'; type Definition = SourceUnit['nodes'][number] & { name: string }; type Scope = { [name in string]: () => { namespace: Scope } | { definition: Definition } }; export function getContractsInScope(item: DocItemWithContext) { const cache = new WeakMap<SourceUnit, Scope>(); return filterValues( flattenScope(run(item.__item_context.file)), isNodeType('ContractDefinition'), ); function run(file: SourceUnit): Scope { if (cache.has(file)) { return cache.get(file)!; } const scope: Scope = {}; cache.set(file, scope); for (const c of file.nodes) { if ('name' in c) { scope[c.name] = () => ({ definition: c }); } } for (const i of findAll('ImportDirective', file)) { const importedFile = item.__item_context.build.deref('SourceUnit', i.sourceUnit); const importedScope = run(importedFile); if (i.unitAlias) { scope[i.unitAlias] = () => ({ namespace: importedScope }); } else if (i.symbolAliases.length === 0) { Object.assign(scope, importedScope); } else { for (const a of i.symbolAliases) { // Delayed function call supports circular dependencies scope[a.local ?? a.foreign.name] = importedScope[a.foreign.name] ?? (() => importedScope[a.foreign.name]!()); } } }; return scope; } } function flattenScope(scope: Scope): Record<string, Definition> { return Object.fromEntries( Object.entries(scope).flatMap(([k, fn]) => { const v = fn(); if ('definition' in v) { return [[k, v.definition] as const]; } else { return Object.entries(mapKeys(flattenScope(v.namespace), k2 => k + '.' + k2)); } }), ); }