@teambit/workspace
Version:
83 lines (82 loc) • 4.49 kB
TypeScript
import { Graph } from '@teambit/graph.cleargraph';
import type { Component, ComponentID } from '@teambit/component';
import type { DependencyResolverMain } from '@teambit/dependency-resolver';
import type { Logger } from '@teambit/logger';
import type { Workspace } from './workspace';
export type ShouldLoadFunc = (id: ComponentID) => Promise<boolean>;
export declare class GraphFromFsBuilder {
private workspace;
private logger;
private dependencyResolver;
private ignoreIds;
private shouldLoadItsDeps?;
private shouldThrowOnMissingDep;
private graph;
private completed;
private depth;
private consumer;
private importedIds;
private currentLane;
constructor(workspace: Workspace, logger: Logger, dependencyResolver: DependencyResolverMain, ignoreIds?: string[], shouldLoadItsDeps?: ShouldLoadFunc | undefined, shouldThrowOnMissingDep?: boolean);
/**
* create a graph with all dependencies and flattened dependencies of the given components.
* the nodes are components and the edges has a label of the dependency type.
*
* the way how it is done is iterations by depths. each depth we gather all the dependencies of
* that depths, make sure all objects exist and then check their dependencies for the next depth.
* once there is no dependency left, we're on the last depth level and the graph is ready.
*
* for example, imagine the following graph:
* A1 -> A2 -> A3
* B1 -> B2 -> B3
* C1 -> C2 -> C3
*
* where the buildGraph is given [A1, B1, C1].
* first, it saves all these components as nodes in the graph. then, it finds the dependencies of
* the next level, in this case they're [A2, B2, C2]. it runs `importMany` in case some objects
* are missing. then, it loads them all (some from FS, some from the model) and sets the edges
* between the component and the dependencies.
* once done, it finds all their dependencies, which are [A3, B3, C3] and repeat the process
* above. since there are no more dependencies, the graph is completed.
* in this case, the total depth levels are 3.
*
* even with a huge project, there are not many depth levels. by iterating through depth levels
* we keep performance sane as the importMany doesn't run multiple time and therefore the round
* trips to the remotes are minimal.
*
* LAZY IMPORT MODE (when shouldLoadItsDeps is provided):
* when a filter function (shouldLoadItsDeps) is provided, we use "lazy import" mode to optimize
* performance. instead of importing all flattened dependencies at once, we:
* 1. only import dependencies that pass the filter (e.g., only aspects)
* 2. don't fetch their flattened dependencies upfront (includeDependencies: false)
* 3. let the recursive depth iteration handle importing deps as needed
* this is much more efficient when building filtered graphs (e.g., aspects-only graph) because
* we avoid fetching huge dependency trees for components we don't care about.
*
* TRADITIONAL MODE (without filter):
* normally, one importMany of the seeders is enough as importMany knows to fetch all flattened.
* however, since this buildGraph is performed on the workspace, a dependency may be new or
* modified and as such, we don't know its flattened yet.
*/
buildGraph(ids: ComponentID[]): Promise<Graph<Component, string>>;
private getAllDepsUnfiltered;
private getAllDepsFiltered;
private processManyComponents;
/**
* only for components from the workspace that can be modified to add/remove dependencies, we need to make sure that
* all their dependencies are imported.
*
* when `shouldLoadItsDeps` is provided, we use "lazy import" mode:
* - only import filtered dependencies (those passing the shouldLoadItsDeps check)
* - use preferDependencyGraph to avoid fetching flattened dependencies
* - the recursive depth iteration will handle importing deps as needed
* this is much more efficient when building a filtered graph (e.g., aspects-only graph)
*
* without a filter, we use the traditional approach:
* - `importMany` fetches all flattened dependencies (preferDependencyGraph: false)
* - once a component from scope is imported, all its flattened dependencies are there
*/
private importObjects;
private processOneComponent;
private loadManyComponents;
}