dependency-cruiser
Version:
Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.
451 lines (436 loc) • 14.6 kB
TypeScript
import { ICruiseOptions } from "./options";
import { IFlattenedRuleSet } from "./rule-set";
import { DependencyType, ModuleSystemType, ProtocolType } from "./shared-types";
import { IViolation } from "./violations";
import { IRuleSummary } from "./rule-summary";
import { IChange } from "watskeburt";
export interface IRevisionChange extends IChange {
// optional because
// - in content strategy 'ignored' and 'deleted' files can't have a checksum
// - in metadata strategy we don't calculate a checksum because ~we're lazy~
// it's an unnecessary expense
checksum?: string;
}
/**
* caching revisionData. doc and proper naming will follow
*/
export interface IRevisionData {
SHA1: string;
changes: IRevisionChange[];
}
export interface ICruiseResult {
/**
* A list of modules, with for each module the modules it depends upon
*/
modules: IModule[];
/**
* A list of folders, as derived from the detected modules, with for each
* folder a bunch of metrics (adapted from 'Agile software development:
* principles, patterns, and practices' by Robert C Martin (ISBN 0-13-597444-5).
* Note: these metrics substitute 'components' and 'classes' from that book
* with 'folders' and 'modules'; the closest relatives that work for the most
* programming styles in JavaScript (and its derivative languages).
*/
folders?: IFolder[];
/**
* Data summarizing the found dependencies
*/
summary: ISummary;
/**
* caching revisionData. doc and proper naming will follow
*/
revisionData?: IRevisionData;
}
export interface IModule {
/**
* The (resolved) file name of the module, e.g. 'src/main/index.js'
*/
source: string;
/**
* 'true' if this module violated a rule; 'false' in all other cases. The violated rule will
* be in the 'rule' object at the same level.
*/
valid: boolean;
/**
* list of modules this module depends on
*/
dependencies: IDependency[];
/**
* list of modules that depend on this module (values are _resolved_ names of
* those modules)
*/
dependents: string[];
/**
* Whether or not this is a node.js core module
*/
coreModule?: boolean;
/**
* 'true' if dependency-cruiser could not resolve the module name in the source code to a
* file name or core module. 'false' in all other cases.
*/
couldNotResolve?: boolean;
/**
* the type of inclusion - local, core, unknown (= we honestly don't know), undetermined (=
* we didn't bother determining it) or one of the npm dependencies defined in a package.json
* ('npm' for 'dependencies', 'npm-dev', 'npm-optional', 'npm-peer', 'npm-no-pkg' for
* development, optional, peer dependencies and dependencies in node_modules but not in
* package.json respectively)
*/
dependencyTypes?: DependencyType[];
/**
* Whether or not this is a dependency that can be followed any further. This will be
* 'false' for for core modules, json, modules that could not be resolved to a file and
* modules that weren't followed because it matches the doNotFollow expression.
*/
followable?: boolean;
/**
* the license, if known (usually known for modules pulled from npm, not for local ones)
*/
license?: string;
/**
* 'true' if the file name of this module matches the 'doNotFollow' regular expression
*/
matchesDoNotFollow?: boolean;
/**
* 'true' if the file name of this module matches the 'focus' filter regular expression
*/
matchesFocus?: boolean;
/**
* 'true' if the file name of this module matches the 'reaches' filter regular expression
*/
matchesReaches?: boolean;
/**
* 'true' if the file name of this module matches the 'highlight' regular expression
*/
matchesHighlight?: boolean;
/**
* 'true' if this module does not have dependencies, and no module has it as a dependency
*/
orphan?: boolean;
/**
* An array of objects that tell whether this module is 'reachable', and according to rule
* in which this reachability was defined
*/
reachable?: IReachable[];
/**
* An array of objects that tell which other modules it reaches,
* and that falls within the definition of the passed rule.
*/
reaches?: IReaches[];
/**
* an array of rules violated by this module - left out if the module is valid
*/
rules?: IRuleSummary[];
/**
* true if the module was 'consolidated'. Consolidating implies the
* entity a Module represents might be several modules at the same time.
* This attribute is set by tools that consolidate modules for reporting
* purposes - it will not be present after a regular cruise.
*/
consolidated?: boolean;
/**
* "number of dependents/ (number of dependents + number of dependencies)
* A measure for how stable the module is; ranging between 0 (completely
* stable module) to 1 (completely instable module). Derived from Uncle
* Bob's instability metric - but applied to a single module instead of
* to a group of them. This attribute is only present when dependency-cruiser
* was asked to calculate metrics.
*/
instability?: number;
/**
* checksum of the contents of the module. This attribute is currently only
* available when the cruise was executed with caching and the cache strategy
* is 'content'.
*/
checksum?: string;
}
export interface IDependency {
/**
* 'true' if following this dependency will ultimately return to the source, false in all
* other cases
*/
circular: boolean;
/**
* Whether or not this is a node.js core module - deprecated in favor of dependencyType ===
* core
*/
coreModule: boolean;
/**
* 'true' if dependency-cruiser could not resolve the module name in the source code to a
* file name or core module. 'false' in all other cases.
*/
couldNotResolve: boolean;
/**
* 'true' if the dependency between this dependency and its parent only
* exists before compilation takes place. 'false in all other cases.
* Dependency-cruiser will only specify this attribute for TypeScript and
* then only when the option 'tsPreCompilationDeps' has the value 'specify'.
*/
preCompilationOnly?: boolean;
/**
* 'true' when the module included the module explicitly as type only with the
* `type` keyword e.g. `import type { IThingus } from 'thing'`. Dependency-cruiser
* will only specify this attribute for TypeScript and when the 'tsPreCompilationDeps'
* option has either the value `true` or `"specify"`.
*/
typeOnly?: boolean;
/**
* If following this dependency will ultimately return to the source (circular === true),
* this attribute will contain an (ordered) array of module names that shows (one of) the
* circular path(s)
*/
cycle?: string[];
/**
* the type of inclusion - local, core, unknown (= we honestly don't know), undetermined (=
* we didn't bother determining it) or one of the npm dependencies defined in a package.json
* ('npm' for 'dependencies', 'npm-dev', 'npm-optional', 'npm-peer', 'npm-no-pkg' for
* development, optional, peer dependencies and dependencies in node_modules but not in
* package.json respectively)
*/
dependencyTypes: DependencyType[];
/**
* true if this dependency is dynamic, false in all other cases
*/
dynamic: boolean;
/**
* true if the dependency was defined by a require not named 'require'
* false in all other cases
*/
exoticallyRequired: boolean;
/**
* If this dependency was defined by a require not named require (as defined in the
* exoticRequireStrings option): the string that was used
*/
exoticRequire?: string;
/**
* Whether or not this is a dependency that can be followed any further. This will be
* 'false' for for core modules, json, modules that could not be resolved to a file and
* modules that weren't followed because it matches the doNotFollow expression.
*/
followable: boolean;
/**
* the license, if known (usually known for modules pulled from npm, not for local ones)
*/
license?: string;
/**
* 'true' if the file name of this module matches the doNotFollow regular expression
*/
matchesDoNotFollow?: boolean;
/**
* The name of the module as it appeared in the source code, e.g. './main'
*/
module: string;
/**
* If the module specification is an URI with a protocol in it (e.g.
* `import * as fs from 'node:fs'` or
* `import stuff from 'data:application/json,some-thing'`) -
* this attribute holds the protocol part (e.g. 'node:', 'data:', 'file:').
*
* Also see https://nodejs.org/api/esm.html#esm_urls
*/
protocol: ProtocolType;
/**
* If the module specification is an URI and contains a mime type, this
* attribute holds the mime type (e.g. in `import stuff from 'data:application/json,some-thing'
* `this would be data:application/json)
*
* Also see https://nodejs.org/api/esm.html#esm_urls
*/
mimeType: string;
moduleSystem: ModuleSystemType;
/**
* The (resolved) file name of the module, e.g. 'src/main//index.js'
*/
resolved: string;
/**
* an array of rules violated by this dependency - left out if the dependency is valid
*/
rules?: IRuleSummary[];
/**
* 'true' if this dependency violated a rule; 'false' in all other cases. The violated rule
* will be in the 'rule' object at the same level.
*/
valid: boolean;
/**
* the (de-normalized) instability of the dependency - also available in
* the module on the 'to' side of this dependency
*/
instability: number;
}
export interface IReachable {
/**
* The name of the rule where the reachability was defined
*/
asDefinedInRule: string;
/**
* The matchedFrom attribute shows what the 'from' module that causes the 'reachable'
* information to be what it is. Sometimes the 'asDefinedInRule' is not specific enough -
* e.g. when the from part can be many modules and/ or contains capturing groups used
* in the to part of the rule.
*/
matchedFrom: string;
/**
* 'true' if this module is reachable from any of the modules matched by the from part of a
* reachability-rule in 'asDefinedInRule', 'false' if not.
*/
value: boolean;
}
export interface IReachesModule {
/**
* The (resolved) file name of the module, e.g. 'src/main/index.js'
*/
source: string;
/**
* The path along which the 'to' module is reachable from this one.
*/
via: string[];
}
export interface IReaches {
/**
* The name of the rule where the reachability was defined
*/
asDefinedInRule: string;
/**
* An array of modules that is (transitively) reachable from this module.
*/
modules: IReachesModule[];
}
/**
* Data summarizing the found dependencies
*/
export interface ISummary {
/**
* the number of errors in the dependencies
*/
error: number;
/**
* the number of ignored notices in the dependencies
*/
ignore: number;
/**
* the number of informational level notices in the dependencies
*/
info: number;
optionsUsed: IOptions;
/**
* rules used in the cruise
*/
ruleSetUsed?: IFlattenedRuleSet;
/**
* the number of modules cruised
*/
totalCruised: number;
/**
* the number of dependencies cruised
*/
totalDependenciesCruised?: number;
/**
* A list of violations found in the dependencies. The dependencies themselves also contain
* this information, this summary is here for convenience.
*/
violations: IViolation[];
/**
* the number of warnings in the dependencies
*/
warn: number;
}
/**
* the (command line) options used to generate the dependency-tree
*/
export interface IOptions extends ICruiseOptions {
/**
* arguments passed on the command line
*/
args?: string;
/**
* File the output was written to ('-' for stdout)
*/
outputTo?: string;
/**
* The rules file used to validate the dependencies (if any)
*/
rulesFile?: string;
}
export interface IFolderDependency {
/**
* the (resolved) name of the dependency
*/
name: string;
/**
* 'true' if this folder dependency violated a rule; 'false' in all other
* cases. The violated rule will be in the 'rules' object at the same level.
*/
valid: boolean;
/**
* the instability of the dependency (de-normalized - this is a duplicate of
* the one found in the instability of the folder with the same name)
*/
instability?: number;
/**
* 'true' if following this dependency will ultimately return to the source, false in all
* other cases
*/
circular: boolean;
/**
* If following this dependency will ultimately return to the source (circular === true),
* this attribute will contain an (ordered) array of module names that shows (one of) the
* circular path(s)
*/
cycle?: string[];
/**
* an array of rules violated by this dependency - left out if the dependency
* is valid
*/
rules?: IRuleSummary[];
}
export interface IFolderDependent {
/**
* name ('path') of the dependent
*/
name: string;
}
export interface IFolder {
/**
* The name of the folder. FOlder names are normalized to posix (so
* separated by forward slashes e.g.: src/things/morethings)
*/
name: string;
/**
* List of folders depending on this folder
*/
dependents?: IFolderDependent[];
/**
* List of folders this folder depends upon
*/
dependencies?: IFolderDependency[];
/**
* The total number of modules detected in this folder and its sub-folders
*/
moduleCount: number;
/**
* The number of modules outside this folder that depend on modules
* within this folder. Only present when dependency-cruiser was
* "asked to calculate it.
*/
afferentCouplings?: number;
/**
* The number of modules inside this folder that depend on modules
* outside this folder. Only present when dependency-cruiser was
* asked to calculate it.
*/
efferentCouplings?: number;
/**
* efferentCouplings/ (afferentCouplings + efferentCouplings)
*
* A measure for how stable the folder is; ranging between 0
* (completely stable folder) to 1 (completely instable folder)
* Note that while 'instability' has a negative connotation it's also
* (unavoidable in any meaningful system. It's the basis of Martin's
* variable component stability principle: 'the instability of a folder
* should be larger than the folders it depends on'. Only present when
* dependency-cruiser was asked to calculate it.,
*/
instability?: number;
}
export * from "./violations";
export * from "./rule-summary";