Skip to content
LogoLogo

Migrate from dependency-cruiser

The config of Oxcruise is much smaller than the config of dependency-cruiser. Oxcruise does not read .dependency-cruiser.* files in a check. The oxcruise --migrate command converts one and says what it could not convert.

Run the migration

npx oxcruise --migrate
npx oxcruise --migrate -c .oxcruiserc.json
npx oxcruise --migrate=config/.dependency-cruiser.cjs -c config/oxcruise.config.ts
  • The first command reads .dependency-cruiser.json, .js, .cjs or .mjs. It writes oxcruise.config.ts.
  • -c names the file to write. A .json name gives a JSON file.
  • --migrate=FILE names the file to read.

--migrate never overwrites a file. When the target exists, the command stops with "already exists". Delete the file or choose another name with -c.

How the conversion works

The conversion is conservative:

  • A path regex becomes a glob only when it has a common shape. See Regex to glob.
  • Oxcruise drops a whole rule that uses a condition that it does not have, with a named warning. Dropping only the condition would make the rule broader than you wrote it.
  • A regex that does not convert drops its rule, with a named warning.
  • When the target is a TypeScript file, every warning is also in that file, as a // TODO: comment. A .json target has no comments, so the warnings go to stderr only.
  • Oxcruise drops allowed and required sections with a warning.

What maps

dependency-cruiserOxcruiseIf dropped, use instead
forbidden[]forbid[]. comment becomes message.
from.path, pathNot (regex)from: a glob or a list. pathNot becomes a !glob in the same list.
to.path, pathNot (regex)to: a glob or a list, or to.path
$1 back-references{c1} captures: from: "src/{c1}/**" and to: ["src/**", "!src/{c1}/**"]Write {name} yourself.
to.dynamic, to.preCompilationOnlyto.dynamic, to.typeOnly
to.couldNotResolve: trueto.kind: "unresolved", or the unresolved-dependencies rule
to.reachable: trueto.reachable: true
severitylevel: error, warn or off. info becomes warn, with a warning.
allowed[], allowedSeverityDropped.The layers rule, or forbid rules.
required[]Dropped.The require option of folder-structure for a file that a folder must have. Otherwise a JS plugin rule.
from.orphan, to.orphanDropped.The orphan-modules rule.
numberOfDependents{Less,More}ThanDropped.A JS plugin rule.
to.dependencyTypes, dependencyTypesNot, moreThanOneDependencyTypeDropped.to.kind and to.typeOnly. The rules undeclared-packages, dev-dependencies-in-production, duplicate-packages, optional-dependencies, peer-dependencies and deprecated-dependencies.
to.circular, via, viaOnlyDropped.The circular-dependencies rule with ignore and includeTypeOnly. Use overrides.files to limit it.
to.exoticallyRequired, license, moreUnstable, ancestorDropped.A JS plugin rule.
scope: "folder"Dropped.The folders option of circular-dependencies for cycles between folders. Otherwise a JS plugin rule.
options.doNotFollowdoNotFollow. Files in node_modules are always leaves.
options.excludeignorePatterns
options.includeOnlyDropped.Start from the right entries and list the rest in ignorePatterns.
options.maxDepthDropped.The --max-depth flag.
options.tsConfig.fileNameresolve.tsconfig
enhancedResolveOptions.conditionNamesresolve.conditions. Oxcruise always tries import, require, node and default.
enhancedResolveOptions.extensions, mainFieldsDropped.The resolver defaults.
options.exoticRequireStringscalls
options.detectJSDocImports, tsPreCompilationDepsAlways on.
extends: "dependency-cruiser/configs/recommended"The default categories.
extends: ".../recommended-strict"categories: { suspicious: "error" }
extends: ".../recommended-warn-only"categories: { correctness: "warn" }
extends: "./other.json"Oxcruise converts the other file too and merges it into the output.
webpackConfig, babelConfigDropped.resolve.alias
knownViolations, cache, combinedDependencies, moduleSystemsDropped.

Regex to glob

RegexGlob
^src/src/**
^srcsrc*. A regex without $ matches src2/, and the glob does too.
[.]spec[.]ts$**/*.spec.ts
(^|/)x/**/x/**
^(src|lib)/{src,lib}/**
^src/([^/]+)/src/{c1}/**
a|b at the top levelTwo globs.

Other regexes do not convert. Examples are \d, [a-z], look-around and quantified groups. Oxcruise drops the rule or the entry and names the regex.

Oxcruise has the rules of the recommended config of dependency-cruiser built in. It sorts them into categories, and the default level of a category applies. Two of the rules are off by default: optional-dependencies and peer-dependencies.

dependency-cruiserOxcruiseCategory
no-circularcircular-dependencies. It checks runtime cycles only.correctness, error
not-to-unresolvableunresolved-dependenciescorrectness
no-non-package-jsonundeclared-packagescorrectness
not-to-dev-depdev-dependencies-in-productioncorrectness
not-to-test, not-to-specdependencies-on-testscorrectness
no-orphansorphan-modules. By default it ignores dotfiles, .d.ts files, tsconfig*.json and *.config.*.suspicious, warn
no-deprecated-core, no-deprecated-npmdeprecated-dependenciessuspicious
no-duplicate-dep-typesduplicate-packagessuspicious
optional-deps-used, peer-deps-usedoptional-dependencies, peer-dependenciesrestriction, off

What behaves differently

  • Globs, not regexes. The regex crate matches rules in linear time, so Oxcruise needs no guard for unsafe regexes. Globs have *, **, ?, [ab], {a,b} and {name} captures.
  • One report for each cycle. Oxcruise reports a cycle once and, by default, only when it exists at runtime. A compiler erases import type.
  • Ignore comments exist. See Inline ignore comments.
  • Exit codes. Errors give 1. --deny-warnings with warnings, and --max-warnings N when exceeded, also give 1. A bad config gives 2. There is no --compat.
  • Output formats. They are default, long, json, github, text and plugin reporters. The --visualize mode replaces dot, mermaid and archi: it writes an interactive site (see Visualize the graph). The json format of Oxcruise has a different shape from the json format of dependency-cruiser. A tool that reads the old output must read the new format. See Output formats.
  • Dual packages. Oxcruise resolves them by import syntax, as Node.js does. See Differences.
  • Merged syntax kinds. A file that both imports and re-exports one module has both kinds on that dependency.
  • No TypeScript install. Oxcruise parses TS, TSX, MTS, CTS, JSX, Vue, Svelte and Astro itself.
  • Always extracted. They are JSDoc imports, triple-slash directives, and new URL("./x", import.meta.url) and new Worker(new URL(...)).
  • calls replaces exoticRequireStrings. The first string argument of the function is a dependency. It resolves as an ES import, unless the name of the function starts with require.
  • AMD. Ids without a leading ./ resolve like package specifiers. Oxcruise does not read the requirejs baseUrl and paths config.

Check your migration

npx oxcruise --migrate -c .oxcruiserc.json
npx depcruise src -T json > before.json
npx oxcruise src -f json > after.json

Compare the modules and the dependencies in the two files. The tasks/conformance folder of the repository does this against dependency-cruiser 18.7. See Differences.