Skip to content

Commit

Permalink
chore: implement ESLint rule to avoid unnecessary min/maxValue
Browse files Browse the repository at this point in the history
  • Loading branch information
AlCalzone committed Sep 26, 2023
1 parent cf21f54 commit 8e6e1dc
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/config/config/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ module.exports = {
],
rules: {
"@zwave-js/consistent-device-config-property-order": "error",
"@zwave-js/no-unnecessary-min-max-value": "error"
}
};
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { consistentCCClasses } from "./rules/consistent-cc-classes.js";
import { consistentDeviceConfigPropertyOrder } from "./rules/consistent-device-config-property-order.js";
import { noDebugInTests } from "./rules/no-debug-in-tests.js";
import { noForbiddenImports } from "./rules/no-forbidden-imports.js";
import { noUnnecessaryMinMaxValue } from "./rules/no-unnecessary-min-max-value.js";

module.exports = {
rules: {
Expand All @@ -12,5 +13,6 @@ module.exports = {
"no-forbidden-imports": noForbiddenImports,
"consistent-device-config-property-order":
consistentDeviceConfigPropertyOrder,
"no-unnecessary-min-max-value": noUnnecessaryMinMaxValue,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ export const consistentDeviceConfigPropertyOrder: JSONCRule.RuleModule = {
},
meta: {
docs: {
description: "foo",
description:
"Ensures consistent ordering of properties in configuration parameter definitions",
},
fixable: "code",
schema: [],
Expand Down
77 changes: 77 additions & 0 deletions packages/eslint-plugin/src/rules/no-unnecessary-min-max-value.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { AST } from "jsonc-eslint-parser";
import { type JSONCRule, removeJSONProperty } from "../utils";

export const noUnnecessaryMinMaxValue: JSONCRule.RuleModule = {
create(context) {
if (!context.parserServices.isJSON) {
return {};
}
return {
// Avoid unnecessary min/max value in parameters with predefined options
"JSONProperty[key.value='paramInformation'] > JSONArrayExpression > JSONObjectExpression"(
node: AST.JSONObjectExpression,
) {
// Imports can make it necessary to override min/maxValue
const hasImport = node.properties.some((p) =>
p.key.type === "JSONLiteral"
&& p.key.value === "$import"
);
if (hasImport) return;

const allowManualEntryFalse = node.properties.some((p) =>
p.key.type === "JSONLiteral"
&& p.key.value === "allowManualEntry"
&& p.value.type === "JSONLiteral"
&& p.value.value === false
);
if (!allowManualEntryFalse) return;

const hasOptions = node.properties.some((p) =>
p.key.type === "JSONLiteral"
&& p.key.value === "options"
&& p.value.type === "JSONArrayExpression"
&& p.value.elements.length > 0
);
if (!hasOptions) return;

const minValue = node.properties.find((p) =>
p.key.type === "JSONLiteral"
&& p.key.value === "minValue"
);
if (minValue) {
context.report({
loc: minValue.loc,
messageId: "no-min-value",
fix: removeJSONProperty(context, minValue),
});
}

const maxValue = node.properties.find((p) =>
p.key.type === "JSONLiteral"
&& p.key.value === "maxValue"
);
if (maxValue) {
context.report({
loc: maxValue.loc,
messageId: "no-max-value",
fix: removeJSONProperty(context, maxValue),
});
}
},
};
},
meta: {
docs: {
description: "Ensures that min/maxValue are not used unnecessarily",
},
fixable: "code",
schema: [],
messages: {
"no-min-value":
`For parameters with "allowManualEntry = false" and predefined options, "minValue" is unnecessary and should not be specified.`,
"no-max-value":
`For parameters with "allowManualEntry = false" and predefined options, "maxValue" is unnecessary and should not be specified.`,
},
type: "problem",
},
};
54 changes: 54 additions & 0 deletions packages/eslint-plugin/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from "@typescript-eslint/utils";
import { CommandClasses } from "@zwave-js/core";
import { type Rule as ESLintRule } from "eslint";
import { type AST as JSONC_AST } from "jsonc-eslint-parser";
import path from "node:path";

export const repoRoot = path.normalize(
Expand Down Expand Up @@ -110,3 +111,56 @@ export namespace JSONCRule {
schema?: ESLintRule.RuleMetaData["schema"];
}
}

export function removeJSONProperty(
context: ESLintRule.RuleContext,
property: JSONC_AST.JSONProperty,
): (fixer: ESLintRule.RuleFixer) => ESLintRule.Fix {
const propIndex = property.parent.properties.indexOf(property);
const prevProp = property.parent.properties[propIndex - 1];
const nextProp = property.parent.properties[propIndex + 1];

let leadingComments = context.sourceCode.getCommentsBefore(property as any);
if (prevProp) {
// Omit leading comments that are actually trailing comments of the previous property
leadingComments = leadingComments.filter((c) =>
c.loc?.start.line !== prevProp.loc.end.line
);
}

// Remove from the beginning of the first actual leading comment...
const actualStart = Math.min(
property.range[0],
...leadingComments.map((c) => c.range![0]),
);

let actualEnd = property.range[1];
if (nextProp) {
// ...to either the first actual leading comment of the next property...
const nextPropLeadingComments = context.sourceCode.getCommentsBefore(
nextProp as any,
).filter((c) => c.loc?.start.line !== property.loc.end.line);
actualEnd = Math.max(
actualEnd,
Math.min(
nextProp.range[0],
...nextPropLeadingComments.map((c) => c.range![0]),
),
);
} else {
// ...or the end of the last trailing comment of this property
const trailingComments = context.sourceCode.getCommentsAfter(
property as any,
);
actualEnd = Math.max(
actualEnd,
...trailingComments.map((c) => c.range![1]),
);
}

return (fixer) =>
fixer.removeRange([
actualStart,
actualEnd,
]);
}

0 comments on commit 8e6e1dc

Please sign in to comment.