From c226d51a70d9e4fe957dcf0a3ddceb6108a12e4d Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sat, 18 Nov 2023 16:11:17 +0900 Subject: [PATCH] feat: add lowercase --- docs/rules/lowercase.md | 62 +++++++++++++ packages/eslint-plugin/lib/rules/index.js | 2 + packages/eslint-plugin/lib/rules/lowercase.js | 93 +++++++++++++++++++ .../tests/rules/lowercase.test.js | 68 ++++++++++++++ 4 files changed, 225 insertions(+) create mode 100644 docs/rules/lowercase.md create mode 100644 packages/eslint-plugin/lib/rules/lowercase.js create mode 100644 packages/eslint-plugin/tests/rules/lowercase.test.js diff --git a/docs/rules/lowercase.md b/docs/rules/lowercase.md new file mode 100644 index 00000000..0d632792 --- /dev/null +++ b/docs/rules/lowercase.md @@ -0,0 +1,62 @@ +--- +id: lowercase +title: "lowercase" +--- + +# lowercase + +Enforce to use lowercase for tag and attribute names. + +## How to use + +.eslintrc.js + +```js +module.exports = { + rules: { + "@html-eslint/lowercase": "error", + }, +}; +``` + +## Rule Details + +Examples of **incorrect** code for this rule: + + +```html +
+``` + + +```html +
+``` + + +```html + +``` + + +```html + +``` + +Examples of **correct** code for this rule: + +```html +
+``` + +```html +
+``` + +```html + +``` + +```html + +``` diff --git a/packages/eslint-plugin/lib/rules/index.js b/packages/eslint-plugin/lib/rules/index.js index a4debf77..ff827945 100644 --- a/packages/eslint-plugin/lib/rules/index.js +++ b/packages/eslint-plugin/lib/rules/index.js @@ -32,6 +32,7 @@ const noTrailingSpaces = require("./no-trailing-spaces"); const requireAttrs = require("./require-attrs"); const noRestrictedAttrValues = require("./no-restricted-attr-values"); const noScriptStyleType = require("./no-script-style-type"); +const lowercase = require("./lowercase"); module.exports = { "require-lang": requireLang, @@ -68,4 +69,5 @@ module.exports = { "no-trailing-spaces": noTrailingSpaces, "no-restricted-attr-values": noRestrictedAttrValues, "no-script-style-type": noScriptStyleType, + lowercase: lowercase, }; diff --git a/packages/eslint-plugin/lib/rules/lowercase.js b/packages/eslint-plugin/lib/rules/lowercase.js new file mode 100644 index 00000000..40d6d847 --- /dev/null +++ b/packages/eslint-plugin/lib/rules/lowercase.js @@ -0,0 +1,93 @@ +const { NODE_TYPES } = require("@html-eslint/parser"); +const { RULE_CATEGORY } = require("../constants"); + +const MESSAGE_IDS = { + UNEXPECTED: "unexpected", +}; + +/** + * @type {Rule} + */ +module.exports = { + meta: { + type: "suggestion", + + docs: { + description: "Enforce to use lowercase for tag and attribute names.", + category: RULE_CATEGORY.STYLE, + recommended: false, + }, + + fixable: "code", + schema: [], + messages: { + [MESSAGE_IDS.UNEXPECTED]: "'{{name}}' is not in lowercase.", + }, + }, + + create(context) { + /** + * @param {TagNode | StyleTagNode | ScriptTagNode} node + */ + function nameOf(node) { + if (node.type === NODE_TYPES.ScriptTag) return "script"; + if (node.type === NODE_TYPES.StyleTag) return "style"; + return node.name; + } + + /** + * @param {TagNode | StyleTagNode | ScriptTagNode} node + */ + function check(node) { + const raw = node.openStart.value.slice(1); + if (nameOf(node) !== raw) { + context.report({ + node: node.openStart, + messageId: MESSAGE_IDS.UNEXPECTED, + data: { + name: raw, + }, + fix(fixer) { + const name = nameOf(node); + const fixes = [ + fixer.replaceTextRange(node.openStart.range, `<${name}`), + ]; + + if (node.close) { + fixes.push( + fixer.replaceTextRange(node.close.range, ``) + ); + } + + return fixes; + }, + }); + } + if (node.attributes && node.attributes.length) { + node.attributes.forEach((attribute) => { + if (attribute.key.value !== attribute.key.value.toLowerCase()) { + context.report({ + node: attribute.key, + messageId: MESSAGE_IDS.UNEXPECTED, + data: { + name: attribute.key.value, + }, + fix(fixer) { + return fixer.replaceText( + attribute.key, + attribute.key.value.toLowerCase() + ); + }, + }); + } + }); + } + } + + return { + Tag: check, + StyleTag: check, + ScriptTag: check, + }; + }, +}; diff --git a/packages/eslint-plugin/tests/rules/lowercase.test.js b/packages/eslint-plugin/tests/rules/lowercase.test.js new file mode 100644 index 00000000..6ca954f5 --- /dev/null +++ b/packages/eslint-plugin/tests/rules/lowercase.test.js @@ -0,0 +1,68 @@ +const createRuleTester = require("../rule-tester"); +const rule = require("../../lib/rules/lowercase"); + +const ruleTester = createRuleTester(); + +ruleTester.run("lowercase", rule, { + valid: [ + { + code: "
", + }, + { + code: "
", + }, + { + code: "", + }, + { + code: "", + }, + ], + invalid: [ + { + code: '', + output: '', + errors: [ + { + message: "'IMG' is not in lowercase.", + }, + ], + }, + { + code: "", + output: "", + errors: [ + { + message: "'Script' is not in lowercase.", + }, + ], + }, + { + code: "", + output: "", + errors: [ + { + message: "'Style' is not in lowercase.", + }, + ], + }, + { + code: "", + output: "", + errors: [ + { + message: "'sTyle' is not in lowercase.", + }, + ], + }, + { + code: "
", + output: "
", + errors: [ + { + message: "'ID' is not in lowercase.", + }, + ], + }, + ], +});