8.1. List functions in a contract#
This function finds a contract in the compilation unit with the given name and returns a list of FunctionDefinition
within it. We use a combination of the Query API and the AST types:
list-functions-in-contract.mts
import { assertNonterminalNode, Query } from "@nomicfoundation/slang/cst";
import { ContractDefinition, FunctionDefinition } from "@nomicfoundation/slang/ast";
import { CompilationUnit } from "@nomicfoundation/slang/compilation";
export function listFunctionsInContract(unit: CompilationUnit, contractName: string): FunctionDefinition[] {
for (const file of unit.files()) {
const cursor = file.createTreeCursor();
const query = Query.create(`
[ContractDefinition
@name name: [Identifier]
]
`);
const matches = cursor.query([query]);
for (const match of matches) {
const contractNode = match.root.node;
assertNonterminalNode(contractNode);
const name = match.captures["name"][0].node.unparse();
if (name == contractName) {
// found the contract
const contract = new ContractDefinition(contractNode);
const functions = contract.members.items
.map((member) => member.variant)
.filter((member) => member instanceof FunctionDefinition);
return functions;
}
}
}
throw new Error(`Could not find contract named ${contractName}`);
}
From the list of FunctionDefinition
nodes, it's easy to obtain the names of the functions:
test-list-functions.mts
import assert from "node:assert";
import { listFunctionsInContract } from "./list-functions-in-contract.mjs";
import buildSampleCompilationUnit from "../../common/sample-contract.mjs";
test("list functions by contract name", async () => {
const unit = await buildSampleCompilationUnit();
const functions = listFunctionsInContract(unit, "Counter");
const functionNames = functions.map((fun) => fun.name.cst.unparse().trim());
assert.deepEqual(functionNames, ["count", "increment"]);
});