Skip to content

Commit dee4f3e

Browse files
committed
Handle head tag in provide-print-css rule
1 parent 628cf39 commit dee4f3e

File tree

3 files changed

+103
-49
lines changed

3 files changed

+103
-49
lines changed

eslint-plugin/docs/rules/provide-print-css.md

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,41 @@
66

77
## Rule Details
88

9-
This rule aims to remind developers to use CSS print to limit the number of pages printed therefore indirectly reducing the impact of the web page.
9+
This rule aims to remind developers to use CSS print to limit the number of pages printed therefore indirectly reducing
10+
the impact of the web page.
1011

1112
## Examples
1213

1314
Examples of **non-compliant** code for this rule:
1415

15-
```js
16-
<link rel="stylesheet" type="text/css" href="styles.css">
16+
```html
17+
<head>
18+
<title>Web Page</title>
19+
<link rel="stylesheet" type="text/css" href="styles.css" />
20+
</head>
1721
```
1822

1923
Examples of **compliant** code for this rule:
2024

21-
```js
22-
<style>
25+
```html
26+
<head>
27+
<title>Web Page</title>
28+
<link rel="stylesheet" media="print" type="text/css" href="print.css" />
29+
</head>
30+
```
31+
32+
```html
33+
<head>
34+
<title>Web Page</title>
35+
<style>
2336
@media print {
2437
/* Print-specific styles */
2538
}
26-
</style>
39+
</style>
40+
</head>
2741
```
42+
43+
## Further details
44+
45+
This recommendation is made by the
46+
CNUMR: [Provide a print CSS](https://github.com/cnumr/best-practices/blob/main/chapters/BP_027_en.md)

eslint-plugin/lib/rules/provide-print-css.js

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717
"use strict";
1818

19-
/** @type {import('eslint').Rule.RuleModule} */
19+
/** @type {import("eslint").Rule.RuleModule} */
2020
module.exports = {
2121
meta: {
2222
type: "suggestion",
@@ -31,38 +31,50 @@ module.exports = {
3131
schema: [],
3232
},
3333
create(context) {
34-
// Track scanned files
35-
const scannedFiles = new Set();
34+
const isStyleWithPrintNode = (node) => {
35+
return (
36+
node.openingElement.name.name === "style" &&
37+
node.children.some((child) => {
38+
let element = null;
39+
if (child.value != null) {
40+
element = child.value;
41+
} else if (child.expression != null) {
42+
if (child.expression.value != null) {
43+
element = child.expression.value;
44+
} else if (
45+
child.expression.quasis != null &&
46+
child.expression.quasis.length > 0
47+
) {
48+
element = child.expression.quasis[0].value.cooked;
49+
}
50+
}
51+
return element != null && element.includes("@media print");
52+
})
53+
);
54+
};
55+
56+
const isLinkForPrintNode = (node) =>
57+
node.openingElement.name.name === "link" &&
58+
node.openingElement.attributes.some(
59+
(attr) => attr.name.name === "media" && attr.value.value === "print",
60+
);
61+
3662
return {
3763
JSXElement(node) {
38-
const filePath = context.getFilename();
64+
if (node.openingElement.name.name === "head") {
65+
const hasValidElement = node.children.some(
66+
(child) =>
67+
child.openingElement != null &&
68+
(isStyleWithPrintNode(child) || isLinkForPrintNode(child)),
69+
);
3970

40-
// Skip if file has already been scanned
41-
if (scannedFiles.has(filePath)) {
42-
return;
71+
if (!hasValidElement) {
72+
context.report({
73+
node: node,
74+
messageId: "noPrintCSSProvided",
75+
});
76+
}
4377
}
44-
45-
// Mark file as scanned
46-
scannedFiles.add(filePath);
47-
if (
48-
node.openingElement.name.name === "link" &&
49-
node.openingElement.attributes.some(
50-
(attr) =>
51-
attr.name.name === "media" && attr.value.value === "print",
52-
)
53-
) {
54-
return;
55-
} else if (
56-
node.openingElement.name.name === "style" &&
57-
node.children.some((child) => child.value.includes("@media print"))
58-
) {
59-
return;
60-
}
61-
62-
context.report({
63-
node: node,
64-
messageId: "noPrintCSSProvided",
65-
});
6678
},
6779
};
6880
},

eslint-plugin/tests/lib/rules/provide-print-css.js

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const ruleTester = new RuleTester({
3636
},
3737
},
3838
});
39+
3940
const expectedError = {
4041
messageId: "noPrintCSSProvided",
4142
type: "JSXElement",
@@ -44,28 +45,50 @@ const expectedError = {
4445
ruleTester.run("provide-print-css", rule, {
4546
valid: [
4647
`
47-
<link rel="stylesheet" href="styles.css" media="print" />
48-
48+
<head>
49+
<title>Web Page</title>
50+
<link rel="stylesheet" href="styles.css" media="print" />
51+
</head>
52+
`,
53+
`
54+
<head>
55+
<title>Web Page</title>
56+
<style>@media print {}</style>
57+
</head>
4958
`,
5059
`
51-
<style>
52-
@media print {
53-
/* Print-specific styles */
54-
}
55-
</style>
60+
<head>
61+
<title>Web Page</title>
62+
<style>{'@media print {}'}</style>
63+
</head>
5664
`,
5765
`
58-
{<link rel="stylesheet" href="styles.css" media="print" />,
59-
<style>
60-
@media print {
61-
/* Print-specific styles */
62-
}
63-
</style>}
66+
<head>
67+
<title>Web Page</title>
68+
<link rel="stylesheet" href="styles.css" media="print" />,
69+
<style>{'@media print {}'}</style>
70+
</head>
6471
`,
72+
"<head><style>{`@media print {}`}</style></head>",
73+
`<link rel="stylesheet" href="styles.css" />`,
6574
],
6675
invalid: [
6776
{
68-
code: `<link rel="stylesheet" href="styles.css" />`,
77+
code: `
78+
<head>
79+
<title>Web Page</title>
80+
<link rel="stylesheet" href="styles.css" />
81+
</head>
82+
`,
83+
errors: [expectedError],
84+
},
85+
{
86+
code: `
87+
<head>
88+
<title>Web Page</title>
89+
<style>{'@media desktop {}'}</style>
90+
</head>
91+
`,
6992
errors: [expectedError],
7093
},
7194
],

0 commit comments

Comments
 (0)