1import { DefaultDependencyKind, DependencyKind, Package } from '../Packages';
2import PackagesGraphEdge from './PackagesGraphEdge';
3
4/**
5 * A graph node that refers to the single package.
6 */
7export default class PackagesGraphNode {
8  /**
9   * The package represented by the node.
10   */
11  pkg: Package;
12
13  /**
14   * The package name.
15   */
16  name: string;
17
18  /**
19   * Indicates how deep the node is placed in the graph.
20   * Depth of nodes without incoming edges is equal to `0`.
21   */
22  depth: number = 0;
23
24  /**
25   * Edges connecting this node with its dependencies.
26   */
27  outgoingEdges: PackagesGraphEdge[] = [];
28
29  /**
30   * Edges connecting this node with its dependents.
31   */
32  incomingEdges: PackagesGraphEdge[] = [];
33
34  constructor(pkg: Package) {
35    this.pkg = pkg;
36    this.name = pkg.packageName;
37  }
38
39  getOutgoingEdgeForNode(node: PackagesGraphNode): PackagesGraphEdge | null {
40    return this.outgoingEdges.find((edge) => edge.destination === node) ?? null;
41  }
42
43  getIncomingEdgeForNode(node: PackagesGraphNode): PackagesGraphEdge | null {
44    return this.incomingEdges.find((edge) => edge.origin === node) ?? null;
45  }
46
47  getAllDependentEdges(kinds: DependencyKind[] = DefaultDependencyKind): PackagesGraphEdge[] {
48    const allDependentEdges = this.incomingEdges
49      .map((edge) => {
50        if (!edge.isCyclic && kinds.includes(edge.getDominantKind())) {
51          return [edge, ...edge.origin.getAllDependentEdges(kinds)];
52        }
53        return [];
54      })
55      .flat();
56
57    return [...new Set(allDependentEdges)];
58  }
59
60  getAllDependents(kinds: DependencyKind[] = DefaultDependencyKind): PackagesGraphNode[] {
61    return [...new Set(this.getAllDependentEdges(kinds).map((edge) => edge.origin))];
62  }
63
64  getAllDependencyEdges(kinds: DependencyKind[] = DefaultDependencyKind): PackagesGraphEdge[] {
65    const allDependencyEdges = this.outgoingEdges
66      .map((edge) => {
67        if (!edge.isCyclic && kinds.includes(edge.getDominantKind())) {
68          return [edge, ...edge.destination.getAllDependencyEdges(kinds)];
69        }
70        return [];
71      })
72      .flat();
73
74    return [...new Set(allDependencyEdges)];
75  }
76
77  getAllDependencies(kinds: DependencyKind[] = DefaultDependencyKind): PackagesGraphNode[] {
78    return [...new Set(this.getAllDependencyEdges(kinds).map((edge) => edge.destination))];
79  }
80
81  getOutgoingEdgesOfKinds(kinds: DependencyKind[]): PackagesGraphEdge[] {
82    return this.outgoingEdges.filter((edge) => {
83      return kinds.some((kind) => edge.isOfKind(kind));
84    });
85  }
86
87  isDependentOf(node: PackagesGraphNode): boolean {
88    return !!this.getOutgoingEdgeForNode(node);
89  }
90
91  isDependencyOf(node: PackagesGraphNode): boolean {
92    return !!this.getIncomingEdgeForNode(node);
93  }
94}
95