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