hyperformula
Version:
HyperFormula is a JavaScript engine for efficient processing of spreadsheet-like data and formulas
184 lines (183 loc) • 6.17 kB
TypeScript
/**
* @license
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/
import { SimpleCellAddress } from '../Cell';
import { SimpleCellRange } from '../AbsoluteCellRange';
import { TopSortResult } from './TopSort';
export declare type NodeId = number;
export declare type NodeAndId<Node> = {
node: Node;
id: NodeId;
};
export declare type DependencyQuery<Node> = (vertex: Node) => [(SimpleCellAddress | SimpleCellRange), Node][];
/**
* Provides directed graph structure.
*
* Idea for performance improvement:
* - use Set<Node>[] instead of NodeId[][] for edgesSparseArray
*/
export declare class Graph<Node> {
private readonly dependencyQuery;
/**
* A sparse array. The value nodesSparseArray[n] exists if and only if node n is in the graph.
* @private
*/
private nodesSparseArray;
/**
* A sparse array. The value edgesSparseArray[n] exists if and only if node n is in the graph.
* The edgesSparseArray[n] is also a sparse array. It may contain removed nodes. To make sure check nodesSparseArray.
* @private
*/
private edgesSparseArray;
/**
* A mapping from node to its id. The value nodesIds.get(node) exists if and only if node is in the graph.
* @private
*/
private nodesIds;
/**
* A ProcessableValue object.
* @private
*/
private dirtyAndVolatileNodeIds;
/**
* A set of node ids. The value infiniteRangeIds.get(nodeId) exists if and only if node is in the graph.
* @private
*/
private infiniteRangeIds;
/**
* A dense array. It may contain duplicates and removed nodes.
* @private
*/
private changingWithStructureNodeIds;
private nextId;
constructor(dependencyQuery: DependencyQuery<Node>);
/**
* Iterate over all nodes the in graph
*/
getNodes(): Node[];
/**
* Checks whether a node is present in graph
*
* @param node - node to check
*/
hasNode(node: Node): boolean;
/**
* Checks whether exists edge between nodes. If one or both of nodes are not present in graph, returns false.
*
* @param fromNode - node from which edge is outcoming
* @param toNode - node to which edge is incoming
*/
existsEdge(fromNode: Node, toNode: Node): boolean;
/**
* Returns nodes adjacent to given node. May contain removed nodes.
*
* @param node - node to which adjacent nodes we want to retrieve
*
* Idea for performance improvement:
* - return an array instead of set
*/
adjacentNodes(node: Node): Set<Node>;
/**
* Returns number of nodes adjacent to given node. Contrary to adjacentNodes(), this method returns only nodes that are present in graph.
*
* @param node - node to which adjacent nodes we want to retrieve
*/
adjacentNodesCount(node: Node): number;
/**
* Adds node to a graph
*
* @param node - a node to be added
*/
addNodeAndReturnId(node: Node): NodeId;
/**
* Adds edge between nodes.
*
* The nodes had to be added to the graph before, or the error will be raised
*
* @param fromNode - node from which edge is outcoming
* @param toNode - node to which edge is incoming
*/
addEdge(fromNode: Node | NodeId, toNode: Node | NodeId): void;
/**
* Removes node from graph
*/
removeNode(node: Node): [(SimpleCellAddress | SimpleCellRange), Node][];
/**
* Removes edge between nodes.
*/
removeEdge(fromNode: Node | NodeId, toNode: Node | NodeId): void;
/**
* Removes edge between nodes if it exists.
*/
removeEdgeIfExists(fromNode: Node | NodeId, toNode: Node | NodeId): void;
/**
* Sorts the whole graph topologically. Nodes that are on cycles are kept separate.
*/
topSortWithScc(): TopSortResult<Node>;
/**
* Sorts the graph topologically. Nodes that are on cycles are kept separate.
*
* @param modifiedNodes - seed for computation. The algorithm assumes that only these nodes have changed since the last run.
* @param operatingFunction - recomputes value of a node, and returns whether a change occurred
* @param onCycle - action to be performed when node is on cycle
*/
getTopSortedWithSccSubgraphFrom(modifiedNodes: Node[], operatingFunction: (node: Node) => boolean, onCycle: (node: Node) => void): TopSortResult<Node>;
/**
* Marks node as volatile.
*/
markNodeAsVolatile(node: Node): void;
/**
* Marks node as dirty.
*/
markNodeAsDirty(node: Node): void;
/**
* Returns an array of nodes that are marked as dirty and/or volatile.
*/
getDirtyAndVolatileNodes(): Node[];
/**
* Clears dirty nodes.
*/
clearDirtyNodes(): void;
/**
* Marks node as changingWithStructure.
*/
markNodeAsChangingWithStructure(node: Node): void;
/**
* Marks all nodes marked as changingWithStructure as dirty.
*/
markChangingWithStructureNodesAsDirty(): void;
/**
* Marks node as infinite range.
*/
markNodeAsInfiniteRange(node: Node | NodeId): void;
/**
* Returns an array of nodes marked as infinite ranges
*/
getInfiniteRanges(): NodeAndId<Node>[];
/**
* Returns the internal id of a node.
*/
getNodeId(node: Node): NodeId | undefined;
/**
*
*/
private getNodeIdIfNotNumber;
/**
* Removes invalid neighbors of a given node from the edges array and returns adjacent nodes for the input node.
*/
private fixEdgesArrayForNode;
/**
* Removes edges from the given node to its dependencies based on the dependencyQuery function.
*/
private removeDependencies;
/**
* processFn for dirtyAndVolatileNodeIds ProcessableValue instance
* @private
*/
private processDirtyAndVolatileNodeIds;
/**
* Returns error for missing node.
*/
private missingNodeError;
}