Skip to content

Commit

Permalink
feat: implement no-script-style-type rule (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
yeonjuan committed Nov 17, 2023
1 parent 4d30656 commit 32ebe14
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 0 deletions.
62 changes: 62 additions & 0 deletions docs/rules/no-script-style-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
id: no-script-style-type
title: "no-script-style-type"
---

# no-script-style-type

Enforce to omit default type attributes for style sheets and scripts.

.eslintrc.js

```js
module.exports = {
rules: {
"@html-eslint/no-script-style-type": "error",
},
};
```

## Rule Details

This rule disallows the use of `type` attributes for style sheets (unless not using CSS) and scripts (unless not using JavaScript).
Specifying below `type` attributes is not necessary as HTML5 implies `text/css` and `text/javascript` as defaults

- script - `type="text/javascript"`
- style, link - `type="text/css"`

Examples of **incorrect** code for this rule:

```html
<script type="text/javascript" src="https://script.js"></script>
```

```html
<link type="text/css" rel="stylesheet" href="https://styles.css" />
```

```html
<style type="text/css"></style>
```

Examples of **correct** code for this rule:

```html
<script src="https://script.js"></script>
```

```html
<script type="module" src="https://script.js"></script>
```

```html
<link rel="stylesheet" href="https://styles.css" />
```

```html
<style></style>
```

## Further reading

- [Google HTML/CSS Style Guide - type Attributes](https://google.github.io/styleguide/htmlcssguide.html#type_Attributes)
2 changes: 2 additions & 0 deletions packages/eslint-plugin/lib/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const noRestrictedAttrs = require("./no-restricted-attrs");
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");

module.exports = {
"require-lang": requireLang,
Expand Down Expand Up @@ -66,4 +67,5 @@ module.exports = {
"no-restricted-attrs": noRestrictedAttrs,
"no-trailing-spaces": noTrailingSpaces,
"no-restricted-attr-values": noRestrictedAttrValues,
"no-script-style-type": noScriptStyleType,
};
69 changes: 69 additions & 0 deletions packages/eslint-plugin/lib/rules/no-script-style-type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const { RULE_CATEGORY } = require("../constants");
const { findAttr } = require("./utils/node");

const MESSAGE_IDS = {
UNNECESSARY: "unnecessary",
};

/**
* @type {Rule}
*/
module.exports = {
meta: {
type: "code",

docs: {
description:
"Enforce to omit type attributes for style sheets and scripts",
category: RULE_CATEGORY.BEST_PRACTICE,
recommended: false,
},

fixable: "code",
schema: [],
messages: {
[MESSAGE_IDS.UNNECESSARY]: "Unnecessary type attributes",
},
},

create(context) {
/**
*
* @param {ScriptTagNode | TagNode | StyleTagNode} node
* @param {string} unnecessaryValue
*/
function check(node, unnecessaryValue) {
const type = findAttr(node, "type");
if (
type &&
type.value &&
type.value.value &&
type.value.value.trim().toLocaleLowerCase() === unnecessaryValue
) {
context.report({
node: type,
messageId: MESSAGE_IDS.UNNECESSARY,
fix(fixer) {
return fixer.remove(type);
},
});
}
}
return {
ScriptTag(node) {
check(node, "text/javascript");
},
StyleTag(node) {
check(node, "text/css");
},
Tag(node) {
if (node.name === "link") {
const rel = findAttr(node, "rel");
if (rel && rel.value && rel.value.value === "stylesheet") {
check(node, "text/css");
}
}
},
};
},
};
47 changes: 47 additions & 0 deletions packages/eslint-plugin/tests/rules/no-script-style-type.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const createRuleTester = require("../rule-tester");
const rule = require("../../lib/rules/no-script-style-type");

const ruleTester = createRuleTester();

ruleTester.run("no-script-style-type", rule, {
valid: [
{
code: '<script src="https://script.js"></script>"',
},
{
code: '<script type="module" src="https://script.js"></script>',
},
{
code: '<link rel="stylesheet" href="https://styles.css" />',
},
],
invalid: [
{
code: '<script type="text/javascript" src="https://script.js"></script>',
output: '<script src="https://script.js"></script>',
errors: [
{
messageId: "unnecessary",
},
],
},
{
code: '<style type="text/css"></style>',
output: "<style ></style>",
errors: [
{
messageId: "unnecessary",
},
],
},
{
code: '<link type="text/css" rel="stylesheet" href="https://styles.css" />',
output: '<link rel="stylesheet" href="https://styles.css" />',
errors: [
{
messageId: "unnecessary",
},
],
},
],
});

0 comments on commit 32ebe14

Please sign in to comment.