Skip to content

Commit

Permalink
feat(config-utl): makes possibly old format known violations forward …
Browse files Browse the repository at this point in the history
…compatible (#890)

## Description, Motivation and Context

- makes possibly old format known violations forward compatible directly
after reading

... to prevent users from bumping into inexplicable errors. See the
comment in extract-known-violations.mjs for details.

## How Has This Been Tested?

- [x] green ci
- [x] additional 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)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
  • Loading branch information
sverweij committed Dec 18, 2023
1 parent c6421e3 commit 20e5b94
Show file tree
Hide file tree
Showing 4 changed files with 237 additions and 3 deletions.
46 changes: 43 additions & 3 deletions src/config-utl/extract-known-violations.mjs
Expand Up @@ -2,15 +2,55 @@ import { readFile } from "node:fs/promises";
import json5 from "json5";
import makeAbsolute from "./make-absolute.mjs";

/**
* @typedef {import("../../types/violations.d.mjs").IViolation} IViolation
* @typedef {import("../../types/shared-types.d.mts").DependencyType} DependencyType
*
* @typedef {IViolation & {cycle: Array<{name: string, dependencyTypes: Array<DependencyType>}>} | {cycle: Array<DependencyType>}} IMaybeOldFormatViolation
*/

/**
* cycles went from Array<string> to Array<{name: string, dependencyTypes: Array<DependencyType>}>
* in version 16.0.0. Known violations would typically be still in the old
* format. To prevent customers from bumping into error messages and having
* to update or regenerate their known violations, we'll make the old format
* forward compatible with this.
*
* @param {IMaybeOldFormatViolation} pKnownViolation
* @returns {IViolation}
*/
function makeForwardCompatible(pKnownViolation) {
if (Boolean(pKnownViolation.cycle)) {
return {
...pKnownViolation,
cycle: pKnownViolation.cycle.map((pModule) => {
if (Boolean(pModule.name)) {
return pModule;
}
return {
name: pModule,
dependencyTypes: [],
};
}),
};
}
return pKnownViolation;
}

export default async function extractKnownViolations(pKnownViolationsFileName) {
try {
return json5.parse(
await readFile(makeAbsolute(pKnownViolationsFileName), "utf8")
const lFileContents = await readFile(
makeAbsolute(pKnownViolationsFileName),
"utf8",
);
const lKnownViolations = json5.parse(lFileContents);
const lForwardCompatible = lKnownViolations.map(makeForwardCompatible);

return lForwardCompatible;
} catch (pError) {
if (pError instanceof SyntaxError) {
throw new SyntaxError(
`'${pKnownViolationsFileName}' should be valid json\n ${pError}`
`'${pKnownViolationsFileName}' should be valid json\n ${pError}`,
);
}
throw pError;
Expand Down
@@ -0,0 +1,47 @@
[
{
"type": "cycle",
"from": "tmp-errors/cycle-1.js",
"to": "tmp-errors/cycle-2.js",
"rule": {
"severity": "error",
"name": "no-circular"
},
"cycle": [
{
"name": "tmp-errors/cycle-2.js",
"dependencyTypes": ["local", "require"]
},
{
"name": "tmp-errors/cycle-3.js",
"dependencyTypes": ["local", "require"]
},
{
"name": "tmp-errors/cycle-4.js",
"dependencyTypes": ["local", "require"]
},
{
"name": "tmp-errors/cycle-1.js",
"dependencyTypes": ["local", "require"]
}
]
},
{
"type": "module",
"from": "tmp-errors/mod.mts",
"to": "tmp-errors/mod.mts",
"rule": {
"severity": "error",
"name": "no-orphans"
}
},
{
"type": "dependency",
"from": "tmp-errors/call-mod.mts",
"to": "./mod.mjs",
"rule": {
"severity": "error",
"name": "not-to-unresolvable"
}
}
]
@@ -0,0 +1,35 @@
[
{
"type": "cycle",
"from": "tmp-errors/cycle-1.js",
"to": "tmp-errors/cycle-2.js",
"rule": {
"severity": "error",
"name": "no-circular"
},
"cycle": [
"tmp-errors/cycle-2.js",
"tmp-errors/cycle-3.js",
"tmp-errors/cycle-4.js",
"tmp-errors/cycle-1.js"
]
},
{
"type": "module",
"from": "tmp-errors/mod.mts",
"to": "tmp-errors/mod.mts",
"rule": {
"severity": "error",
"name": "no-orphans"
}
},
{
"type": "dependency",
"from": "tmp-errors/call-mod.mts",
"to": "./mod.mjs",
"rule": {
"severity": "error",
"name": "not-to-unresolvable"
}
}
]
112 changes: 112 additions & 0 deletions test/config-utl/extract-known-violations.spec.mjs
Expand Up @@ -55,4 +55,116 @@ describe("[I] config-utl/extractKnownViolations", () => {
},
]);
});

it("Makes a forward compatible version of the known violations", async () => {
process.chdir("./test/config-utl/__mocks__/known-violations");
deepEqual(
await extractKnownViolations(
"known-violations-with-cycles-in-old-format.json",
),
[
{
type: "cycle",
from: "tmp-errors/cycle-1.js",
to: "tmp-errors/cycle-2.js",
rule: {
severity: "error",
name: "no-circular",
},
cycle: [
{
name: "tmp-errors/cycle-2.js",
dependencyTypes: [],
},
{
name: "tmp-errors/cycle-3.js",
dependencyTypes: [],
},
{
name: "tmp-errors/cycle-4.js",
dependencyTypes: [],
},
{
name: "tmp-errors/cycle-1.js",
dependencyTypes: [],
},
],
},
{
type: "module",
from: "tmp-errors/mod.mts",
to: "tmp-errors/mod.mts",
rule: {
severity: "error",
name: "no-orphans",
},
},
{
type: "dependency",
from: "tmp-errors/call-mod.mts",
to: "./mod.mjs",
rule: {
severity: "error",
name: "not-to-unresolvable",
},
},
],
);
});

it("Leaves new format cycles alone", async () => {
process.chdir("./test/config-utl/__mocks__/known-violations");
deepEqual(
await extractKnownViolations(
"known-violations-with-cycles-in-new-format.json",
),
[
{
type: "cycle",
from: "tmp-errors/cycle-1.js",
to: "tmp-errors/cycle-2.js",
rule: {
severity: "error",
name: "no-circular",
},
cycle: [
{
name: "tmp-errors/cycle-2.js",
dependencyTypes: ["local", "require"],
},
{
name: "tmp-errors/cycle-3.js",
dependencyTypes: ["local", "require"],
},
{
name: "tmp-errors/cycle-4.js",
dependencyTypes: ["local", "require"],
},
{
name: "tmp-errors/cycle-1.js",
dependencyTypes: ["local", "require"],
},
],
},
{
type: "module",
from: "tmp-errors/mod.mts",
to: "tmp-errors/mod.mts",
rule: {
severity: "error",
name: "no-orphans",
},
},
{
type: "dependency",
from: "tmp-errors/call-mod.mts",
to: "./mod.mjs",
rule: {
severity: "error",
name: "not-to-unresolvable",
},
},
],
);
});
});

0 comments on commit 20e5b94

Please sign in to comment.