hardhat
Version:
Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.
127 lines • 5.35 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.DependencyGraph = void 0;
const errors_1 = require("../core/errors");
const errors_list_1 = require("../core/errors-list");
class DependencyGraph {
static async createFromResolvedFiles(resolver, resolvedFiles) {
const graph = new DependencyGraph();
// TODO refactor this to make the results deterministic
await Promise.all(resolvedFiles.map((resolvedFile) => graph._addDependenciesFrom(resolver, resolvedFile)));
return graph;
}
constructor() {
this._resolvedFiles = new Map();
this._dependenciesPerFile = new Map();
// map absolute paths to source names
this._visitedFiles = new Map();
}
getResolvedFiles() {
return Array.from(this._resolvedFiles.values());
}
has(file) {
return this._resolvedFiles.has(file.sourceName);
}
isEmpty() {
return this._resolvedFiles.size === 0;
}
entries() {
return Array.from(this._dependenciesPerFile.entries()).map(([key, value]) => [this._resolvedFiles.get(key), value]);
}
getDependencies(file) {
const dependencies = this._dependenciesPerFile.get(file.sourceName) ?? new Set();
return [...dependencies];
}
getTransitiveDependencies(file) {
const visited = new Set();
const transitiveDependencies = this._getTransitiveDependencies(file, visited, []);
return [...transitiveDependencies];
}
getConnectedComponents() {
const undirectedGraph = {};
for (const [sourceName, dependencies,] of this._dependenciesPerFile.entries()) {
undirectedGraph[sourceName] = undirectedGraph[sourceName] ?? new Set();
for (const dependency of dependencies) {
undirectedGraph[dependency.sourceName] =
undirectedGraph[dependency.sourceName] ?? new Set();
undirectedGraph[sourceName].add(dependency.sourceName);
undirectedGraph[dependency.sourceName].add(sourceName);
}
}
const components = [];
const visited = new Set();
for (const node of Object.keys(undirectedGraph)) {
if (visited.has(node)) {
continue;
}
visited.add(node);
const component = new Set([node]);
const stack = [...undirectedGraph[node]];
while (stack.length > 0) {
const newNode = stack.pop();
if (visited.has(newNode)) {
continue;
}
visited.add(newNode);
component.add(newNode);
[...undirectedGraph[newNode]].forEach((adjacent) => {
if (!visited.has(adjacent)) {
stack.push(adjacent);
}
});
}
components.push(component);
}
const connectedComponents = [];
for (const component of components) {
const dependencyGraph = new DependencyGraph();
for (const sourceName of component) {
const file = this._resolvedFiles.get(sourceName);
const dependencies = this._dependenciesPerFile.get(sourceName);
dependencyGraph._resolvedFiles.set(sourceName, file);
dependencyGraph._dependenciesPerFile.set(sourceName, dependencies);
}
connectedComponents.push(dependencyGraph);
}
return connectedComponents;
}
_getTransitiveDependencies(file, visited, path) {
if (visited.has(file)) {
return new Set();
}
visited.add(file);
const directDependencies = this.getDependencies(file).map((dependency) => ({
dependency,
path,
}));
const transitiveDependencies = new Set(directDependencies);
for (const { dependency } of transitiveDependencies) {
this._getTransitiveDependencies(dependency, visited, path.concat(dependency)).forEach((x) => transitiveDependencies.add(x));
}
return transitiveDependencies;
}
async _addDependenciesFrom(resolver, file) {
const sourceName = this._visitedFiles.get(file.absolutePath);
if (sourceName !== undefined) {
if (sourceName !== file.sourceName) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.RESOLVER.AMBIGUOUS_SOURCE_NAMES, {
sourcenames: `'${sourceName}' and '${file.sourceName}'`,
file: file.absolutePath,
});
}
return;
}
this._visitedFiles.set(file.absolutePath, file.sourceName);
const dependencies = new Set();
this._resolvedFiles.set(file.sourceName, file);
this._dependenciesPerFile.set(file.sourceName, dependencies);
// TODO refactor this to make the results deterministic
await Promise.all(file.content.imports.map(async (imp) => {
const dependency = await resolver.resolveImport(file, imp);
dependencies.add(dependency);
await this._addDependenciesFrom(resolver, dependency);
}));
}
}
exports.DependencyGraph = DependencyGraph;
//# sourceMappingURL=dependencyGraph.js.map
;