diff --git a/bin/depcruise-fmt.mjs b/bin/depcruise-fmt.mjs index 87f3a66a6..2a970c16f 100755 --- a/bin/depcruise-fmt.mjs +++ b/bin/depcruise-fmt.mjs @@ -24,7 +24,7 @@ try { ) .option( "-T, --output-type ", - "output type; e.g. err, err-html, dot, ddot, archi, flat, baseline or json", + "output type; e.g. err, err-html, dot, ddot, archi, flat, d2, mermaid or json", "err", ) .option( diff --git a/bin/dependency-cruise.mjs b/bin/dependency-cruise.mjs index fdb447126..fc9c09ff1 100755 --- a/bin/dependency-cruise.mjs +++ b/bin/dependency-cruise.mjs @@ -30,7 +30,7 @@ try { ) .option( "-T, --output-type ", - "output type; e.g. err, err-html, dot, ddot, archi, flat, text or json", + "output type; e.g. err, err-html, dot, ddot, archi, flat, d2, mermaid, text or json", "err", ) .option("-m, --metrics", "calculate stability metrics", false) diff --git a/doc/assets/d2.svg b/doc/assets/d2.svg new file mode 100644 index 000000000..4f039b082 --- /dev/null +++ b/doc/assets/d2.svg @@ -0,0 +1 @@ +srccachecache.mjscontent-strategy.mjsfind-content-changes.mjshelpers.mjsmetadata-strategy.mjsoptions-compatible.mjs \ No newline at end of file diff --git a/doc/assets/filtering/snazzy-focus.svg b/doc/assets/filtering/snazzy-focus.svg index 192e0249d..40a790cdf 100644 --- a/doc/assets/filtering/snazzy-focus.svg +++ b/doc/assets/filtering/snazzy-focus.svg @@ -1,646 +1 @@ - - - - - - -dependency-cruiser output - - -cluster_src - -src - - -cluster_src/cache - -cache - - -cluster_src/cli - -cli - - -cluster_src/config-utl - -config-utl - - -cluster_src/config-utl/extract-depcruise-config - -extract-depcruise-config - - -cluster_src/enrich - -enrich - - -cluster_src/enrich/summarize - -summarize - - -cluster_src/graph-utl - -graph-utl - - -cluster_src/extract - -extract - - -cluster_src/extract/transpile - -transpile - - -cluster_src/main - -main - - -cluster_src/main/files-and-dirs - -files-and-dirs - - -cluster_src/main/options - -options - - -cluster_src/main/resolve-options - -resolve-options - - -cluster_src/main/rule-set - -rule-set - - -cluster_src/report - -report - - -cluster_src/schema - -schema - - -cluster_src/utl - -utl - - - -src/cache/cache.mjs - - -cache.mjs - - - - - -src/extract/transpile/meta.mjs - - -meta.mjs - - - - - -src/cache/cache.mjs->src/extract/transpile/meta.mjs - - - - - -src/utl/bus.mjs - - -bus.mjs - - - - - -src/cache/cache.mjs->src/utl/bus.mjs - - - - - -src/cli/format-meta-info.mjs - - -format-meta-info.mjs - - - - - -src/main/index.mjs - - -index.mjs - - - - - -src/cli/format-meta-info.mjs->src/main/index.mjs - - - - - -src/main/index.mjs->src/extract/transpile/meta.mjs - - - - - -src/main/format.mjs - - -format.mjs - - - - - -src/main/index.mjs->src/main/format.mjs - - - - - -src/main/cruise.mjs - - -cruise.mjs - - - - - -src/main/index.mjs->src/main/cruise.mjs - - - - - -src/cli/format.mjs - - -format.mjs - - - - - -src/cli/format.mjs->src/main/format.mjs - - - - - -src/main/options/assert-validity.mjs - - -assert-validity.mjs - - - - - -src/main/format.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/options/normalize.mjs - - -normalize.mjs - - - - - -src/main/format.mjs->src/main/options/normalize.mjs - - - - - -src/main/report-wrap.mjs - - -report-wrap.mjs - - - - - -src/main/format.mjs->src/main/report-wrap.mjs - - - - - -src/schema/cruise-result.schema.mjs - - -cruise-result.schema.mjs - - - - - -src/main/format.mjs->src/schema/cruise-result.schema.mjs - - - - - -src/cli/index.mjs - - -index.mjs - - - - - -src/cli/index.mjs->src/utl/bus.mjs - - - - - -src/cli/index.mjs->src/cli/format-meta-info.mjs - - - - - -src/cli/index.mjs->src/main/cruise.mjs - - - - - -src/main/cruise.mjs->src/cache/cache.mjs - - - - - -src/main/cruise.mjs->src/utl/bus.mjs - - - - - -src/main/resolve-options/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/resolve-options/normalize.mjs - - - - - -src/enrich/index.mjs - - -index.mjs - - - - - -src/main/cruise.mjs->src/enrich/index.mjs - - - - - -src/extract/index.mjs - - -index.mjs - - - - - -src/main/cruise.mjs->src/extract/index.mjs - - - - - -src/main/files-and-dirs/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/files-and-dirs/normalize.mjs - - - - - -src/main/cruise.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/cruise.mjs->src/main/options/normalize.mjs - - - - - -src/main/cruise.mjs->src/main/report-wrap.mjs - - - - - -src/main/rule-set/assert-validity.mjs - - -assert-validity.mjs - - - - - -src/main/cruise.mjs->src/main/rule-set/assert-validity.mjs - - - - - -src/main/rule-set/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/rule-set/normalize.mjs - - - - - -src/config-utl/extract-depcruise-config/index.mjs - - -index.mjs - - - - - -src/config-utl/extract-depcruise-config/index.mjs->src/main/resolve-options/normalize.mjs - - - - - -src/main/resolve-options/normalize.mjs->src/extract/transpile/meta.mjs - - - - - -src/graph-utl/rule-set.mjs - - -rule-set.mjs - - - - - -src/main/resolve-options/normalize.mjs->src/graph-utl/rule-set.mjs - - - - - -src/enrich/summarize/index.mjs - - -index.mjs - - - - - -src/enrich/index.mjs->src/enrich/summarize/index.mjs - - - - - -src/graph-utl/compare.mjs - - -compare.mjs - - - - - -src/enrich/summarize/index.mjs->src/graph-utl/compare.mjs - - - - - -src/extract/index.mjs->src/utl/bus.mjs - - - - - -src/graph-utl/consolidate-to-pattern.mjs - - -consolidate-to-pattern.mjs - - - - - -src/graph-utl/filter-bank.mjs - - -filter-bank.mjs - - - - - -src/graph-utl/strip-self-transitions.mjs - - -strip-self-transitions.mjs - - - - - -src/report/index.mjs - - -index.mjs - - - - - -src/main/options/assert-validity.mjs->src/report/index.mjs - - - - - -src/main/helpers.mjs - - -helpers.mjs - - - - - -src/main/options/normalize.mjs->src/main/helpers.mjs - - - - - -src/main/options/defaults.mjs - - -defaults.mjs - - - - - -src/main/options/normalize.mjs->src/main/options/defaults.mjs - - - - - -src/main/report-wrap.mjs->src/enrich/summarize/index.mjs - - - - - -src/main/report-wrap.mjs->src/graph-utl/compare.mjs - - - - - -src/main/report-wrap.mjs->src/graph-utl/consolidate-to-pattern.mjs - - - - - -src/main/report-wrap.mjs->src/graph-utl/filter-bank.mjs - - - - - -src/main/report-wrap.mjs->src/graph-utl/strip-self-transitions.mjs - - - - - -src/main/report-wrap.mjs->src/report/index.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/main/helpers.mjs - - - - - -src/schema/configuration.schema.mjs - - -configuration.schema.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/schema/configuration.schema.mjs - - - - - -src/main/rule-set/normalize.mjs->src/main/helpers.mjs - - - - - -src/main/index.d.ts - - -index.d.ts - - - - - +srcconfig-utlextract-depcruise-configenrichsummarizeextracttranspilereportschemautlclicachemainresolve-optionsrule-setfiles-and-dirsoptionsgraph-utlcache.mjsmeta.mjsbus.mjsformat-meta-info.mjsindex.mjsformat.mjscruise.mjsformat.mjsassert-validity.mjsnormalize.mjsreport-wrap.mjscruise-result.schema.mjsindex.mjsnormalize.mjsindex.mjsindex.mjsnormalize.mjsassert-validity.mjsnormalize.mjsindex.mjsrule-set.mjsindex.mjscompare.mjsconsolidate-to-pattern.mjsfilter-bank.mjsstrip-self-transitions.mjsindex.mjshelpers.mjsdefaults.mjsconfiguration.schema.mjsindex.d.ts \ No newline at end of file diff --git a/doc/assets/flat-report-counter-example.svg b/doc/assets/flat-report-counter-example.svg index c0dfcd26b..b154ad27e 100644 --- a/doc/assets/flat-report-counter-example.svg +++ b/doc/assets/flat-report-counter-example.svg @@ -1,510 +1 @@ - - - - - - -dependency-cruiser output - - -cluster_src - -src - - -cluster_src/graph-utl - -graph-utl - - -cluster_src/report - -report - - -cluster_src/utl - -utl - - - -src/graph-utl/add-focus.mjs - - -add-focus.mjs - - - - - -src/graph-utl/indexed-module-graph.mjs - - -indexed-module-graph.mjs - - - - - -src/graph-utl/add-focus.mjs->src/graph-utl/indexed-module-graph.mjs - - - - - -src/graph-utl/match-facade.mjs - - -match-facade.mjs - - - - - -src/graph-utl/add-focus.mjs->src/graph-utl/match-facade.mjs - - - - - -src/graph-utl/compare.mjs - - -compare.mjs - - - - - -src/graph-utl/consolidate-module-dependencies.mjs - - -consolidate-module-dependencies.mjs - - - - - -src/graph-utl/consolidate-module-dependencies.mjs->src/graph-utl/compare.mjs - - - - - -src/graph-utl/consolidate-modules.mjs - - -consolidate-modules.mjs - - - - - -src/graph-utl/consolidate-modules.mjs->src/graph-utl/compare.mjs - - - - - -src/graph-utl/consolidate-to-folder.mjs - - -consolidate-to-folder.mjs - - - - - -src/graph-utl/consolidate-to-folder.mjs->src/graph-utl/consolidate-module-dependencies.mjs - - - - - -src/graph-utl/consolidate-to-folder.mjs->src/graph-utl/consolidate-modules.mjs - - - - - -src/graph-utl/consolidate-to-pattern.mjs - - -consolidate-to-pattern.mjs - - - - - -src/graph-utl/consolidate-to-pattern.mjs->src/graph-utl/consolidate-module-dependencies.mjs - - - - - -src/graph-utl/consolidate-to-pattern.mjs->src/graph-utl/consolidate-modules.mjs - - - - - -src/graph-utl/filter-bank.mjs - - -filter-bank.mjs - - - - - -src/graph-utl/filter-bank.mjs->src/graph-utl/add-focus.mjs - - - - - -src/graph-utl/filter-bank.mjs->src/graph-utl/indexed-module-graph.mjs - - - - - -src/graph-utl/filter-bank.mjs->src/graph-utl/match-facade.mjs - - - - - -src/graph-utl/rule-set.mjs - - -rule-set.mjs - - - - - -src/graph-utl/strip-self-transitions.mjs - - -strip-self-transitions.mjs - - - - - -src/report/anon - - - - - -anon - - - - - -src/report/azure-devops.mjs - - -azure-devops.mjs - - - - - -src/report/utl - - - - - -utl - - - - - -src/report/azure-devops.mjs->src/report/utl - - - - - -src/report/baseline.mjs - - -baseline.mjs - - - - - -src/report/csv.mjs - - -csv.mjs - - - - - -src/report/csv.mjs->src/report/utl - - - - - -src/report/dot - - - - - -dot - - - - - -src/report/dot->src/graph-utl/compare.mjs - - - - - -src/report/dot->src/graph-utl/consolidate-to-folder.mjs - - - - - -src/report/dot->src/graph-utl/consolidate-to-pattern.mjs - - - - - -src/report/dot->src/graph-utl/filter-bank.mjs - - - - - -src/report/dot->src/graph-utl/strip-self-transitions.mjs - - - - - -src/report/dot->src/report/utl - - - - - -src/report/error-html - - - - - -error-html - - - - - -src/report/error-html->src/report/utl - - - - - -src/report/error-long.mjs - - -error-long.mjs - - - - - -src/report/error.mjs - - -error.mjs - - - - - -src/report/error-long.mjs->src/report/error.mjs - - - - - -src/report/error.mjs->src/graph-utl/rule-set.mjs - - - - - -src/report/error.mjs->src/report/utl - - - - - -src/utl/wrap-and-indent.mjs - - -wrap-and-indent.mjs - - - - - -src/report/error.mjs->src/utl/wrap-and-indent.mjs - - - - - -src/report/html - - - - - -html - - - - - -src/report/html->src/report/utl - - - - - -src/report/identity.mjs - - -identity.mjs - - - - - -src/report/index.mjs - - -index.mjs - - - - - -src/report/plugins.mjs - - -plugins.mjs - - - - - -src/report/index.mjs->src/report/plugins.mjs - - - - - -src/report/json.mjs - - -json.mjs - - - - - -src/report/markdown.mjs - - -markdown.mjs - - - - - -src/report/markdown.mjs->src/report/error-html - - - - - -src/report/mermaid.mjs - - -mermaid.mjs - - - - - -src/report/metrics.mjs - - -metrics.mjs - - - - - -src/report/metrics.mjs->src/report/utl - - - - - -src/report/null.mjs - - -null.mjs - - - - - -src/report/teamcity.mjs - - -teamcity.mjs - - - - - -src/report/teamcity.mjs->src/report/utl - - - - - -src/report/text.mjs - - -text.mjs - - - - - +srcgraph-utlreportutladd-focus.mjsindexed-module-graph.mjsmatch-facade.mjscompare.mjsconsolidate-module-dependencies.mjsconsolidate-modules.mjsconsolidate-to-folder.mjsconsolidate-to-pattern.mjsfilter-bank.mjsrule-set.mjsstrip-self-transitions.mjsanonazure-devops.mjsutlbaseline.mjscsv.mjsd2.mjsdoterror-htmlerror-long.mjserror.mjswrap-and-indent.mjshtmlidentity.mjsindex.mjsplugins.mjsjson.mjsmarkdown.mjsmermaid.mjsmetrics.mjsnull.mjsteamcity.mjstext.mjs \ No newline at end of file diff --git a/doc/assets/flat-report-example.svg b/doc/assets/flat-report-example.svg index 0c62aaaec..4ccab8881 100644 --- a/doc/assets/flat-report-example.svg +++ b/doc/assets/flat-report-example.svg @@ -1,815 +1 @@ - - - - - - -dependency-cruiser output - - - -src/graph-utl/add-focus.mjs - - -src/graph-utl/ -add-focus.mjs - - - - - -src/graph-utl/indexed-module-graph.mjs - - -src/graph-utl/ -indexed-module-graph.mjs - - - - - -src/graph-utl/add-focus.mjs->src/graph-utl/indexed-module-graph.mjs - - - - - -src/graph-utl/match-facade.mjs - - -src/graph-utl/ -match-facade.mjs - - - - - -src/graph-utl/add-focus.mjs->src/graph-utl/match-facade.mjs - - - - - -src/graph-utl/compare.mjs - - -src/graph-utl/ -compare.mjs - - - - - -src/graph-utl/consolidate-module-dependencies.mjs - - -src/graph-utl/ -consolidate-module-dependencies.mjs - - - - - -src/graph-utl/consolidate-module-dependencies.mjs->src/graph-utl/compare.mjs - - - - - -src/graph-utl/consolidate-modules.mjs - - -src/graph-utl/ -consolidate-modules.mjs - - - - - -src/graph-utl/consolidate-modules.mjs->src/graph-utl/compare.mjs - - - - - -src/graph-utl/consolidate-to-folder.mjs - - -src/graph-utl/ -consolidate-to-folder.mjs - - - - - -src/graph-utl/consolidate-to-folder.mjs->src/graph-utl/consolidate-module-dependencies.mjs - - - - - -src/graph-utl/consolidate-to-folder.mjs->src/graph-utl/consolidate-modules.mjs - - - - - -src/graph-utl/consolidate-to-pattern.mjs - - -src/graph-utl/ -consolidate-to-pattern.mjs - - - - - -src/graph-utl/consolidate-to-pattern.mjs->src/graph-utl/consolidate-module-dependencies.mjs - - - - - -src/graph-utl/consolidate-to-pattern.mjs->src/graph-utl/consolidate-modules.mjs - - - - - -src/graph-utl/filter-bank.mjs - - -src/graph-utl/ -filter-bank.mjs - - - - - -src/graph-utl/filter-bank.mjs->src/graph-utl/add-focus.mjs - - - - - -src/graph-utl/filter-bank.mjs->src/graph-utl/indexed-module-graph.mjs - - - - - -src/graph-utl/filter-bank.mjs->src/graph-utl/match-facade.mjs - - - - - -src/graph-utl/rule-set.mjs - - -src/graph-utl/ -rule-set.mjs - - - - - -src/graph-utl/strip-self-transitions.mjs - - -src/graph-utl/ -strip-self-transitions.mjs - - - - - -src/report/anon/anonymize-path-element.mjs - - -src/report/anon/ -anonymize-path-element.mjs - - - - - -src/report/anon/random-string.mjs - - -src/report/anon/ -random-string.mjs - - - - - -src/report/anon/anonymize-path-element.mjs->src/report/anon/random-string.mjs - - - - - -src/report/anon/anonymize-path.mjs - - -src/report/anon/ -anonymize-path.mjs - - - - - -src/report/anon/anonymize-path.mjs->src/report/anon/anonymize-path-element.mjs - - - - - -src/report/anon/index.mjs - - -src/report/anon/ -index.mjs - - - - - -src/report/anon/index.mjs->src/report/anon/anonymize-path.mjs - - - - - -src/report/azure-devops.mjs - - -src/report/ -azure-devops.mjs - - - - - -src/report/utl/index.mjs - - -src/report/utl/ -index.mjs - - - - - -src/report/azure-devops.mjs->src/report/utl/index.mjs - - - - - -src/report/baseline.mjs - - -src/report/ -baseline.mjs - - - - - -src/report/csv.mjs - - -src/report/ -csv.mjs - - - - - -src/report/utl/dependency-to-incidence-transformer.mjs - - -src/report/utl/ -dependency-to-incidence-transformer.mjs - - - - - -src/report/csv.mjs->src/report/utl/dependency-to-incidence-transformer.mjs - - - - - -src/report/dot/default-theme.mjs - - -src/report/dot/ -default-theme.mjs - - - - - -src/report/dot/dot-custom.mjs - - -src/report/dot/ -dot-custom.mjs - - - - - -src/report/dot/index.mjs - - -src/report/dot/ -index.mjs - - - - - -src/report/dot/dot-custom.mjs->src/report/dot/index.mjs - - - - - -src/report/dot/index.mjs->src/graph-utl/filter-bank.mjs - - - - - -src/report/dot/module-utl.mjs - - -src/report/dot/ -module-utl.mjs - - - - - -src/report/dot/index.mjs->src/report/dot/module-utl.mjs - - - - - -src/report/dot/prepare-custom-level.mjs - - -src/report/dot/ -prepare-custom-level.mjs - - - - - -src/report/dot/index.mjs->src/report/dot/prepare-custom-level.mjs - - - - - -src/report/dot/prepare-flat-level.mjs - - -src/report/dot/ -prepare-flat-level.mjs - - - - - -src/report/dot/index.mjs->src/report/dot/prepare-flat-level.mjs - - - - - -src/report/dot/prepare-folder-level.mjs - - -src/report/dot/ -prepare-folder-level.mjs - - - - - -src/report/dot/index.mjs->src/report/dot/prepare-folder-level.mjs - - - - - -src/report/dot/theming.mjs - - -src/report/dot/ -theming.mjs - - - - - -src/report/dot/index.mjs->src/report/dot/theming.mjs - - - - - -src/report/dot/dot-flat.mjs - - -src/report/dot/ -dot-flat.mjs - - - - - -src/report/dot/dot-flat.mjs->src/report/dot/index.mjs - - - - - -src/report/dot/dot-folder.mjs - - -src/report/dot/ -dot-folder.mjs - - - - - -src/report/dot/dot-folder.mjs->src/report/dot/index.mjs - - - - - -src/report/dot/dot-module.mjs - - -src/report/dot/ -dot-module.mjs - - - - - -src/report/dot/dot-module.mjs->src/report/dot/index.mjs - - - - - -src/report/dot/module-utl.mjs->src/report/utl/index.mjs - - - - - -src/report/dot/module-utl.mjs->src/report/dot/theming.mjs - - - - - -src/report/dot/prepare-custom-level.mjs->src/graph-utl/compare.mjs - - - - - -src/report/dot/prepare-custom-level.mjs->src/graph-utl/consolidate-to-pattern.mjs - - - - - -src/report/dot/prepare-custom-level.mjs->src/graph-utl/strip-self-transitions.mjs - - - - - -src/report/dot/prepare-custom-level.mjs->src/report/dot/module-utl.mjs - - - - - -src/report/dot/prepare-flat-level.mjs->src/graph-utl/compare.mjs - - - - - -src/report/dot/prepare-flat-level.mjs->src/report/dot/module-utl.mjs - - - - - -src/report/dot/prepare-folder-level.mjs->src/graph-utl/compare.mjs - - - - - -src/report/dot/prepare-folder-level.mjs->src/graph-utl/consolidate-to-folder.mjs - - - - - -src/report/dot/prepare-folder-level.mjs->src/graph-utl/strip-self-transitions.mjs - - - - - -src/report/dot/prepare-folder-level.mjs->src/report/dot/module-utl.mjs - - - - - -src/report/dot/theming.mjs->src/report/dot/default-theme.mjs - - - - - -src/report/error-html/error-html-template.mjs - - -src/report/error-html/ -error-html-template.mjs - - - - - -src/report/error-html/index.mjs - - -src/report/error-html/ -index.mjs - - - - - -src/report/error-html/index.mjs->src/report/error-html/error-html-template.mjs - - - - - -src/report/error-html/utl.mjs - - -src/report/error-html/ -utl.mjs - - - - - -src/report/error-html/index.mjs->src/report/error-html/utl.mjs - - - - - -src/report/error-html/utl.mjs->src/report/utl/index.mjs - - - - - -src/report/error-long.mjs - - -src/report/ -error-long.mjs - - - - - -src/report/error.mjs - - -src/report/ -error.mjs - - - - - -src/report/error-long.mjs->src/report/error.mjs - - - - - -src/report/error.mjs->src/graph-utl/rule-set.mjs - - - - - -src/report/error.mjs->src/report/utl/index.mjs - - - - - -src/utl/wrap-and-indent.mjs - - -src/utl/ -wrap-and-indent.mjs - - - - - -src/report/error.mjs->src/utl/wrap-and-indent.mjs - - - - - -src/report/html/html-template.mjs - - -src/report/html/ -html-template.mjs - - - - - -src/report/html/index.mjs - - -src/report/html/ -index.mjs - - - - - -src/report/html/index.mjs->src/report/utl/dependency-to-incidence-transformer.mjs - - - - - -src/report/html/index.mjs->src/report/html/html-template.mjs - - - - - -src/report/identity.mjs - - -src/report/ -identity.mjs - - - - - -src/report/index.mjs - - -src/report/ -index.mjs - - - - - -src/report/plugins.mjs - - -src/report/ -plugins.mjs - - - - - -src/report/index.mjs->src/report/plugins.mjs - - - - - -src/report/json.mjs - - -src/report/ -json.mjs - - - - - -src/report/markdown.mjs - - -src/report/ -markdown.mjs - - - - - -src/report/markdown.mjs->src/report/error-html/utl.mjs - - - - - -src/report/mermaid.mjs - - -src/report/ -mermaid.mjs - - - - - -src/report/metrics.mjs - - -src/report/ -metrics.mjs - - - - - -src/report/metrics.mjs->src/report/utl/index.mjs - - - - - -src/report/null.mjs - - -src/report/ -null.mjs - - - - - -src/report/teamcity.mjs - - -src/report/ -teamcity.mjs - - - - - -src/report/teamcity.mjs->src/report/utl/index.mjs - - - - - -src/report/text.mjs - - -src/report/ -text.mjs - - - - - +src/graph-utl/add-focus.mjssrc/graph-utl/indexed-module-graph.mjssrc/graph-utl/match-facade.mjssrc/graph-utl/compare.mjssrc/graph-utl/consolidate-module-dependencies.mjssrc/graph-utl/consolidate-modules.mjssrc/graph-utl/consolidate-to-folder.mjssrc/graph-utl/consolidate-to-pattern.mjssrc/graph-utl/filter-bank.mjssrc/graph-utl/rule-set.mjssrc/graph-utl/strip-self-transitions.mjssrc/report/anon/anonymize-path-element.mjssrc/report/anon/random-string.mjssrc/report/anon/anonymize-path.mjssrc/report/anon/index.mjssrc/report/azure-devops.mjssrc/report/utl/index.mjssrc/report/baseline.mjssrc/report/csv.mjssrc/report/utl/dependency-to-incidence-transformer.mjssrc/report/d2.mjssrc/report/dot/default-theme.mjssrc/report/dot/dot-custom.mjssrc/report/dot/index.mjssrc/report/dot/module-utl.mjssrc/report/dot/prepare-custom-level.mjssrc/report/dot/prepare-flat-level.mjssrc/report/dot/prepare-folder-level.mjssrc/report/dot/theming.mjssrc/report/dot/dot-flat.mjssrc/report/dot/dot-folder.mjssrc/report/dot/dot-module.mjssrc/report/error-html/error-html-template.mjssrc/report/error-html/index.mjssrc/report/error-html/utl.mjssrc/report/error-long.mjssrc/report/error.mjssrc/utl/wrap-and-indent.mjssrc/report/html/html-template.mjssrc/report/html/index.mjssrc/report/identity.mjssrc/report/index.mjssrc/report/plugins.mjssrc/report/json.mjssrc/report/markdown.mjssrc/report/mermaid.mjssrc/report/metrics.mjssrc/report/null.mjssrc/report/teamcity.mjssrc/report/text.mjs \ No newline at end of file diff --git a/doc/assets/theming/bare.svg b/doc/assets/theming/bare.svg index 8cfcb5630..2759a36cc 100644 --- a/doc/assets/theming/bare.svg +++ b/doc/assets/theming/bare.svg @@ -1,262 +1 @@ - - - - - - -dependency-cruiser output - - -cluster_src - -src - - -cluster_src/main - -main - - -cluster_src/main/files-and-dirs - -files-and-dirs - - -cluster_src/main/options - -options - - -cluster_src/main/resolve-options - -resolve-options - - -cluster_src/main/rule-set - -rule-set - - - -src/main/cruise.mjs - - -cruise.mjs - - - - - -src/main/files-and-dirs/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/files-and-dirs/normalize.mjs - - - - - -src/main/options/assert-validity.mjs - - -assert-validity.mjs - - - - - -src/main/cruise.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/options/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/options/normalize.mjs - - - - - -src/main/report-wrap.mjs - - -report-wrap.mjs - - - - - -src/main/cruise.mjs->src/main/report-wrap.mjs - - - - - -src/main/resolve-options/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/resolve-options/normalize.mjs - - - - - -src/main/rule-set/assert-validity.mjs - - -assert-validity.mjs - - - - - -src/main/cruise.mjs->src/main/rule-set/assert-validity.mjs - - - - - -src/main/rule-set/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/rule-set/normalize.mjs - - - - - -src/main/helpers.mjs - - -helpers.mjs - - - - - -src/main/options/normalize.mjs->src/main/helpers.mjs - - - - - -src/main/options/defaults.mjs - - -defaults.mjs - - - - - -src/main/options/normalize.mjs->src/main/options/defaults.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/main/helpers.mjs - - - - - -src/main/rule-set/normalize.mjs->src/main/helpers.mjs - - - - - -src/main/format.mjs - - -format.mjs - - - - - -src/main/format.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/format.mjs->src/main/options/normalize.mjs - - - - - -src/main/format.mjs->src/main/report-wrap.mjs - - - - - -src/main/index.d.ts - - -index.d.ts - - - - - -src/main/index.mjs - - -index.mjs - - - - - -src/main/index.mjs->src/main/cruise.mjs - - - - - -src/main/index.mjs->src/main/format.mjs - - - - - +srcmainfiles-and-dirsoptionsresolve-optionsrule-setcruise.mjsnormalize.mjsassert-validity.mjsnormalize.mjsreport-wrap.mjsnormalize.mjsassert-validity.mjsnormalize.mjshelpers.mjsdefaults.mjsformat.mjsindex.d.tsindex.mjs \ No newline at end of file diff --git a/doc/assets/theming/base.svg b/doc/assets/theming/base.svg index f98604c8d..a3b212e38 100644 --- a/doc/assets/theming/base.svg +++ b/doc/assets/theming/base.svg @@ -1,262 +1 @@ - - - - - - -dependency-cruiser output - - -cluster_src - -src - - -cluster_src/main - -main - - -cluster_src/main/files-and-dirs - -files-and-dirs - - -cluster_src/main/options - -options - - -cluster_src/main/resolve-options - -resolve-options - - -cluster_src/main/rule-set - -rule-set - - - -src/main/cruise.mjs - - -cruise.mjs - - - - - -src/main/files-and-dirs/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/files-and-dirs/normalize.mjs - - - - - -src/main/options/assert-validity.mjs - - -assert-validity.mjs - - - - - -src/main/cruise.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/options/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/options/normalize.mjs - - - - - -src/main/report-wrap.mjs - - -report-wrap.mjs - - - - - -src/main/cruise.mjs->src/main/report-wrap.mjs - - - - - -src/main/resolve-options/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/resolve-options/normalize.mjs - - - - - -src/main/rule-set/assert-validity.mjs - - -assert-validity.mjs - - - - - -src/main/cruise.mjs->src/main/rule-set/assert-validity.mjs - - - - - -src/main/rule-set/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/rule-set/normalize.mjs - - - - - -src/main/helpers.mjs - - -helpers.mjs - - - - - -src/main/options/normalize.mjs->src/main/helpers.mjs - - - - - -src/main/options/defaults.mjs - - -defaults.mjs - - - - - -src/main/options/normalize.mjs->src/main/options/defaults.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/main/helpers.mjs - - - - - -src/main/rule-set/normalize.mjs->src/main/helpers.mjs - - - - - -src/main/format.mjs - - -format.mjs - - - - - -src/main/format.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/format.mjs->src/main/options/normalize.mjs - - - - - -src/main/format.mjs->src/main/report-wrap.mjs - - - - - -src/main/index.d.ts - - -index.d.ts - - - - - -src/main/index.mjs - - -index.mjs - - - - - -src/main/index.mjs->src/main/cruise.mjs - - - - - -src/main/index.mjs->src/main/format.mjs - - - - - +srcmainfiles-and-dirsoptionsresolve-optionsrule-setcruise.mjsnormalize.mjsassert-validity.mjsnormalize.mjsreport-wrap.mjsnormalize.mjsassert-validity.mjsnormalize.mjshelpers.mjsdefaults.mjsformat.mjsindex.d.tsindex.mjs \ No newline at end of file diff --git a/doc/assets/theming/engineering.svg b/doc/assets/theming/engineering.svg index c375344ba..6dad81740 100644 --- a/doc/assets/theming/engineering.svg +++ b/doc/assets/theming/engineering.svg @@ -1,262 +1 @@ - - - - - - -dependency-cruiser output - - -cluster_src - -src - - -cluster_src/main - -main - - -cluster_src/main/files-and-dirs - -files-and-dirs - - -cluster_src/main/options - -options - - -cluster_src/main/resolve-options - -resolve-options - - -cluster_src/main/rule-set - -rule-set - - - -src/main/cruise.mjs - - -cruise.mjs - - - - - -src/main/files-and-dirs/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/files-and-dirs/normalize.mjs - - - - - -src/main/options/assert-validity.mjs - - -assert-validity.mjs - - - - - -src/main/cruise.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/options/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/options/normalize.mjs - - - - - -src/main/report-wrap.mjs - - -report-wrap.mjs - - - - - -src/main/cruise.mjs->src/main/report-wrap.mjs - - - - - -src/main/resolve-options/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/resolve-options/normalize.mjs - - - - - -src/main/rule-set/assert-validity.mjs - - -assert-validity.mjs - - - - - -src/main/cruise.mjs->src/main/rule-set/assert-validity.mjs - - - - - -src/main/rule-set/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/rule-set/normalize.mjs - - - - - -src/main/helpers.mjs - - -helpers.mjs - - - - - -src/main/options/normalize.mjs->src/main/helpers.mjs - - - - - -src/main/options/defaults.mjs - - -defaults.mjs - - - - - -src/main/options/normalize.mjs->src/main/options/defaults.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/main/helpers.mjs - - - - - -src/main/rule-set/normalize.mjs->src/main/helpers.mjs - - - - - -src/main/format.mjs - - -format.mjs - - - - - -src/main/format.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/format.mjs->src/main/options/normalize.mjs - - - - - -src/main/format.mjs->src/main/report-wrap.mjs - - - - - -src/main/index.d.ts - - -index.d.ts - - - - - -src/main/index.mjs - - -index.mjs - - - - - -src/main/index.mjs->src/main/cruise.mjs - - - - - -src/main/index.mjs->src/main/format.mjs - - - - - +srcmainfiles-and-dirsoptionsresolve-optionsrule-setcruise.mjsnormalize.mjsassert-validity.mjsnormalize.mjsreport-wrap.mjsnormalize.mjsassert-validity.mjsnormalize.mjshelpers.mjsdefaults.mjsformat.mjsindex.d.tsindex.mjs \ No newline at end of file diff --git a/doc/assets/theming/vertical.svg b/doc/assets/theming/vertical.svg index 13141cf6f..c77ebce8b 100644 --- a/doc/assets/theming/vertical.svg +++ b/doc/assets/theming/vertical.svg @@ -1,262 +1 @@ - - - - - - -dependency-cruiser output - - -cluster_src - -src - - -cluster_src/main - -main - - -cluster_src/main/files-and-dirs - -files-and-dirs - - -cluster_src/main/options - -options - - -cluster_src/main/resolve-options - -resolve-options - - -cluster_src/main/rule-set - -rule-set - - - -src/main/cruise.mjs - - -cruise.mjs - - - - - -src/main/files-and-dirs/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/files-and-dirs/normalize.mjs - - - - - -src/main/options/assert-validity.mjs - - -assert-validity.mjs - - - - - -src/main/cruise.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/options/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/options/normalize.mjs - - - - - -src/main/report-wrap.mjs - - -report-wrap.mjs - - - - - -src/main/cruise.mjs->src/main/report-wrap.mjs - - - - - -src/main/resolve-options/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/resolve-options/normalize.mjs - - - - - -src/main/rule-set/assert-validity.mjs - - -assert-validity.mjs - - - - - -src/main/cruise.mjs->src/main/rule-set/assert-validity.mjs - - - - - -src/main/rule-set/normalize.mjs - - -normalize.mjs - - - - - -src/main/cruise.mjs->src/main/rule-set/normalize.mjs - - - - - -src/main/helpers.mjs - - -helpers.mjs - - - - - -src/main/options/normalize.mjs->src/main/helpers.mjs - - - - - -src/main/options/defaults.mjs - - -defaults.mjs - - - - - -src/main/options/normalize.mjs->src/main/options/defaults.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/rule-set/assert-validity.mjs->src/main/helpers.mjs - - - - - -src/main/rule-set/normalize.mjs->src/main/helpers.mjs - - - - - -src/main/format.mjs - - -format.mjs - - - - - -src/main/format.mjs->src/main/options/assert-validity.mjs - - - - - -src/main/format.mjs->src/main/options/normalize.mjs - - - - - -src/main/format.mjs->src/main/report-wrap.mjs - - - - - -src/main/index.d.ts - - -index.d.ts - - - - - -src/main/index.mjs - - -index.mjs - - - - - -src/main/index.mjs->src/main/cruise.mjs - - - - - -src/main/index.mjs->src/main/format.mjs - - - - - +srcmainfiles-and-dirsoptionsresolve-optionsrule-setcruise.mjsnormalize.mjsassert-validity.mjsnormalize.mjsreport-wrap.mjsnormalize.mjsassert-validity.mjsnormalize.mjshelpers.mjsdefaults.mjsformat.mjsindex.d.tsindex.mjs \ No newline at end of file diff --git a/doc/cli.md b/doc/cli.md index 3b2aabf0a..fb3cffb1a 100644 --- a/doc/cli.md +++ b/doc/cli.md @@ -204,7 +204,7 @@ GitLab support this out of the box in their on-line rendering of markdown. Both due to limitations in the mermaid format and to the relative newness of this reporter the graph cannot be (made as) feature rich as those produced by the -`dot` reporters. +`dot` or `d2` reporters.
Sample output @@ -259,6 +259,26 @@ style src_main_rule_set_normalize_js fill:lime,color:black
+#### d2 + +Generates a graph in [d2](https://d2lang.com/) format. D2 is a nice, well thought +out alternative to mermaid. It supports a several layout engines, of which ELK looks +especially pleasing. The current trade-off between D2 and dot is that its graphs +tend to take up more space than the dot ones. + +Sample use: + +```sh +dependency-cruise src/cache --include-only "^src/cache" -T d2 | d2 --layout elk --scale 1 - > dependencygraph.svg +``` + +
+Sample output + +![d2 representation of dependency-cruiser's caching feature, with d2 set to use the 'ELK' layout](./assets/d2.svg)] + +
+ #### err-html Generates a stand-alone html report with: diff --git a/src/report/d2.mjs b/src/report/d2.mjs new file mode 100644 index 000000000..8faffb440 --- /dev/null +++ b/src/report/d2.mjs @@ -0,0 +1,161 @@ +import { EOL } from "node:os"; +import { basename, dirname } from "node:path"; +import { getURLForModule } from "./utl/index.mjs"; + +const severity2color = new Map([ + ["error", "red"], + ["warn", "orange"], + ["info", "blue"], +]); + +/** + * @param {import("../../types/rule-summary").IRuleSummary} pRules + * @returns {string} + */ +function getMaxSeverity(pRules) { + const lSeverity2Number = new Map([ + // eslint-disable-next-line no-magic-numbers + ["error", 3], + // eslint-disable-next-line no-magic-numbers + ["warn", 2], + ["info", 1], + ]); + return pRules + .map((pRule) => pRule.severity) + .reduce((pMax, pCurrent) => { + return (lSeverity2Number.get(pMax) ?? 0) > + (lSeverity2Number.get(pCurrent) ?? 0) + ? pMax + : pCurrent; + }); +} + +/** + * @param {string} pSource + * @return {string} + */ +function getVertexName(pSource) { + const lFolderName = dirname(pSource) + .split("/") + .map((pPart) => `"${pPart}"`) + .join("."); + const lBaseName = `"${basename(pSource)}"`; + if (lFolderName === `"."`) { + return lBaseName; + } + return `${lFolderName}.${lBaseName}`; +} + +/** + * @param {import("../../types/cruise-result").IModule} pModule + * @param {import("../../types/cruise-result").IOptions} pOptions + * @returns {string} + */ +// eslint-disable-next-line complexity +function getModuleAttributes(pModule, pOptions) { + let lReturnValue = "class: module"; + if (pModule.consolidated) { + lReturnValue = `${lReturnValue}; style.multiple: true`; + } + if ( + pModule.matchesFocus || + pModule.matchesHighlight || + pModule.matchesReaches + ) { + lReturnValue = `${lReturnValue}; style.fill: yellow`; + } + if (pModule.valid === false) { + lReturnValue = `${lReturnValue}; style.stroke: ${ + severity2color.get(getMaxSeverity(pModule.rules)) ?? "orange" + }`; + lReturnValue = `${lReturnValue}; tooltip: "${pModule.rules + .map((pRule) => pRule.name) + .join("\\n")}"`; + } + if ( + pModule.dependencyTypes?.some((pDependencyType) => + pDependencyType.includes("npm"), + ) + ) { + lReturnValue = `${lReturnValue}; shape: package`; + } + lReturnValue = `${lReturnValue}; link: "${getURLForModule( + pModule, + pOptions?.prefix, + )}"`; + return lReturnValue; +} + +/** + * @param {import("../../types/cruise-result").IDependency} pDependency + * @returns {string} + */ +// eslint-disable-next-line complexity +function getDependencyAttributes(pDependency) { + let lThing = ""; + if (pDependency.valid === false) { + lThing = + `style: {stroke: ${ + severity2color.get(getMaxSeverity(pDependency.rules)) ?? "orange" + }}; ` + + `label: "${pDependency.rules.map((pRule) => pRule.name).join("\\n")}"`; + } + if (pDependency.circular) { + lThing = `${ + lThing ? `${lThing};` : lThing + } target-arrowhead: {shape: circle}`; + } + if (pDependency.dynamic) { + lThing = `${ + lThing ? `${lThing};` : lThing + } target-arrowhead: {shape: arrow}`; + } + return lThing ? `: {${lThing}}` : lThing; +} + +/** + * @param {import('../../types/cruise-result').ICruiseResult} pCruiseResult + * @return {string} + */ +function renderD2Source(pCruiseResult) { + const lVertices = pCruiseResult.modules + .map((pModule) => { + return `${getVertexName(pModule.source)}: {${getModuleAttributes( + pModule, + pCruiseResult.summary.optionsUsed, + )}}`; + }) + .join(EOL); + const lEdges = pCruiseResult.modules + .flatMap((pModule) => { + return pModule.dependencies.map((pDependency) => { + return `${getVertexName(pModule.source)} -> ${getVertexName( + pDependency.resolved, + )}${getDependencyAttributes(pDependency)}`; + }); + }) + .join(EOL); + const lStyles = `classes: { + module: { + height: 30; + style.border-radius: 10; + } +}`; + return ( + `# modules${EOL}${EOL}${lVertices}${EOL}${EOL}` + + `# dependencies${EOL}${EOL}${lEdges}${EOL}${EOL}` + + `# styling${EOL}${EOL}${lStyles}${EOL}` + ); +} +/** + * d2 reporter + * + * @param {import('../../types/dependency-cruiser').ICruiseResult} pCruiseResult + * @return {import('../../types/dependency-cruiser').IReporterOutput} + */ +export default function d2(pCruiseResult) { + return { + output: renderD2Source(pCruiseResult), + exitCode: 0, + }; +} diff --git a/src/report/index.mjs b/src/report/index.mjs index 187bfd9a1..4a7318ec8 100644 --- a/src/report/index.mjs +++ b/src/report/index.mjs @@ -2,26 +2,27 @@ import { getExternalPluginReporter } from "./plugins.mjs"; const TYPE2MODULE = new Map([ ["anon", "./anon/index.mjs"], + ["archi", "./dot/dot-custom.mjs"], + ["azure-devops", "./azure-devops.mjs"], + ["baseline", "./baseline.mjs"], + ["cdot", "./dot/dot-custom.mjs"], ["csv", "./csv.mjs"], - ["dot", "./dot/dot-module.mjs"], + ["d2", "./d2.mjs"], ["ddot", "./dot/dot-folder.mjs"], - ["cdot", "./dot/dot-custom.mjs"], - ["archi", "./dot/dot-custom.mjs"], - ["fdot", "./dot/dot-flat.mjs"], - ["flat", "./dot/dot-flat.mjs"], + ["dot", "./dot/dot-module.mjs"], ["err-html", "./error-html/index.mjs"], - ["markdown", "./markdown.mjs"], ["err-long", "./error-long.mjs"], ["err", "./error.mjs"], + ["fdot", "./dot/dot-flat.mjs"], + ["flat", "./dot/dot-flat.mjs"], ["html", "./html/index.mjs"], ["json", "./json.mjs"], - ["teamcity", "./teamcity.mjs"], - ["text", "./text.mjs"], - ["baseline", "./baseline.mjs"], - ["metrics", "./metrics.mjs"], + ["markdown", "./markdown.mjs"], ["mermaid", "./mermaid.mjs"], + ["metrics", "./metrics.mjs"], ["null", "./null.mjs"], - ["azure-devops", "./azure-devops.mjs"], + ["teamcity", "./teamcity.mjs"], + ["text", "./text.mjs"], ]); /** diff --git a/test/report/d2/__fixtures__/00-empty.d2 b/test/report/d2/__fixtures__/00-empty.d2 new file mode 100644 index 000000000..936eebd0d --- /dev/null +++ b/test/report/d2/__fixtures__/00-empty.d2 @@ -0,0 +1,16 @@ +# modules + + + +# dependencies + + + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/01-one-module-no-dependencies.d2 b/test/report/d2/__fixtures__/01-one-module-no-dependencies.d2 new file mode 100644 index 000000000..6a830105f --- /dev/null +++ b/test/report/d2/__fixtures__/01-one-module-no-dependencies.d2 @@ -0,0 +1,16 @@ +# modules + +"aap"."noot"."mies.js": {class: module; link: "aap/noot/mies.js"} + +# dependencies + + + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/02-one-module-invalid-error.d2 b/test/report/d2/__fixtures__/02-one-module-invalid-error.d2 new file mode 100644 index 000000000..30e3828da --- /dev/null +++ b/test/report/d2/__fixtures__/02-one-module-invalid-error.d2 @@ -0,0 +1,16 @@ +# modules + +"aap"."noot"."mies.js": {class: module; style.stroke: red; tooltip: "no-orphans"; link: "aap/noot/mies.js"} + +# dependencies + + + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/03-one-module-invalid-info-and-warning.d2 b/test/report/d2/__fixtures__/03-one-module-invalid-info-and-warning.d2 new file mode 100644 index 000000000..6c4e03993 --- /dev/null +++ b/test/report/d2/__fixtures__/03-one-module-invalid-info-and-warning.d2 @@ -0,0 +1,16 @@ +# modules + +"aap"."noot"."mies.js": {class: module; style.stroke: orange; tooltip: "ignored-rule\nno-orphans\nsome-other-rule\nsome-other-rule-again"; link: "aap/noot/mies.js"} + +# dependencies + + + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/04-one-module-invalid-weird-severity.d2 b/test/report/d2/__fixtures__/04-one-module-invalid-weird-severity.d2 new file mode 100644 index 000000000..d6d63031e --- /dev/null +++ b/test/report/d2/__fixtures__/04-one-module-invalid-weird-severity.d2 @@ -0,0 +1,16 @@ +# modules + +"aap"."noot"."mies.js": {class: module; style.stroke: orange; tooltip: "yolo-rule"; link: "aap/noot/mies.js"} + +# dependencies + + + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/05-one-module-in-root.d2 b/test/report/d2/__fixtures__/05-one-module-in-root.d2 new file mode 100644 index 000000000..92d426f75 --- /dev/null +++ b/test/report/d2/__fixtures__/05-one-module-in-root.d2 @@ -0,0 +1,16 @@ +# modules + +"mies.js": {class: module; link: "mies.js"} + +# dependencies + + + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/06-one-module-npm.d2 b/test/report/d2/__fixtures__/06-one-module-npm.d2 new file mode 100644 index 000000000..a87dc6ea3 --- /dev/null +++ b/test/report/d2/__fixtures__/06-one-module-npm.d2 @@ -0,0 +1,16 @@ +# modules + +"node_modules"."yudelyo"."index.js": {class: module; shape: package; link: "https://www.npmjs.com/package/yudelyo"} + +# dependencies + + + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/07-one-module-matches-highlight.d2 b/test/report/d2/__fixtures__/07-one-module-matches-highlight.d2 new file mode 100644 index 000000000..6a2d3052f --- /dev/null +++ b/test/report/d2/__fixtures__/07-one-module-matches-highlight.d2 @@ -0,0 +1,16 @@ +# modules + +"aap"."noot"."mies.js": {class: module; style.fill: yellow; link: "aap/noot/mies.js"} + +# dependencies + + + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/08-one-module-is-consolidated-and-node-module.d2 b/test/report/d2/__fixtures__/08-one-module-is-consolidated-and-node-module.d2 new file mode 100644 index 000000000..34afe2a71 --- /dev/null +++ b/test/report/d2/__fixtures__/08-one-module-is-consolidated-and-node-module.d2 @@ -0,0 +1,16 @@ +# modules + +"node_modules"."slodash": {class: module; style.multiple: true; shape: package; link: "https://www.npmjs.com/package/slodash"} + +# dependencies + + + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/10-one-dependency.d2 b/test/report/d2/__fixtures__/10-one-dependency.d2 new file mode 100644 index 000000000..34ca98640 --- /dev/null +++ b/test/report/d2/__fixtures__/10-one-dependency.d2 @@ -0,0 +1,17 @@ +# modules + +"aap"."noot"."mies.js": {class: module; link: "aap/noot/mies.js"} +"aap"."noot"."zus.js": {class: module; link: "aap/noot/zus.js"} + +# dependencies + +"aap"."noot"."mies.js" -> "aap"."noot"."zus.js" + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/11-one-dependency-invalid.d2 b/test/report/d2/__fixtures__/11-one-dependency-invalid.d2 new file mode 100644 index 000000000..f2a45bba0 --- /dev/null +++ b/test/report/d2/__fixtures__/11-one-dependency-invalid.d2 @@ -0,0 +1,17 @@ +# modules + +"aap"."noot"."mies.js": {class: module; link: "aap/noot/mies.js"} +"aap"."noot"."zus.js": {class: module; link: "aap/noot/zus.js"} + +# dependencies + +"aap"."noot"."mies.js" -> "aap"."noot"."zus.js": {style: {stroke: orange}; label: "pas-de-alez-houpe"} + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/12-one-dependency-invalid-with-weird-severity.d2 b/test/report/d2/__fixtures__/12-one-dependency-invalid-with-weird-severity.d2 new file mode 100644 index 000000000..f1857ee67 --- /dev/null +++ b/test/report/d2/__fixtures__/12-one-dependency-invalid-with-weird-severity.d2 @@ -0,0 +1,17 @@ +# modules + +"aap"."noot"."mies.js": {class: module; link: "aap/noot/mies.js"} +"aap"."noot"."zus.js": {class: module; link: "aap/noot/zus.js"} + +# dependencies + +"aap"."noot"."mies.js" -> "aap"."noot"."zus.js": {style: {stroke: orange}; label: "keine-ahnung"} + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/13-one-dependency-cycle-invalid.d2 b/test/report/d2/__fixtures__/13-one-dependency-cycle-invalid.d2 new file mode 100644 index 000000000..b3ac2891d --- /dev/null +++ b/test/report/d2/__fixtures__/13-one-dependency-cycle-invalid.d2 @@ -0,0 +1,18 @@ +# modules + +"aap"."noot"."mies.js": {class: module; link: "aap/noot/mies.js"} +"aap"."noot"."zus.js": {class: module; link: "aap/noot/zus.js"} + +# dependencies + +"aap"."noot"."mies.js" -> "aap"."noot"."zus.js": {style: {stroke: red}; label: "pas-de-alez-houpe\nno-cycles"; target-arrowhead: {shape: circle}} +"aap"."noot"."zus.js" -> "aap"."noot"."mies.js": {style: {stroke: red}; label: "no-cycles"; target-arrowhead: {shape: circle}} + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/14-one-dependency-cycle-valid.d2 b/test/report/d2/__fixtures__/14-one-dependency-cycle-valid.d2 new file mode 100644 index 000000000..7c1520139 --- /dev/null +++ b/test/report/d2/__fixtures__/14-one-dependency-cycle-valid.d2 @@ -0,0 +1,18 @@ +# modules + +"aap"."noot"."mies.js": {class: module; link: "aap/noot/mies.js"} +"aap"."noot"."zus.js": {class: module; link: "aap/noot/zus.js"} + +# dependencies + +"aap"."noot"."mies.js" -> "aap"."noot"."zus.js": { target-arrowhead: {shape: circle}} +"aap"."noot"."zus.js" -> "aap"."noot"."mies.js": { target-arrowhead: {shape: circle}} + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/15-one-dependency-dynamic.d2 b/test/report/d2/__fixtures__/15-one-dependency-dynamic.d2 new file mode 100644 index 000000000..cfe1a615c --- /dev/null +++ b/test/report/d2/__fixtures__/15-one-dependency-dynamic.d2 @@ -0,0 +1,17 @@ +# modules + +"aap"."noot"."mies.js": {class: module; link: "aap/noot/mies.js"} +"aap"."noot"."zus.js": {class: module; link: "aap/noot/zus.js"} + +# dependencies + +"aap"."noot"."mies.js" -> "aap"."noot"."zus.js": { target-arrowhead: {shape: arrow}} + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/16-one-dependency-dynamic-invalid.d2 b/test/report/d2/__fixtures__/16-one-dependency-dynamic-invalid.d2 new file mode 100644 index 000000000..b13c0dbc3 --- /dev/null +++ b/test/report/d2/__fixtures__/16-one-dependency-dynamic-invalid.d2 @@ -0,0 +1,18 @@ +# modules + +"aap"."noot"."mies.js": {class: module; link: "aap/noot/mies.js"} +"aap"."noot"."zus.js": {class: module; link: "aap/noot/zus.js"} + +# dependencies + +"aap"."noot"."mies.js" -> "aap"."noot"."zus.js": {style: {stroke: red}; label: "pas-de-alez-houpe\nno-cycles"; target-arrowhead: {shape: circle}; target-arrowhead: {shape: arrow}} +"aap"."noot"."zus.js" -> "aap"."noot"."mies.js": {style: {stroke: red}; label: "no-cycles"; target-arrowhead: {shape: circle}} + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__fixtures__/20-real-world-sample.d2 b/test/report/d2/__fixtures__/20-real-world-sample.d2 new file mode 100644 index 000000000..bd9905c55 --- /dev/null +++ b/test/report/d2/__fixtures__/20-real-world-sample.d2 @@ -0,0 +1,76 @@ +# modules + +"src"."cache"."cache.mjs": {class: module; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/cache/cache.mjs"} +"fs"."promises": {class: module; link: "https://nodejs.org/api/fs.html"} +"path": {class: module; link: "https://nodejs.org/api/path.html"} +"src"."cache"."content-strategy.mjs": {class: module; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/cache/content-strategy.mjs"} +"path"."posix": {class: module; link: "https://nodejs.org/api/path.html"} +"util": {class: module; link: "https://nodejs.org/api/util.html"} +"src"."cache"."find-content-changes.mjs": {class: module; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/cache/find-content-changes.mjs"} +"src"."cache"."helpers.mjs": {class: module; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/cache/helpers.mjs"} +"crypto": {class: module; link: "https://nodejs.org/api/crypto.html"} +"fs": {class: module; link: "https://nodejs.org/api/fs.html"} +"node_modules"."lodash"."memoize.js": {class: module; shape: package; link: "https://www.npmjs.com/package/lodash"} +"src"."graph-utl"."match-facade.mjs": {class: module; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/graph-utl/match-facade.mjs"} +"src"."utl"."bus.mjs": {class: module; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/utl/bus.mjs"} +"events": {class: module; link: "https://nodejs.org/api/events.html"} +"src"."utl"."find-all-files.mjs": {class: module; style.stroke: blue; tooltip: "utl-module-not-shared-enough"; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/utl/find-all-files.mjs"} +"node_modules"."ignore"."index.js": {class: module; shape: package; link: "https://www.npmjs.com/package/ignore"} +"src"."utl"."path-to-posix.mjs": {class: module; style.stroke: blue; tooltip: "utl-module-not-shared-enough"; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/utl/path-to-posix.mjs"} +"src"."cache"."metadata-strategy.mjs": {class: module; style.fill: yellow; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/cache/metadata-strategy.mjs"} +"node_modules"."watskeburt"."dist"."main.js": {class: module; shape: package; link: "https://www.npmjs.com/package/watskeburt"} +"src"."cache"."options-compatible.mjs": {class: module; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/cache/options-compatible.mjs"} +"src"."extract"."transpile"."meta.mjs": {class: module; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/extract/transpile/meta.mjs"} +"src"."extract"."transpile"."try-import-available.mjs": {class: module; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/extract/transpile/try-import-available.mjs"} +"module": {class: module; link: "https://nodejs.org/api/module.html"} +"node_modules"."semver"."index.js": {class: module; shape: package; link: "https://www.npmjs.com/package/semver"} +"src"."meta.js": {class: module; link: "https://github.com/sverweij/dependency-cruiser/blob/main/src/meta.js"} + +# dependencies + +"src"."cache"."cache.mjs" -> "src"."cache"."content-strategy.mjs" +"src"."cache"."cache.mjs" -> "src"."cache"."metadata-strategy.mjs" +"src"."cache"."cache.mjs" -> "src"."cache"."options-compatible.mjs" +"src"."cache"."cache.mjs" -> "src"."extract"."transpile"."meta.mjs" +"src"."cache"."cache.mjs" -> "src"."utl"."bus.mjs" +"src"."cache"."cache.mjs" -> "fs"."promises" +"src"."cache"."cache.mjs" -> "path" +"src"."cache"."content-strategy.mjs" -> "src"."cache"."find-content-changes.mjs" +"src"."cache"."content-strategy.mjs" -> "src"."cache"."helpers.mjs" +"src"."cache"."content-strategy.mjs" -> "path"."posix" +"src"."cache"."content-strategy.mjs" -> "util" +"src"."cache"."find-content-changes.mjs" -> "src"."cache"."helpers.mjs" +"src"."cache"."find-content-changes.mjs" -> "src"."utl"."bus.mjs" +"src"."cache"."find-content-changes.mjs" -> "src"."utl"."find-all-files.mjs" +"src"."cache"."find-content-changes.mjs" -> "path"."posix" +"src"."cache"."helpers.mjs" -> "src"."graph-utl"."match-facade.mjs" +"src"."cache"."helpers.mjs" -> "crypto" +"src"."cache"."helpers.mjs" -> "fs" +"src"."cache"."helpers.mjs" -> "fs"."promises" +"src"."cache"."helpers.mjs" -> "node_modules"."lodash"."memoize.js" +"src"."cache"."helpers.mjs" -> "path" +"src"."utl"."bus.mjs" -> "events" +"src"."utl"."find-all-files.mjs" -> "src"."utl"."path-to-posix.mjs" +"src"."utl"."find-all-files.mjs" -> "fs" +"src"."utl"."find-all-files.mjs" -> "node_modules"."ignore"."index.js" +"src"."utl"."find-all-files.mjs" -> "path" +"src"."utl"."path-to-posix.mjs" -> "path" +"src"."cache"."metadata-strategy.mjs" -> "src"."cache"."helpers.mjs" +"src"."cache"."metadata-strategy.mjs" -> "src"."utl"."bus.mjs" +"src"."cache"."metadata-strategy.mjs" -> "util" +"src"."cache"."metadata-strategy.mjs" -> "node_modules"."watskeburt"."dist"."main.js" +"src"."cache"."options-compatible.mjs" -> "util" +"src"."extract"."transpile"."meta.mjs" -> "src"."extract"."transpile"."try-import-available.mjs" +"src"."extract"."transpile"."meta.mjs" -> "src"."meta.js" +"src"."extract"."transpile"."try-import-available.mjs" -> "module" +"src"."extract"."transpile"."try-import-available.mjs" -> "path"."posix" +"src"."extract"."transpile"."try-import-available.mjs" -> "node_modules"."semver"."index.js" + +# styling + +classes: { + module: { + height: 30; + style.border-radius: 10; + } +} diff --git a/test/report/d2/__mocks__/00-empty.mjs b/test/report/d2/__mocks__/00-empty.mjs new file mode 100644 index 000000000..820f74f7d --- /dev/null +++ b/test/report/d2/__mocks__/00-empty.mjs @@ -0,0 +1,6 @@ +export default { + modules: [], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/01-one-module-no-dependencies.mjs b/test/report/d2/__mocks__/01-one-module-no-dependencies.mjs new file mode 100644 index 000000000..255083f84 --- /dev/null +++ b/test/report/d2/__mocks__/01-one-module-no-dependencies.mjs @@ -0,0 +1,12 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/02-one-module-invalid-error.mjs b/test/report/d2/__mocks__/02-one-module-invalid-error.mjs new file mode 100644 index 000000000..ef42764bf --- /dev/null +++ b/test/report/d2/__mocks__/02-one-module-invalid-error.mjs @@ -0,0 +1,26 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + valid: false, + orphan: true, + rules: [ + { + severity: "error", + name: "no-orphans", + from: { + path: "aap/noot/mies.js", + }, + to: { + path: "aap/noot/mies.js", + }, + }, + ], + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/03-one-module-invalid-info-and-warning.mjs b/test/report/d2/__mocks__/03-one-module-invalid-info-and-warning.mjs new file mode 100644 index 000000000..cc5a0d349 --- /dev/null +++ b/test/report/d2/__mocks__/03-one-module-invalid-info-and-warning.mjs @@ -0,0 +1,56 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + valid: false, + orphan: true, + rules: [ + { + severity: "ignore", + name: "ignored-rule", + from: { + path: "aap/noot/mies.js", + }, + to: { + path: "aap/noot/mies.js", + }, + }, + { + severity: "info", + name: "no-orphans", + from: { + path: "aap/noot/mies.js", + }, + to: { + path: "aap/noot/mies.js", + }, + }, + { + severity: "warn", + name: "some-other-rule", + from: { + path: "aap/noot/mies.js", + }, + to: { + path: "aap/noot/mies.js", + }, + }, + { + severity: "ignore", + name: "some-other-rule-again", + from: { + path: "aap/noot/mies.js", + }, + to: { + path: "aap/noot/mies.js", + }, + }, + ], + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/04-one-module-invalid-weird-severity.mjs b/test/report/d2/__mocks__/04-one-module-invalid-weird-severity.mjs new file mode 100644 index 000000000..7618971b5 --- /dev/null +++ b/test/report/d2/__mocks__/04-one-module-invalid-weird-severity.mjs @@ -0,0 +1,26 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + valid: false, + orphan: true, + rules: [ + { + severity: "don't know", + name: "yolo-rule", + from: { + path: "aap/noot/mies.js", + }, + to: { + path: "aap/noot/mies.js", + }, + }, + ], + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/05-one-module-in-root.mjs b/test/report/d2/__mocks__/05-one-module-in-root.mjs new file mode 100644 index 000000000..cb10a876c --- /dev/null +++ b/test/report/d2/__mocks__/05-one-module-in-root.mjs @@ -0,0 +1,14 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "mies.js", + valid: true, + orphan: true, + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/06-one-module-npm.mjs b/test/report/d2/__mocks__/06-one-module-npm.mjs new file mode 100644 index 000000000..c179e1d11 --- /dev/null +++ b/test/report/d2/__mocks__/06-one-module-npm.mjs @@ -0,0 +1,15 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "node_modules/yudelyo/index.js", + valid: true, + orphan: true, + dependencyTypes: ["npm-dev"], + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/07-one-module-matches-highlight.mjs b/test/report/d2/__mocks__/07-one-module-matches-highlight.mjs new file mode 100644 index 000000000..0ee8b1dab --- /dev/null +++ b/test/report/d2/__mocks__/07-one-module-matches-highlight.mjs @@ -0,0 +1,15 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + valid: true, + orphan: true, + matchesHighlight: true, + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/08-one-module-is-consolidated-and-node-module.mjs b/test/report/d2/__mocks__/08-one-module-is-consolidated-and-node-module.mjs new file mode 100644 index 000000000..fc8c9a029 --- /dev/null +++ b/test/report/d2/__mocks__/08-one-module-is-consolidated-and-node-module.mjs @@ -0,0 +1,16 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "node_modules/slodash", + valid: true, + orphan: true, + consolidated: true, + dependencyTypes: ["npm"], + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/10-one-dependency.mjs b/test/report/d2/__mocks__/10-one-dependency.mjs new file mode 100644 index 000000000..e7bedd23e --- /dev/null +++ b/test/report/d2/__mocks__/10-one-dependency.mjs @@ -0,0 +1,29 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + dependencies: [ + { + resolved: "aap/noot/zus.js", + module: "#noot/zus.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dynamic: false, + exoticallyRequired: false, + matchesDoNotFollow: false, + moduleSystem: "es6", + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + }, + ], + }, + { + source: "aap/noot/zus.js", + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/11-one-dependency-invalid.mjs b/test/report/d2/__mocks__/11-one-dependency-invalid.mjs new file mode 100644 index 000000000..a75b908dc --- /dev/null +++ b/test/report/d2/__mocks__/11-one-dependency-invalid.mjs @@ -0,0 +1,36 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + dependencies: [ + { + resolved: "aap/noot/zus.js", + module: "#noot/zus.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dynamic: false, + exoticallyRequired: false, + matchesDoNotFollow: false, + moduleSystem: "es6", + valid: false, + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + rules: [ + { + severity: "warn", + name: "pas-de-alez-houpe", + }, + ], + }, + ], + }, + { + source: "aap/noot/zus.js", + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/12-one-dependency-invalid-with-weird-severity.mjs b/test/report/d2/__mocks__/12-one-dependency-invalid-with-weird-severity.mjs new file mode 100644 index 000000000..1164a2dae --- /dev/null +++ b/test/report/d2/__mocks__/12-one-dependency-invalid-with-weird-severity.mjs @@ -0,0 +1,36 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + dependencies: [ + { + resolved: "aap/noot/zus.js", + module: "#noot/zus.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dynamic: false, + exoticallyRequired: false, + matchesDoNotFollow: false, + moduleSystem: "es6", + valid: false, + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + rules: [ + { + severity: "bist-du-verrückt?", + name: "keine-ahnung", + }, + ], + }, + ], + }, + { + source: "aap/noot/zus.js", + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/13-one-dependency-cycle-invalid.mjs b/test/report/d2/__mocks__/13-one-dependency-cycle-invalid.mjs new file mode 100644 index 000000000..1d56cba2f --- /dev/null +++ b/test/report/d2/__mocks__/13-one-dependency-cycle-invalid.mjs @@ -0,0 +1,64 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + dependencies: [ + { + resolved: "aap/noot/zus.js", + module: "#noot/zus.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dynamic: false, + exoticallyRequired: false, + matchesDoNotFollow: false, + moduleSystem: "es6", + valid: false, + circular: true, + cycle: ["aap/noot/mies.js", "aap/noot/zus.js"], + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + rules: [ + { + severity: "warn", + name: "pas-de-alez-houpe", + }, + { + severity: "error", + name: "no-cycles", + }, + ], + }, + ], + }, + { + source: "aap/noot/zus.js", + dependencies: [ + { + resolved: "aap/noot/mies.js", + module: "#noot/mies.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dynamic: false, + exoticallyRequired: false, + matchesDoNotFollow: false, + moduleSystem: "es6", + valid: false, + circular: true, + cycle: ["aap/noot/zus.js", "aap/noot/mies.js"], + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + rules: [ + { + severity: "error", + name: "no-cycles", + }, + ], + }, + ], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/14-one-dependency-cycle-valid.mjs b/test/report/d2/__mocks__/14-one-dependency-cycle-valid.mjs new file mode 100644 index 000000000..b6fbc5b02 --- /dev/null +++ b/test/report/d2/__mocks__/14-one-dependency-cycle-valid.mjs @@ -0,0 +1,48 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + dependencies: [ + { + resolved: "aap/noot/zus.js", + module: "#noot/zus.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dynamic: false, + exoticallyRequired: false, + matchesDoNotFollow: false, + moduleSystem: "es6", + valid: true, + circular: true, + cycle: ["aap/noot/mies.js", "aap/noot/zus.js"], + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + }, + ], + }, + { + source: "aap/noot/zus.js", + dependencies: [ + { + resolved: "aap/noot/mies.js", + module: "#noot/mies.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dynamic: false, + exoticallyRequired: false, + matchesDoNotFollow: false, + moduleSystem: "es6", + valid: true, + circular: true, + cycle: ["aap/noot/zus.js", "aap/noot/mies.js"], + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + }, + ], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/15-one-dependency-dynamic.mjs b/test/report/d2/__mocks__/15-one-dependency-dynamic.mjs new file mode 100644 index 000000000..4e0b33aa6 --- /dev/null +++ b/test/report/d2/__mocks__/15-one-dependency-dynamic.mjs @@ -0,0 +1,29 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + dependencies: [ + { + resolved: "aap/noot/zus.js", + module: "#noot/zus.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dynamic: true, + exoticallyRequired: false, + matchesDoNotFollow: false, + moduleSystem: "es6", + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + }, + ], + }, + { + source: "aap/noot/zus.js", + dependencies: [], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/16-one-dependency-dynamic-invalid.mjs b/test/report/d2/__mocks__/16-one-dependency-dynamic-invalid.mjs new file mode 100644 index 000000000..3a4353b16 --- /dev/null +++ b/test/report/d2/__mocks__/16-one-dependency-dynamic-invalid.mjs @@ -0,0 +1,64 @@ +/** @type {import('../../../../types/dependency-cruiser').ICruiseResult} */ +export default { + modules: [ + { + source: "aap/noot/mies.js", + dependencies: [ + { + resolved: "aap/noot/zus.js", + module: "#noot/zus.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dynamic: true, + exoticallyRequired: false, + matchesDoNotFollow: false, + moduleSystem: "es6", + valid: false, + circular: true, + cycle: ["aap/noot/mies.js", "aap/noot/zus.js"], + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + rules: [ + { + severity: "warn", + name: "pas-de-alez-houpe", + }, + { + severity: "error", + name: "no-cycles", + }, + ], + }, + ], + }, + { + source: "aap/noot/zus.js", + dependencies: [ + { + resolved: "aap/noot/mies.js", + module: "#noot/mies.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dynamic: false, + exoticallyRequired: false, + matchesDoNotFollow: false, + moduleSystem: "es6", + valid: false, + circular: true, + cycle: ["aap/noot/zus.js", "aap/noot/mies.js"], + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + rules: [ + { + severity: "error", + name: "no-cycles", + }, + ], + }, + ], + }, + ], + summary: { + optionsUsed: {}, + }, +}; diff --git a/test/report/d2/__mocks__/20-real-world-sample.mjs b/test/report/d2/__mocks__/20-real-world-sample.mjs new file mode 100644 index 000000000..0d8536f9e --- /dev/null +++ b/test/report/d2/__mocks__/20-real-world-sample.mjs @@ -0,0 +1,1575 @@ +export default { + modules: [ + { + source: "src/cache/cache.mjs", + dependencies: [ + { + dynamic: false, + module: "./content-strategy.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/cache/content-strategy.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "./metadata-strategy.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/cache/metadata-strategy.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "./options-compatible.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/cache/options-compatible.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "#extract/transpile/meta.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/extract/transpile/meta.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "#utl/bus.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/utl/bus.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "fs/promises", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "fs/promises", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "path", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "path", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + ], + dependents: [], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "fs/promises", + followable: false, + coreModule: true, + couldNotResolve: false, + matchesDoNotFollow: false, + dependencyTypes: ["core"], + dependencies: [], + dependents: ["src/cache/cache.mjs", "src/cache/helpers.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "path", + followable: false, + coreModule: true, + couldNotResolve: false, + matchesDoNotFollow: false, + dependencyTypes: ["core"], + dependencies: [], + dependents: [ + "src/cache/cache.mjs", + "src/cache/helpers.mjs", + "src/utl/find-all-files.mjs", + "src/utl/path-to-posix.mjs", + ], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/cache/content-strategy.mjs", + dependencies: [ + { + dynamic: false, + module: "./find-content-changes.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/cache/find-content-changes.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "./helpers.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/cache/helpers.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "path/posix", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "path/posix", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "util", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "util", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + ], + dependents: ["src/cache/cache.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "path/posix", + followable: false, + coreModule: true, + couldNotResolve: false, + matchesDoNotFollow: false, + dependencyTypes: ["core"], + dependencies: [], + dependents: [ + "src/cache/content-strategy.mjs", + "src/cache/find-content-changes.mjs", + "src/extract/transpile/try-import-available.mjs", + ], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "util", + followable: false, + coreModule: true, + couldNotResolve: false, + matchesDoNotFollow: false, + dependencyTypes: ["core"], + dependencies: [], + dependents: [ + "src/cache/content-strategy.mjs", + "src/cache/metadata-strategy.mjs", + "src/cache/options-compatible.mjs", + ], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/cache/find-content-changes.mjs", + dependencies: [ + { + dynamic: false, + module: "./helpers.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/cache/helpers.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "#utl/bus.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/utl/bus.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "#utl/find-all-files.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/utl/find-all-files.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "path/posix", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "path/posix", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + ], + dependents: ["src/cache/content-strategy.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/cache/helpers.mjs", + dependencies: [ + { + dynamic: false, + module: "#graph-utl/match-facade.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/graph-utl/match-facade.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "crypto", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "crypto", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "fs", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "fs", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "fs/promises", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "fs/promises", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "lodash/memoize.js", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "node_modules/lodash/memoize.js", + coreModule: false, + followable: false, + couldNotResolve: false, + license: "MIT", + dependencyTypes: ["npm"], + matchesDoNotFollow: true, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "path", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "path", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + ], + dependents: [ + "src/cache/content-strategy.mjs", + "src/cache/find-content-changes.mjs", + "src/cache/metadata-strategy.mjs", + ], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "crypto", + followable: false, + coreModule: true, + couldNotResolve: false, + matchesDoNotFollow: false, + dependencyTypes: ["core"], + dependencies: [], + dependents: ["src/cache/helpers.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "fs", + followable: false, + coreModule: true, + couldNotResolve: false, + matchesDoNotFollow: false, + dependencyTypes: ["core"], + dependencies: [], + dependents: ["src/cache/helpers.mjs", "src/utl/find-all-files.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "node_modules/lodash/memoize.js", + followable: false, + coreModule: false, + couldNotResolve: false, + matchesDoNotFollow: true, + dependencyTypes: ["npm"], + dependencies: [], + dependents: ["src/cache/helpers.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/graph-utl/match-facade.mjs", + dependencies: [], + dependents: ["src/cache/helpers.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/utl/bus.mjs", + dependencies: [ + { + dynamic: false, + module: "events", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "events", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + ], + dependents: [ + "src/cache/cache.mjs", + "src/cache/find-content-changes.mjs", + "src/cache/metadata-strategy.mjs", + ], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "events", + followable: false, + coreModule: true, + couldNotResolve: false, + matchesDoNotFollow: false, + dependencyTypes: ["core"], + dependencies: [], + dependents: ["src/utl/bus.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/utl/find-all-files.mjs", + dependencies: [ + { + dynamic: false, + module: "./path-to-posix.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/utl/path-to-posix.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "fs", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "fs", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "ignore", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "node_modules/ignore/index.js", + coreModule: false, + followable: false, + couldNotResolve: false, + license: "MIT", + dependencyTypes: ["npm"], + matchesDoNotFollow: true, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "path", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "path", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + ], + dependents: ["src/cache/find-content-changes.mjs"], + orphan: false, + valid: false, + rules: [ + { + severity: "info", + name: "utl-module-not-shared-enough", + }, + ], + matchesHighlight: false, + }, + { + source: "node_modules/ignore/index.js", + followable: false, + coreModule: false, + couldNotResolve: false, + matchesDoNotFollow: true, + dependencyTypes: ["npm"], + dependencies: [], + dependents: ["src/utl/find-all-files.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/utl/path-to-posix.mjs", + dependencies: [ + { + dynamic: false, + module: "path", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "path", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + ], + dependents: ["src/utl/find-all-files.mjs"], + orphan: false, + valid: false, + rules: [ + { + severity: "info", + name: "utl-module-not-shared-enough", + }, + ], + matchesHighlight: false, + }, + { + source: "src/cache/metadata-strategy.mjs", + dependencies: [ + { + dynamic: false, + module: "./helpers.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/cache/helpers.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "#utl/bus.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/utl/bus.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "util", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "util", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "watskeburt", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "node_modules/watskeburt/dist/main.js", + coreModule: false, + followable: false, + couldNotResolve: false, + license: "MIT", + dependencyTypes: ["npm"], + matchesDoNotFollow: true, + circular: false, + valid: true, + }, + ], + dependents: ["src/cache/cache.mjs"], + orphan: false, + valid: true, + matchesHighlight: true, + }, + { + source: "node_modules/watskeburt/dist/main.js", + followable: false, + coreModule: false, + couldNotResolve: false, + matchesDoNotFollow: true, + dependencyTypes: ["npm"], + dependencies: [], + dependents: ["src/cache/metadata-strategy.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/cache/options-compatible.mjs", + dependencies: [ + { + dynamic: false, + module: "util", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "util", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + ], + dependents: ["src/cache/cache.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/extract/transpile/meta.mjs", + dependencies: [ + { + dynamic: false, + module: "./try-import-available.mjs", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/extract/transpile/try-import-available.mjs", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "#meta.js", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "src/meta.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + ], + dependents: ["src/cache/cache.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/extract/transpile/try-import-available.mjs", + dependencies: [ + { + dynamic: false, + module: "module", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "module", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "path/posix", + moduleSystem: "es6", + exoticallyRequired: false, + protocol: "node:", + resolved: "path/posix", + coreModule: true, + followable: false, + couldNotResolve: false, + dependencyTypes: ["core"], + matchesDoNotFollow: false, + circular: false, + valid: true, + }, + { + dynamic: false, + module: "semver", + moduleSystem: "es6", + exoticallyRequired: false, + resolved: "node_modules/semver/index.js", + coreModule: false, + followable: false, + couldNotResolve: false, + license: "ISC", + dependencyTypes: ["npm"], + matchesDoNotFollow: true, + circular: false, + valid: true, + }, + ], + dependents: ["src/extract/transpile/meta.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "module", + followable: false, + coreModule: true, + couldNotResolve: false, + matchesDoNotFollow: false, + dependencyTypes: ["core"], + dependencies: [], + dependents: ["src/extract/transpile/try-import-available.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "node_modules/semver/index.js", + followable: false, + coreModule: false, + couldNotResolve: false, + matchesDoNotFollow: true, + dependencyTypes: ["npm"], + dependencies: [], + dependents: ["src/extract/transpile/try-import-available.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + { + source: "src/meta.js", + dependencies: [], + dependents: ["src/extract/transpile/meta.mjs"], + orphan: false, + valid: true, + matchesHighlight: false, + }, + ], + summary: { + violations: [ + { + type: "module", + from: "src/utl/find-all-files.mjs", + to: "src/utl/find-all-files.mjs", + rule: { + severity: "info", + name: "utl-module-not-shared-enough", + }, + }, + { + type: "module", + from: "src/utl/path-to-posix.mjs", + to: "src/utl/path-to-posix.mjs", + rule: { + severity: "info", + name: "utl-module-not-shared-enough", + }, + }, + ], + error: 0, + warn: 0, + info: 2, + ignore: 0, + totalCruised: 25, + totalDependenciesCruised: 37, + optionsUsed: { + baseDir: "/Users/sander/prg/js/dependency-cruiser", + cache: { + folder: "node_modules/.cache/dependency-cruiser", + strategy: "metadata", + }, + combinedDependencies: false, + doNotFollow: { + path: "node_modules", + dependencyTypes: [ + "npm", + "npm-dev", + "npm-optional", + "npm-peer", + "npm-bundled", + "npm-no-pkg", + ], + }, + enhancedResolveOptions: { + exportsFields: ["exports"], + conditionNames: ["import", "require"], + extensions: [".js", ".mjs", ".d.ts"], + }, + exclude: { + path: "mocks|fixtures|test/integration|src/cli/tools/svg-in-html-snippets/script.snippet.js", + }, + exoticRequireStrings: [ + "tryRequire", + "tryImport", + "requireJSON", + "proxyquire.load", + ], + externalModuleResolutionStrategy: "node_modules", + metrics: false, + moduleSystems: ["cjs", "es6"], + outputTo: "-", + outputType: "json", + prefix: "https://github.com/sverweij/dependency-cruiser/blob/main/", + preserveSymlinks: false, + reporterOptions: { + archi: { + collapsePattern: + "^(src|test)/[^/]+|^bin/|node_modules/(@[^/]+/[^/]+|[^/]+)", + }, + dot: { + collapsePattern: "^src/report/[^/]+|^src/enrich/derive/[^/]+", + filters: { + includeOnly: { + path: "^(src|bin)", + }, + exclude: { + path: "^src/meta\\.js$|^src/utl/bus.+", + }, + }, + theme: { + replace: false, + graph: { + splines: "ortho", + }, + modules: [ + { + criteria: { + matchesFocus: true, + }, + attributes: { + fillcolor: "lime", + penwidth: 2, + }, + }, + { + criteria: { + matchesReaches: true, + }, + attributes: { + fillcolor: "lime", + penwidth: 2, + }, + }, + { + criteria: { + matchesHighlight: true, + }, + attributes: { + fillcolor: "yellow", + penwidth: 2, + }, + }, + { + criteria: { + source: "^src/cli", + }, + attributes: { + fillcolor: "#ccccff", + }, + }, + { + criteria: { + source: "^src/config-utl", + }, + attributes: { + fillcolor: "#99ffff", + }, + }, + { + criteria: { + source: "^src/report", + }, + attributes: { + fillcolor: "#ffccff", + }, + }, + { + criteria: { + source: "^src/extract", + }, + attributes: { + fillcolor: "#ccffcc", + }, + }, + { + criteria: { + source: "^src/enrich", + }, + attributes: { + fillcolor: "#77eeaa", + }, + }, + { + criteria: { + source: "^src/validate", + }, + attributes: { + fillcolor: "#ccccff", + }, + }, + { + criteria: { + source: "^src/main", + }, + attributes: { + fillcolor: "#ffcccc", + }, + }, + { + criteria: { + source: "^src/utl", + }, + attributes: { + fillcolor: "#cccccc", + }, + }, + { + criteria: { + source: "^src/graph-utl", + }, + attributes: { + fillcolor: "#ffcccc", + }, + }, + { + criteria: { + source: "^src/meta\\.js$|\\.schema\\.mjs$", + }, + attributes: { + style: "filled", + }, + }, + { + criteria: { + source: "\\.json$", + }, + attributes: { + shape: "cylinder", + }, + }, + ], + dependencies: [ + { + criteria: { + "rules[0].severity": "error", + }, + attributes: { + fontcolor: "red", + color: "red", + }, + }, + { + criteria: { + "rules[0].severity": "warn", + }, + attributes: { + fontcolor: "orange", + color: "orange", + }, + }, + { + criteria: { + "rules[0].severity": "info", + }, + attributes: { + fontcolor: "blue", + color: "blue", + }, + }, + { + criteria: { + valid: false, + }, + attributes: { + fontcolor: "red", + color: "red", + }, + }, + { + criteria: { + resolved: "^src/cli", + }, + attributes: { + color: "#0000ff77", + }, + }, + { + criteria: { + resolved: "^src/config-utl", + }, + attributes: { + color: "#22999977", + }, + }, + { + criteria: { + resolved: "^src/report", + }, + attributes: { + color: "#ff00ff77", + }, + }, + { + criteria: { + resolved: "^src/extract", + }, + attributes: { + color: "#00770077", + }, + }, + { + criteria: { + resolved: "^src/enrich", + }, + attributes: { + color: "#00776677", + }, + }, + { + criteria: { + resolved: "^src/validate", + }, + attributes: { + color: "#0000ff77", + }, + }, + { + criteria: { + resolved: "^src/main", + }, + attributes: { + color: "#77000077", + }, + }, + { + criteria: { + resolved: "^src/utl", + }, + attributes: { + color: "#aaaaaa77", + }, + }, + { + criteria: { + resolved: "^src/graph-utl", + }, + attributes: { + color: "#77000077", + }, + }, + ], + }, + }, + metrics: { + orderBy: "name", + hideModules: true, + hideFolders: false, + }, + text: { + highlightFocused: true, + }, + anon: { + wordlist: [ + "aap", + "noot", + "mies", + "wim", + "zus", + "jet", + "teun", + "vuur", + "gijs", + "lam", + "kees", + "bok", + "weide", + "does", + "hok", + "duif", + "schapen", + "raam", + "roos", + "neef", + "fik", + "gat", + "wiel", + "zes", + "juk", + "schop", + "voet", + "neus", + "muur", + "bijl", + "ei", + "ui", + ], + }, + }, + rulesFile: ".dependency-cruiser.json", + tsPreCompilationDeps: true, + args: "src/cache", + }, + ruleSetUsed: { + forbidden: [ + { + name: "not-to-unresolvable", + comment: + "This module tried to depend on something that can't be resolved to disk. Revise yer code", + severity: "error", + from: {}, + to: { + couldNotResolve: true, + exoticallyRequired: false, + }, + }, + { + name: "no-orphans", + comment: + "This is an orphan module - it's likely not used (anymore?). Either use it or remove it. If it's logical this module is an orphan (i.e. it's a config file), add an exception for it in your dependency-cruiser configuration. By default this rule does not scrutinize dotfiles (e.g. .eslintrc.js), TypeScript declaration files (.d.ts/ .d.cts/ .d.mts), tsconfig.json and some of the babel and webpack configs.", + severity: "error", + from: { + orphan: true, + pathNot: [ + "(^|/)\\.[^/]+\\.(js|cjs|mjs|ts|json)$", + "\\.d\\.ts$", + "(^|/)tsconfig\\.json$", + "(^|/)(babel|webpack)\\.config\\.(js|cjs|mjs|ts|json)$", + "-reporter-plugin\\.mjs$", + "\\.schema\\.json$", + "^tools/istanbul-json-summary-to-markdown\\.mjs$", + "^src/report/json\\.mjs", + "^src/report/identity\\.mjs", + "^src/report/null\\.mjs", + ], + }, + to: {}, + }, + { + name: "cli-to-main-only", + comment: + "This cli module depends on something not in the public interface - which means it either doesn't belong in cli, or the main public interface needs to be expanded.", + severity: "error", + from: { + path: "(^src/cli/)", + }, + to: { + pathNot: [ + "^src/(main|utl|config-utl)/", + "node_modules/", + "^os$", + "^fs(/promises)?$", + "^path$", + "^url$", + "$1", + "^src/meta\\.js$", + "^src/extract/transpile/meta\\.mjs$", + ], + }, + }, + { + name: "report-stays-in-report", + comment: + "This reporting module depends directly on a non-reporting one that is not a utility. That is odd as reporting modules should only read dependency cruiser output json.", + severity: "error", + from: { + path: "(^src/report/)", + }, + to: { + pathNot: [ + "$1", + "node_modules/", + "^os$", + "^path$", + "^path/posix$", + "^src/meta\\.js$", + "^src/graph-utl", + "^src/utl", + ], + }, + }, + { + name: "extract-to-utl-only", + comment: + "This extraction module depends on something outside extraction that is not a utility. Which is odd, given the goal of the extraction step.", + severity: "error", + from: { + path: "(^src/extract/)", + }, + to: { + pathNot: [ + "$1", + "node_modules/", + "^(path|path/posix|fs|module|os)$", + "^src/meta\\.js$", + "^types/", + "^src/graph-utl", + "^src/utl", + ], + exoticallyRequired: false, + }, + }, + { + name: "not-to-json", + comment: + "We don't want to depend on .json modules as long as they're still impractical to work with in ecmascript modules", + from: { + path: "^src/", + }, + to: { + path: "\\.json$", + }, + }, + { + name: "bin-to-cli-only", + comment: + "This module in the bin/ folder depends on something not in the cli interface. This means it either contains code that doesn't belong in bin/, or the thing it depends upon should be put in the cli interface. ", + severity: "error", + from: { + path: "(^bin/)", + }, + to: { + pathNot: ["^src/cli", "node_modules/", "^src/meta\\.js$", "^os$"], + }, + }, + { + name: "restrict-fs-access", + comment: + "This module depends on a the node 'fs' module, and it resides in a spot where that is not allowed.", + severity: "error", + from: { + pathNot: [ + "^src/(main/resolve-options/normalize\\.mjs|extract/parse|extract/resolve|extract/gather-initial-sources\\.mjs|config-utl|cli|cache|utl/find-all-files\\.mjs)", + "^test", + "^tools", + ], + }, + to: { + path: "^fs$", + }, + }, + { + name: "no-inter-module-test", + comment: + "This test depends on something in the test tree that is neither a utility, nor a mock nor a fixture.", + severity: "error", + from: { + path: "(^test/[^\\/]+/)[^\\.]+\\.spec\\.js", + }, + to: { + path: "^test/[^\\/]+/.+", + pathNot: ["utl", "$1.+\\.json$"], + }, + }, + { + name: "prefer-lodash-individuals", + comment: + "This module directly depends on 'lodash' as a whole. Preferably don't include lodash as a whole, but use individual lodash packages instead e.g. 'lodash/get' - this keeps the download of the package small(er)", + severity: "info", + from: {}, + to: { + path: "lodash\\.js$", + }, + }, + { + name: "no-dep-on-test", + comment: + "This module depends on a spec files. A spec file should have a single responsibility (testing whether a module function correctly). If there's something in a spec that's of use, factor it out into (e.g.) a separate utility/ helper or mock", + severity: "error", + from: { + path: "^(src|bin)", + }, + to: { + path: "^test|\\.spec\\.js$", + }, + }, + { + name: "no-external-to-here", + comment: + "Apparently something outside of the src/ test/ and bin/ points to something inside them. That's incredibly odd and might denote a security problem.", + severity: "error", + from: { + pathNot: "^(src|test|bin)", + }, + to: { + path: "^(src|test)", + }, + }, + { + name: "not-to-dev-dep", + severity: "error", + comment: + "In production code do not depend on external ('npm') modules not declared in your package.json's dependencies - otherwise a production only install (i.e. 'npm ci') will break. If this rule triggers on something that's only used during development, adapt the 'from' of the rule in the dependency-cruiser configuration.", + from: { + path: "^(bin|src)", + }, + to: { + dependencyTypes: ["npm-dev"], + exoticallyRequired: false, + }, + }, + { + name: "only-known-exotic", + severity: "error", + comment: + "The only 'exotic' requires allowed are tryRequire and requireJSON", + from: {}, + to: { + exoticRequireNot: + "^(tryRequire|tryImport|requireJSON|proxyquire\\.load)$", + exoticallyRequired: true, + }, + }, + { + name: "optional-deps-used", + severity: "error", + comment: + "This module uses an external dependency that in package.json shows up as an optional dependency. In dependency-cruiser optional dependencies donot make sense - and are hence forbidden. Either make it a regular dependency (if it's production code) or a dev one (if it's for development only)", + from: {}, + to: { + dependencyTypes: ["npm-optional"], + }, + }, + { + name: "peer-deps-used", + comment: + "This module uses an external dependency that in package.json shows up as a peer dependency. In dependency-cruiser peer dependencies donot make sense - and are hence forbidden. Either make it a regular dependency (if it's production code) or a dev one (if it's for development only)", + severity: "error", + from: {}, + to: { + dependencyTypes: ["npm-peer"], + }, + }, + { + name: "no-unvetted-license", + comment: + "This module uses an external dependency that has license that's not vetted. The license itself might be OK, but bigcorp legal departments might get jittery over anything other than MIT (or ISC).", + severity: "error", + from: {}, + to: { + licenseNot: "MIT|ISC|Apache-2\\.0", + }, + }, + { + name: "not-unreachable-from-cli", + severity: "error", + comment: + "This module in the src/ tree is not reachable from the cli - and is likely dead wood. Either use it or remove it. If a module is flagged for which it's logical it is not reachable from cli (i.e. a configuration file), add it to the pathNot in the 'to' of this rule.", + from: { + path: "^bin/", + }, + to: { + path: "^src", + pathNot: ["\\.schema\\.json$", "\\.d\\.ts$", "^src/report/"], + reachable: false, + }, + }, + { + name: "not-unreachable-from-test", + comment: + "This module in src is not reachable by any test. Please provide a test that covers this (poor man's test coverage - this task is better suited for a proper test coverage tool :-) )", + severity: "warn", + from: { + path: "\\.spec\\.m?js$", + }, + to: { + path: "^src", + pathNot: ["\\.schema\\.json$", "\\.d\\.ts$", "^src/report/"], + reachable: false, + }, + }, + { + name: "not-reachable-from-folder-index", + comment: + "(sample rule to demo reachable rules with capturing groups)", + severity: "info", + from: { + path: "^src/([^/]+)/index\\.js$", + }, + to: { + path: ["^src/$1/"], + pathNot: "\\.d\\.ts$", + reachable: false, + }, + }, + { + name: "utl-module-not-shared-enough", + comment: "(sample rule to demo rules based on dependents)", + severity: "info", + from: { + path: "^src", + }, + module: { + path: "^src/utl", + numberOfDependentsLessThan: 3, + }, + }, + { + name: "no-circular", + comment: + "This dependency is part of a circular relationship. You might want to revise your solution (i.e. use dependency inversion, make sure the modules have a single responsibility) ", + severity: "error", + from: {}, + to: { + circular: true, + }, + }, + { + name: "no-deprecated-core", + comment: + "This module depends on a node core module that has been deprecated. Find an alternative - these are bound to exist - node doesn't deprecate lightly.", + severity: "error", + from: {}, + to: { + dependencyTypes: ["core"], + path: "^(punycode|domain|constants|sys|_linklist|_stream_wrap)$", + }, + }, + { + name: "no-duplicate-dep-types", + comment: + 'Likely this module depends on an external (\'npm\') package that occurs more than once in your package.json i.e. bot as a devDependencies and in dependencies. This will cause maintenance problems later on. If it\'s intentional, you can disable this rule by adding this override as a rule in the \'forbidden\' section of your dependency-cruiser configuration: {"name": "no-duplicate-dep-types", "severity": "ignore"}', + severity: "error", + from: {}, + to: { + moreThanOneDependencyType: true, + dependencyTypesNot: ["type-only"], + }, + }, + { + name: "no-non-package-json", + severity: "error", + comment: + "This module depends on an npm package that isn't in the 'dependencies' section of your package.json. That's problematic as the package either (1) won't be available on live (2 - worse) will be available on live with an non-guaranteed version. Fix it by adding the package to the dependencies in your package.json.", + from: {}, + to: { + dependencyTypes: ["npm-no-pkg", "npm-unknown"], + }, + }, + { + name: "not-to-deprecated", + comment: + "This module uses a (version of an) npm module that has been deprecated. Either upgrade to a later version of that module, or find an alternative. Deprecated modules are a security risk.", + severity: "error", + from: {}, + to: { + dependencyTypes: ["deprecated"], + }, + }, + ], + }, + }, + revisionData: { + SHA1: "e95e9f481df42643f2b2a119d1773caa8a49e82e", + changes: [ + { + changeType: "modified", + name: "src/report/d2.mjs", + checksum: "aeaxFY//FK1eGFfWGhzAwMndvfw=", + }, + { + changeType: "modified", + name: "test/report/d2/d2.spec.mjs", + checksum: "/Y0t37YrfoM4O9Hn/nwA/S+bM3A=", + }, + ], + }, +}; diff --git a/test/report/d2/d2.spec.mjs b/test/report/d2/d2.spec.mjs new file mode 100644 index 000000000..f2362f970 --- /dev/null +++ b/test/report/d2/d2.spec.mjs @@ -0,0 +1,20 @@ +import { equal } from "node:assert/strict"; +import { readFileSync, readdirSync } from "node:fs"; +import d2 from "#report/d2.mjs"; + +describe("[I] d2", () => { + const lMocks = readdirSync("./test/report/d2/__mocks__"); + + lMocks.forEach((pMock, pIndex, pArray) => { + it(`renders a d2 - ${pMock}`, async () => { + const lCruiseResult = await import(`./__mocks__/${pMock}`); + const lExpected = readFileSync( + `./test/report/d2/__fixtures__/${pMock.split(".").shift()}.d2`, + { encoding: "utf8" }, + ).replace(/\r\n/g, "\n"); + const lActual = d2(lCruiseResult.default).output.replace(/\r\n/g, "\n"); + + equal(lActual, lExpected); + }); + }); +}); diff --git a/tools/generate-d2-fixtures.utl.mjs b/tools/generate-d2-fixtures.utl.mjs new file mode 100644 index 000000000..27ff16fcd --- /dev/null +++ b/tools/generate-d2-fixtures.utl.mjs @@ -0,0 +1,13 @@ +import { mkdirSync, readdirSync, rmSync, writeFileSync } from "node:fs"; +import d2 from "#report/d2.mjs"; + +rmSync("./test/report/d2/__fixtures__", { recursive: true }); +mkdirSync("./test/report/d2/__fixtures__"); +readdirSync("./test/report/d2/__mocks__").forEach(async (pMock) => { + const lCruiseResult = await import(`../test/report/d2/__mocks__/${pMock}`); + const lD2Output = d2(lCruiseResult.default).output; + writeFileSync( + `./test/report/d2/__fixtures__/${pMock.split(".").shift()}.d2`, + lD2Output, + ); +}); diff --git a/tools/generate-samples.sh b/tools/generate-samples.sh index 51e1d4acf..fcc636c06 100644 --- a/tools/generate-samples.sh +++ b/tools/generate-samples.sh @@ -2,13 +2,15 @@ set -e ASSET_DIR=doc/assets -node bin/dependency-cruise.mjs -Tdot -c "$ASSET_DIR/theming/bare.config.js" src/main | dot -Tsvg > "$ASSET_DIR/theming/bare.svg" -node bin/dependency-cruise.mjs -Tdot -c "$ASSET_DIR/theming/base.config.js" src/main | dot -Tsvg > "$ASSET_DIR/theming/base.svg" -node bin/dependency-cruise.mjs -Tdot -c "$ASSET_DIR/theming/engineering.config.js" src/main | dot -Tsvg > "$ASSET_DIR/theming/engineering.svg" -node bin/dependency-cruise.mjs -Tdot -c "$ASSET_DIR/theming/vertical.config.js" src/main | dot -Tsvg > "$ASSET_DIR/theming/vertical.svg" +node bin/dependency-cruise.mjs -Tdot --no-progress --config "$ASSET_DIR/theming/bare.config.js" src/main | dot -Tsvg | npx svgo -i - -o - > "$ASSET_DIR/theming/bare.svg" +node bin/dependency-cruise.mjs -Tdot --no-progress --config "$ASSET_DIR/theming/base.config.js" src/main | dot -Tsvg | npx svgo -i - -o - > "$ASSET_DIR/theming/base.svg" +node bin/dependency-cruise.mjs -Tdot --no-progress --config "$ASSET_DIR/theming/engineering.config.js" src/main | dot -Tsvg | npx svgo -i - -o - > "$ASSET_DIR/theming/engineering.svg" +node bin/dependency-cruise.mjs -Tdot --no-progress --config "$ASSET_DIR/theming/vertical.config.js" src/main | dot -Tsvg | npx svgo -i - -o - > "$ASSET_DIR/theming/vertical.svg" -node bin/dependency-cruise.mjs -Tdot -c "$ASSET_DIR/filtering/focus.config.json" src | dot -Tsvg > "$ASSET_DIR/filtering/focus.svg" -node bin/dependency-cruise.mjs -Tdot -c "$ASSET_DIR/filtering/snazzy-focus.config.json" src | dot -Tsvg > "$ASSET_DIR/filtering/snazzy-focus.svg" +node bin/dependency-cruise.mjs -Tdot --no-progress --config "$ASSET_DIR/filtering/focus.config.json" src | dot -Tsvg > "$ASSET_DIR/filtering/focus.svg" +node bin/dependency-cruise.mjs -Tdot --no-progress --config "$ASSET_DIR/filtering/snazzy-focus.config.json" src | dot -Tsvg | npx svgo -i - -o - > "$ASSET_DIR/filtering/snazzy-focus.svg" -node bin/dependency-cruise.mjs -Tflat -c --progress none --include-only ^src src/report | fdp -Gsplines=ortho -Gdim=10 -Tsvg > "$ASSET_DIR/flat-report-example.svg" -node bin/dependency-cruise.mjs -Tdot -c --progress none --include-only ^src src/report | dot -Gsplines=ortho -Tsvg > "$ASSET_DIR/flat-report-counter-example.svg" +node bin/dependency-cruise.mjs -Tflat --no-progress --include-only ^src src/report | fdp -Gsplines=ortho -Gdim=10 -Tsvg | npx svgo -i - -o - > "$ASSET_DIR/flat-report-example.svg" +node bin/dependency-cruise.mjs -Tdot --no-progress --include-only ^src src/report | dot -Gsplines=ortho -Tsvg | npx svgo -i - -o - > "$ASSET_DIR/flat-report-counter-example.svg" + +node bin/dependency-cruise.mjs -Td2 --no-progress --include-only ^src/cache/ --highlight metadata-strategy src/cache | d2 --layout elk --scale 1 - | npx svgo -i - -o - > "$ASSET_DIR/d2.svg" \ No newline at end of file diff --git a/tools/schema/output-type.mjs b/tools/schema/output-type.mjs index 0e3b2c42a..4d62d79fa 100644 --- a/tools/schema/output-type.mjs +++ b/tools/schema/output-type.mjs @@ -23,6 +23,7 @@ export default { "metrics", "markdown", "mermaid", + "d2", "null", ], }, diff --git a/types/shared-types.d.ts b/types/shared-types.d.ts index 69aec9845..58936b336 100644 --- a/types/shared-types.d.ts +++ b/types/shared-types.d.ts @@ -25,9 +25,10 @@ export type OutputType = | "metrics" | "markdown" | "mermaid" + | "d2" | "null" // for plugins: string. TODO: research whether it's possible to - // tie this down to the `^plugin:[^:]+-reporter-plugin.c?js$` regex + // tie this down to the `^plugin:[^:]+-reporter-plugin.[cm]?js$` regex | string; export type SeverityType = "error" | "warn" | "info" | "ignore";