Skip to content

Commit 0f2963f

Browse files
Adds a new rule req-webp-in-picture (#110)
* Adds a new rule req-webp-in-picture * Добавляет описание правила * Добавляет правило в список * Update CHANGELOG.md
1 parent d96a632 commit 0f2963f

File tree

4 files changed

+97
-34
lines changed

4 files changed

+97
-34
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
## 1.0.20
44
- Adds a `req-tags-presence` rule that requires the specified tags on the page.
55
- Adds a `req-preload-font` rule that requires the `preload` value for the font.
6+
- Adds a `req-webp-in-picture` rule that requires `webp` in `<picture>`
67

78

89
```json
910
{
1011
"htmlacademy/req-tags-presence": [ true, ["header", "nav", "main", "section", "h1", "footer"]],
11-
"htmlacademy/req-preload-font": true
12+
"htmlacademy/req-preload-font": true,
13+
"htmlacademy/req-webp-in-picture": true
1214
}
1315
```
1416

docs/list-of-rules.md

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
11
# Список правил от HTML Academy
22

3-
| Имя правила | Описания |
4-
|------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
5-
| [htmlacademy/a-target-rel](../rules/a-target-rel/README.md) | Проверяет наличие `rel="noopener noreferrer"` у `<a target="_blank"></a>` |
6-
| [htmlacademy/aria-label-misuse](../rules/aria-label-misuse/README.md) | Требует использование `aria-label` на определённых элементах |
7-
| [htmlacademy/attr-delimiter](../rules/attr-delimiter/README.md) | Требует удалить пробел между `=` для атрибутов |
8-
| [htmlacademy/attr-req-value](../rules/attr-req-value/README.md) | Запрещает пустые атрибуты `""`, кроме тех что в `ignore: []` |
9-
| [htmlacademy/attribute-allowed-values](../rules/attribute-allowed-values/README.md) | Проверяет атрибуты на наличие допустимых значений |
10-
| [htmlacademy/ban-url-spaces](../rules/ban-url-spaces/README.md) | Проверяет наличие пробелов в адресах в атрибутах `href` и `src`. |
11-
| [htmlacademy/charset-position](../rules/charset-position/README.md) | Требует указывать `<meta charset="utf-8">` первым элементов в `<head>` |
12-
| [htmlacademy/class-first](../rules/class-first/README.md) | Требует указывать первым атрибутом у любого элемента `class` |
13-
| [htmlacademy/form-action-attribute](../rules/form-action-attribute/README.md) | Требует указывать атрибут `action` у `<form>` |
14-
| [htmlacademy/head-meta-charset](../rules/head-meta-charset/README.md) | Проверяет наличие `<meta charset="utf-8">` в `<head>` |
15-
| [htmlacademy/id-no-dup](../rules/id-no-dup/README.md) | Запрешает дублирование `id` на странице |
16-
| [htmlacademy/img-svg-req-dimensions](../rules/img-svg-req-dimensions/README.md) | Требует атрибуты `width` и `height` у `<img>` и `<svg>` |
17-
| [htmlacademy/input-req-label](../rules/input-req-label/README.md) | Требует наличие метки для поля ввода, и позволяет указать метку в `aria-label` |
18-
| [htmlacademy/link-req-content](../rules/link-req-content/README.md) | Проверяет наличие текстового содержания у `<a>` |
19-
| [htmlacademy/no-blocking-script](../rules/no-blocking-script/README.md) | Проверяет расположение скриптов в разметке |
20-
| [htmlacademy/no-double-br](../rules/no-double-br/README.md) | Запрещает идущие подряд двойной `<br>` |
21-
| [htmlacademy/no-px-size](../rules/no-px-size/README.md) | Атрибуты `width` и `height` содержат только цифры, без единиц измерения |
22-
| [htmlacademy/req-charset-utf](../rules/req-charset-utf/README.md) | Требует `UTF-8` для `<meta charset="">` |
23-
| [htmlacademy/req-head-styles](../rules/req-head-styles/README.md) | Запрещает подключение стилей вне `<head>` |
24-
| [htmlacademy/req-mailto](../rules/req-mailto/README.md) | Требует `mailto:` для ссылок c email-текстом |
3+
| Имя правила | Описания |
4+
|------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------|
5+
| [htmlacademy/a-target-rel](../rules/a-target-rel/README.md) | Проверяет наличие `rel="noopener noreferrer"` у `<a target="_blank"></a>` |
6+
| [htmlacademy/aria-label-misuse](../rules/aria-label-misuse/README.md) | Требует использование `aria-label` на определённых элементах |
7+
| [htmlacademy/attr-delimiter](../rules/attr-delimiter/README.md) | Требует удалить пробел между `=` для атрибутов |
8+
| [htmlacademy/attr-req-value](../rules/attr-req-value/README.md) | Запрещает пустые атрибуты `""`, кроме тех что в `ignore: []` |
9+
| [htmlacademy/attribute-allowed-values](../rules/attribute-allowed-values/README.md) | Проверяет атрибуты на наличие допустимых значений |
10+
| [htmlacademy/ban-url-spaces](../rules/ban-url-spaces/README.md) | Проверяет наличие пробелов в адресах в атрибутах `href` и `src`. |
11+
| [htmlacademy/charset-position](../rules/charset-position/README.md) | Требует указывать `<meta charset="utf-8">` первым элементов в `<head>` |
12+
| [htmlacademy/class-first](../rules/class-first/README.md) | Требует указывать первым атрибутом у любого элемента `class` |
13+
| [htmlacademy/form-action-attribute](../rules/form-action-attribute/README.md) | Требует указывать атрибут `action` у `<form>` |
14+
| [htmlacademy/head-meta-charset](../rules/head-meta-charset/README.md) | Проверяет наличие `<meta charset="utf-8">` в `<head>` |
15+
| [htmlacademy/id-no-dup](../rules/id-no-dup/README.md) | Запрешает дублирование `id` на странице |
16+
| [htmlacademy/img-svg-req-dimensions](../rules/img-svg-req-dimensions/README.md) | Требует атрибуты `width` и `height` у `<img>` и `<svg>` |
17+
| [htmlacademy/input-req-label](../rules/input-req-label/README.md) | Требует наличие метки для поля ввода, и позволяет указать метку в `aria-label` |
18+
| [htmlacademy/link-req-content](../rules/link-req-content/README.md) | Проверяет наличие текстового содержания у `<a>` |
19+
| [htmlacademy/no-blocking-script](../rules/no-blocking-script/README.md) | Проверяет расположение скриптов в разметке |
20+
| [htmlacademy/no-double-br](../rules/no-double-br/README.md) | Запрещает идущие подряд двойной `<br>` |
21+
| [htmlacademy/no-px-size](../rules/no-px-size/README.md) | Атрибуты `width` и `height` содержат только цифры, без единиц измерения |
22+
| [htmlacademy/req-charset-utf](../rules/req-charset-utf/README.md) | Требует `UTF-8` для `<meta charset="">` |
23+
| [htmlacademy/req-head-styles](../rules/req-head-styles/README.md) | Запрещает подключение стилей вне `<head>` |
24+
| [htmlacademy/req-mailto](../rules/req-mailto/README.md) | Требует `mailto:` для ссылок c email-текстом |
2525
| [htmlacademy/req-meta-viewport](../rules/req-meta-viewport/README.md) | Проверяет наличие `<meta name="viewport" content="width=device-width,initial-scale=1">` в `<head>` |
26-
| [htmlacademy/req-preload-font](../rules/req-preload-font/README.md) | Проверяет наличие предзагрузки шрифта в `<head>` |
27-
| [htmlacademy/req-single-styles](../rules/req-single-styles/README.md) | Разрешает не более одного `link rel="stylesheet"` в `<head>` |
28-
| [htmlacademy/req-source-width-height](../rules/req-source-width-height/README.md) | Требует `width` и `height` у `<source>` внутри `<picture>` |
29-
| [htmlacademy/req-stylesheet-link](../rules/req-stylesheet-link/README.md) | Проверяет наличие `<link rel="stylesheet" href="">` с непустым `href` |
30-
| [htmlacademy/req-tags-presence](../rules/req-tags-presence/README.md) | Требует указанные теги на странице |
31-
| [htmlacademy/section-has-heading](../rules/section-has-heading/README.md) | Требует добавление заголовка любого уровня в `<section>` |
32-
| [htmlacademy/space-between-comments](../rules/space-between-comments/README.md) | Проверят пробелы у комментария `<!-- Это комментарий -->` |
33-
| [htmlacademy/tag-forbid-attr](../rules/tag-forbid-attr/README.md) | Указанные атрибуты должны отсутствовать в указанном теге |
34-
| [htmlacademy/tag-name-lowercase](../rules/tag-name-lowercase/README.md) | Имена тегов должны быть строчными |
35-
| [htmlacademy/tag-req-attr](../rules/tag-req-attr/README.md) | Указанные атрибуты должны присутствовать в указанном теге |
36-
| [htmlacademy/tag-self-close](../rules/tag-self-close/README.md) | Одиночные элементы не должны быть закрыты, `<br>` вместо `<br/>` |
26+
| [htmlacademy/req-preload-font](../rules/req-preload-font/README.md) | Проверяет наличие предзагрузки шрифта в `<head>` |
27+
| [htmlacademy/req-single-styles](../rules/req-single-styles/README.md) | Разрешает не более одного `link rel="stylesheet"` в `<head>` |
28+
| [htmlacademy/req-source-width-height](../rules/req-source-width-height/README.md) | Требует `width` и `height` у `<source>` внутри `<picture>` |
29+
| [htmlacademy/req-stylesheet-link](../rules/req-stylesheet-link/README.md) | Проверяет наличие `<link rel="stylesheet" href="">` с непустым `href` |
30+
| [htmlacademy/req-tags-presence](../rules/req-tags-presence/README.md) | Требует указанные теги на странице |
31+
| [htmlacademy/req-webp-in-picture](../rules/req-webp-in-picture/README.md) | Требует `webp` в `<picture>` |
32+
| [htmlacademy/section-has-heading](../rules/section-has-heading/README.md) | Требует добавление заголовка любого уровня в `<section>` |
33+
| [htmlacademy/space-between-comments](../rules/space-between-comments/README.md) | Проверят пробелы у комментария `<!-- Это комментарий -->` |
34+
| [htmlacademy/tag-forbid-attr](../rules/tag-forbid-attr/README.md) | Указанные атрибуты должны отсутствовать в указанном теге |
35+
| [htmlacademy/tag-name-lowercase](../rules/tag-name-lowercase/README.md) | Имена тегов должны быть строчными |
36+
| [htmlacademy/tag-req-attr](../rules/tag-req-attr/README.md) | Указанные атрибуты должны присутствовать в указанном теге |
37+
| [htmlacademy/tag-self-close](../rules/tag-self-close/README.md) | Одиночные элементы не должны быть закрыты, `<br>` вместо `<br/>` |

rules/req-webp-in-picture/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# htmlacademy/req-webp-in-picture
2+
3+
Правило проверяет наличие webp изображений в теге `<picture>`.
4+
5+
## true
6+
7+
Проблемными считаются следующие шаблоны:
8+
9+
```html
10+
<picture>
11+
<source width="400" height="200" srcset="image.jpg" type="image/jpeg">
12+
<img width="400" height="200" src="image.png" alt="Example image">
13+
</picture>
14+
15+
<picture
16+
<source width="800" height="400" srcset="image-800w.png" type="image/png" media="(min-width: 800px)">
17+
<source width="400" height="200" srcset="image-400w.png" type="image/png" media="(min-width: 400px)">
18+
<img width="400" height="200" src="image.png" alt="Example image">
19+
</picture>
20+
```
21+
22+
Следующие шаблоны **не** считаются проблемами:
23+
24+
```html
25+
<picture>
26+
<source width="800" height="400" srcset="image-800w.webp" type="image/webp" media="(min-width: 800px)">
27+
<source width="400" height="200" srcset="image-400w.webp" type="image/webp" media="(min-width: 400px)">
28+
<source width="800" height="400" srcset="image-800w.png" type="image/png" media="(min-width: 800px)">
29+
<source width="400" height="200" srcset="image-400w.png" type="image/png" media="(min-width: 400px)">
30+
<img width="400" height="200" src="image.png" alt="Example image">
31+
</picture>
32+
```
33+
34+
```html
35+
<picture>
36+
<source width="400" height="200" srcset="image.webp" type="image/webp">
37+
<source width="400" height="200" srcset="image.jpg" type="image/jpeg">
38+
<img width="400" height="200" src="image.png" alt="Example image">
39+
</picture>
40+
```

rules/req-webp-in-picture/index.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
const { is_tag_node, attribute_has_value } = require('@linthtml/dom-utils');
3+
4+
module.exports = {
5+
name: 'htmlacademy/req-webp-in-picture',
6+
// eslint-disable-next-line camelcase
7+
lint(node, rule_config, { report }) {
8+
if (is_tag_node(node) && node.tagName === 'picture') {
9+
const sourceElements = node.children.filter((child) => child.tagName === 'source');
10+
const hasWebpSource = sourceElements.some((source) => attribute_has_value(source, 'type', 'image/webp'));
11+
12+
if (!hasWebpSource) {
13+
report({
14+
position: node.loc,
15+
message: 'Element "picture" must contain a "source" child with a "type" attribute containing "webp".'
16+
});
17+
}
18+
}
19+
}
20+
};

0 commit comments

Comments
 (0)