typir
Version:
General purpose type checking library
98 lines • 4.87 kB
JavaScript
/******************************************************************************
* Copyright 2025 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
export class DefaultGraphAlgorithms {
constructor(services) {
this.graph = services.infrastructure.Graph;
}
collectReachableTypes(from, $relations, filterEdges) {
const result = new Set();
const remainingToCheck = [from];
while (remainingToCheck.length > 0) {
const current = remainingToCheck.pop();
const outgoingEdges = $relations.flatMap(r => current.getOutgoingEdges(r));
for (const edge of outgoingEdges) {
if (edge.cachingInformation === 'LINK_EXISTS' && (filterEdges === undefined || filterEdges(edge))) {
if (result.has(edge.to)) {
// already checked
}
else {
result.add(edge.to); // this type is reachable
remainingToCheck.push(edge.to); // check it for recursive conversions
}
}
}
}
return result;
}
existsEdgePath(from, to, $relations, filterEdges) {
const visited = new Set();
const stack = [from];
while (stack.length > 0) {
const current = stack.pop();
visited.add(current);
const outgoingEdges = $relations.flatMap(r => current.getOutgoingEdges(r));
for (const edge of outgoingEdges) {
if (edge.cachingInformation === 'LINK_EXISTS' && (filterEdges === undefined || filterEdges(edge))) {
if (edge.to === to) {
/* It was possible to reach our goal type using this path.
* Base case that also catches the case in which start and end are the same
* (is there a cycle?). Therefore it is allowed to have been "visited".
* True will only be returned if there is a real path (cycle) made up of edges
*/
return true;
}
if (!visited.has(edge.to)) {
/* The target node of this edge has not been visited before and is also not our goal node
* Add it to the stack and investigate this path later.
*/
stack.push(edge.to);
}
}
}
}
// Fall through means that we could not reach the goal type
return false;
}
getEdgePath(from, to, $relations, filterEdges) {
const visited = new Map(); // the edge from the parent to the current node
visited.set(from, undefined);
const stack = [from];
while (stack.length > 0) {
const current = stack.pop();
const outgoingEdges = $relations.flatMap(r => current.getOutgoingEdges(r));
for (const edge of outgoingEdges) {
if (edge.cachingInformation === 'LINK_EXISTS' && (filterEdges === undefined || filterEdges(edge))) {
if (edge.to === to) {
/* It was possible to reach our goal type using this path.
* Base case that also catches the case in which start and end are the same
* (is there a cycle?). Therefore it is allowed to have been "visited".
* True will only be returned if there is a real path (cycle) made up of edges
*/
const result = [edge];
// collect the path of used edges, from "to" back to "from"
let backNode = edge.from;
while (backNode !== from) {
const backEdge = visited.get(backNode);
result.unshift(backEdge);
backNode = backEdge.from;
}
return result;
}
if (!visited.has(edge.to)) {
/* The target node of this edge has not been visited before and is also not our goal node
* Add it to the stack and investigate this path later.
*/
stack.push(edge.to);
visited.set(edge.to, edge);
}
}
}
}
// Fall through means that we could not reach the goal type
return [];
}
}
//# sourceMappingURL=graph-algorithms.js.map