From c6421e3c3b1b1b2f82f066295aabe6443b1e42c8 Mon Sep 17 00:00:00 2001 From: Sander Verweij Date: Sun, 17 Dec 2023 20:42:18 +0100 Subject: [PATCH] feat!: makes entries in 'cycle' contain more information (BREAKING for API users) (#888) ## Description - makes getCycle to emit richer content - both a _name_ and _dependencyTypes_ for now, instead of a string. This is a breaking change on the API _only_ - rules keep the same interface and behavior. ## Motivation and Context So we can define rules on the additional attributes - prerequisite to fixing #695 ## How Has This Been Tested? - [x] green ci - [x] additional automated non-regression tests ## Types of changes - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] Documentation only change - [ ] Refactor (non-breaking change which fixes an issue without changing functionality) - [x] New feature (non-breaking change which adds functionality) - [x] Breaking change (fix or feature that would cause existing functionality to change) - on the API only. --- .c8rc.json | 2 +- Makefile | 1 + src/cache/cache.mjs | 16 +- src/enrich/summarize/is-same-violation.mjs | 12 +- src/graph-utl/indexed-module-graph.mjs | 76 ++++-- src/report/anon/anonymize-path.mjs | 2 +- src/report/anon/index.mjs | 19 +- src/report/anon/random-string.mjs | 2 +- src/report/azure-devops.mjs | 4 +- src/report/error-html/utl.mjs | 2 +- src/report/error.mjs | 11 +- src/report/teamcity.mjs | 20 +- src/schema/baseline-violations.schema.json | 56 +++- src/schema/baseline-violations.schema.mjs | 2 +- src/schema/configuration.schema.json | 16 +- src/schema/configuration.schema.mjs | 2 +- src/schema/cruise-result.schema.json | 20 +- src/schema/cruise-result.schema.mjs | 2 +- src/validate/matchers.mjs | 36 ++- .../result-has-a-dependency-violation.json | 10 +- test/enrich/__mocks__/cycle-fest.mjs | 26 +- test/enrich/de-duplicate-violations.spec.mjs | 110 +++++++- test/enrich/summarize.spec.mjs | 38 ++- .../__mocks__/cycle-input-graphs.mjs | 30 ++- test/graph-utl/indexed-module-graph.spec.mjs | 46 +++- .../cruise-reporterless/commonjs.json | 65 ++++- .../cruise-reporterless/folder.json | 20 +- .../cruise-reporterless/typescript.json | 20 +- .../__mocks__/dynamic-imports/es/output.json | 60 ++++- .../output-pre-compilation-deps.json | 60 ++++- .../dynamic-imports/typescript/output.json | 60 ++++- .../main/main.cruise.dynamic-imports.spec.mjs | 5 +- test/report/anon/__fixtures__/cycle.mjs | 44 +++- .../anon/__fixtures__/folder-cycles.mjs | 90 ++++++- test/report/anon/__mocks__/cycle.mjs | 248 +++++++++--------- test/report/anon/__mocks__/folder-cycles.mjs | 36 ++- .../azure-devops/__mocks__/circular-deps.mjs | 36 +-- .../__mocks__/orphans-cycles-metrics.mjs | 32 ++- test/report/error-html/utl.spec.mjs | 7 +- test/report/error/__mocks__/circular-deps.mjs | 36 +-- .../__mocks__/orphans-cycles-metrics.mjs | 32 ++- .../teamcity/__mocks__/circular-deps.mjs | 36 +-- test/validate/index.cycle-via-not.spec.mjs | 21 +- .../index.cycle-via-some-not.spec.mjs | 15 +- test/validate/index.cycle-via.spec.mjs | 67 +++-- tools/schema/dependencies.mjs | 4 +- tools/schema/folders.mjs | 4 +- tools/schema/mini-dependency-type.mjs | 29 ++ tools/schema/violations.mjs | 4 +- types/cruise-result.d.mts | 5 +- types/shared-types.d.mts | 12 + types/violations.d.mts | 4 +- 52 files changed, 1220 insertions(+), 393 deletions(-) create mode 100644 tools/schema/mini-dependency-type.mjs diff --git a/.c8rc.json b/.c8rc.json index bb36883dc..56d01de06 100644 --- a/.c8rc.json +++ b/.c8rc.json @@ -1,7 +1,7 @@ { "checkCoverage": true, "statements": 99.89, - "branches": 98.75, + "branches": 98.77, "functions": 100, "lines": 99.89, "exclude": [ diff --git a/Makefile b/Makefile index 4bc17a68f..5b512289a 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ SCHEMA_SOURCES=tools/schema/baseline-violations.schema.mjs \ tools/schema/compound-reaches-type.mjs \ tools/schema/configuration.schema.mjs \ tools/schema/cruise-result.schema.mjs \ + tools/schema/mini-dependency-type.mjs \ tools/schema/dependencies.mjs \ tools/schema/dependency-type.mjs \ tools/schema/folders.mjs \ diff --git a/src/cache/cache.mjs b/src/cache/cache.mjs index eb9c56302..496386974 100644 --- a/src/cache/cache.mjs +++ b/src/cache/cache.mjs @@ -30,7 +30,7 @@ const EMPTY_CACHE = { export default class Cache { /** - * @param {import("../../types/cache-options.js").cacheStrategyType=} pCacheStrategy + * @param {import("../../types/cache-options.mjs").cacheStrategyType=} pCacheStrategy * @param {boolean=} pCompress */ constructor(pCacheStrategy, pCompress) { @@ -43,9 +43,9 @@ export default class Cache { } /** - * @param {import("../../types/strict-options.js").IStrictCruiseOptions} pCruiseOptions - * @param {import("../../types/dependency-cruiser.js").ICruiseResult} pCachedCruiseResult - * @param {import("../../types/dependency-cruiser.js").IRevisionData=} pRevisionData + * @param {import("../../types/strict-options.mjs").IStrictCruiseOptions} pCruiseOptions + * @param {import("../../types/dependency-cruiser.mjs").ICruiseResult} pCachedCruiseResult + * @param {import("../../types/dependency-cruiser.mjs").IRevisionData=} pRevisionData * @returns {Promise} */ async canServeFromCache(pCruiseOptions, pCachedCruiseResult, pRevisionData) { @@ -68,8 +68,6 @@ export default class Cache { this.revisionData, ) && optionsAreCompatible( - // @ts-expect-error ts(2345) - it's indeed not strict cruise options, - // but it will do for now (_it works_) pCachedCruiseResult.summary.optionsUsed, pCruiseOptions, ) @@ -78,7 +76,7 @@ export default class Cache { /** * @param {string} pCacheFolder - * @returns {Promise} + * @returns {Promise} */ async read(pCacheFolder) { try { @@ -133,8 +131,8 @@ export default class Cache { /** * @param {string} pCacheFolder - * @param {import("../../types/dependency-cruiser.js").ICruiseResult} pCruiseResult - * @param {import("../../types/dependency-cruiser.js").IRevisionData=} pRevisionData + * @param {import("../../types/dependency-cruiser.mjs").ICruiseResult} pCruiseResult + * @param {import("../../types/dependency-cruiser.mjs").IRevisionData=} pRevisionData */ async write(pCacheFolder, pCruiseResult, pRevisionData) { const lRevisionData = pRevisionData ?? this.revisionData; diff --git a/src/enrich/summarize/is-same-violation.mjs b/src/enrich/summarize/is-same-violation.mjs index 05927afe9..7bc32dd03 100644 --- a/src/enrich/summarize/is-same-violation.mjs +++ b/src/enrich/summarize/is-same-violation.mjs @@ -1,3 +1,7 @@ +function pluckName({ name }) { + return name; +} + export default function isSameViolation(pLeftViolation, pRightViolation) { let lReturnValue = false; @@ -5,9 +9,11 @@ export default function isSameViolation(pLeftViolation, pRightViolation) { if (pRightViolation.cycle && pLeftViolation.cycle) { lReturnValue = pLeftViolation.cycle.length === pRightViolation.cycle.length && - pLeftViolation.cycle.every((pModule) => - pRightViolation.cycle.includes(pModule) - ); + pLeftViolation.cycle + .map(pluckName) + .every((pModule) => + pRightViolation.cycle.map(pluckName).includes(pModule), + ); } else { lReturnValue = pLeftViolation.from === pRightViolation.from && diff --git a/src/graph-utl/indexed-module-graph.mjs b/src/graph-utl/indexed-module-graph.mjs index 3e515c252..ff19c3597 100644 --- a/src/graph-utl/indexed-module-graph.mjs +++ b/src/graph-utl/indexed-module-graph.mjs @@ -6,12 +6,13 @@ * @typedef {import("../../types/cruise-result.d.mts").IFolder} IFolder * @typedef {import("../../types/cruise-result.d.mts").IModule} IModule * @typedef {import("../../types/shared-types.d.mts").DependencyType} DependencyType + * @typedef {import("../../types/shared-types.d.mjs").IMiniDependency} IMiniDependency * * @typedef {(IDependency|IFolderDependency) & {name:string; dependencyTypes?: DependencyType[]}} IEdge * @typedef {IModule|IFolder} IModuleOrFolder * @typedef {IModuleOrFolder & {dependencies: IEdge[]}} IVertex - * @typedef {{name:string; dependencyTypes: string[];}} IGeldedDependency */ + export default class IndexedModuleGraph { /** * @param {IModuleOrFolder} pModule @@ -55,7 +56,6 @@ export default class IndexedModuleGraph { } /** - * * @param {string} pName - the name of the module to find transitive dependents of. * @param {number} pMaxDepth - the maximum depth to search for dependents. * Defaults to 0 (no maximum). To only get direct dependents. @@ -98,7 +98,6 @@ export default class IndexedModuleGraph { } /** - * * @param {string} pName - the name of the module to find transitive dependencies of. * @param {number} pMaxDepth - the maximum depth to search for dependencies * Defaults to 0 (no maximum). To only get direct dependencies. @@ -172,47 +171,70 @@ export default class IndexedModuleGraph { return lReturnValue; } + /** + * + * @param {IEdge} pEdge + * @returns {IMiniDependency} + */ + #geldEdge(pEdge) { + let lReturnValue = {}; + lReturnValue.name = pEdge.name; + lReturnValue.dependencyTypes = pEdge.dependencyTypes + ? pEdge.dependencyTypes + : []; + return lReturnValue; + } + /** * Returns the first non-zero length path from pInitialSource to pInitialSource * Returns the empty array if there is no such path * * @param {string} pInitialSource The 'source' attribute of the node to be tested * (source uniquely identifying a node) - * @param {string} pCurrentSource The 'source' attribute of the 'to' node to - * be traversed + * @param {IEdge} pCurrentDependency + * The 'to' node to be traversed as a dependency + * object of the previous 'from' traversed * @param {Set=} pVisited Technical parameter - best to leave out of direct calls - * @return {string[]} see description above + * @return {Array} see description above */ - #getCycle(pInitialSource, pCurrentSource, pVisited) { + #getCycleNew(pInitialSource, pCurrentDependency, pVisited) { let lVisited = pVisited || new Set(); - const lCurrentVertex = this.findVertexByName(pCurrentSource); - const lDependencies = lCurrentVertex.dependencies.filter( + const lCurrentVertex = this.findVertexByName(pCurrentDependency.name); + const lEdges = lCurrentVertex.dependencies.filter( (pDependency) => !lVisited.has(pDependency.name), ); - const lInitialAsDependency = lDependencies.find( + const lInitialAsDependency = lEdges.find( (pDependency) => pDependency.name === pInitialSource, ); if (lInitialAsDependency) { - return pInitialSource === pCurrentSource - ? [lInitialAsDependency.name] - : [pCurrentSource, lInitialAsDependency.name]; + return pInitialSource === pCurrentDependency.name + ? [this.#geldEdge(lInitialAsDependency)] + : [ + this.#geldEdge(pCurrentDependency), + this.#geldEdge(lInitialAsDependency), + ]; } - return lDependencies.reduce( + return lEdges.reduce( /** - * @param {Array} pAll + * @param {Array} pAll * @param {IEdge} pDependency - * @returns {Array} + * @returns {Array} */ (pAll, pDependency) => { - if (!pAll.includes(pCurrentSource)) { - const lCycle = this.#getCycle( + if (!pAll.some((pSome) => pSome.name === pCurrentDependency.name)) { + const lCycle = this.#getCycleNew( pInitialSource, - pDependency.name, + pDependency, lVisited.add(pDependency.name), ); - if (lCycle.length > 0 && !lCycle.includes(pCurrentSource)) { - return pAll.concat(pCurrentSource).concat(lCycle); + if ( + lCycle.length > 0 && + !lCycle.some((pSome) => pSome.name === pCurrentDependency.name) + ) { + return pAll + .concat(this.#geldEdge(pCurrentDependency)) + .concat(lCycle); } } return pAll; @@ -229,9 +251,17 @@ export default class IndexedModuleGraph { * (source uniquely identifying a node) * @param {string} pCurrentSource The 'source' attribute of the 'to' node to * be traversed - * @return {string[]} see description above + * @return {Array} see description above */ getCycle(pInitialSource, pCurrentSource) { - return this.#getCycle(pInitialSource, pCurrentSource); + const lInitialNode = this.findVertexByName(pInitialSource); + const lCurrentDependency = lInitialNode.dependencies.find( + (pDependency) => pDependency.name === pCurrentSource, + ); + + if (!lCurrentDependency) { + return []; + } + return this.#getCycleNew(pInitialSource, lCurrentDependency); } } diff --git a/src/report/anon/anonymize-path.mjs b/src/report/anon/anonymize-path.mjs index 40896b922..a5b000a92 100644 --- a/src/report/anon/anonymize-path.mjs +++ b/src/report/anon/anonymize-path.mjs @@ -2,7 +2,7 @@ import { anonymizePathElement } from "./anonymize-path-element.mjs"; export const WHITELIST_RE = // eslint-disable-next-line security/detect-unsafe-regex - /^(|[.]+|~|bin|apps?|cli|src|libs?|configs?|components?|fixtures?|helpers?|i18n|index\.(jsx?|[mc]js|d\.ts|tsx?|vue|coffee|ls)|_?_?mocks?_?_?|node_modules|packages?|package\.json|scripts?|services?|sources?|specs?|_?_?tests?_?_?|types?|uti?ls?)$/; + /^(|[.]+|~|bin|apps?|cli|src|libs?|configs?|components?|fixtures?|helpers?|i18n|index\.(jsx?|[mc]js|d\.ts|tsx?|vue|coffee|ls)|_?_?mocks?_?_?|node_modules|packages?|package\.json|scripts?|services?|sources?|specs?|_?_?tests?_?_?|types?|uti?ls?|tools)$/; /** * Kind of smartly anonymizes paths, by diff --git a/src/report/anon/index.mjs b/src/report/anon/index.mjs index f5cce2dd3..f593ae1b1 100644 --- a/src/report/anon/index.mjs +++ b/src/report/anon/index.mjs @@ -2,15 +2,26 @@ import has from "lodash/has.js"; import { anonymizePath, WHITELIST_RE } from "./anonymize-path.mjs"; function anonymizePathArray(pPathArray, pWordList) { + // the coverage ignore is here because the || [] branch isn't taken when running + // tests and with the current setup of the anonymize module that's not going + // to change. Still want to keep the branch from robustness perspective though. + /* c8 ignore next 1 */ return (pPathArray || []).map((pPath) => anonymizePath(pPath, pWordList)); } +function anonymizeCycleArray(pCycleArray, pWordList, pAttribute = "name") { + return (pCycleArray || []).map((pCycle) => ({ + ...pCycle, + [pAttribute]: anonymizePath(pCycle.name, pWordList), + })); +} + function anonymizeDependencies(pDependencies, pWordList) { return pDependencies.map((pDependency) => ({ ...pDependency, resolved: anonymizePath(pDependency.resolved, pWordList), module: anonymizePath(pDependency.module, pWordList), - cycle: anonymizePathArray(pDependency.cycle, pWordList), + cycle: anonymizeCycleArray(pDependency.cycle, pWordList), })); } @@ -74,7 +85,7 @@ function anonymizeFolders(pFolders, pWordList) { name: anonymizePath(pDependency.name, pWordList), }; if (lReturnDependencies.cycle) { - lReturnDependencies.cycle = anonymizePathArray( + lReturnDependencies.cycle = anonymizeCycleArray( pDependency.cycle, pWordList, ); @@ -98,7 +109,7 @@ function anonymizeViolations(pViolations, pWordList) { ...pViolation, from: anonymizePath(pViolation.from, pWordList), to: anonymizePath(pViolation.to, pWordList), - cycle: anonymizePathArray(pViolation.cycle, pWordList), + cycle: anonymizeCycleArray(pViolation.cycle, pWordList), }; if (pViolation.via) { lReturnValue.via = anonymizePathArray(pViolation.via, pWordList); @@ -145,7 +156,7 @@ function sanitizeWordList(pWordList) { * - summary.violations.to * - summary.violations.cycle[m] * - * (note: the algorith _removes_ elements from pWordList to prevent duplicates, + * (note: the algorithm _removes_ elements from pWordList to prevent duplicates, * so if the word list is precious to you - pass a clone) * * @param {import("../../../types/cruise-result.mjs").ICruiseResult} pResults - the output of a dependency-cruise adhering to ../schema/cruise-result.schema.json diff --git a/src/report/anon/random-string.mjs b/src/report/anon/random-string.mjs index 610bd558c..999d11112 100644 --- a/src/report/anon/random-string.mjs +++ b/src/report/anon/random-string.mjs @@ -42,7 +42,7 @@ function getRandomChar(pChar) { /** * Returns a random string with the same length as pString - * acii characters - respecting case & numbers + leaving separators + * ascii characters - respecting case & numbers + leaving separators * (-, _, .) in place * * hello => tbkwd diff --git a/src/report/azure-devops.mjs b/src/report/azure-devops.mjs index 2c5701c9d..f2cddf69c 100644 --- a/src/report/azure-devops.mjs +++ b/src/report/azure-devops.mjs @@ -42,7 +42,9 @@ function formatDependencyViolation(pViolation) { * @returns {string} */ function formatCycleViolation(pViolation) { - return `${pViolation.from} -> ${pViolation.cycle.join(" -> ")}`; + return `${pViolation.from} -> ${pViolation.cycle + .map(({ name }) => name) + .join(" -> ")}`; } /** diff --git a/src/report/error-html/utl.mjs b/src/report/error-html/utl.mjs index d44cb523e..5c8e65e90 100644 --- a/src/report/error-html/utl.mjs +++ b/src/report/error-html/utl.mjs @@ -30,7 +30,7 @@ function mergeCountsIntoRule(pRule, pViolationCounts) { } function formatCycleTo(pViolation) { - return pViolation.cycle.join(" →
"); + return pViolation.cycle.map(({ name }) => name).join(" →
"); } function formatReachabilityTo(pViolation) { diff --git a/src/report/error.mjs b/src/report/error.mjs index 10ddd8272..868de5287 100644 --- a/src/report/error.mjs +++ b/src/report/error.mjs @@ -17,6 +17,15 @@ const SEVERITY2CHALK = new Map([ const EXTRA_PATH_INFORMATION_INDENT = 6; +function formatExtraCycleInformation(pCycle) { + return EOL.concat( + wrapAndIndent( + pCycle.map(({ name }) => name).join(` ${figures.arrowRight} ${EOL}`), + EXTRA_PATH_INFORMATION_INDENT, + ), + ); +} + function formatExtraPathInformation(pExtra) { return EOL.concat( wrapAndIndent( @@ -39,7 +48,7 @@ function formatDependencyViolation(pViolation) { function formatCycleViolation(pViolation) { return `${chalk.bold(pViolation.from)} ${ figures.arrowRight - } ${formatExtraPathInformation(pViolation.cycle)}`; + } ${formatExtraCycleInformation(pViolation.cycle)}`; } function formatReachabilityViolation(pViolation) { diff --git a/src/report/teamcity.mjs b/src/report/teamcity.mjs index 682d2dc1b..a4013a884 100644 --- a/src/report/teamcity.mjs +++ b/src/report/teamcity.mjs @@ -15,7 +15,7 @@ function severity2teamcitySeverity(pSeverity) { function reportRules(pRules, pViolations) { return pRules .filter((pRule) => - pViolations.some((pViolation) => pRule.name === pViolation.rule.name) + pViolations.some((pViolation) => pRule.name === pViolation.rule.name), ) .map((pRule) => tsm.inspectionType({ @@ -23,7 +23,7 @@ function reportRules(pRules, pViolations) { name: pRule.name, description: pRule.comment || pRule.name, category: CATEGORY, - }) + }), ); } @@ -75,20 +75,22 @@ function formatDependencyViolation(pViolation) { } function formatCycleViolation(pViolation) { - return `${pViolation.from} -> ${pViolation.cycle.join(" -> ")}`; + return `${pViolation.from} -> ${pViolation.cycle + .map(({ name }) => name) + .join(" -> ")}`; } function formatReachabilityViolation(pViolation) { return `${formatDependencyViolation(pViolation)} ${pViolation.via.join( - " -> " + " -> ", )}`; } function formatInstabilityViolation(pViolation) { return `${formatDependencyViolation( - pViolation + pViolation, )} (instability: ${formatPercentage( - pViolation.metrics.from.instability + pViolation.metrics.from.instability, )} -> ${formatPercentage(pViolation.metrics.to.instability)})`; } @@ -103,7 +105,7 @@ function bakeViolationMessage(pViolation) { return formatViolation( pViolation, lViolationType2Formatter, - formatDependencyViolation + formatDependencyViolation, ); } @@ -128,7 +130,7 @@ function reportViolations(pViolations, pIgnoredCount) { message: bakeViolationMessage(pViolation), file: pViolation.from, SEVERITY: severity2teamcitySeverity(pViolation.rule.severity), - }) + }), ) .concat(reportIgnoredViolation(pIgnoredCount)); } @@ -152,7 +154,7 @@ export default function teamcity(pResults) { const lRuleSet = pResults?.summary?.ruleSetUsed ?? []; const lViolations = (pResults?.summary?.violations ?? []).filter( - (pViolation) => pViolation.rule.severity !== "ignore" + (pViolation) => pViolation.rule.severity !== "ignore", ); const lIgnoredCount = pResults?.summary?.ignore ?? 0; diff --git a/src/schema/baseline-violations.schema.json b/src/schema/baseline-violations.schema.json index d8a330345..edf93bbbd 100644 --- a/src/schema/baseline-violations.schema.json +++ b/src/schema/baseline-violations.schema.json @@ -20,7 +20,7 @@ "rule": { "$ref": "#/definitions/RuleSummaryType" }, "cycle": { "type": "array", - "items": { "type": "string" }, + "items": { "$ref": "#/definitions/MiniDependency" }, "description": "The circular path if the violation is about circularity" }, "via": { @@ -81,6 +81,60 @@ "instability", "folder" ] + }, + "MiniDependency": { + "type": "object", + "description": "A small dependency object with the uniquely identifying name of the module +the dependency types it has relative to the _previous_ module in the chain it is part of (e.g. a cycle).", + "required": ["name", "dependencyTypes"], + "additionalProperties": false, + "properties": { + "name": { "type": "string", "description": "The name of the module" }, + "dependencyTypes": { + "type": "array", + "items": { "$ref": "#/definitions/DependencyTypeType" }, + "description": "The dependency types of the module relative to the previous module in the chain it is a part of (e.g. a cycle)" + } + } + }, + "DependencyTypeType": { + "type": "string", + "enum": [ + "aliased-subpath-import", + "aliased-tsconfig-base-url", + "aliased-tsconfig-paths", + "aliased-tsconfig", + "aliased-webpack", + "aliased-workspace", + "aliased", + "amd-define", + "amd-require", + "amd-exotic-require", + "core", + "deprecated", + "dynamic-import", + "exotic-require", + "export", + "import-equals", + "import", + "local", + "localmodule", + "npm-bundled", + "npm-dev", + "npm-no-pkg", + "npm-optional", + "npm-peer", + "npm-unknown", + "npm", + "require", + "triple-slash-amd-dependency", + "triple-slash-directive", + "triple-slash-file-reference", + "triple-slash-type-reference", + "type-import", + "type-only", + "undetermined", + "unknown" + ] } } } diff --git a/src/schema/baseline-violations.schema.mjs b/src/schema/baseline-violations.schema.mjs index 7ceb392c0..7d46d6f81 100644 --- a/src/schema/baseline-violations.schema.mjs +++ b/src/schema/baseline-violations.schema.mjs @@ -1 +1 @@ -/* generated - don't edit */export default {"title":"dependency-cruiser baseline ('known errors') format","$schema":"http://json-schema.org/draft-07/schema#","$id":"https://dependency-cruiser.js.org/schema/baseline-violations.schema.json","$ref":"#/definitions/ViolationsType","definitions":{"ViolationsType":{"type":"array","items":{"$ref":"#/definitions/ViolationType"}},"ViolationType":{"type":"object","required":["from","to","rule"],"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"},"type":{"$ref":"#/definitions/ViolationTypeType"},"rule":{"$ref":"#/definitions/RuleSummaryType"},"cycle":{"type":"array","items":{"type":"string"}},"via":{"type":"array","items":{"type":"string"}},"metrics":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}},"to":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}}}},"comment":{"type":"string"}}},"RuleSummaryType":{"type":"object","required":["name","severity"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"}}},"SeverityType":{"type":"string","enum":["error","warn","info","ignore"]},"ViolationTypeType":{"type":"string","enum":["dependency","module","reachability","cycle","instability","folder"]}}} \ No newline at end of file +/* generated - don't edit */export default {"title":"dependency-cruiser baseline ('known errors') format","$schema":"http://json-schema.org/draft-07/schema#","$id":"https://dependency-cruiser.js.org/schema/baseline-violations.schema.json","$ref":"#/definitions/ViolationsType","definitions":{"ViolationsType":{"type":"array","items":{"$ref":"#/definitions/ViolationType"}},"ViolationType":{"type":"object","required":["from","to","rule"],"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"},"type":{"$ref":"#/definitions/ViolationTypeType"},"rule":{"$ref":"#/definitions/RuleSummaryType"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"via":{"type":"array","items":{"type":"string"}},"metrics":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}},"to":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}}}},"comment":{"type":"string"}}},"RuleSummaryType":{"type":"object","required":["name","severity"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"}}},"SeverityType":{"type":"string","enum":["error","warn","info","ignore"]},"ViolationTypeType":{"type":"string","enum":["dependency","module","reachability","cycle","instability","folder"]},"MiniDependency":{"type":"object","required":["name","dependencyTypes"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"DependencyTypeType":{"type":"string","enum":["aliased-subpath-import","aliased-tsconfig-base-url","aliased-tsconfig-paths","aliased-tsconfig","aliased-webpack","aliased-workspace","aliased","amd-define","amd-require","amd-exotic-require","core","deprecated","dynamic-import","exotic-require","export","import-equals","import","local","localmodule","npm-bundled","npm-dev","npm-no-pkg","npm-optional","npm-peer","npm-unknown","npm","require","triple-slash-amd-dependency","triple-slash-directive","triple-slash-file-reference","triple-slash-type-reference","type-import","type-only","undetermined","unknown"]}}} \ No newline at end of file diff --git a/src/schema/configuration.schema.json b/src/schema/configuration.schema.json index 979a55fee..c4930fadc 100644 --- a/src/schema/configuration.schema.json +++ b/src/schema/configuration.schema.json @@ -1003,7 +1003,7 @@ "rule": { "$ref": "#/definitions/RuleSummaryType" }, "cycle": { "type": "array", - "items": { "type": "string" }, + "items": { "$ref": "#/definitions/MiniDependency" }, "description": "The circular path if the violation is about circularity" }, "via": { @@ -1060,6 +1060,20 @@ "folder" ] }, + "MiniDependency": { + "type": "object", + "description": "A small dependency object with the uniquely identifying name of the module +the dependency types it has relative to the _previous_ module in the chain it is part of (e.g. a cycle).", + "required": ["name", "dependencyTypes"], + "additionalProperties": false, + "properties": { + "name": { "type": "string", "description": "The name of the module" }, + "dependencyTypes": { + "type": "array", + "items": { "$ref": "#/definitions/DependencyTypeType" }, + "description": "The dependency types of the module relative to the previous module in the chain it is a part of (e.g. a cycle)" + } + } + }, "CacheOptionsType": { "type": "object", "additionalProperties": false, diff --git a/src/schema/configuration.schema.mjs b/src/schema/configuration.schema.mjs index c50498734..7accabe25 100644 --- a/src/schema/configuration.schema.mjs +++ b/src/schema/configuration.schema.mjs @@ -1 +1 @@ -/* generated - don't edit */export default {"title":"dependency-cruiser configuration","$schema":"http://json-schema.org/draft-07/schema#","$id":"https://dependency-cruiser.js.org/schema/configuration.schema.json","type":"object","additionalProperties":false,"properties":{"$schema":{"type":"string"},"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}},"options":{"$ref":"#/definitions/OptionsType"},"extends":{"$ref":"#/definitions/ExtendsType"}},"definitions":{"RuleSetType":{"type":"object","additionalProperties":false,"properties":{"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}}}},"AllowedRuleType":{"oneOf":[{"$ref":"#/definitions/RegularAllowedRuleType"},{"$ref":"#/definitions/ReachabilityAllowedRuleType"}]},"RegularAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"ReachabilityAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"ForbiddenRuleType":{"oneOf":[{"$ref":"#/definitions/RegularForbiddenRuleType"},{"$ref":"#/definitions/ReachabilityForbiddenRuleType"},{"$ref":"#/definitions/DependentsForbiddenRuleType"}]},"RegularForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"DependentsForbiddenRuleType":{"type":"object","required":["module","from"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/DependentsModuleRestrictionType"},"from":{"$ref":"#/definitions/DependentsFromRestrictionType"}}},"ReachabilityForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"RequiredRuleType":{"type":"object","required":["module","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/RequiredModuleRestrictionType"},"to":{"$ref":"#/definitions/RequiredToRestrictionType"}}},"FromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"orphan":{"type":"boolean"}}},"ReachabilityFromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ToRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"couldNotResolve":{"type":"boolean"},"circular":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"$ref":"#/definitions/REAsStringsType"},"exoticRequireNot":{"$ref":"#/definitions/REAsStringsType"},"preCompilationOnly":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"moreThanOneDependencyType":{"type":"boolean"},"license":{"$ref":"#/definitions/REAsStringsType"},"licenseNot":{"$ref":"#/definitions/REAsStringsType"},"via":{"$ref":"#/definitions/REAsStringsType"},"viaOnly":{"$ref":"#/definitions/REAsStringsType"},"viaNot":{"$ref":"#/definitions/REAsStringsType"},"viaSomeNot":{"$ref":"#/definitions/REAsStringsType"},"moreUnstable":{"type":"boolean"}}},"DependentsModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"numberOfDependentsLessThan":{"type":"integer","minimum":0,"maximum":100},"numberOfDependentsMoreThan":{"type":"integer","minimum":0,"maximum":100}}},"DependentsFromRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ReachabilityToRestrictionType":{"required":["reachable"],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"reachable":{"type":"boolean"}}},"RequiredModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"RequiredToRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"DependencyTypeType":{"type":"string","enum":["aliased-subpath-import","aliased-tsconfig-base-url","aliased-tsconfig-paths","aliased-tsconfig","aliased-webpack","aliased-workspace","aliased","amd-define","amd-require","amd-exotic-require","core","deprecated","dynamic-import","exotic-require","export","import-equals","import","local","localmodule","npm-bundled","npm-dev","npm-no-pkg","npm-optional","npm-peer","npm-unknown","npm","require","triple-slash-amd-dependency","triple-slash-directive","triple-slash-file-reference","triple-slash-type-reference","type-import","type-only","undetermined","unknown"]},"REAsStringsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"SeverityType":{"type":"string","enum":["error","warn","info","ignore"]},"OptionsType":{"type":"object","additionalProperties":false,"properties":{"doNotFollow":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundDoNotFollowType"}]},"exclude":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundExcludeType"}]},"includeOnly":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundIncludeOnlyType"}]},"focus":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundFocusType"}]},"reaches":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundReachesType"}]},"highlight":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundHighlightType"}]},"knownViolations":{"$ref":"#/definitions/ViolationsType"},"collapse":{"oneOf":[{"type":"string"},{"type":"integer","minimum":1,"maximum":9}]},"maxDepth":{"type":"integer","minimum":0,"maximum":99},"moduleSystems":{"$ref":"#/definitions/ModuleSystemsType"},"prefix":{"type":"string"},"preserveSymlinks":{"type":"boolean"},"combinedDependencies":{"type":"boolean"},"tsConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"tsPreCompilationDeps":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["specify"]}]},"extraExtensionsToScan":{"type":"array","items":{"type":"string"}},"externalModuleResolutionStrategy":{"type":"string","enum":["node_modules","yarn-pnp"]},"builtInModules":{"type":"object","additionalProperties":false,"properties":{"override":{"type":"array","items":{"type":"string"}},"add":{"type":"array","items":{"type":"string"}}}},"forceDeriveDependents":{"type":"boolean"},"webpackConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"},"env":{"oneOf":[{"type":"object"},{"type":"string"}]},"arguments":{"type":"object"}}},"enhancedResolveOptions":{"type":"object","additionalProperties":false,"properties":{"exportsFields":{"type":"array","items":{"type":"string"}},"conditionNames":{"type":"array","items":{"type":"string"}},"extensions":{"type":"array","items":{"type":"string"}},"mainFields":{"type":"array","items":{"type":"string"}},"mainFiles":{"type":"array"},"aliasFields":{"type":"array","items":{"type":"string"}},"cachedInputFileSystem":{"type":"object","additionalProperties":false,"properties":{"cacheDuration":{"type":"integer","minimum":0,"maximum":1800000}}}}},"babelConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"parser":{"type":"string","enum":["acorn","swc","tsc"]},"exoticRequireStrings":{"type":"array","items":{"type":"string"}},"reporterOptions":{"$ref":"#/definitions/ReporterOptionsType"},"progress":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["cli-feedback","performance-log","ndjson","none"]},"maximumLevel":{"type":"number","enum":[-1,40,50,60,70,80,99]}}},"metrics":{"type":"boolean"},"baseDir":{"type":"string"},"cache":{"oneOf":[{"type":"boolean"},{"type":"string"},{"$ref":"#/definitions/CacheOptionsType"}]}}},"ModuleSystemType":{"type":"string","enum":["cjs","es6","amd","tsd"]},"ModuleSystemsType":{"type":"array","items":{"$ref":"#/definitions/ModuleSystemType"}},"CompoundExcludeType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dynamic":{"type":"boolean"}}},"CompoundDoNotFollowType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CompoundIncludeOnlyType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundFocusType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"depth":{"type":"number","minimum":1,"maximum":4}}},"CompoundReachesType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundHighlightType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"ReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"anon":{"$ref":"#/definitions/AnonReporterOptionsType"},"archi":{"$ref":"#/definitions/DotReporterOptionsType"},"dot":{"$ref":"#/definitions/DotReporterOptionsType"},"ddot":{"$ref":"#/definitions/DotReporterOptionsType"},"flat":{"$ref":"#/definitions/DotReporterOptionsType"},"markdown":{"$ref":"#/definitions/MarkdownReporterOptionsType"},"metrics":{"$ref":"#/definitions/MetricsReporterOptionsType"},"mermaid":{"$ref":"#/definitions/MermaidReporterOptionsType"},"text":{"$ref":"#/definitions/TextReporterOptionsType"}}},"AnonReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"wordlist":{"type":"array","items":{"type":"string"}}}},"MetricsReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"orderBy":{"type":"string","enum":["instability","moduleCount","afferentCouplings","efferentCouplings","name"]},"hideModules":{"type":"boolean"},"hideFolders":{"type":"boolean"}}},"MarkdownReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"showTitle":{"type":"boolean"},"title":{"type":"string"},"showSummary":{"type":"boolean"},"showSummaryHeader":{"type":"boolean"},"summaryHeader":{"type":"string"},"showStatsSummary":{"type":"boolean"},"showRulesSummary":{"type":"boolean"},"includeIgnoredInSummary":{"type":"boolean"},"showDetails":{"type":"boolean"},"includeIgnoredInDetails":{"type":"boolean"},"showDetailsHeader":{"type":"boolean"},"detailsHeader":{"type":"string"},"collapseDetails":{"type":"boolean"},"collapsedMessage":{"type":"string"},"noViolationsMessage":{"type":"string"},"showFooter":{"type":"boolean"}}},"MermaidReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"minify":{"type":"boolean"}}},"TextReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"highlightFocused":{"type":"boolean"}}},"DotReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"collapsePattern":{"$ref":"#/definitions/REAsStringsType"},"filters":{"$ref":"#/definitions/ReporterFiltersType"},"showMetrics":{"type":"boolean"},"theme":{"$ref":"#/definitions/DotThemeType"}}},"DotThemeType":{"type":"object","additionalProperties":false,"properties":{"replace":{"type":"boolean"},"graph":{"type":"object"},"node":{"type":"object"},"edge":{"type":"object"},"modules":{"$ref":"#/definitions/DotThemeArrayType"},"dependencies":{"$ref":"#/definitions/DotThemeArrayType"}}},"DotThemeArrayType":{"type":"array","items":{"$ref":"#/definitions/DotThemeEntryType"}},"DotThemeEntryType":{"type":"object","additionalProperties":false,"properties":{"criteria":{"type":"object"},"attributes":{"type":"object"}}},"ReporterFiltersType":{"type":"object","additionalProperties":false,"properties":{"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"$ref":"#/definitions/CompoundIncludeOnlyType"},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"}}},"ViolationsType":{"type":"array","items":{"$ref":"#/definitions/ViolationType"}},"ViolationType":{"type":"object","required":["from","to","rule"],"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"},"type":{"$ref":"#/definitions/ViolationTypeType"},"rule":{"$ref":"#/definitions/RuleSummaryType"},"cycle":{"type":"array","items":{"type":"string"}},"via":{"type":"array","items":{"type":"string"}},"metrics":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}},"to":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}}}},"comment":{"type":"string"}}},"RuleSummaryType":{"type":"object","required":["name","severity"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"}}},"ViolationTypeType":{"type":"string","enum":["dependency","module","reachability","cycle","instability","folder"]},"CacheOptionsType":{"type":"object","additionalProperties":false,"properties":{"folder":{"type":"string"},"strategy":{"$ref":"#/definitions/CacheStrategyType"},"compress":{"type":"boolean","default":false}}},"CacheStrategyType":{"type":"string","enum":["metadata","content"]},"ExtendsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}}} \ No newline at end of file +/* generated - don't edit */export default {"title":"dependency-cruiser configuration","$schema":"http://json-schema.org/draft-07/schema#","$id":"https://dependency-cruiser.js.org/schema/configuration.schema.json","type":"object","additionalProperties":false,"properties":{"$schema":{"type":"string"},"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}},"options":{"$ref":"#/definitions/OptionsType"},"extends":{"$ref":"#/definitions/ExtendsType"}},"definitions":{"RuleSetType":{"type":"object","additionalProperties":false,"properties":{"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}}}},"AllowedRuleType":{"oneOf":[{"$ref":"#/definitions/RegularAllowedRuleType"},{"$ref":"#/definitions/ReachabilityAllowedRuleType"}]},"RegularAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"ReachabilityAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"ForbiddenRuleType":{"oneOf":[{"$ref":"#/definitions/RegularForbiddenRuleType"},{"$ref":"#/definitions/ReachabilityForbiddenRuleType"},{"$ref":"#/definitions/DependentsForbiddenRuleType"}]},"RegularForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"DependentsForbiddenRuleType":{"type":"object","required":["module","from"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/DependentsModuleRestrictionType"},"from":{"$ref":"#/definitions/DependentsFromRestrictionType"}}},"ReachabilityForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"RequiredRuleType":{"type":"object","required":["module","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/RequiredModuleRestrictionType"},"to":{"$ref":"#/definitions/RequiredToRestrictionType"}}},"FromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"orphan":{"type":"boolean"}}},"ReachabilityFromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ToRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"couldNotResolve":{"type":"boolean"},"circular":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"$ref":"#/definitions/REAsStringsType"},"exoticRequireNot":{"$ref":"#/definitions/REAsStringsType"},"preCompilationOnly":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"moreThanOneDependencyType":{"type":"boolean"},"license":{"$ref":"#/definitions/REAsStringsType"},"licenseNot":{"$ref":"#/definitions/REAsStringsType"},"via":{"$ref":"#/definitions/REAsStringsType"},"viaOnly":{"$ref":"#/definitions/REAsStringsType"},"viaNot":{"$ref":"#/definitions/REAsStringsType"},"viaSomeNot":{"$ref":"#/definitions/REAsStringsType"},"moreUnstable":{"type":"boolean"}}},"DependentsModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"numberOfDependentsLessThan":{"type":"integer","minimum":0,"maximum":100},"numberOfDependentsMoreThan":{"type":"integer","minimum":0,"maximum":100}}},"DependentsFromRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ReachabilityToRestrictionType":{"required":["reachable"],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"reachable":{"type":"boolean"}}},"RequiredModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"RequiredToRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"DependencyTypeType":{"type":"string","enum":["aliased-subpath-import","aliased-tsconfig-base-url","aliased-tsconfig-paths","aliased-tsconfig","aliased-webpack","aliased-workspace","aliased","amd-define","amd-require","amd-exotic-require","core","deprecated","dynamic-import","exotic-require","export","import-equals","import","local","localmodule","npm-bundled","npm-dev","npm-no-pkg","npm-optional","npm-peer","npm-unknown","npm","require","triple-slash-amd-dependency","triple-slash-directive","triple-slash-file-reference","triple-slash-type-reference","type-import","type-only","undetermined","unknown"]},"REAsStringsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"SeverityType":{"type":"string","enum":["error","warn","info","ignore"]},"OptionsType":{"type":"object","additionalProperties":false,"properties":{"doNotFollow":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundDoNotFollowType"}]},"exclude":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundExcludeType"}]},"includeOnly":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundIncludeOnlyType"}]},"focus":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundFocusType"}]},"reaches":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundReachesType"}]},"highlight":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundHighlightType"}]},"knownViolations":{"$ref":"#/definitions/ViolationsType"},"collapse":{"oneOf":[{"type":"string"},{"type":"integer","minimum":1,"maximum":9}]},"maxDepth":{"type":"integer","minimum":0,"maximum":99},"moduleSystems":{"$ref":"#/definitions/ModuleSystemsType"},"prefix":{"type":"string"},"preserveSymlinks":{"type":"boolean"},"combinedDependencies":{"type":"boolean"},"tsConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"tsPreCompilationDeps":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["specify"]}]},"extraExtensionsToScan":{"type":"array","items":{"type":"string"}},"externalModuleResolutionStrategy":{"type":"string","enum":["node_modules","yarn-pnp"]},"builtInModules":{"type":"object","additionalProperties":false,"properties":{"override":{"type":"array","items":{"type":"string"}},"add":{"type":"array","items":{"type":"string"}}}},"forceDeriveDependents":{"type":"boolean"},"webpackConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"},"env":{"oneOf":[{"type":"object"},{"type":"string"}]},"arguments":{"type":"object"}}},"enhancedResolveOptions":{"type":"object","additionalProperties":false,"properties":{"exportsFields":{"type":"array","items":{"type":"string"}},"conditionNames":{"type":"array","items":{"type":"string"}},"extensions":{"type":"array","items":{"type":"string"}},"mainFields":{"type":"array","items":{"type":"string"}},"mainFiles":{"type":"array"},"aliasFields":{"type":"array","items":{"type":"string"}},"cachedInputFileSystem":{"type":"object","additionalProperties":false,"properties":{"cacheDuration":{"type":"integer","minimum":0,"maximum":1800000}}}}},"babelConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"parser":{"type":"string","enum":["acorn","swc","tsc"]},"exoticRequireStrings":{"type":"array","items":{"type":"string"}},"reporterOptions":{"$ref":"#/definitions/ReporterOptionsType"},"progress":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["cli-feedback","performance-log","ndjson","none"]},"maximumLevel":{"type":"number","enum":[-1,40,50,60,70,80,99]}}},"metrics":{"type":"boolean"},"baseDir":{"type":"string"},"cache":{"oneOf":[{"type":"boolean"},{"type":"string"},{"$ref":"#/definitions/CacheOptionsType"}]}}},"ModuleSystemType":{"type":"string","enum":["cjs","es6","amd","tsd"]},"ModuleSystemsType":{"type":"array","items":{"$ref":"#/definitions/ModuleSystemType"}},"CompoundExcludeType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dynamic":{"type":"boolean"}}},"CompoundDoNotFollowType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CompoundIncludeOnlyType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundFocusType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"depth":{"type":"number","minimum":1,"maximum":4}}},"CompoundReachesType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundHighlightType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"ReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"anon":{"$ref":"#/definitions/AnonReporterOptionsType"},"archi":{"$ref":"#/definitions/DotReporterOptionsType"},"dot":{"$ref":"#/definitions/DotReporterOptionsType"},"ddot":{"$ref":"#/definitions/DotReporterOptionsType"},"flat":{"$ref":"#/definitions/DotReporterOptionsType"},"markdown":{"$ref":"#/definitions/MarkdownReporterOptionsType"},"metrics":{"$ref":"#/definitions/MetricsReporterOptionsType"},"mermaid":{"$ref":"#/definitions/MermaidReporterOptionsType"},"text":{"$ref":"#/definitions/TextReporterOptionsType"}}},"AnonReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"wordlist":{"type":"array","items":{"type":"string"}}}},"MetricsReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"orderBy":{"type":"string","enum":["instability","moduleCount","afferentCouplings","efferentCouplings","name"]},"hideModules":{"type":"boolean"},"hideFolders":{"type":"boolean"}}},"MarkdownReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"showTitle":{"type":"boolean"},"title":{"type":"string"},"showSummary":{"type":"boolean"},"showSummaryHeader":{"type":"boolean"},"summaryHeader":{"type":"string"},"showStatsSummary":{"type":"boolean"},"showRulesSummary":{"type":"boolean"},"includeIgnoredInSummary":{"type":"boolean"},"showDetails":{"type":"boolean"},"includeIgnoredInDetails":{"type":"boolean"},"showDetailsHeader":{"type":"boolean"},"detailsHeader":{"type":"string"},"collapseDetails":{"type":"boolean"},"collapsedMessage":{"type":"string"},"noViolationsMessage":{"type":"string"},"showFooter":{"type":"boolean"}}},"MermaidReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"minify":{"type":"boolean"}}},"TextReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"highlightFocused":{"type":"boolean"}}},"DotReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"collapsePattern":{"$ref":"#/definitions/REAsStringsType"},"filters":{"$ref":"#/definitions/ReporterFiltersType"},"showMetrics":{"type":"boolean"},"theme":{"$ref":"#/definitions/DotThemeType"}}},"DotThemeType":{"type":"object","additionalProperties":false,"properties":{"replace":{"type":"boolean"},"graph":{"type":"object"},"node":{"type":"object"},"edge":{"type":"object"},"modules":{"$ref":"#/definitions/DotThemeArrayType"},"dependencies":{"$ref":"#/definitions/DotThemeArrayType"}}},"DotThemeArrayType":{"type":"array","items":{"$ref":"#/definitions/DotThemeEntryType"}},"DotThemeEntryType":{"type":"object","additionalProperties":false,"properties":{"criteria":{"type":"object"},"attributes":{"type":"object"}}},"ReporterFiltersType":{"type":"object","additionalProperties":false,"properties":{"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"$ref":"#/definitions/CompoundIncludeOnlyType"},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"}}},"ViolationsType":{"type":"array","items":{"$ref":"#/definitions/ViolationType"}},"ViolationType":{"type":"object","required":["from","to","rule"],"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"},"type":{"$ref":"#/definitions/ViolationTypeType"},"rule":{"$ref":"#/definitions/RuleSummaryType"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"via":{"type":"array","items":{"type":"string"}},"metrics":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}},"to":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}}}},"comment":{"type":"string"}}},"RuleSummaryType":{"type":"object","required":["name","severity"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"}}},"ViolationTypeType":{"type":"string","enum":["dependency","module","reachability","cycle","instability","folder"]},"MiniDependency":{"type":"object","required":["name","dependencyTypes"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CacheOptionsType":{"type":"object","additionalProperties":false,"properties":{"folder":{"type":"string"},"strategy":{"$ref":"#/definitions/CacheStrategyType"},"compress":{"type":"boolean","default":false}}},"CacheStrategyType":{"type":"string","enum":["metadata","content"]},"ExtendsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}}} \ No newline at end of file diff --git a/src/schema/cruise-result.schema.json b/src/schema/cruise-result.schema.json index 8e0f6f557..5b630f654 100644 --- a/src/schema/cruise-result.schema.json +++ b/src/schema/cruise-result.schema.json @@ -245,7 +245,7 @@ }, "cycle": { "type": "array", - "items": { "type": "string" }, + "items": { "$ref": "#/definitions/MiniDependency" }, "description": "If following this dependency will ultimately return to the source (circular === true), this attribute will contain an (ordered) array of module names that shows (one of) the circular path(s)" }, "moduleSystem": { "$ref": "#/definitions/ModuleSystemType" }, @@ -326,6 +326,20 @@ "description": "How severe a violation of a rule is. The 'error' severity will make some reporters return a non-zero exit code, so if you want e.g. a build to stop when there's a rule violated: use that.", "enum": ["error", "warn", "info", "ignore"] }, + "MiniDependency": { + "type": "object", + "description": "A small dependency object with the uniquely identifying name of the module +the dependency types it has relative to the _previous_ module in the chain it is part of (e.g. a cycle).", + "required": ["name", "dependencyTypes"], + "additionalProperties": false, + "properties": { + "name": { "type": "string", "description": "The name of the module" }, + "dependencyTypes": { + "type": "array", + "items": { "$ref": "#/definitions/DependencyTypeType" }, + "description": "The dependency types of the module relative to the previous module in the chain it is a part of (e.g. a cycle)" + } + } + }, "FoldersType": { "type": "array", "description": "A list of folders, as derived from the detected modules, with for each folder a bunch of metrics (adapted from 'Agile software development: principles, patterns, and practices' by Robert C Martin (ISBN 0-13-597444-5). Note: these metrics substitute 'components' and 'classes' from that book with 'folders' and 'modules'; the closest relatives that work for the most programming styles in JavaScript (and its derivative languages).", @@ -381,7 +395,7 @@ }, "cycle": { "type": "array", - "items": { "type": "string" }, + "items": { "$ref": "#/definitions/MiniDependency" }, "description": "If following this dependency will ultimately return to the source (circular === true), this attribute will contain an (ordered) array of module names that shows (one of) the circular path(s)" }, "rules": { @@ -468,7 +482,7 @@ "rule": { "$ref": "#/definitions/RuleSummaryType" }, "cycle": { "type": "array", - "items": { "type": "string" }, + "items": { "$ref": "#/definitions/MiniDependency" }, "description": "The circular path if the violation is about circularity" }, "via": { diff --git a/src/schema/cruise-result.schema.mjs b/src/schema/cruise-result.schema.mjs index 8c6b71d97..9e60c5a78 100644 --- a/src/schema/cruise-result.schema.mjs +++ b/src/schema/cruise-result.schema.mjs @@ -1 +1 @@ -/* generated - don't edit */export default {"title":"dependency-cruiser output format","$schema":"http://json-schema.org/draft-07/schema#","$id":"https://dependency-cruiser.js.org/schema/cruise-result.schema.json","type":"object","required":["summary","modules"],"additionalProperties":false,"properties":{"modules":{"$ref":"#/definitions/ModulesType"},"folders":{"$ref":"#/definitions/FoldersType"},"summary":{"$ref":"#/definitions/SummaryType"},"revisionData":{"$ref":"#/definitions/RevisionDataType"}},"definitions":{"ModulesType":{"type":"array","items":{"$ref":"#/definitions/ModuleType"}},"ModuleType":{"type":"object","required":["source","dependencies","valid"],"additionalProperties":false,"properties":{"source":{"type":"string"},"valid":{"type":"boolean"},"dependencies":{"$ref":"#/definitions/DependenciesType"},"dependents":{"type":"array","items":{"type":"string"}},"followable":{"type":"boolean"},"matchesDoNotFollow":{"type":"boolean"},"matchesFocus":{"type":"boolean"},"matchesReaches":{"type":"boolean"},"matchesHighlight":{"type":"boolean"},"coreModule":{"type":"boolean"},"couldNotResolve":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"license":{"type":"string"},"orphan":{"type":"boolean"},"reachable":{"type":"array","items":{"$ref":"#/definitions/ReachableType"}},"reaches":{"type":"array","items":{"$ref":"#/definitions/ReachesType"}},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}},"consolidated":{"type":"boolean"},"instability":{"type":"number"},"checksum":{"type":"string"}}},"ReachableType":{"type":"object","required":["value","asDefinedInRule","matchedFrom"],"additionalProperties":false,"properties":{"value":{"type":"boolean"},"asDefinedInRule":{"type":"string"},"matchedFrom":{"type":"string"}}},"ReachesType":{"type":"object","required":["modules","asDefinedInRule"],"additionalProperties":false,"properties":{"modules":{"type":"array","items":{"type":"object","required":["source","via"],"additionalProperties":false,"properties":{"source":{"type":"string"},"via":{"type":"array","items":{"type":"string"}}}}},"asDefinedInRule":{"type":"string"}}},"DependenciesType":{"type":"array","items":{"$ref":"#/definitions/DependencyType"}},"DependencyType":{"type":"object","required":["circular","coreModule","couldNotResolve","dependencyTypes","exoticallyRequired","dynamic","followable","module","moduleSystem","resolved","valid"],"additionalProperties":false,"properties":{"module":{"type":"string"},"protocol":{"type":"string","enum":["data:","file:","node:"]},"mimeType":{"type":"string"},"resolved":{"type":"string"},"coreModule":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"license":{"type":"string"},"followable":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"type":"string"},"matchesDoNotFollow":{"type":"boolean"},"couldNotResolve":{"type":"boolean"},"preCompilationOnly":{"type":"boolean"},"typeOnly":{"type":"boolean"},"circular":{"type":"boolean"},"cycle":{"type":"array","items":{"type":"string"}},"moduleSystem":{"$ref":"#/definitions/ModuleSystemType"},"valid":{"type":"boolean"},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}},"instability":{"type":"number"}}},"DependencyTypeType":{"type":"string","enum":["aliased-subpath-import","aliased-tsconfig-base-url","aliased-tsconfig-paths","aliased-tsconfig","aliased-webpack","aliased-workspace","aliased","amd-define","amd-require","amd-exotic-require","core","deprecated","dynamic-import","exotic-require","export","import-equals","import","local","localmodule","npm-bundled","npm-dev","npm-no-pkg","npm-optional","npm-peer","npm-unknown","npm","require","triple-slash-amd-dependency","triple-slash-directive","triple-slash-file-reference","triple-slash-type-reference","type-import","type-only","undetermined","unknown"]},"ModuleSystemType":{"type":"string","enum":["cjs","es6","amd","tsd"]},"RuleSummaryType":{"type":"object","required":["name","severity"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"}}},"SeverityType":{"type":"string","enum":["error","warn","info","ignore"]},"FoldersType":{"type":"array","items":{"$ref":"#/definitions/FolderType"}},"FolderType":{"type":"object","required":["name","moduleCount"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependents":{"type":"array","items":{"type":"object","required":["name"],"additionalProperties":false,"properties":{"name":{"type":"string"}}}},"dependencies":{"type":"array","items":{"type":"object","required":["name","valid","circular"],"additionalProperties":false,"properties":{"name":{"type":"string"},"instability":{"type":"number"},"valid":{"type":"boolean"},"circular":{"type":"boolean"},"cycle":{"type":"array","items":{"type":"string"}},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}}}}},"moduleCount":{"type":"number"},"afferentCouplings":{"type":"number"},"efferentCouplings":{"type":"number"},"instability":{"type":"number"}}},"SummaryType":{"type":"object","required":["violations","error","warn","info","totalCruised","optionsUsed"],"additionalProperties":false,"properties":{"violations":{"$ref":"#/definitions/ViolationsType"},"error":{"type":"number"},"warn":{"type":"number"},"info":{"type":"number"},"ignore":{"type":"number"},"totalCruised":{"type":"number"},"totalDependenciesCruised":{"type":"number"},"ruleSetUsed":{"$ref":"#/definitions/RuleSetType"},"optionsUsed":{"$ref":"#/definitions/OptionsUsedType"}}},"ViolationsType":{"type":"array","items":{"$ref":"#/definitions/ViolationType"}},"ViolationType":{"type":"object","required":["from","to","rule"],"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"},"type":{"$ref":"#/definitions/ViolationTypeType"},"rule":{"$ref":"#/definitions/RuleSummaryType"},"cycle":{"type":"array","items":{"type":"string"}},"via":{"type":"array","items":{"type":"string"}},"metrics":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}},"to":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}}}},"comment":{"type":"string"}}},"ViolationTypeType":{"type":"string","enum":["dependency","module","reachability","cycle","instability","folder"]},"RuleSetType":{"type":"object","additionalProperties":false,"properties":{"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}}}},"AllowedRuleType":{"oneOf":[{"$ref":"#/definitions/RegularAllowedRuleType"},{"$ref":"#/definitions/ReachabilityAllowedRuleType"}]},"RegularAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"ReachabilityAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"ForbiddenRuleType":{"oneOf":[{"$ref":"#/definitions/RegularForbiddenRuleType"},{"$ref":"#/definitions/ReachabilityForbiddenRuleType"},{"$ref":"#/definitions/DependentsForbiddenRuleType"}]},"RegularForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"DependentsForbiddenRuleType":{"type":"object","required":["module","from"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/DependentsModuleRestrictionType"},"from":{"$ref":"#/definitions/DependentsFromRestrictionType"}}},"ReachabilityForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"RequiredRuleType":{"type":"object","required":["module","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/RequiredModuleRestrictionType"},"to":{"$ref":"#/definitions/RequiredToRestrictionType"}}},"FromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"orphan":{"type":"boolean"}}},"ReachabilityFromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ToRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"couldNotResolve":{"type":"boolean"},"circular":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"$ref":"#/definitions/REAsStringsType"},"exoticRequireNot":{"$ref":"#/definitions/REAsStringsType"},"preCompilationOnly":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"moreThanOneDependencyType":{"type":"boolean"},"license":{"$ref":"#/definitions/REAsStringsType"},"licenseNot":{"$ref":"#/definitions/REAsStringsType"},"via":{"$ref":"#/definitions/REAsStringsType"},"viaOnly":{"$ref":"#/definitions/REAsStringsType"},"viaNot":{"$ref":"#/definitions/REAsStringsType"},"viaSomeNot":{"$ref":"#/definitions/REAsStringsType"},"moreUnstable":{"type":"boolean"}}},"DependentsModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"numberOfDependentsLessThan":{"type":"integer","minimum":0,"maximum":100},"numberOfDependentsMoreThan":{"type":"integer","minimum":0,"maximum":100}}},"DependentsFromRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ReachabilityToRestrictionType":{"required":["reachable"],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"reachable":{"type":"boolean"}}},"RequiredModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"RequiredToRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"REAsStringsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"OptionsUsedType":{"type":"object","additionalProperties":false,"properties":{"doNotFollow":{"$ref":"#/definitions/CompoundDoNotFollowType"},"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundIncludeOnlyType"}]},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"},"highlight":{"$ref":"#/definitions/CompoundHighlightType"},"knownViolations":{"$ref":"#/definitions/ViolationsType"},"collapse":{"type":"string"},"maxDepth":{"type":"integer","minimum":0,"maximum":99},"moduleSystems":{"$ref":"#/definitions/ModuleSystemsType"},"prefix":{"type":"string"},"preserveSymlinks":{"type":"boolean"},"combinedDependencies":{"type":"boolean"},"tsConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"tsPreCompilationDeps":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["specify"]}]},"extraExtensionsToScan":{"type":"array","items":{"type":"string"}},"externalModuleResolutionStrategy":{"type":"string","enum":["node_modules","yarn-pnp"]},"builtInModules":{"type":"object","additionalProperties":false,"properties":{"override":{"type":"array","items":{"type":"string"}},"add":{"type":"array","items":{"type":"string"}}}},"forceDeriveDependents":{"type":"boolean"},"webpackConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"},"env":{"oneOf":[{"type":"object"},{"type":"string"}]},"arguments":{"type":"object"}}},"enhancedResolveOptions":{"type":"object","additionalProperties":false,"properties":{"exportsFields":{"type":"array","items":{"type":"string"}},"conditionNames":{"type":"array","items":{"type":"string"}},"extensions":{"type":"array","items":{"type":"string"}},"mainFields":{"type":"array","items":{"type":"string"}},"mainFiles":{"type":"array"},"aliasFields":{"type":"array","items":{"type":"string"}},"cachedInputFileSystem":{"type":"object","additionalProperties":false,"properties":{"cacheDuration":{"type":"integer","minimum":0,"maximum":1800000}}}}},"babelConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"parser":{"type":"string","enum":["acorn","swc","tsc"]},"exoticRequireStrings":{"type":"array","items":{"type":"string"}},"reporterOptions":{"$ref":"#/definitions/ReporterOptionsType"},"progress":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["cli-feedback","performance-log","ndjson","none"]},"maximumLevel":{"type":"number","enum":[-1,40,50,60,70,80,99]}}},"metrics":{"type":"boolean"},"baseDir":{"type":"string"},"cache":{"oneOf":[{"type":"boolean","enum":[false]},{"$ref":"#/definitions/CacheOptionsType"}]},"args":{"type":"string"},"rulesFile":{"type":"string"},"outputTo":{"type":"string"},"outputType":{"$ref":"#/definitions/OutputType"}}},"ModuleSystemsType":{"type":"array","items":{"$ref":"#/definitions/ModuleSystemType"}},"OutputType":{"oneOf":[{"type":"string","enum":["json","html","dot","ddot","cdot","archi","fdot","flat","csv","err","err-long","err-html","teamcity","anon","text","metrics","markdown","mermaid","d2","null"]},{"type":"string","pattern":"^plugin:[^:]+$"}]},"CompoundExcludeType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dynamic":{"type":"boolean"}}},"CompoundDoNotFollowType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CompoundIncludeOnlyType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundFocusType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"depth":{"type":"number","minimum":1,"maximum":4}}},"CompoundReachesType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundHighlightType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"ReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"anon":{"$ref":"#/definitions/AnonReporterOptionsType"},"archi":{"$ref":"#/definitions/DotReporterOptionsType"},"dot":{"$ref":"#/definitions/DotReporterOptionsType"},"ddot":{"$ref":"#/definitions/DotReporterOptionsType"},"flat":{"$ref":"#/definitions/DotReporterOptionsType"},"markdown":{"$ref":"#/definitions/MarkdownReporterOptionsType"},"metrics":{"$ref":"#/definitions/MetricsReporterOptionsType"},"mermaid":{"$ref":"#/definitions/MermaidReporterOptionsType"},"text":{"$ref":"#/definitions/TextReporterOptionsType"}}},"AnonReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"wordlist":{"type":"array","items":{"type":"string"}}}},"MetricsReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"orderBy":{"type":"string","enum":["instability","moduleCount","afferentCouplings","efferentCouplings","name"]},"hideModules":{"type":"boolean"},"hideFolders":{"type":"boolean"}}},"MarkdownReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"showTitle":{"type":"boolean"},"title":{"type":"string"},"showSummary":{"type":"boolean"},"showSummaryHeader":{"type":"boolean"},"summaryHeader":{"type":"string"},"showStatsSummary":{"type":"boolean"},"showRulesSummary":{"type":"boolean"},"includeIgnoredInSummary":{"type":"boolean"},"showDetails":{"type":"boolean"},"includeIgnoredInDetails":{"type":"boolean"},"showDetailsHeader":{"type":"boolean"},"detailsHeader":{"type":"string"},"collapseDetails":{"type":"boolean"},"collapsedMessage":{"type":"string"},"noViolationsMessage":{"type":"string"},"showFooter":{"type":"boolean"}}},"MermaidReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"minify":{"type":"boolean"}}},"TextReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"highlightFocused":{"type":"boolean"}}},"DotReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"collapsePattern":{"$ref":"#/definitions/REAsStringsType"},"filters":{"$ref":"#/definitions/ReporterFiltersType"},"showMetrics":{"type":"boolean"},"theme":{"$ref":"#/definitions/DotThemeType"}}},"DotThemeType":{"type":"object","additionalProperties":false,"properties":{"replace":{"type":"boolean"},"graph":{"type":"object"},"node":{"type":"object"},"edge":{"type":"object"},"modules":{"$ref":"#/definitions/DotThemeArrayType"},"dependencies":{"$ref":"#/definitions/DotThemeArrayType"}}},"DotThemeArrayType":{"type":"array","items":{"$ref":"#/definitions/DotThemeEntryType"}},"DotThemeEntryType":{"type":"object","additionalProperties":false,"properties":{"criteria":{"type":"object"},"attributes":{"type":"object"}}},"ReporterFiltersType":{"type":"object","additionalProperties":false,"properties":{"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"$ref":"#/definitions/CompoundIncludeOnlyType"},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"}}},"CacheOptionsType":{"type":"object","additionalProperties":false,"properties":{"folder":{"type":"string"},"strategy":{"$ref":"#/definitions/CacheStrategyType"},"compress":{"type":"boolean","default":false}}},"CacheStrategyType":{"type":"string","enum":["metadata","content"]},"RevisionDataType":{"type":"object","required":["SHA1","changes"],"properties":{"SHA1":{"type":"string"},"changes":{"type":"array","items":{"type":"object","required":["name","changeType"],"properties":{"name":{"type":"string"},"changeType":{"type":"string","enum":["added","copied","deleted","modified","renamed","type changed","unmerged","pairing broken","unknown","unmodified","untracked","ignored"]},"oldName":{"type":"string"},"checksum":{"type":"string"},"args":{"type":"array","items":{"type":"string"}},"rulesFile":{"type":"string"}}}}}}}} \ No newline at end of file +/* generated - don't edit */export default {"title":"dependency-cruiser output format","$schema":"http://json-schema.org/draft-07/schema#","$id":"https://dependency-cruiser.js.org/schema/cruise-result.schema.json","type":"object","required":["summary","modules"],"additionalProperties":false,"properties":{"modules":{"$ref":"#/definitions/ModulesType"},"folders":{"$ref":"#/definitions/FoldersType"},"summary":{"$ref":"#/definitions/SummaryType"},"revisionData":{"$ref":"#/definitions/RevisionDataType"}},"definitions":{"ModulesType":{"type":"array","items":{"$ref":"#/definitions/ModuleType"}},"ModuleType":{"type":"object","required":["source","dependencies","valid"],"additionalProperties":false,"properties":{"source":{"type":"string"},"valid":{"type":"boolean"},"dependencies":{"$ref":"#/definitions/DependenciesType"},"dependents":{"type":"array","items":{"type":"string"}},"followable":{"type":"boolean"},"matchesDoNotFollow":{"type":"boolean"},"matchesFocus":{"type":"boolean"},"matchesReaches":{"type":"boolean"},"matchesHighlight":{"type":"boolean"},"coreModule":{"type":"boolean"},"couldNotResolve":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"license":{"type":"string"},"orphan":{"type":"boolean"},"reachable":{"type":"array","items":{"$ref":"#/definitions/ReachableType"}},"reaches":{"type":"array","items":{"$ref":"#/definitions/ReachesType"}},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}},"consolidated":{"type":"boolean"},"instability":{"type":"number"},"checksum":{"type":"string"}}},"ReachableType":{"type":"object","required":["value","asDefinedInRule","matchedFrom"],"additionalProperties":false,"properties":{"value":{"type":"boolean"},"asDefinedInRule":{"type":"string"},"matchedFrom":{"type":"string"}}},"ReachesType":{"type":"object","required":["modules","asDefinedInRule"],"additionalProperties":false,"properties":{"modules":{"type":"array","items":{"type":"object","required":["source","via"],"additionalProperties":false,"properties":{"source":{"type":"string"},"via":{"type":"array","items":{"type":"string"}}}}},"asDefinedInRule":{"type":"string"}}},"DependenciesType":{"type":"array","items":{"$ref":"#/definitions/DependencyType"}},"DependencyType":{"type":"object","required":["circular","coreModule","couldNotResolve","dependencyTypes","exoticallyRequired","dynamic","followable","module","moduleSystem","resolved","valid"],"additionalProperties":false,"properties":{"module":{"type":"string"},"protocol":{"type":"string","enum":["data:","file:","node:"]},"mimeType":{"type":"string"},"resolved":{"type":"string"},"coreModule":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"license":{"type":"string"},"followable":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"type":"string"},"matchesDoNotFollow":{"type":"boolean"},"couldNotResolve":{"type":"boolean"},"preCompilationOnly":{"type":"boolean"},"typeOnly":{"type":"boolean"},"circular":{"type":"boolean"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"moduleSystem":{"$ref":"#/definitions/ModuleSystemType"},"valid":{"type":"boolean"},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}},"instability":{"type":"number"}}},"DependencyTypeType":{"type":"string","enum":["aliased-subpath-import","aliased-tsconfig-base-url","aliased-tsconfig-paths","aliased-tsconfig","aliased-webpack","aliased-workspace","aliased","amd-define","amd-require","amd-exotic-require","core","deprecated","dynamic-import","exotic-require","export","import-equals","import","local","localmodule","npm-bundled","npm-dev","npm-no-pkg","npm-optional","npm-peer","npm-unknown","npm","require","triple-slash-amd-dependency","triple-slash-directive","triple-slash-file-reference","triple-slash-type-reference","type-import","type-only","undetermined","unknown"]},"ModuleSystemType":{"type":"string","enum":["cjs","es6","amd","tsd"]},"RuleSummaryType":{"type":"object","required":["name","severity"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"}}},"SeverityType":{"type":"string","enum":["error","warn","info","ignore"]},"MiniDependency":{"type":"object","required":["name","dependencyTypes"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"FoldersType":{"type":"array","items":{"$ref":"#/definitions/FolderType"}},"FolderType":{"type":"object","required":["name","moduleCount"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependents":{"type":"array","items":{"type":"object","required":["name"],"additionalProperties":false,"properties":{"name":{"type":"string"}}}},"dependencies":{"type":"array","items":{"type":"object","required":["name","valid","circular"],"additionalProperties":false,"properties":{"name":{"type":"string"},"instability":{"type":"number"},"valid":{"type":"boolean"},"circular":{"type":"boolean"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}}}}},"moduleCount":{"type":"number"},"afferentCouplings":{"type":"number"},"efferentCouplings":{"type":"number"},"instability":{"type":"number"}}},"SummaryType":{"type":"object","required":["violations","error","warn","info","totalCruised","optionsUsed"],"additionalProperties":false,"properties":{"violations":{"$ref":"#/definitions/ViolationsType"},"error":{"type":"number"},"warn":{"type":"number"},"info":{"type":"number"},"ignore":{"type":"number"},"totalCruised":{"type":"number"},"totalDependenciesCruised":{"type":"number"},"ruleSetUsed":{"$ref":"#/definitions/RuleSetType"},"optionsUsed":{"$ref":"#/definitions/OptionsUsedType"}}},"ViolationsType":{"type":"array","items":{"$ref":"#/definitions/ViolationType"}},"ViolationType":{"type":"object","required":["from","to","rule"],"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"},"type":{"$ref":"#/definitions/ViolationTypeType"},"rule":{"$ref":"#/definitions/RuleSummaryType"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"via":{"type":"array","items":{"type":"string"}},"metrics":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}},"to":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}}}},"comment":{"type":"string"}}},"ViolationTypeType":{"type":"string","enum":["dependency","module","reachability","cycle","instability","folder"]},"RuleSetType":{"type":"object","additionalProperties":false,"properties":{"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}}}},"AllowedRuleType":{"oneOf":[{"$ref":"#/definitions/RegularAllowedRuleType"},{"$ref":"#/definitions/ReachabilityAllowedRuleType"}]},"RegularAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"ReachabilityAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"ForbiddenRuleType":{"oneOf":[{"$ref":"#/definitions/RegularForbiddenRuleType"},{"$ref":"#/definitions/ReachabilityForbiddenRuleType"},{"$ref":"#/definitions/DependentsForbiddenRuleType"}]},"RegularForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"DependentsForbiddenRuleType":{"type":"object","required":["module","from"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/DependentsModuleRestrictionType"},"from":{"$ref":"#/definitions/DependentsFromRestrictionType"}}},"ReachabilityForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"RequiredRuleType":{"type":"object","required":["module","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/RequiredModuleRestrictionType"},"to":{"$ref":"#/definitions/RequiredToRestrictionType"}}},"FromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"orphan":{"type":"boolean"}}},"ReachabilityFromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ToRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"couldNotResolve":{"type":"boolean"},"circular":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"$ref":"#/definitions/REAsStringsType"},"exoticRequireNot":{"$ref":"#/definitions/REAsStringsType"},"preCompilationOnly":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"moreThanOneDependencyType":{"type":"boolean"},"license":{"$ref":"#/definitions/REAsStringsType"},"licenseNot":{"$ref":"#/definitions/REAsStringsType"},"via":{"$ref":"#/definitions/REAsStringsType"},"viaOnly":{"$ref":"#/definitions/REAsStringsType"},"viaNot":{"$ref":"#/definitions/REAsStringsType"},"viaSomeNot":{"$ref":"#/definitions/REAsStringsType"},"moreUnstable":{"type":"boolean"}}},"DependentsModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"numberOfDependentsLessThan":{"type":"integer","minimum":0,"maximum":100},"numberOfDependentsMoreThan":{"type":"integer","minimum":0,"maximum":100}}},"DependentsFromRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ReachabilityToRestrictionType":{"required":["reachable"],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"reachable":{"type":"boolean"}}},"RequiredModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"RequiredToRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"REAsStringsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"OptionsUsedType":{"type":"object","additionalProperties":false,"properties":{"doNotFollow":{"$ref":"#/definitions/CompoundDoNotFollowType"},"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundIncludeOnlyType"}]},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"},"highlight":{"$ref":"#/definitions/CompoundHighlightType"},"knownViolations":{"$ref":"#/definitions/ViolationsType"},"collapse":{"type":"string"},"maxDepth":{"type":"integer","minimum":0,"maximum":99},"moduleSystems":{"$ref":"#/definitions/ModuleSystemsType"},"prefix":{"type":"string"},"preserveSymlinks":{"type":"boolean"},"combinedDependencies":{"type":"boolean"},"tsConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"tsPreCompilationDeps":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["specify"]}]},"extraExtensionsToScan":{"type":"array","items":{"type":"string"}},"externalModuleResolutionStrategy":{"type":"string","enum":["node_modules","yarn-pnp"]},"builtInModules":{"type":"object","additionalProperties":false,"properties":{"override":{"type":"array","items":{"type":"string"}},"add":{"type":"array","items":{"type":"string"}}}},"forceDeriveDependents":{"type":"boolean"},"webpackConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"},"env":{"oneOf":[{"type":"object"},{"type":"string"}]},"arguments":{"type":"object"}}},"enhancedResolveOptions":{"type":"object","additionalProperties":false,"properties":{"exportsFields":{"type":"array","items":{"type":"string"}},"conditionNames":{"type":"array","items":{"type":"string"}},"extensions":{"type":"array","items":{"type":"string"}},"mainFields":{"type":"array","items":{"type":"string"}},"mainFiles":{"type":"array"},"aliasFields":{"type":"array","items":{"type":"string"}},"cachedInputFileSystem":{"type":"object","additionalProperties":false,"properties":{"cacheDuration":{"type":"integer","minimum":0,"maximum":1800000}}}}},"babelConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"parser":{"type":"string","enum":["acorn","swc","tsc"]},"exoticRequireStrings":{"type":"array","items":{"type":"string"}},"reporterOptions":{"$ref":"#/definitions/ReporterOptionsType"},"progress":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["cli-feedback","performance-log","ndjson","none"]},"maximumLevel":{"type":"number","enum":[-1,40,50,60,70,80,99]}}},"metrics":{"type":"boolean"},"baseDir":{"type":"string"},"cache":{"oneOf":[{"type":"boolean","enum":[false]},{"$ref":"#/definitions/CacheOptionsType"}]},"args":{"type":"string"},"rulesFile":{"type":"string"},"outputTo":{"type":"string"},"outputType":{"$ref":"#/definitions/OutputType"}}},"ModuleSystemsType":{"type":"array","items":{"$ref":"#/definitions/ModuleSystemType"}},"OutputType":{"oneOf":[{"type":"string","enum":["json","html","dot","ddot","cdot","archi","fdot","flat","csv","err","err-long","err-html","teamcity","anon","text","metrics","markdown","mermaid","d2","null"]},{"type":"string","pattern":"^plugin:[^:]+$"}]},"CompoundExcludeType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dynamic":{"type":"boolean"}}},"CompoundDoNotFollowType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CompoundIncludeOnlyType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundFocusType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"depth":{"type":"number","minimum":1,"maximum":4}}},"CompoundReachesType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundHighlightType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"ReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"anon":{"$ref":"#/definitions/AnonReporterOptionsType"},"archi":{"$ref":"#/definitions/DotReporterOptionsType"},"dot":{"$ref":"#/definitions/DotReporterOptionsType"},"ddot":{"$ref":"#/definitions/DotReporterOptionsType"},"flat":{"$ref":"#/definitions/DotReporterOptionsType"},"markdown":{"$ref":"#/definitions/MarkdownReporterOptionsType"},"metrics":{"$ref":"#/definitions/MetricsReporterOptionsType"},"mermaid":{"$ref":"#/definitions/MermaidReporterOptionsType"},"text":{"$ref":"#/definitions/TextReporterOptionsType"}}},"AnonReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"wordlist":{"type":"array","items":{"type":"string"}}}},"MetricsReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"orderBy":{"type":"string","enum":["instability","moduleCount","afferentCouplings","efferentCouplings","name"]},"hideModules":{"type":"boolean"},"hideFolders":{"type":"boolean"}}},"MarkdownReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"showTitle":{"type":"boolean"},"title":{"type":"string"},"showSummary":{"type":"boolean"},"showSummaryHeader":{"type":"boolean"},"summaryHeader":{"type":"string"},"showStatsSummary":{"type":"boolean"},"showRulesSummary":{"type":"boolean"},"includeIgnoredInSummary":{"type":"boolean"},"showDetails":{"type":"boolean"},"includeIgnoredInDetails":{"type":"boolean"},"showDetailsHeader":{"type":"boolean"},"detailsHeader":{"type":"string"},"collapseDetails":{"type":"boolean"},"collapsedMessage":{"type":"string"},"noViolationsMessage":{"type":"string"},"showFooter":{"type":"boolean"}}},"MermaidReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"minify":{"type":"boolean"}}},"TextReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"highlightFocused":{"type":"boolean"}}},"DotReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"collapsePattern":{"$ref":"#/definitions/REAsStringsType"},"filters":{"$ref":"#/definitions/ReporterFiltersType"},"showMetrics":{"type":"boolean"},"theme":{"$ref":"#/definitions/DotThemeType"}}},"DotThemeType":{"type":"object","additionalProperties":false,"properties":{"replace":{"type":"boolean"},"graph":{"type":"object"},"node":{"type":"object"},"edge":{"type":"object"},"modules":{"$ref":"#/definitions/DotThemeArrayType"},"dependencies":{"$ref":"#/definitions/DotThemeArrayType"}}},"DotThemeArrayType":{"type":"array","items":{"$ref":"#/definitions/DotThemeEntryType"}},"DotThemeEntryType":{"type":"object","additionalProperties":false,"properties":{"criteria":{"type":"object"},"attributes":{"type":"object"}}},"ReporterFiltersType":{"type":"object","additionalProperties":false,"properties":{"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"$ref":"#/definitions/CompoundIncludeOnlyType"},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"}}},"CacheOptionsType":{"type":"object","additionalProperties":false,"properties":{"folder":{"type":"string"},"strategy":{"$ref":"#/definitions/CacheStrategyType"},"compress":{"type":"boolean","default":false}}},"CacheStrategyType":{"type":"string","enum":["metadata","content"]},"RevisionDataType":{"type":"object","required":["SHA1","changes"],"properties":{"SHA1":{"type":"string"},"changes":{"type":"array","items":{"type":"object","required":["name","changeType"],"properties":{"name":{"type":"string"},"changeType":{"type":"string","enum":["added","copied","deleted","modified","renamed","type changed","unmerged","pairing broken","unknown","unmodified","untracked","ignored"]},"oldName":{"type":"string"},"checksum":{"type":"string"},"args":{"type":"array","items":{"type":"string"}},"rulesFile":{"type":"string"}}}}}}}} \ No newline at end of file diff --git a/src/validate/matchers.mjs b/src/validate/matchers.mjs index 43184bbac..d362656d3 100644 --- a/src/validate/matchers.mjs +++ b/src/validate/matchers.mjs @@ -107,14 +107,18 @@ function toDependencyTypesNot(pRule, pDependency) { !intersects(pDependency.dependencyTypes, pRule.to.dependencyTypesNot), ); } - +function pluckName({ name }) { + return name; +} function toVia(pRule, pDependency, pGroups) { return Boolean( !pRule.to.via || (pDependency.cycle && - pDependency.cycle.some((pVia) => - pVia.match(replaceGroupPlaceholders(pRule.to.via, pGroups)), - )), + pDependency.cycle + .map(pluckName) + .some((pVia) => + pVia.match(replaceGroupPlaceholders(pRule.to.via, pGroups)), + )), ); } @@ -122,9 +126,11 @@ function toViaOnly(pRule, pDependency, pGroups) { return Boolean( !pRule.to.viaOnly || (pDependency.cycle && - pDependency.cycle.every((pVia) => - pVia.match(replaceGroupPlaceholders(pRule.to.viaOnly, pGroups)), - )), + pDependency.cycle + .map(pluckName) + .every((pVia) => + pVia.match(replaceGroupPlaceholders(pRule.to.viaOnly, pGroups)), + )), ); } @@ -132,9 +138,11 @@ function toViaNot(pRule, pDependency, pGroups) { return Boolean( !pRule.to.viaNot || (pDependency.cycle && - !pDependency.cycle.some((pVia) => - pVia.match(replaceGroupPlaceholders(pRule.to.viaNot, pGroups)), - )), + !pDependency.cycle + .map(pluckName) + .some((pVia) => + pVia.match(replaceGroupPlaceholders(pRule.to.viaNot, pGroups)), + )), ); } @@ -142,9 +150,11 @@ function toviaSomeNot(pRule, pDependency, pGroups) { return Boolean( !pRule.to.viaSomeNot || (pDependency.cycle && - !pDependency.cycle.every((pVia) => - pVia.match(replaceGroupPlaceholders(pRule.to.viaSomeNot, pGroups)), - )), + !pDependency.cycle + .map(pluckName) + .every((pVia) => + pVia.match(replaceGroupPlaceholders(pRule.to.viaSomeNot, pGroups)), + )), ); } diff --git a/test/cli/__fixtures__/result-has-a-dependency-violation.json b/test/cli/__fixtures__/result-has-a-dependency-violation.json index 314b372a9..501020326 100644 --- a/test/cli/__fixtures__/result-has-a-dependency-violation.json +++ b/test/cli/__fixtures__/result-has-a-dependency-violation.json @@ -8605,7 +8605,10 @@ "name": "src/extract/transpile", "instability": 0.6153846153846154, "circular": true, - "cycle": ["src/extract/transpile", "src/extract/parse"], + "cycle": [ + { "name": "src/extract/transpile", "dependencyTypes": [] }, + { "name": "src/extract/parse", "dependencyTypes": [] } + ], "valid": true }, { @@ -8647,7 +8650,10 @@ "name": "src/extract/parse", "instability": 0.46153846153846156, "circular": true, - "cycle": ["src/extract/parse", "src/extract/transpile"], + "cycle": [ + { "name": "src/extract/parse", "dependencyTypes": [] }, + { "name": "src/extract/transpile", "dependencyTypes": [] } + ], "valid": true } ], diff --git a/test/enrich/__mocks__/cycle-fest.mjs b/test/enrich/__mocks__/cycle-fest.mjs index 111bfa7dd..16c9fa68e 100644 --- a/test/enrich/__mocks__/cycle-fest.mjs +++ b/test/enrich/__mocks__/cycle-fest.mjs @@ -14,7 +14,11 @@ export default [ exoticallyRequired: false, matchesDoNotFollow: false, circular: true, - cycle: ["src/domain.js", "src/market.js", "src/brand.js"], + cycle: [ + { name: "src/domain.js", dependencyTypes: ["local"] }, + { name: "src/market.js", dependencyTypes: ["local"] }, + { name: "src/brand.js", dependencyTypes: ["local"] }, + ], valid: false, rules: [ { @@ -35,7 +39,10 @@ export default [ exoticallyRequired: false, matchesDoNotFollow: false, circular: true, - cycle: ["src/market.js", "src/brand.js"], + cycle: [ + { name: "src/market.js", dependencyTypes: ["local"] }, + { name: "src/brand.js", dependencyTypes: ["local"] }, + ], valid: false, rules: [ { @@ -63,7 +70,10 @@ export default [ exoticallyRequired: false, matchesDoNotFollow: false, circular: true, - cycle: ["src/market.js", "src/domain.js"], + cycle: [ + { name: "src/market.js", dependencyTypes: ["local"] }, + { name: "src/domain.js", dependencyTypes: ["local"] }, + ], valid: false, rules: [ { @@ -91,7 +101,10 @@ export default [ exoticallyRequired: false, matchesDoNotFollow: false, circular: true, - cycle: ["src/brand.js", "src/market.js"], + cycle: [ + { name: "src/brand.js", dependencyTypes: ["local"] }, + { name: "src/market.js", dependencyTypes: ["local"] }, + ], valid: false, rules: [ { @@ -112,7 +125,10 @@ export default [ exoticallyRequired: false, matchesDoNotFollow: false, circular: true, - cycle: ["src/domain.js", "src/market.js"], + cycle: [ + { name: "src/domain.js", dependencyTypes: ["local"] }, + { name: "src/market.js", dependencyTypes: ["local"] }, + ], valid: false, rules: [ { diff --git a/test/enrich/de-duplicate-violations.spec.mjs b/test/enrich/de-duplicate-violations.spec.mjs index a8f867f8d..b4d374719 100644 --- a/test/enrich/de-duplicate-violations.spec.mjs +++ b/test/enrich/de-duplicate-violations.spec.mjs @@ -39,7 +39,16 @@ describe("[U] enrich/de-duplicate-violations", () => { severity: "error", name: "no-circular", }, - cycle: ["src/report/not/module-utl.js", "src/report/not/index.js"], + cycle: [ + { + name: "src/report/not/module-utl.js", + dependencyTypes: ["local", "require"], + }, + { + name: "src/report/not/index.js", + dependencyTypes: ["local", "require"], + }, + ], }, { from: "src/report/dot/module-utl.js", @@ -48,7 +57,16 @@ describe("[U] enrich/de-duplicate-violations", () => { severity: "error", name: "no-circular", }, - cycle: ["src/report/dot/index.js", "src/report/dot/module-utl.js"], + cycle: [ + { + name: "src/report/dot/index.js", + dependencyTypes: ["local", "require"], + }, + { + name: "src/report/dot/module-utl.js", + dependencyTypes: ["local", "require"], + }, + ], }, ]; deepEqual(deDuplicateViolations(lViolations), lViolations); @@ -63,7 +81,16 @@ describe("[U] enrich/de-duplicate-violations", () => { severity: "error", name: "no-circular", }, - cycle: ["src/report/dot/module-utl.js", "src/report/dot/index.js"], + cycle: [ + { + name: "src/report/dot/module-utl.js", + dependencyTypes: ["local", "require"], + }, + { + name: "src/report/dot/index.js", + dependencyTypes: ["local", "require"], + }, + ], }, { from: "src/report/dot/module-utl.js", @@ -72,7 +99,16 @@ describe("[U] enrich/de-duplicate-violations", () => { severity: "error", name: "no-circular", }, - cycle: ["src/report/dot/index.js", "src/report/dot/module-utl.js"], + cycle: [ + { + name: "src/report/dot/index.js", + dependencyTypes: ["local", "require"], + }, + { + name: "src/report/dot/module-utl.js", + dependencyTypes: ["local", "require"], + }, + ], }, ]; const lDeDuplicatedViolations = [ @@ -83,7 +119,16 @@ describe("[U] enrich/de-duplicate-violations", () => { severity: "error", name: "no-circular", }, - cycle: ["src/report/dot/module-utl.js", "src/report/dot/index.js"], + cycle: [ + { + name: "src/report/dot/module-utl.js", + dependencyTypes: ["local", "require"], + }, + { + name: "src/report/dot/index.js", + dependencyTypes: ["local", "require"], + }, + ], }, ]; deepEqual(deDuplicateViolations(lViolations), lDeDuplicatedViolations); @@ -98,7 +143,16 @@ describe("[U] enrich/de-duplicate-violations", () => { severity: "error", name: "no-ride-the-lightning", }, - cycle: ["src/report/dot/module-utl.js", "src/report/dot/index.js"], + cycle: [ + { + name: "src/report/dot/module-utl.js", + dependencyTypes: ["local", "require"], + }, + { + name: "src/report/dot/index.js", + dependencyTypes: ["local", "require"], + }, + ], }, { from: "src/report/dot/module-utl.js", @@ -107,7 +161,16 @@ describe("[U] enrich/de-duplicate-violations", () => { severity: "error", name: "no-circular", }, - cycle: ["src/report/dot/index.js", "src/report/dot/module-utl.js"], + cycle: [ + { + name: "src/report/dot/index.js", + dependencyTypes: ["local", "require"], + }, + { + name: "src/report/dot/module-utl.js", + dependencyTypes: ["local", "require"], + }, + ], }, ]; deepEqual(deDuplicateViolations(lViolations), lViolations); @@ -130,7 +193,16 @@ describe("[U] enrich/de-duplicate-violations", () => { severity: "error", name: "no-circular", }, - cycle: ["src/report/dot/module-utl.js", "src/report/dot/index.js"], + cycle: [ + { + name: "src/report/dot/module-utl.js", + dependencyTypes: ["local", "require"], + }, + { + name: "src/report/dot/index.js", + dependencyTypes: ["local", "require"], + }, + ], }, { from: "src/report/dot/module-utl.js", @@ -139,7 +211,16 @@ describe("[U] enrich/de-duplicate-violations", () => { severity: "error", name: "no-circular", }, - cycle: ["src/report/dot/index.js", "src/report/dot/module-utl.js"], + cycle: [ + { + name: "src/report/dot/index.js", + dependencyTypes: ["local", "require"], + }, + { + name: "src/report/dot/module-utl.js", + dependencyTypes: ["local", "require"], + }, + ], }, ]; const lDeDuplicatedViolations = [ @@ -158,7 +239,16 @@ describe("[U] enrich/de-duplicate-violations", () => { severity: "error", name: "no-circular", }, - cycle: ["src/report/dot/module-utl.js", "src/report/dot/index.js"], + cycle: [ + { + name: "src/report/dot/module-utl.js", + dependencyTypes: ["local", "require"], + }, + { + name: "src/report/dot/index.js", + dependencyTypes: ["local", "require"], + }, + ], }, ]; deepEqual(deDuplicateViolations(lViolations), lDeDuplicatedViolations); diff --git a/test/enrich/summarize.spec.mjs b/test/enrich/summarize.spec.mjs index 9ebebc6ef..351db3a5f 100644 --- a/test/enrich/summarize.spec.mjs +++ b/test/enrich/summarize.spec.mjs @@ -92,7 +92,20 @@ describe("[I] enrich/summarize", () => { severity: "warn", name: "no-circular", }, - cycle: ["src/domain.js", "src/market.js", "src/brand.js"], + cycle: [ + { + name: "src/domain.js", + dependencyTypes: ["local"], + }, + { + name: "src/market.js", + dependencyTypes: ["local"], + }, + { + name: "src/brand.js", + dependencyTypes: ["local"], + }, + ], }, { type: "cycle", @@ -102,7 +115,16 @@ describe("[I] enrich/summarize", () => { severity: "warn", name: "no-circular", }, - cycle: ["src/market.js", "src/brand.js"], + cycle: [ + { + name: "src/market.js", + dependencyTypes: ["local"], + }, + { + name: "src/brand.js", + dependencyTypes: ["local"], + }, + ], }, { type: "cycle", @@ -112,7 +134,16 @@ describe("[I] enrich/summarize", () => { severity: "warn", name: "no-circular", }, - cycle: ["src/market.js", "src/domain.js"], + cycle: [ + { + name: "src/market.js", + dependencyTypes: ["local"], + }, + { + name: "src/domain.js", + dependencyTypes: ["local"], + }, + ], }, ], error: 0, @@ -137,6 +168,7 @@ describe("[I] enrich/summarize", () => { ], }, }; + const lSummary = summarize(cycleFest, lOptions, ["src"]); deepEqual(lSummary, lExpected); ajv.validate(cruiseResultSchema, { modules: [], summary: lSummary }); diff --git a/test/graph-utl/__mocks__/cycle-input-graphs.mjs b/test/graph-utl/__mocks__/cycle-input-graphs.mjs index b7bf7961e..a7769a4b5 100644 --- a/test/graph-utl/__mocks__/cycle-input-graphs.mjs +++ b/test/graph-utl/__mocks__/cycle-input-graphs.mjs @@ -5,6 +5,7 @@ export default { dependencies: [ { resolved: "b", + dependencyTypes: ["npm"], }, ], }, @@ -29,7 +30,14 @@ export default { dependencies: [ { resolved: "e", - dependencyTypes: ["aliased", "aliased-subpath-import", "local"], + exoticallyRequired: false, + moduleSystem: "es6", + dependencyTypes: [ + "aliased", + "aliased-subpath-import", + "local", + "import", + ], }, ], }, @@ -38,6 +46,9 @@ export default { dependencies: [ { resolved: "d", + exoticallyRequired: false, + moduleSystem: "es6", + dependencyTypes: ["local", "import"], }, ], }, @@ -48,6 +59,7 @@ export default { dependencies: [ { resolved: "r", + dependencyTypes: ["local"], }, ], }, @@ -56,6 +68,7 @@ export default { dependencies: [ { resolved: "s", + dependencyTypes: ["local"], }, ], }, @@ -64,6 +77,7 @@ export default { dependencies: [ { resolved: "q", + dependencyTypes: ["local"], }, ], }, @@ -74,9 +88,11 @@ export default { dependencies: [ { resolved: "u", + dependencyTypes: ["local"], }, { resolved: "v", + dependencyTypes: ["npm"], }, ], }, @@ -85,6 +101,7 @@ export default { dependencies: [ { resolved: "t", + dependencyTypes: ["local"], }, ], }, @@ -216,21 +233,16 @@ export default { { resolved: "b", }, - ], - }, - { - source: "b", - dependencies: [ { - resolved: "a", + resolved: "c", }, ], }, { - source: "a", + source: "b", dependencies: [ { - resolved: "c", + resolved: "a", }, ], }, diff --git a/test/graph-utl/indexed-module-graph.spec.mjs b/test/graph-utl/indexed-module-graph.spec.mjs index 86b6f0a6b..3b9f5594a 100644 --- a/test/graph-utl/indexed-module-graph.spec.mjs +++ b/test/graph-utl/indexed-module-graph.spec.mjs @@ -408,10 +408,10 @@ describe("[U] graph-utl/indexed-module-graph - getPath", () => { function getCycle(pGraph, pFrom, pToDep) { const lIndexedGraph = new IndexedModuleGraph(pGraph); - return lIndexedGraph.getCycle(pFrom, pToDep); + return lIndexedGraph.getCycle(pFrom, pToDep).map(({ name }) => name); } -describe("[U] graph-utl/indexed-module-graph - getCycle", () => { +describe("[U] graph-utl/indexed-module-graph - getCycle (algorithm check)", () => { it("leaves non circular dependencies alone", () => { deepEqual(getCycle(cycleInputGraphs.A_B, "a", "b"), []); }); @@ -476,4 +476,46 @@ describe("[U] graph-utl/indexed-module-graph - getCycle", () => { it("just returns one cycle when querying a hub node", () => { deepEqual(getCycle(cycleInputGraphs.FLOWER, "a", "b"), ["b", "a"]); }); + it("if the 'to' node is not in the graph, it returns []", () => { + deepEqual(getCycle(cycleInputGraphs.D_E_D, "d", "not-in-graph"), []); + }); +}); + +function getCycleRich(pGraph, pFrom, pToDep) { + const lIndexedGraph = new IndexedModuleGraph(pGraph); + return lIndexedGraph.getCycle(pFrom, pToDep); +} + +describe("[U] graph-utl/indexed-module-graph - getCycle (verify the necessary attributes are there)", () => { + it("returns the cycle with the 'name' and 'dependencyTypes' attributes added (and none else)", () => { + const lCycle = getCycleRich(cycleInputGraphs.D_E_D, "d", "e"); + deepEqual(lCycle, [ + { + name: "e", + dependencyTypes: [ + "aliased", + "aliased-subpath-import", + "local", + "import", + ], + }, + { + name: "d", + dependencyTypes: ["local", "import"], + }, + ]); + }); + it("returns the cycle with the 'name' and 'dependencyTypes' attributes even when dependencyTypes wasn't defined", () => { + const lCycle = getCycleRich(cycleInputGraphs.FLOWER, "a", "b"); + deepEqual(lCycle, [ + { + name: "b", + dependencyTypes: [], + }, + { + name: "a", + dependencyTypes: [], + }, + ]); + }); }); diff --git a/test/main/__fixtures__/cruise-reporterless/commonjs.json b/test/main/__fixtures__/cruise-reporterless/commonjs.json index 697bde7b3..d07f3d763 100644 --- a/test/main/__fixtures__/cruise-reporterless/commonjs.json +++ b/test/main/__fixtures__/cruise-reporterless/commonjs.json @@ -759,8 +759,14 @@ "valid": false, "circular": true, "cycle": [ - "test/main/__mocks__/cruise-reporterless/commonjs/ralucric.js", - "test/main/__mocks__/cruise-reporterless/commonjs/circular.js" + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/ralucric.js", + "dependencyTypes": ["local", "require"] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circular.js", + "dependencyTypes": ["local", "require"] + } ], "rules": [ { @@ -802,8 +808,14 @@ "valid": false, "circular": true, "cycle": [ - "test/main/__mocks__/cruise-reporterless/commonjs/circular.js", - "test/main/__mocks__/cruise-reporterless/commonjs/ralucric.js" + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circular.js", + "dependencyTypes": ["local", "require"] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/ralucric.js", + "dependencyTypes": ["local", "require"] + } ], "rules": [ { @@ -866,9 +878,18 @@ "valid": true, "circular": true, "cycle": [ - "test/main/__mocks__/cruise-reporterless/commonjs/circle-two.js", - "test/main/__mocks__/cruise-reporterless/commonjs/circle-three.js", - "test/main/__mocks__/cruise-reporterless/commonjs/circle-one.js" + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circle-two.js", + "dependencyTypes": ["local", "require"] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circle-three.js", + "dependencyTypes": ["local", "require"] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circle-one.js", + "dependencyTypes": ["local", "require"] + } ] } ], @@ -897,9 +918,18 @@ "valid": true, "circular": true, "cycle": [ - "test/main/__mocks__/cruise-reporterless/commonjs/circle-three.js", - "test/main/__mocks__/cruise-reporterless/commonjs/circle-one.js", - "test/main/__mocks__/cruise-reporterless/commonjs/circle-two.js" + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circle-three.js", + "dependencyTypes": ["local", "require"] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circle-one.js", + "dependencyTypes": ["local", "require"] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circle-two.js", + "dependencyTypes": ["local", "require"] + } ] } ], @@ -926,9 +956,18 @@ "valid": true, "circular": true, "cycle": [ - "test/main/__mocks__/cruise-reporterless/commonjs/circle-one.js", - "test/main/__mocks__/cruise-reporterless/commonjs/circle-two.js", - "test/main/__mocks__/cruise-reporterless/commonjs/circle-three.js" + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circle-one.js", + "dependencyTypes": ["local", "require"] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circle-two.js", + "dependencyTypes": ["local", "require"] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/commonjs/circle-three.js", + "dependencyTypes": ["local", "require"] + } ] } ], diff --git a/test/main/__fixtures__/cruise-reporterless/folder.json b/test/main/__fixtures__/cruise-reporterless/folder.json index 277c35c93..c4c0dd729 100644 --- a/test/main/__fixtures__/cruise-reporterless/folder.json +++ b/test/main/__fixtures__/cruise-reporterless/folder.json @@ -769,8 +769,14 @@ "instability": 0.875, "circular": true, "cycle": [ - "test/main/__mocks__/cruise-reporterless/folder/unstable", - "test/main/__mocks__/cruise-reporterless/folder/stable" + { + "name": "test/main/__mocks__/cruise-reporterless/folder/unstable", + "dependencyTypes": [] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/folder/stable", + "dependencyTypes": [] + } ], "valid": false, "rules": [ @@ -800,8 +806,14 @@ "valid": true, "circular": true, "cycle": [ - "test/main/__mocks__/cruise-reporterless/folder/stable", - "test/main/__mocks__/cruise-reporterless/folder/unstable" + { + "name": "test/main/__mocks__/cruise-reporterless/folder/stable", + "dependencyTypes": [] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/folder/unstable", + "dependencyTypes": [] + } ] }, { diff --git a/test/main/__fixtures__/cruise-reporterless/typescript.json b/test/main/__fixtures__/cruise-reporterless/typescript.json index 33e27179c..54a5731c6 100644 --- a/test/main/__fixtures__/cruise-reporterless/typescript.json +++ b/test/main/__fixtures__/cruise-reporterless/typescript.json @@ -209,8 +209,14 @@ "valid": true, "circular": true, "cycle": [ - "test/main/__mocks__/cruise-reporterless/typescript-circular-with-types/B.ts", - "test/main/__mocks__/cruise-reporterless/typescript-circular-with-types/A.ts" + { + "name": "test/main/__mocks__/cruise-reporterless/typescript-circular-with-types/B.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/typescript-circular-with-types/A.ts", + "dependencyTypes": ["local", "import"] + } ] } ], @@ -237,8 +243,14 @@ "valid": true, "circular": true, "cycle": [ - "test/main/__mocks__/cruise-reporterless/typescript-circular-with-types/A.ts", - "test/main/__mocks__/cruise-reporterless/typescript-circular-with-types/B.ts" + { + "name": "test/main/__mocks__/cruise-reporterless/typescript-circular-with-types/A.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "test/main/__mocks__/cruise-reporterless/typescript-circular-with-types/B.ts", + "dependencyTypes": ["local", "import"] + } ] } ], diff --git a/test/main/__mocks__/dynamic-imports/es/output.json b/test/main/__mocks__/dynamic-imports/es/output.json index aefa498b7..af503a117 100644 --- a/test/main/__mocks__/dynamic-imports/es/output.json +++ b/test/main/__mocks__/dynamic-imports/es/output.json @@ -16,9 +16,18 @@ "matchesDoNotFollow": false, "circular": true, "cycle": [ - "src/index.js", - "src/dynamic-to-circular.js", - "src/circular.js" + { + "name": "src/index.js", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/dynamic-to-circular.js", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/circular.js", + "dependencyTypes": ["local", "dynamic-import"] + } ], "valid": false, "rules": [{ "severity": "info", "name": "no-circular" }] @@ -44,9 +53,18 @@ "matchesDoNotFollow": false, "circular": true, "cycle": [ - "src/dynamic-to-circular.js", - "src/circular.js", - "src/index.js" + { + "name": "src/dynamic-to-circular.js", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/circular.js", + "dependencyTypes": ["local", "dynamic-import"] + }, + { + "name": "src/index.js", + "dependencyTypes": ["local", "import"] + } ], "valid": false, "rules": [{ "severity": "info", "name": "no-circular" }] @@ -72,9 +90,18 @@ "matchesDoNotFollow": false, "circular": true, "cycle": [ - "src/circular.js", - "src/index.js", - "src/dynamic-to-circular.js" + { + "name": "src/circular.js", + "dependencyTypes": ["local", "dynamic-import"] + }, + { + "name": "src/index.js", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/dynamic-to-circular.js", + "dependencyTypes": ["local", "import"] + } ], "valid": false, "rules": [{ "severity": "warn", "name": "no-dynamic" }] @@ -99,9 +126,18 @@ "to": "src/index.js", "rule": { "severity": "info", "name": "no-circular" }, "cycle": [ - "src/index.js", - "src/dynamic-to-circular.js", - "src/circular.js" + { + "name": "src/index.js", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/dynamic-to-circular.js", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/circular.js", + "dependencyTypes": ["local", "dynamic-import"] + } ] } ], diff --git a/test/main/__mocks__/dynamic-imports/typescript/output-pre-compilation-deps.json b/test/main/__mocks__/dynamic-imports/typescript/output-pre-compilation-deps.json index d9b55a1f6..9e25a644e 100644 --- a/test/main/__mocks__/dynamic-imports/typescript/output-pre-compilation-deps.json +++ b/test/main/__mocks__/dynamic-imports/typescript/output-pre-compilation-deps.json @@ -16,9 +16,18 @@ "matchesDoNotFollow": false, "circular": true, "cycle": [ - "src/index.ts", - "src/dynamic-to-circular.ts", - "src/circular.ts" + { + "name": "src/index.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/dynamic-to-circular.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/circular.ts", + "dependencyTypes": ["local", "dynamic-import"] + } ], "valid": false, "rules": [{ "severity": "info", "name": "no-circular" }] @@ -44,9 +53,18 @@ "matchesDoNotFollow": false, "circular": true, "cycle": [ - "src/dynamic-to-circular.ts", - "src/circular.ts", - "src/index.ts" + { + "name": "src/dynamic-to-circular.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/circular.ts", + "dependencyTypes": ["local", "dynamic-import"] + }, + { + "name": "src/index.ts", + "dependencyTypes": ["local", "import"] + } ], "valid": false, "rules": [{ "severity": "info", "name": "no-circular" }] @@ -72,9 +90,18 @@ "matchesDoNotFollow": false, "circular": true, "cycle": [ - "src/circular.ts", - "src/index.ts", - "src/dynamic-to-circular.ts" + { + "name": "src/circular.ts", + "dependencyTypes": ["local", "dynamic-import"] + }, + { + "name": "src/index.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/dynamic-to-circular.ts", + "dependencyTypes": ["local", "import"] + } ], "valid": false, "rules": [{ "severity": "warn", "name": "no-dynamic" }] @@ -99,9 +126,18 @@ "to": "src/index.ts", "rule": { "severity": "info", "name": "no-circular" }, "cycle": [ - "src/index.ts", - "src/dynamic-to-circular.ts", - "src/circular.ts" + { + "name": "src/index.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/dynamic-to-circular.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/circular.ts", + "dependencyTypes": ["local", "dynamic-import"] + } ] } ], diff --git a/test/main/__mocks__/dynamic-imports/typescript/output.json b/test/main/__mocks__/dynamic-imports/typescript/output.json index c6e8f75e1..3956ef392 100644 --- a/test/main/__mocks__/dynamic-imports/typescript/output.json +++ b/test/main/__mocks__/dynamic-imports/typescript/output.json @@ -16,9 +16,18 @@ "matchesDoNotFollow": false, "circular": true, "cycle": [ - "src/index.ts", - "src/dynamic-to-circular.ts", - "src/circular.ts" + { + "name": "src/index.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/dynamic-to-circular.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/circular.ts", + "dependencyTypes": ["local", "dynamic-import"] + } ], "valid": false, "rules": [{ "severity": "info", "name": "no-circular" }] @@ -44,9 +53,18 @@ "matchesDoNotFollow": false, "circular": true, "cycle": [ - "src/dynamic-to-circular.ts", - "src/circular.ts", - "src/index.ts" + { + "name": "src/dynamic-to-circular.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/circular.ts", + "dependencyTypes": ["local", "dynamic-import"] + }, + { + "name": "src/index.ts", + "dependencyTypes": ["local", "import"] + } ], "valid": false, "rules": [{ "severity": "info", "name": "no-circular" }] @@ -72,9 +90,18 @@ "matchesDoNotFollow": false, "circular": true, "cycle": [ - "src/circular.ts", - "src/index.ts", - "src/dynamic-to-circular.ts" + { + "name": "src/circular.ts", + "dependencyTypes": ["local", "dynamic-import"] + }, + { + "name": "src/index.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/dynamic-to-circular.ts", + "dependencyTypes": ["local", "import"] + } ], "valid": false, "rules": [{ "severity": "warn", "name": "no-dynamic" }] @@ -99,9 +126,18 @@ "to": "src/index.ts", "rule": { "severity": "info", "name": "no-circular" }, "cycle": [ - "src/index.ts", - "src/dynamic-to-circular.ts", - "src/circular.ts" + { + "name": "src/index.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/dynamic-to-circular.ts", + "dependencyTypes": ["local", "import"] + }, + { + "name": "src/circular.ts", + "dependencyTypes": ["local", "dynamic-import"] + } ] } ], diff --git a/test/main/main.cruise.dynamic-imports.spec.mjs b/test/main/main.cruise.dynamic-imports.spec.mjs index 5b968c02b..8ae0c4cff 100644 --- a/test/main/main.cruise.dynamic-imports.spec.mjs +++ b/test/main/main.cruise.dynamic-imports.spec.mjs @@ -98,8 +98,9 @@ describe("[E] main.cruise - dynamic imports", () => { { bustTheCache: true }, ); - deepEqual(lResult.output, tsOut); ajv.validate(cruiseResultSchema, lResult.output); + + deepEqual(lResult.output, tsOut); }); it("detects dynamic dependencies in typescript when using tsPreCompilationDeps", async () => { @@ -134,7 +135,7 @@ describe("[E] main.cruise - dynamic imports", () => { { bustTheCache: true }, ); - deepEqual(lResult.output, tsOutpre); ajv.validate(cruiseResultSchema, lResult.output); + deepEqual(lResult.output, tsOutpre); }); }); diff --git a/test/report/anon/__fixtures__/cycle.mjs b/test/report/anon/__fixtures__/cycle.mjs index f3ebdc647..a5a1cc59f 100644 --- a/test/report/anon/__fixtures__/cycle.mjs +++ b/test/report/anon/__fixtures__/cycle.mjs @@ -14,7 +14,16 @@ export default { dynamic: false, matchesDoNotFollow: false, circular: true, - cycle: ["src/foo.js", "src/bar.js"], + cycle: [ + { + name: "src/foo.js", + dependencyTypes: ["local"], + }, + { + name: "src/bar.js", + dependencyTypes: ["local"], + }, + ], exoticallyRequired: false, valid: false, rules: [ @@ -42,7 +51,16 @@ export default { dynamic: false, matchesDoNotFollow: false, circular: true, - cycle: ["src/bar.js", "src/foo.js"], + cycle: [ + { + name: "src/bar.js", + dependencyTypes: ["local"], + }, + { + name: "src/foo.js", + dependencyTypes: ["local"], + }, + ], exoticallyRequired: false, valid: false, rules: [ @@ -78,7 +96,16 @@ export default { severity: "warn", name: "no-circular", }, - cycle: ["src/foo.js", "src/bar.js"], + cycle: [ + { + name: "src/foo.js", + dependencyTypes: ["local"], + }, + { + name: "src/bar.js", + dependencyTypes: ["local"], + }, + ], }, { from: "src/foo.js", @@ -87,7 +114,16 @@ export default { severity: "warn", name: "no-circular", }, - cycle: ["src/bar.js", "src/foo.js"], + cycle: [ + { + name: "src/bar.js", + dependencyTypes: ["local"], + }, + { + name: "src/foo.js", + dependencyTypes: ["local"], + }, + ], }, { from: "src/baz.js", diff --git a/test/report/anon/__fixtures__/folder-cycles.mjs b/test/report/anon/__fixtures__/folder-cycles.mjs index 8d58f99bb..9e0ecfaf4 100644 --- a/test/report/anon/__fixtures__/folder-cycles.mjs +++ b/test/report/anon/__fixtures__/folder-cycles.mjs @@ -100,7 +100,20 @@ export default { name: "foo", instability: 0.5, circular: true, - cycle: ["foo", "qux", "baz"], + cycle: [ + { + name: "foo", + dependencyTypes: [], + }, + { + name: "qux", + dependencyTypes: [], + }, + { + name: "baz", + dependencyTypes: [], + }, + ], valid: false, rules: [ { @@ -127,7 +140,20 @@ export default { name: "qux", instability: 0.5, circular: true, - cycle: ["qux", "baz", "foo"], + cycle: [ + { + name: "qux", + dependencyTypes: [], + }, + { + name: "baz", + dependencyTypes: [], + }, + { + name: "foo", + dependencyTypes: [], + }, + ], valid: false, rules: [ { @@ -154,7 +180,20 @@ export default { name: "baz", instability: 0.5, circular: true, - cycle: ["baz", "foo", "qux"], + cycle: [ + { + name: "baz", + dependencyTypes: [], + }, + { + name: "foo", + dependencyTypes: [], + }, + { + name: "qux", + dependencyTypes: [], + }, + ], valid: false, rules: [ { @@ -185,7 +224,20 @@ export default { severity: "warn", name: "no-folder-cycles", }, - cycle: ["foo", "qux", "baz"], + cycle: [ + { + name: "foo", + dependencyTypes: [], + }, + { + name: "qux", + dependencyTypes: [], + }, + { + name: "baz", + dependencyTypes: [], + }, + ], }, { type: "cycle", @@ -195,7 +247,20 @@ export default { severity: "warn", name: "no-folder-cycles", }, - cycle: ["baz", "foo", "qux"], + cycle: [ + { + name: "baz", + dependencyTypes: [], + }, + { + name: "foo", + dependencyTypes: [], + }, + { + name: "qux", + dependencyTypes: [], + }, + ], }, { type: "cycle", @@ -205,7 +270,20 @@ export default { severity: "warn", name: "no-folder-cycles", }, - cycle: ["qux", "baz", "foo"], + cycle: [ + { + name: "qux", + dependencyTypes: [], + }, + { + name: "baz", + dependencyTypes: [], + }, + { + name: "foo", + dependencyTypes: [], + }, + ], }, ], error: 0, diff --git a/test/report/anon/__mocks__/cycle.mjs b/test/report/anon/__mocks__/cycle.mjs index 61218b4cb..fc1c8fbf3 100644 --- a/test/report/anon/__mocks__/cycle.mjs +++ b/test/report/anon/__mocks__/cycle.mjs @@ -1,150 +1,164 @@ export default { - "modules": [ + modules: [ { - "source": "src/entrypoint.js", - "dependencies": [ + source: "src/entrypoint.js", + dependencies: [ { - "resolved": "src/yo.js", - "coreModule": false, - "followable": true, - "couldNotResolve": false, - "dependencyTypes": ["local"], - "module": "./yo", - "moduleSystem": "cjs", - "dynamic": false, - "matchesDoNotFollow": false, - "circular": true, - "cycle": ["src/yo.js", "src/entrypoint.js"], - "exoticallyRequired": false, - "valid": false, - "rules": [ + resolved: "src/yo.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + module: "./yo", + moduleSystem: "cjs", + dynamic: false, + matchesDoNotFollow: false, + circular: true, + cycle: [ + { name: "src/yo.js", dependencyTypes: ["local"] }, + { name: "src/entrypoint.js", dependencyTypes: ["local"] }, + ], + exoticallyRequired: false, + valid: false, + rules: [ { - "severity": "warn", - "name": "no-circular" - } - ] - } + severity: "warn", + name: "no-circular", + }, + ], + }, ], - "orphan": false, - "valid": true + orphan: false, + valid: true, }, { - "source": "src/yo.js", - "dependencies": [ + source: "src/yo.js", + dependencies: [ { - "resolved": "src/entrypoint.js", - "coreModule": false, - "followable": true, - "couldNotResolve": false, - "dependencyTypes": ["local"], - "module": "./entrypoint", - "moduleSystem": "cjs", - "dynamic": false, - "matchesDoNotFollow": false, - "circular": true, - "cycle": ["src/entrypoint.js", "src/yo.js"], - "exoticallyRequired": false, - "valid": false, - "rules": [ + resolved: "src/entrypoint.js", + coreModule: false, + followable: true, + couldNotResolve: false, + dependencyTypes: ["local"], + module: "./entrypoint", + moduleSystem: "cjs", + dynamic: false, + matchesDoNotFollow: false, + circular: true, + cycle: [ + { name: "src/entrypoint.js", dependencyTypes: ["local"] }, + { name: "src/yo.js", dependencyTypes: ["local"] }, + ], + exoticallyRequired: false, + valid: false, + rules: [ { - "severity": "warn", - "name": "no-circular" - } - ] - } + severity: "warn", + name: "no-circular", + }, + ], + }, ], - "orphan": false, - "valid": true + orphan: false, + valid: true, }, { - "source": "src/remi.js", - "dependencies": [], - "orphan": true, - "valid": false, - "rules": [ + source: "src/remi.js", + dependencies: [], + orphan: true, + valid: false, + rules: [ { - "severity": "warn", - "name": "no-orphans" - } - ] - } + severity: "warn", + name: "no-orphans", + }, + ], + }, ], - "summary": { - "violations": [ + summary: { + violations: [ { - "from": "src/entrypoint.js", - "to": "src/yo.js", - "rule": { - "severity": "warn", - "name": "no-circular" + from: "src/entrypoint.js", + to: "src/yo.js", + rule: { + severity: "warn", + name: "no-circular", }, - "cycle": ["src/yo.js", "src/entrypoint.js"] + cycle: [ + { name: "src/yo.js", dependencyTypes: ["local"] }, + { name: "src/entrypoint.js", dependencyTypes: ["local"] }, + ], }, { - "from": "src/yo.js", - "to": "src/entrypoint.js", - "rule": { - "severity": "warn", - "name": "no-circular" + from: "src/yo.js", + to: "src/entrypoint.js", + rule: { + severity: "warn", + name: "no-circular", }, - "cycle": ["src/entrypoint.js", "src/yo.js"] + cycle: [ + { name: "src/entrypoint.js", dependencyTypes: ["local"] }, + { name: "src/yo.js", dependencyTypes: ["local"] }, + ], }, { - "from": "src/remi.js", - "to": "src/remi.js", - "rule": { - "severity": "warn", - "name": "no-orphans" - } - } + from: "src/remi.js", + to: "src/remi.js", + rule: { + severity: "warn", + name: "no-orphans", + }, + }, ], - "error": 0, - "warn": 3, - "info": 0, - "totalCruised": 3, - "totalDependenciesCruised": 2, - "optionsUsed": { - "combinedDependencies": false, - "doNotFollow": { - "dependencyTypes": [ + error: 0, + warn: 3, + info: 0, + totalCruised: 3, + totalDependenciesCruised: 2, + optionsUsed: { + combinedDependencies: false, + doNotFollow: { + dependencyTypes: [ "npm", "npm-dev", "npm-optional", "npm-peer", "npm-bundled", - "npm-no-pkg" - ] + "npm-no-pkg", + ], }, - "externalModuleResolutionStrategy": "node_modules", - "moduleSystems": ["amd", "cjs", "es6"], - "outputTo": "-", - "outputType": "json", - "preserveSymlinks": false, - "rulesFile": ".dependency-cruiser.js", - "tsPreCompilationDeps": false, - "args": "src" + externalModuleResolutionStrategy: "node_modules", + moduleSystems: ["amd", "cjs", "es6"], + outputTo: "-", + outputType: "json", + preserveSymlinks: false, + rulesFile: ".dependency-cruiser.js", + tsPreCompilationDeps: false, + args: "src", }, - "ruleSetUsed": { - "forbidden": [ + ruleSetUsed: { + forbidden: [ { - "name": "no-circular", - "severity": "warn", - "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) ", - "from": {}, - "to": { - "circular": true - } + name: "no-circular", + severity: "warn", + 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) ", + from: {}, + to: { + circular: true, + }, }, { - "name": "no-orphans", - "severity": "warn", - "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) ", - "from": { - "orphan": true + name: "no-orphans", + severity: "warn", + 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) ", + from: { + orphan: true, }, - "to": {} - } - ] - } - } -} + to: {}, + }, + ], + }, + }, +}; diff --git a/test/report/anon/__mocks__/folder-cycles.mjs b/test/report/anon/__mocks__/folder-cycles.mjs index 5bf64c89a..fe2bec485 100644 --- a/test/report/anon/__mocks__/folder-cycles.mjs +++ b/test/report/anon/__mocks__/folder-cycles.mjs @@ -97,7 +97,11 @@ export default { name: "cycle-two", instability: 0.5, circular: true, - cycle: ["cycle-two", "cycle-three", "cycle-one"], + cycle: [ + { name: "cycle-two", dependencyTypes: [] }, + { name: "cycle-three", dependencyTypes: [] }, + { name: "cycle-one", dependencyTypes: [] }, + ], valid: false, rules: [ { @@ -124,7 +128,11 @@ export default { name: "cycle-three", instability: 0.5, circular: true, - cycle: ["cycle-three", "cycle-one", "cycle-two"], + cycle: [ + { name: "cycle-three", dependencyTypes: [] }, + { name: "cycle-one", dependencyTypes: [] }, + { name: "cycle-two", dependencyTypes: [] }, + ], valid: false, rules: [ { @@ -151,7 +159,11 @@ export default { name: "cycle-one", instability: 0.5, circular: true, - cycle: ["cycle-one", "cycle-two", "cycle-three"], + cycle: [ + { name: "cycle-one", dependencyTypes: [] }, + { name: "cycle-two", dependencyTypes: [] }, + { name: "cycle-three", dependencyTypes: [] }, + ], valid: false, rules: [ { @@ -182,7 +194,11 @@ export default { severity: "warn", name: "no-folder-cycles", }, - cycle: ["cycle-two", "cycle-three", "cycle-one"], + cycle: [ + { name: "cycle-two", dependencyTypes: [] }, + { name: "cycle-three", dependencyTypes: [] }, + { name: "cycle-one", dependencyTypes: [] }, + ], }, { type: "cycle", @@ -192,7 +208,11 @@ export default { severity: "warn", name: "no-folder-cycles", }, - cycle: ["cycle-one", "cycle-two", "cycle-three"], + cycle: [ + { name: "cycle-one", dependencyTypes: [] }, + { name: "cycle-two", dependencyTypes: [] }, + { name: "cycle-three", dependencyTypes: [] }, + ], }, { type: "cycle", @@ -202,7 +222,11 @@ export default { severity: "warn", name: "no-folder-cycles", }, - cycle: ["cycle-three", "cycle-one", "cycle-two"], + cycle: [ + { name: "cycle-three", dependencyTypes: [] }, + { name: "cycle-one", dependencyTypes: [] }, + { name: "cycle-two", dependencyTypes: [] }, + ], }, ], error: 0, diff --git a/test/report/azure-devops/__mocks__/circular-deps.mjs b/test/report/azure-devops/__mocks__/circular-deps.mjs index 16e565a84..0dedd41e5 100644 --- a/test/report/azure-devops/__mocks__/circular-deps.mjs +++ b/test/report/azure-devops/__mocks__/circular-deps.mjs @@ -14,9 +14,9 @@ export default { moduleSystem: "es6", valid: true, cycle: [ - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, ], rules: [ { @@ -42,9 +42,9 @@ export default { moduleSystem: "es6", valid: true, cycle: [ - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, ], rules: [ { @@ -70,9 +70,9 @@ export default { moduleSystem: "es6", valid: false, cycle: [ - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, ], rules: [ { @@ -96,9 +96,9 @@ export default { name: "no-circular", }, cycle: [ - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, ], }, { @@ -110,9 +110,9 @@ export default { name: "no-circular", }, cycle: [ - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, ], }, { @@ -124,9 +124,9 @@ export default { name: "no-circular", }, cycle: [ - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, ], }, ], diff --git a/test/report/error-html/__mocks__/orphans-cycles-metrics.mjs b/test/report/error-html/__mocks__/orphans-cycles-metrics.mjs index f33d25e1e..9c915ca6d 100644 --- a/test/report/error-html/__mocks__/orphans-cycles-metrics.mjs +++ b/test/report/error-html/__mocks__/orphans-cycles-metrics.mjs @@ -1771,7 +1771,13 @@ export default { name: "src/extract/transpile", instability: 0.25, circular: true, - cycle: ["src/extract/transpile", "src/extract/parse"], + cycle: [ + { + name: "src/extract/transpile", + dependencyTypes: ["local", "import"], + }, + { name: "src/extract/parse", dependencyTypes: ["local", "import"] }, + ], valid: false, rules: [ { @@ -1807,7 +1813,13 @@ export default { name: "src/extract/parse", instability: 0.36363636363636365, circular: true, - cycle: ["src/extract/parse", "src/extract/transpile"], + cycle: [ + { name: "src/extract/parse", dependencyTypes: ["local", "import"] }, + { + name: "src/extract/transpile", + dependencyTypes: ["local", "import"], + }, + ], valid: false, rules: [ { @@ -1936,7 +1948,13 @@ export default { severity: "warn", name: "no-folder-cycles", }, - cycle: ["src/extract/transpile", "src/extract/parse"], + cycle: [ + { + name: "src/extract/transpile", + dependencyTypes: ["local", "import"], + }, + { name: "src/extract/parse", dependencyTypes: ["local", "import"] }, + ], }, { type: "cycle", @@ -1946,7 +1964,13 @@ export default { severity: "warn", name: "no-folder-cycles", }, - cycle: ["src/extract/parse", "src/extract/transpile"], + cycle: [ + { name: "src/extract/parse", dependencyTypes: ["local", "import"] }, + { + name: "src/extract/transpile", + dependencyTypes: ["local", "import"], + }, + ], }, { type: "instability", diff --git a/test/report/error-html/utl.spec.mjs b/test/report/error-html/utl.spec.mjs index f6ee2b4c6..6db00bf91 100644 --- a/test/report/error-html/utl.spec.mjs +++ b/test/report/error-html/utl.spec.mjs @@ -161,7 +161,12 @@ describe("[U] report/error-html/utl", () => { it("determineTo - circular violation", () => { const lInputViolation = { type: "cycle", - cycle: ["thing/a", "b", "thingy/bingy/c", "a"], + cycle: [ + { name: "thing/a", dependencyTypes: ["local", "import"] }, + { name: "b", dependencyTypes: ["local", "import"] }, + { name: "thingy/bingy/c", dependencyTypes: ["local", "import"] }, + { name: "a", dependencyTypes: ["local", "import"] }, + ], from: "a", to: "thing/a", }; diff --git a/test/report/error/__mocks__/circular-deps.mjs b/test/report/error/__mocks__/circular-deps.mjs index 16e565a84..0dedd41e5 100644 --- a/test/report/error/__mocks__/circular-deps.mjs +++ b/test/report/error/__mocks__/circular-deps.mjs @@ -14,9 +14,9 @@ export default { moduleSystem: "es6", valid: true, cycle: [ - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, ], rules: [ { @@ -42,9 +42,9 @@ export default { moduleSystem: "es6", valid: true, cycle: [ - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, ], rules: [ { @@ -70,9 +70,9 @@ export default { moduleSystem: "es6", valid: false, cycle: [ - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, ], rules: [ { @@ -96,9 +96,9 @@ export default { name: "no-circular", }, cycle: [ - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, ], }, { @@ -110,9 +110,9 @@ export default { name: "no-circular", }, cycle: [ - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, ], }, { @@ -124,9 +124,9 @@ export default { name: "no-circular", }, cycle: [ - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, ], }, ], diff --git a/test/report/markdown/__mocks__/orphans-cycles-metrics.mjs b/test/report/markdown/__mocks__/orphans-cycles-metrics.mjs index f33d25e1e..9c915ca6d 100644 --- a/test/report/markdown/__mocks__/orphans-cycles-metrics.mjs +++ b/test/report/markdown/__mocks__/orphans-cycles-metrics.mjs @@ -1771,7 +1771,13 @@ export default { name: "src/extract/transpile", instability: 0.25, circular: true, - cycle: ["src/extract/transpile", "src/extract/parse"], + cycle: [ + { + name: "src/extract/transpile", + dependencyTypes: ["local", "import"], + }, + { name: "src/extract/parse", dependencyTypes: ["local", "import"] }, + ], valid: false, rules: [ { @@ -1807,7 +1813,13 @@ export default { name: "src/extract/parse", instability: 0.36363636363636365, circular: true, - cycle: ["src/extract/parse", "src/extract/transpile"], + cycle: [ + { name: "src/extract/parse", dependencyTypes: ["local", "import"] }, + { + name: "src/extract/transpile", + dependencyTypes: ["local", "import"], + }, + ], valid: false, rules: [ { @@ -1936,7 +1948,13 @@ export default { severity: "warn", name: "no-folder-cycles", }, - cycle: ["src/extract/transpile", "src/extract/parse"], + cycle: [ + { + name: "src/extract/transpile", + dependencyTypes: ["local", "import"], + }, + { name: "src/extract/parse", dependencyTypes: ["local", "import"] }, + ], }, { type: "cycle", @@ -1946,7 +1964,13 @@ export default { severity: "warn", name: "no-folder-cycles", }, - cycle: ["src/extract/parse", "src/extract/transpile"], + cycle: [ + { name: "src/extract/parse", dependencyTypes: ["local", "import"] }, + { + name: "src/extract/transpile", + dependencyTypes: ["local", "import"], + }, + ], }, { type: "instability", diff --git a/test/report/teamcity/__mocks__/circular-deps.mjs b/test/report/teamcity/__mocks__/circular-deps.mjs index 16e565a84..0dedd41e5 100644 --- a/test/report/teamcity/__mocks__/circular-deps.mjs +++ b/test/report/teamcity/__mocks__/circular-deps.mjs @@ -14,9 +14,9 @@ export default { moduleSystem: "es6", valid: true, cycle: [ - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, ], rules: [ { @@ -42,9 +42,9 @@ export default { moduleSystem: "es6", valid: true, cycle: [ - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, ], rules: [ { @@ -70,9 +70,9 @@ export default { moduleSystem: "es6", valid: false, cycle: [ - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, ], rules: [ { @@ -96,9 +96,9 @@ export default { name: "no-circular", }, cycle: [ - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, ], }, { @@ -110,9 +110,9 @@ export default { name: "no-circular", }, cycle: [ - "src/some/folder/loop-b.js", - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, ], }, { @@ -124,9 +124,9 @@ export default { name: "no-circular", }, cycle: [ - "src/some/folder/nested/center.js", - "src/some/folder/loop-a.js", - "src/some/folder/loop-b.js", + { name: "src/some/folder/nested/center.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-a.js", dependencyTypes: [] }, + { name: "src/some/folder/loop-b.js", dependencyTypes: [] }, ], }, ], diff --git a/test/validate/index.cycle-via-not.spec.mjs b/test/validate/index.cycle-via-not.spec.mjs index f4111cae9..6edc4d6cf 100644 --- a/test/validate/index.cycle-via-not.spec.mjs +++ b/test/validate/index.cycle-via-not.spec.mjs @@ -2,6 +2,13 @@ import { deepEqual } from "node:assert/strict"; import parseRuleSet from "./parse-ruleset.utl.mjs"; import validate from "#validate/index.mjs"; +function stringToCycleEntry(pString) { + return { + name: pString, + dependencyTypes: [], + }; +} + describe("[I] validate/index dependency - cycle viaNot", () => { const lCycleViaNotRuleSet = parseRuleSet({ forbidden: [ @@ -22,7 +29,9 @@ describe("[I] validate/index dependency - cycle viaNot", () => { { resolved: "tmp/ba.js", circular: true, - cycle: ["tmp/ba.js", "tmp/bb.js", "tmp/bc.js", "tmp/a.js"], + cycle: ["tmp/ba.js", "tmp/bb.js", "tmp/bc.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -40,7 +49,9 @@ describe("[I] validate/index dependency - cycle viaNot", () => { { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"], + cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -74,7 +85,7 @@ describe("[I] validate/index dependency - cycle viaNot - with group matching", ( "src/module-b/bb.js", "src/module-b/bc.js", "src/module-a/a.js", - ], + ].map(stringToCycleEntry), }, ), { @@ -96,7 +107,7 @@ describe("[I] validate/index dependency - cycle viaNot - with group matching", ( "src/module-a/ab.js", "src/module-b/bc.js", "src/module-a/a.js", - ], + ].map(stringToCycleEntry), }, ), { @@ -118,7 +129,7 @@ describe("[I] validate/index dependency - cycle viaNot - with group matching", ( "src/module-a/ab.js", "src/module-a/ac.js", "src/module-a/a.js", - ], + ].map(stringToCycleEntry), }, ), { diff --git a/test/validate/index.cycle-via-some-not.spec.mjs b/test/validate/index.cycle-via-some-not.spec.mjs index a690e669a..47b177e3c 100644 --- a/test/validate/index.cycle-via-some-not.spec.mjs +++ b/test/validate/index.cycle-via-some-not.spec.mjs @@ -2,6 +2,13 @@ import { deepEqual } from "node:assert/strict"; import parseRuleSet from "./parse-ruleset.utl.mjs"; import validate from "#validate/index.mjs"; +function stringToCycleEntry(pString) { + return { + name: pString, + dependencyTypes: [], + }; +} + describe("[I] validate/index dependency - cycle viaSomeNot - with group matching", () => { const lCycleButNotViaGroupMatchRuleSet = { forbidden: [ @@ -26,7 +33,7 @@ describe("[I] validate/index dependency - cycle viaSomeNot - with group matching "src/module-b/bb.js", "src/module-b/bc.js", "src/module-a/a.js", - ], + ].map(stringToCycleEntry), }, ), { @@ -54,7 +61,7 @@ describe("[I] validate/index dependency - cycle viaSomeNot - with group matching "src/module-a/ab.js", "src/module-b/bc.js", "src/module-a/a.js", - ], + ].map(stringToCycleEntry), }, ), { @@ -82,7 +89,7 @@ describe("[I] validate/index dependency - cycle viaSomeNot - with group matching "src/module-a/ab.js", "src/module-a/ac.js", "src/module-a/a.js", - ], + ].map(stringToCycleEntry), }, ), { @@ -116,7 +123,7 @@ describe("[I] validate/index dependency - cycle viaSomeNot - with group matching "src/module-a/ab.js", "src/module-a/ac.js", "src/module-a/a.js", - ], + ].map(stringToCycleEntry), }, ), { diff --git a/test/validate/index.cycle-via.spec.mjs b/test/validate/index.cycle-via.spec.mjs index f48ec4081..8ecb2875a 100644 --- a/test/validate/index.cycle-via.spec.mjs +++ b/test/validate/index.cycle-via.spec.mjs @@ -2,6 +2,13 @@ import { deepEqual } from "node:assert/strict"; import parseRuleSet from "./parse-ruleset.utl.mjs"; import validate from "#validate/index.mjs"; +function stringToCycleEntry(pString) { + return { + name: pString, + dependencyTypes: [], + }; +} + describe("[I] validate/index dependency - cycle via", () => { const lCycleViaRuleSet = parseRuleSet({ forbidden: [ @@ -23,7 +30,9 @@ describe("[I] validate/index dependency - cycle via", () => { { resolved: "tmp/ba.js", circular: true, - cycle: ["tmp/ba.js", "tmp/bb.js", "tmp/bc.js", "tmp/a.js"], + cycle: ["tmp/ba.js", "tmp/bb.js", "tmp/bc.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -40,7 +49,9 @@ describe("[I] validate/index dependency - cycle via", () => { { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"], + cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -69,7 +80,9 @@ describe("[I] validate/index dependency - cycle via", () => { { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"], + cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -103,7 +116,9 @@ describe("[I] validate/index dependency - cycle via - with group matching", () = { resolved: "tmp/ba.js", circular: true, - cycle: ["tmp/ba.js", "tmp/bb.js", "tmp/bc.js", "tmp/a.js"], + cycle: ["tmp/ba.js", "tmp/bb.js", "tmp/bc.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -120,7 +135,9 @@ describe("[I] validate/index dependency - cycle via - with group matching", () = { resolved: "tmp/ba.js", circular: true, - cycle: ["tmp/ba.js", "not-tmp/ab.js", "tmp/bc.js", "tmp/a.js"], + cycle: ["tmp/ba.js", "not-tmp/ab.js", "tmp/bc.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -137,7 +154,9 @@ describe("[I] validate/index dependency - cycle via - with group matching", () = { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"], + cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -166,7 +185,9 @@ describe("[I] validate/index dependency - cycle via - with group matching", () = { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"], + cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -198,7 +219,9 @@ describe("[I] validate/index dependency - cycle viaOnly", () => { { resolved: "tmp/ba.js", circular: true, - cycle: ["tmp/ba.js", "tmp/bb.js", "tmp/bc.js", "tmp/a.js"], + cycle: ["tmp/ba.js", "tmp/bb.js", "tmp/bc.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -215,7 +238,9 @@ describe("[I] validate/index dependency - cycle viaOnly", () => { { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"], + cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -232,7 +257,7 @@ describe("[I] validate/index dependency - cycle viaOnly", () => { { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/ab.js", "tmp/a.js"], + cycle: ["tmp/ab.js", "tmp/a.js"].map(stringToCycleEntry), }, ), { @@ -260,7 +285,9 @@ describe("[I] validate/index dependency - cycle viaOnly", () => { { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"], + cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -293,7 +320,9 @@ describe("[I] validate/index dependency - cycle viaOnly - with group matching", { resolved: "tmp/ba.js", circular: true, - cycle: ["tmp/ba.js", "tmp/bb.js", "tmp/bc.js", "tmp/a.js"], + cycle: ["tmp/ba.js", "tmp/bb.js", "tmp/bc.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -310,7 +339,9 @@ describe("[I] validate/index dependency - cycle viaOnly - with group matching", { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"], + cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -327,7 +358,7 @@ describe("[I] validate/index dependency - cycle viaOnly - with group matching", { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/ab.js", "tmp/a.js"], + cycle: ["tmp/ab.js", "tmp/a.js"].map(stringToCycleEntry), }, ), { @@ -355,7 +386,9 @@ describe("[I] validate/index dependency - cycle viaOnly - with group matching", { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"], + cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { @@ -383,7 +416,9 @@ describe("[I] validate/index dependency - cycle viaOnly - with group matching", { resolved: "tmp/aa.js", circular: true, - cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"], + cycle: ["tmp/aa.js", "tmp/ab.js", "tmp/ac.js", "tmp/a.js"].map( + stringToCycleEntry, + ), }, ), { diff --git a/tools/schema/dependencies.mjs b/tools/schema/dependencies.mjs index 465300fd8..0df7a70e2 100644 --- a/tools/schema/dependencies.mjs +++ b/tools/schema/dependencies.mjs @@ -1,6 +1,7 @@ import dependencyType from "./dependency-type.mjs"; import moduleSystemType from "./module-system-type.mjs"; import ruleSummary from "./rule-summary.mjs"; +import miniDependency from "./mini-dependency-type.mjs"; export default { definitions: { @@ -137,7 +138,7 @@ export default { }, cycle: { type: "array", - items: { type: "string" }, + items: { $ref: "#/definitions/MiniDependency" }, description: "If following this dependency will ultimately return to the source " + "(circular === true), this attribute will contain an (ordered) array " + @@ -168,5 +169,6 @@ export default { ...dependencyType.definitions, ...moduleSystemType.definitions, ...ruleSummary.definitions, + ...miniDependency.definitions, }, }; diff --git a/tools/schema/folders.mjs b/tools/schema/folders.mjs index ff75306e8..8031340f0 100644 --- a/tools/schema/folders.mjs +++ b/tools/schema/folders.mjs @@ -1,4 +1,5 @@ import ruleSummary from "./rule-summary.mjs"; +import miniDependency from "./mini-dependency-type.mjs"; export default { definitions: { @@ -73,7 +74,7 @@ export default { }, cycle: { type: "array", - items: { type: "string" }, + items: { $ref: "#/definitions/MiniDependency" }, description: "If following this dependency will ultimately return to the source " + "(circular === true), this attribute will contain an (ordered) array " + @@ -123,5 +124,6 @@ export default { }, }, ...ruleSummary.definitions, + ...miniDependency.definitions, }, }; diff --git a/tools/schema/mini-dependency-type.mjs b/tools/schema/mini-dependency-type.mjs new file mode 100644 index 000000000..6d5d1dfc2 --- /dev/null +++ b/tools/schema/mini-dependency-type.mjs @@ -0,0 +1,29 @@ +import dependencyType from "./dependency-type.mjs"; + +export default { + definitions: { + MiniDependency: { + type: "object", + description: + "A small dependency object with the uniquely identifying name of the module +" + + "the dependency types it has relative to the _previous_ module in the chain " + + " it is part of (e.g. a cycle).", + required: ["name", "dependencyTypes"], + additionalProperties: false, + properties: { + name: { + type: "string", + description: "The name of the module", + }, + dependencyTypes: { + type: "array", + items: { $ref: "#/definitions/DependencyTypeType" }, + description: + "The dependency types of the module relative to the previous module " + + "in the chain it is a part of (e.g. a cycle)", + }, + }, + }, + ...dependencyType.definitions, + }, +}; diff --git a/tools/schema/violations.mjs b/tools/schema/violations.mjs index e3a0bf374..2b9641f6a 100644 --- a/tools/schema/violations.mjs +++ b/tools/schema/violations.mjs @@ -1,5 +1,6 @@ import ruleSummary from "./rule-summary.mjs"; import violationType from "./violation-type.mjs"; +import miniDependency from "./mini-dependency-type.mjs"; export default { definitions: { @@ -25,7 +26,7 @@ export default { rule: { $ref: "#/definitions/RuleSummaryType" }, cycle: { type: "array", - items: { type: "string" }, + items: { $ref: "#/definitions/MiniDependency" }, description: "The circular path if the violation is about circularity", }, @@ -68,5 +69,6 @@ export default { }, ...ruleSummary.definitions, ...violationType.definitions, + ...miniDependency.definitions, }, }; diff --git a/types/cruise-result.d.mts b/types/cruise-result.d.mts index a8786dcc6..9aa522afc 100644 --- a/types/cruise-result.d.mts +++ b/types/cruise-result.d.mts @@ -1,6 +1,7 @@ import type { ICruiseOptions } from "./options.mjs"; import type { IFlattenedRuleSet } from "./rule-set.mjs"; import type { + IMiniDependency, DependencyType, ModuleSystemType, ProtocolType, @@ -188,7 +189,7 @@ export interface IDependency { * this attribute will contain an (ordered) array of module names that shows (one of) the * circular path(s) */ - cycle?: string[]; + cycle?: IMiniDependency[]; /** * the type of inclusion - local, core, unknown (= we honestly don't know), undetermined (= * we didn't bother determining it) or one of the npm dependencies defined in a package.json @@ -391,7 +392,7 @@ export interface IFolderDependency { * this attribute will contain an (ordered) array of module names that shows (one of) the * circular path(s) */ - cycle?: string[]; + cycle?: IMiniDependency[]; /** * an array of rules violated by this dependency - left out if the dependency * is valid diff --git a/types/shared-types.d.mts b/types/shared-types.d.mts index d10ed8121..9fc966ea2 100644 --- a/types/shared-types.d.mts +++ b/types/shared-types.d.mts @@ -81,3 +81,15 @@ export type ViolationType = | "instability"; export type RuleScopeType = "module" | "folder"; + +export interface IMiniDependency { + /** + * The name of the module + */ + name: string; + /** + * The dependency types of the module relative to the previous module " + + * in the chain it is a part of (e.g. a cycle) + */ + dependencyTypes: DependencyType[]; +} diff --git a/types/violations.d.mts b/types/violations.d.mts index 0387de3eb..bcee21319 100644 --- a/types/violations.d.mts +++ b/types/violations.d.mts @@ -1,5 +1,5 @@ import type { IRuleSummary } from "./rule-summary.mjs"; -import type { ViolationType } from "./shared-types.mjs"; +import type { IMiniDependency, ViolationType } from "./shared-types.mjs"; export interface IMetricsSummary { from: { @@ -30,7 +30,7 @@ export interface IViolation { /** * The circular path if the violation is about circularity */ - cycle?: string[]; + cycle?: IMiniDependency[]; /** * The path from the from to the to if the violation is transitive */