Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(report/dot): adds ability to match arrays for conditional coloring #882

Merged
merged 1 commit into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion doc/options-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,9 @@ Most representational aspects of the 'dot' reporter are customizable:
- You can use any
[module attribute](https://github.com/sverweij/dependency-cruiser/blob/main/types/cruise-result.d.ts#L16)
and any [dependency attribute](https://github.com/sverweij/dependency-cruiser/blob/main/types/cruise-result.d.ts#L73)
for dependencies.
for dependencies in the criteria of those.
- If you provide an array of criteria for the attributes the module/ dependency
will be matched if it matches _any_ of the criteria.
- For attributes you can use anything GraphViz dot can understand as an attribute
(see their [attributes](https://graphviz.gitlab.io/_pages/doc/info/attrs.html)
documentation for a complete overview).
Expand Down
41 changes: 35 additions & 6 deletions src/report/dot/theming.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,42 @@ function matchesRE(pValue, pRE) {
return Boolean(lMatchResult) && lMatchResult.length > 0;
}

function matchesCriterion(pModuleKey, pCriterion) {
return pModuleKey === pCriterion || matchesRE(pModuleKey, pCriterion);
}

function moduleOrDependencyMatchesCriteria(pSchemeEntry, pModule) {
return Object.keys(pSchemeEntry.criteria).every(
(pKey) =>
(get(pModule, pKey) || has(pModule, pKey)) &&
(get(pModule, pKey) === get(pSchemeEntry.criteria, pKey) ||
matchesRE(get(pModule, pKey), get(pSchemeEntry.criteria, pKey))),
);
return Object.keys(pSchemeEntry.criteria).every((pKey) => {
// we use lodash.get here because in the criteria you can enter
// nested keys like "rules[0].severity" : "error", and lodash.get handles
// that for us
const lCriterion = get(pSchemeEntry.criteria, pKey);
const lModuleKey = get(pModule, pKey);

if (!(lModuleKey || has(pModule, pKey))) {
return false;
}

if (Array.isArray(lModuleKey)) {
if (Array.isArray(lCriterion)) {
return lCriterion.some((pCriterionEntry) =>
lModuleKey.some((pModuleKeyEntry) =>
matchesCriterion(pModuleKeyEntry, pCriterionEntry),
),
);
} else {
return lModuleKey.some((pModuleKeyEntry) =>
matchesCriterion(pModuleKeyEntry, lCriterion),
);
}
}
if (Array.isArray(lCriterion)) {
return lCriterion.some((pCriterionEntry) =>
matchesCriterion(lModuleKey, pCriterionEntry),
);
}
return matchesCriterion(lModuleKey, lCriterion);
});
}

function determineAttributes(pModuleOrDependency, pAttributeCriteria) {
Expand Down
173 changes: 173 additions & 0 deletions test/report/dot/theming.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,177 @@ describe("[U] report/dot/theming - determineModuleColors - default theme", () =>
theming.normalizeTheme({ graph: { someAttribute: 1234 } });
deepEqual(theming.normalizeTheme(), lOriginalDefaultTheme);
});

it("determines attributes when the property is a string and one of the criteria is an array", () => {
deepEqual(
theming.determineAttributes(
{ source: "package.json" },
theming.normalizeTheme({
modules: [
{
criteria: { source: ["package.json", "package-lock.json"] },
attributes: { fillcolor: "red" },
},
],
}).modules,
),
{ fillcolor: "red" },
);
});

it("determines attributes when the property is an array and one of the criteria is an array", () => {
deepEqual(
theming.determineAttributes(
{
source: "src/heide/does.js",
dependencyTypes: [
"local",
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-base-url",
],
},
theming.normalizeTheme({
modules: [
{
criteria: { dependencyTypes: ["aliased-tsconfig"] },
attributes: { fillcolor: "blue" },
},
],
}).modules,
),
{ fillcolor: "blue" },
);
});

it("determines attributes when the property is an array and one of the criteria is an array - on multiple it takes the logical OR", () => {
deepEqual(
theming.determineAttributes(
{
source: "src/heide/does.js",
dependencyTypes: [
"local",
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-base-url",
],
},
theming.normalizeTheme({
modules: [
{
criteria: {
dependencyTypes: [
"npm",
"aliased-workspace",
"aliased-tsconfig",
],
},
attributes: { fillcolor: "blue" },
},
],
}).modules,
),
{ fillcolor: "blue" },
);
});

it("determines attributes when the property is an array and one of the criteria is a regexy array", () => {
deepEqual(
theming.determineAttributes(
{
source: "src/heide/does.js",
dependencyTypes: [
"local",
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-base-url",
],
},
theming.normalizeTheme({
modules: [
{
criteria: { dependencyTypes: ["aliased-t.+"] },
attributes: { fillcolor: "blue" },
},
],
}).modules,
),
{ fillcolor: "blue" },
);
});

it("determines attributes when the property is an array and one of the criteria is a regexy array but there's no match", () => {
deepEqual(
theming.determineAttributes(
{
source: "src/heide/does.js",
dependencyTypes: [
"local",
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-base-url",
],
},
theming.normalizeTheme({
modules: [
{
criteria: { dependencyTypes: ["npm"] },
attributes: { fillcolor: "blue" },
},
],
}).modules,
),
{},
);
});

it("determines attributes when the property is an array and one of the criteria is a string", () => {
deepEqual(
theming.determineAttributes(
{
source: "src/heide/does.js",
dependencyTypes: [
"local",
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-base-url",
],
},
theming.normalizeTheme({
modules: [
{
criteria: { dependencyTypes: "aliased-tsconfig" },
attributes: { fillcolor: "blue" },
},
],
}).modules,
),
{ fillcolor: "blue" },
);
});

it("determines attributes when the property is an array and one of the criteria is a regexy string", () => {
deepEqual(
theming.determineAttributes(
{
source: "src/heide/does.js",
dependencyTypes: [
"local",
"aliased",
"aliased-tsconfig",
"aliased-tsconfig-base-url",
],
},
theming.normalizeTheme({
modules: [
{
criteria: { dependencyTypes: "aliased-tsconfig" },
attributes: { fillcolor: "blue" },
},
],
}).modules,
),
{ fillcolor: "blue" },
);
});
});