Skip to content

Commit

Permalink
feat: allow setting granularity per dependency type (#14)
Browse files Browse the repository at this point in the history
Co-authored-by: Idan Attias <idanat@google.com>
  • Loading branch information
idan-at and Idan Attias authored Oct 21, 2023
1 parent 5fad4e1 commit cfd23d6
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 38 deletions.
11 changes: 10 additions & 1 deletion __tests__/fixtures/controlled-versions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,14 @@
"bar": "^4.17.0",
"baz": "~4.17.0",
"ignored": "latest"
},
"devDependencies": {
"baz": "~1.0.0"
},
"peerDependencies": {
"bay": "~1.2.3"
},
"optionalDependencies": {
"bak": "~1.2.3"
}
}
}
44 changes: 17 additions & 27 deletions __tests__/integration_tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,38 +85,28 @@ describe("integration tests", () => {
const results = await createLiner(CONTROLLED_VERSIONS_FIXTURE_PATH, {
"package-json-dependencies/controlled-versions": [
"error",
{ granularity: "patch", excludePatterns: ["ignored"] },
{ granularity: { dependencies: "patch", devDepdendencies: "fixed" }, excludePatterns: ["ignored"] },
],
}).lintFiles("package.json");

expect(results).toHaveLength(1);
expect(results[0]).toHaveProperty("errorCount", 2);
expect(results[0]).toHaveProperty("errorCount", 5);
expect(results[0]).toHaveProperty("warningCount", 0);
expect(results[0].messages).toHaveLength(2);
expect(results[0].messages[0]).toHaveProperty(
"ruleId",
"package-json-dependencies/controlled-versions"
);
expect(results[0].messages[0]).toHaveProperty(
"messageId",
"nonControlledDependency"
);
expect(results[0].messages[0]).toHaveProperty(
"message",
"Non controlled version found for dependency 'foo'"
);
expect(results[0].messages[1]).toHaveProperty(
"ruleId",
"package-json-dependencies/controlled-versions"
);
expect(results[0].messages[1]).toHaveProperty(
"messageId",
"nonControlledDependency"
);
expect(results[0].messages[1]).toHaveProperty(
"message",
"Non controlled version found for dependency 'bar'"
);
expect(results[0].messages).toHaveLength(5);
for (const [i, dependency] of ["foo", "bar", "baz", "bay", "bak"].entries()) {
expect(results[0].messages[i]).toHaveProperty(
"ruleId",
"package-json-dependencies/controlled-versions"
);
expect(results[0].messages[i]).toHaveProperty(
"messageId",
"nonControlledDependency"
);
expect(results[0].messages[i]).toHaveProperty(
"message",
`Non controlled version found for dependency '${dependency}'`
);
}
});

test("better-alternative", async () => {
Expand Down
2 changes: 1 addition & 1 deletion docs/rules/controlled-versions.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ NOTE: This rule will update your dependencies' versions, if the --fix flag is pa


## Options
- `granularity`: `fixed` / `patch` / `minor`, as mentioned above. If not provided, defaults to `fixed`.
- `granularity`: Either a string: `fixed` / `patch` / `minor`, as mentioned above, or an object where the key is the dependencies key (`dependencies`, `devDependencies`, `peerDependencies`, `optionalDependencies`) and the value is one of the values above. If not provided, defaults to `fixed`.
- `excludePatterns: string[]`: Makes this rule ignore packages that match the given patterns and do not fail. Might be useful for specific packages that are used with dist-tags.
53 changes: 45 additions & 8 deletions src/rules/controlled-versions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import { isPackageJsonFile } from "../utils";
import { Rule } from "eslint";
import _ from "lodash";
import { parse as parseSemver, clean as cleanSemver, coerce, valid as validSemver } from "semver";
import { parse as parseSemver, clean as cleanSemver } from "semver";
import { DEPENDENCIES_KEYS } from "./constants";
import { Dependencies, DependencyGranularity } from "../types";
import { Dependencies, DependencyGranularity, GranularityOption } from "../types";
import micromatch from "micromatch";
import { toControlledSemver } from "../to-controlled-semver";

const getGranularily = (key: typeof DEPENDENCIES_KEYS[number], granularity?: GranularityOption): DependencyGranularity => {
if (!granularity) {
return "fixed"
}

if (typeof granularity === 'string') {
return granularity
}

return granularity[key] || "fixed"
}

const isGitDependency = (version: string): boolean => version.startsWith("git");
const isFileDependency = (version: string): boolean => version.startsWith("file");

Expand Down Expand Up @@ -52,7 +64,7 @@ const fix = (
};

interface RuleOptions {
granularity?: DependencyGranularity;
granularity?: GranularityOption;
excludePatterns: string[];
}

Expand All @@ -74,9 +86,33 @@ const rule: Rule.RuleModule = {
type: "object",
properties: {
granularity: {
type: "string",
// All options of DependencyGranularity
enum: ["fixed", "patch", "minor"],
anyOf: [
{
type: "string",
enum: ["fixed", "patch", "minor"],
},
{
type: 'object',
properties: {
dependencies: {
type: 'string',
enum: ["fixed", "patch", "minor"],
},
devDependencies: {
type: 'string',
enum: ["fixed", "patch", "minor"],
},
peerDependencies: {
type: 'string',
enum: ["fixed", "patch", "minor"],
},
optionalDependencies: {
type: 'string',
enum: ["fixed", "patch", "minor"],
},
}
}
]
},
excludePatterns: {
type: "array",
Expand All @@ -100,7 +136,7 @@ const rule: Rule.RuleModule = {

const { text } = context.getSourceCode();

const { granularity = "fixed", excludePatterns = [] } = (context
const { granularity: maybeGranularity, excludePatterns = [] } = (context
.options[0] || {}) as RuleOptions;

const packageJson = JSON.parse(text);
Expand All @@ -120,7 +156,8 @@ const rule: Rule.RuleModule = {
}

const versions = version.split(/\|\|| - /).map(s => s.trim());

const granularity = getGranularily(key, maybeGranularity)

switch (granularity) {
case "fixed":
if (versions.some(v => !isFixedVersion(v))) {
Expand Down
9 changes: 8 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,11 @@ interface Dependencies extends Dictionary<string> {

type DependencyGranularity = "fixed" | "patch" | "minor";

export { Dependencies, DependencyGranularity };
type GranularityOption = DependencyGranularity | {
dependencies?: DependencyGranularity
devDependencies?: DependencyGranularity
peerDependencies?: DependencyGranularity
optionalDependencies?: DependencyGranularity
}

export { Dependencies, DependencyGranularity, GranularityOption };

0 comments on commit cfd23d6

Please # to comment.