From b498c0c39dc26f29135e81ce79b6110ce2eb58a9 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Fri, 19 Mar 2021 00:16:54 +0400 Subject: [PATCH 01/10] add no-invalid-position-at-import-rule --- docs/user-guide/rules/list.md | 1 + lib/rules/index.js | 3 + .../README.md | 49 ++++++++++++ .../__tests__/index.js | 80 +++++++++++++++++++ .../index.js | 67 ++++++++++++++++ 5 files changed, 200 insertions(+) create mode 100644 lib/rules/no-invalid-position-at-import-rule/README.md create mode 100644 lib/rules/no-invalid-position-at-import-rule/__tests__/index.js create mode 100644 lib/rules/no-invalid-position-at-import-rule/index.js diff --git a/docs/user-guide/rules/list.md b/docs/user-guide/rules/list.md index f3934ebb2e..89c538b648 100644 --- a/docs/user-guide/rules/list.md +++ b/docs/user-guide/rules/list.md @@ -79,6 +79,7 @@ Grouped first by the following categories and then by the [_thing_](http://apps. - [`no-empty-source`](../../../lib/rules/no-empty-source/README.md): Disallow empty sources. - [`no-extra-semicolons`](../../../lib/rules/no-extra-semicolons/README.md): Disallow extra semicolons (Autofixable). - [`no-invalid-double-slash-comments`](../../../lib/rules/no-invalid-double-slash-comments/README.md): Disallow double-slash comments (`//...`) which are not supported by CSS. +- [`no-invalid-position-at-import-rule`](../../../lib/rules/no-invalid-position-at-import-rule/README.md): Disallow invalid position @import rules within a stylesheet. ## Limit language features diff --git a/lib/rules/index.js b/lib/rules/index.js index 395ac241c0..5c966a243e 100644 --- a/lib/rules/index.js +++ b/lib/rules/index.js @@ -242,6 +242,9 @@ const rules = { 'no-invalid-double-slash-comments': importLazy(() => require('./no-invalid-double-slash-comments'), )(), + 'no-invalid-position-at-import-rule': importLazy(() => + require('./no-invalid-position-at-import-rule'), + )(), 'no-missing-end-of-source-newline': importLazy(() => require('./no-missing-end-of-source-newline'), )(), diff --git a/lib/rules/no-invalid-position-at-import-rule/README.md b/lib/rules/no-invalid-position-at-import-rule/README.md new file mode 100644 index 0000000000..daa05bc2b9 --- /dev/null +++ b/lib/rules/no-invalid-position-at-import-rule/README.md @@ -0,0 +1,49 @@ +# no-invalid-position-at-import-rule + +Disallow invalid position `@import` rules within a stylesheet. + + +```css +a {} +@import 'foo.css'; +/** ↑ + * Invalid position */ +``` + +## Options + +### `true` + +The following patterns are considered violations: + + +```css +a {} +@import 'foo.css'; +``` + + +```css +@media print {} +@import 'foo.css'; +``` + +The following patterns are _not_ considered violations: + + +```css +@import 'foo.css'; +a {} +``` + + +```css +/* some comment */ +@import 'foo.css'; +``` + + +```css +@charset 'utf-8'; +@import 'foo.css'; +``` diff --git a/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js b/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js new file mode 100644 index 0000000000..93ea4dff05 --- /dev/null +++ b/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js @@ -0,0 +1,80 @@ +'use strict'; + +const { messages, ruleName } = require('..'); + +testRule({ + ruleName, + config: [true], + + accept: [ + { + code: ` + @import 'foo.css'; + a {} + `, + description: '@import on first line', + }, + { + code: ` + /* some comment */ + @import 'foo.css'; + `, + description: '@import after comment', + }, + { + code: ` + @charset 'utf-8'; + @import 'foo.css'; + `, + description: '@import after @charset ', + }, + { + code: ` + @import 'foo.css'; + @import 'bar.css'; + `, + description: '@import after another @import', + }, + { + code: ` + @CHARSET 'utf-8'; + @imPORT 'foo.css'; + @import 'bar.css'; + `, + description: 'case insensitive', + }, + ], + + reject: [ + { + code: ` + a {} + @import 'foo.css'; + `, + message: messages.rejected('foo.css'), + description: '@import after selector', + line: 3, + column: 4, + }, + { + code: ` + @media print {} + @import url('foo.css'); + `, + message: messages.rejected('foo.css'), + description: '@import after another at-rule', + line: 3, + column: 4, + }, + { + code: ` + @media print {} + @imPort URl('foo.css'); + `, + message: messages.rejected('foo.css'), + description: 'case insensitive', + line: 3, + column: 4, + }, + ], +}); diff --git a/lib/rules/no-invalid-position-at-import-rule/index.js b/lib/rules/no-invalid-position-at-import-rule/index.js new file mode 100644 index 0000000000..23263acdda --- /dev/null +++ b/lib/rules/no-invalid-position-at-import-rule/index.js @@ -0,0 +1,67 @@ +// @ts-nocheck + +'use strict'; + +const report = require('../../utils/report'); +const ruleMessages = require('../../utils/ruleMessages'); +const validateOptions = require('../../utils/validateOptions'); +const valueParser = require('postcss-value-parser'); + +const ruleName = 'no-invalid-position-at-import-rule'; + +const messages = ruleMessages(ruleName, { + rejected: (atImport) => `Unexpected invalid position @import rule ${atImport}`, +}); + +function rule(actual) { + return (root, result) => { + const validOptions = validateOptions(result, ruleName, { actual }); + + if (!validOptions) { + return; + } + + let invalidPosition = false; + + root.walk((node) => { + if (node.type === 'comment' || (node.type === 'atrule' && /^charset$/i.test(node.name))) { + return; + } + + if (node.type === 'atrule' && /^import$/i.test(node.name)) { + if (invalidPosition) { + const url = getAtImportUrl(node); + + if (url) { + report({ + message: messages.rejected(url), + node, + result, + ruleName, + }); + } + } + + return; + } + + invalidPosition = true; + }); + }; +} + +function getAtImportUrl(node) { + const params = valueParser(node.params).nodes; + + if (!params.length) { + return null; + } + + return params[0].type === 'function' && /^url$/i.test(params[0].value) + ? params[0].nodes[0].value + : params[0].value; +} + +rule.ruleName = ruleName; +rule.messages = messages; +module.exports = rule; From 1e3a40762f25fc08e53a9de6b1b2b742f0fdd9a2 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Sun, 21 Mar 2021 14:22:03 +0400 Subject: [PATCH 02/10] Update lib/rules/no-invalid-position-at-import-rule/README.md Co-authored-by: Richard Hallows --- lib/rules/no-invalid-position-at-import-rule/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/rules/no-invalid-position-at-import-rule/README.md b/lib/rules/no-invalid-position-at-import-rule/README.md index daa05bc2b9..e896e5df61 100644 --- a/lib/rules/no-invalid-position-at-import-rule/README.md +++ b/lib/rules/no-invalid-position-at-import-rule/README.md @@ -6,9 +6,8 @@ Disallow invalid position `@import` rules within a stylesheet. ```css a {} @import 'foo.css'; -/** ↑ - * Invalid position */ -``` +/** ↑ + * This @import */ ## Options From 3c345584a5adf276d7d33b8b7010e44784f40c96 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Sun, 21 Mar 2021 14:22:11 +0400 Subject: [PATCH 03/10] Update docs/user-guide/rules/list.md Co-authored-by: Richard Hallows --- docs/user-guide/rules/list.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user-guide/rules/list.md b/docs/user-guide/rules/list.md index 89c538b648..5ab5df0221 100644 --- a/docs/user-guide/rules/list.md +++ b/docs/user-guide/rules/list.md @@ -79,7 +79,7 @@ Grouped first by the following categories and then by the [_thing_](http://apps. - [`no-empty-source`](../../../lib/rules/no-empty-source/README.md): Disallow empty sources. - [`no-extra-semicolons`](../../../lib/rules/no-extra-semicolons/README.md): Disallow extra semicolons (Autofixable). - [`no-invalid-double-slash-comments`](../../../lib/rules/no-invalid-double-slash-comments/README.md): Disallow double-slash comments (`//...`) which are not supported by CSS. -- [`no-invalid-position-at-import-rule`](../../../lib/rules/no-invalid-position-at-import-rule/README.md): Disallow invalid position @import rules within a stylesheet. +- [`no-invalid-position-at-import-rule`](../../../lib/rules/no-invalid-position-at-import-rule/README.md): Disallow invalid position `@import` rules within a stylesheet. ## Limit language features From 44d75567d4b9d23512c7ba5491e1424ce39c53f0 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Sun, 21 Mar 2021 14:27:41 +0400 Subject: [PATCH 04/10] Update lib/rules/no-invalid-position-at-import-rule/README.md --- lib/rules/no-invalid-position-at-import-rule/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/rules/no-invalid-position-at-import-rule/README.md b/lib/rules/no-invalid-position-at-import-rule/README.md index e896e5df61..fe7abfefe6 100644 --- a/lib/rules/no-invalid-position-at-import-rule/README.md +++ b/lib/rules/no-invalid-position-at-import-rule/README.md @@ -8,6 +8,7 @@ a {} @import 'foo.css'; /** ↑ * This @import */ +``` ## Options From 27e4fb86050770049718c60a4369f65067879818 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Sun, 21 Mar 2021 14:43:09 +0400 Subject: [PATCH 05/10] remove url from violation message --- .../__tests__/index.js | 6 ++-- .../index.js | 31 +++++-------------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js b/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js index 93ea4dff05..37c5aa73af 100644 --- a/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js +++ b/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js @@ -51,7 +51,7 @@ testRule({ a {} @import 'foo.css'; `, - message: messages.rejected('foo.css'), + message: messages.rejected, description: '@import after selector', line: 3, column: 4, @@ -61,7 +61,7 @@ testRule({ @media print {} @import url('foo.css'); `, - message: messages.rejected('foo.css'), + message: messages.rejected, description: '@import after another at-rule', line: 3, column: 4, @@ -71,7 +71,7 @@ testRule({ @media print {} @imPort URl('foo.css'); `, - message: messages.rejected('foo.css'), + message: messages.rejected, description: 'case insensitive', line: 3, column: 4, diff --git a/lib/rules/no-invalid-position-at-import-rule/index.js b/lib/rules/no-invalid-position-at-import-rule/index.js index 23263acdda..12b6bd9fd0 100644 --- a/lib/rules/no-invalid-position-at-import-rule/index.js +++ b/lib/rules/no-invalid-position-at-import-rule/index.js @@ -5,12 +5,11 @@ const report = require('../../utils/report'); const ruleMessages = require('../../utils/ruleMessages'); const validateOptions = require('../../utils/validateOptions'); -const valueParser = require('postcss-value-parser'); const ruleName = 'no-invalid-position-at-import-rule'; const messages = ruleMessages(ruleName, { - rejected: (atImport) => `Unexpected invalid position @import rule ${atImport}`, + rejected: 'Unexpected invalid position @import rule', }); function rule(actual) { @@ -30,16 +29,12 @@ function rule(actual) { if (node.type === 'atrule' && /^import$/i.test(node.name)) { if (invalidPosition) { - const url = getAtImportUrl(node); - - if (url) { - report({ - message: messages.rejected(url), - node, - result, - ruleName, - }); - } + report({ + message: messages.rejected, + node, + result, + ruleName, + }); } return; @@ -50,18 +45,6 @@ function rule(actual) { }; } -function getAtImportUrl(node) { - const params = valueParser(node.params).nodes; - - if (!params.length) { - return null; - } - - return params[0].type === 'function' && /^url$/i.test(params[0].value) - ? params[0].nodes[0].value - : params[0].value; -} - rule.ruleName = ruleName; rule.messages = messages; module.exports = rule; From 89f70d1434a36242cb0a9653998311efd0a140a0 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Sun, 21 Mar 2021 14:57:58 +0400 Subject: [PATCH 06/10] add stripIndent in test cases --- .../__tests__/index.js | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js b/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js index 37c5aa73af..38635be0f2 100644 --- a/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js +++ b/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js @@ -1,5 +1,7 @@ 'use strict'; +const stripIndent = require('common-tags').stripIndent; + const { messages, ruleName } = require('..'); testRule({ @@ -8,38 +10,38 @@ testRule({ accept: [ { - code: ` - @import 'foo.css'; - a {} + code: stripIndent` + @import 'foo.css'; + a {} `, description: '@import on first line', }, { - code: ` - /* some comment */ - @import 'foo.css'; + code: stripIndent` + /* some comment */ + @import 'foo.css'; `, description: '@import after comment', }, { - code: ` - @charset 'utf-8'; - @import 'foo.css'; + code: stripIndent` + @charset 'utf-8'; + @import 'foo.css'; `, description: '@import after @charset ', }, { - code: ` - @import 'foo.css'; - @import 'bar.css'; + code: stripIndent` + @import 'foo.css'; + @import 'bar.css'; `, description: '@import after another @import', }, { - code: ` - @CHARSET 'utf-8'; - @imPORT 'foo.css'; - @import 'bar.css'; + code: stripIndent` + @CHARSET 'utf-8'; + @imPORT 'foo.css'; + @import 'bar.css'; `, description: 'case insensitive', }, @@ -47,34 +49,34 @@ testRule({ reject: [ { - code: ` - a {} - @import 'foo.css'; + code: stripIndent` + a {} + @import 'foo.css'; `, message: messages.rejected, description: '@import after selector', - line: 3, - column: 4, + line: 2, + column: 1, }, { - code: ` - @media print {} - @import url('foo.css'); + code: stripIndent` + @media print {} + @import url('foo.css'); `, message: messages.rejected, description: '@import after another at-rule', - line: 3, - column: 4, + line: 2, + column: 1, }, { - code: ` - @media print {} - @imPort URl('foo.css'); + code: stripIndent` + @media print {} + @imPort URl('foo.css'); `, message: messages.rejected, description: 'case insensitive', - line: 3, - column: 4, + line: 2, + column: 1, }, ], }); From 77bf542591abae51db1162af6bcb94c4ad13c1db Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Sun, 21 Mar 2021 15:18:21 +0400 Subject: [PATCH 07/10] add more tests --- .../__tests__/index.js | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js b/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js index 38635be0f2..8699f3d36c 100644 --- a/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js +++ b/lib/rules/no-invalid-position-at-import-rule/__tests__/index.js @@ -78,5 +78,36 @@ testRule({ line: 2, column: 1, }, + { + code: stripIndent` + @import 'foo.css'; + a {} + @import 'bar.css'; + `, + message: messages.rejected, + description: 'only second @import reported', + line: 3, + column: 1, + }, + { + code: stripIndent` + a {} + @import 'foo.css'; + @import 'bar.css'; + `, + warnings: [ + { + message: messages.rejected, + line: 2, + column: 1, + }, + { + message: messages.rejected, + line: 3, + column: 1, + }, + ], + description: 'all @import reported', + }, ], }); From 5f3d45408cdeb0b47ffbee02f2badb03ce77b820 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Sun, 21 Mar 2021 18:12:57 +0400 Subject: [PATCH 08/10] Update lib/rules/no-invalid-position-at-import-rule/README.md Co-authored-by: Richard Hallows --- lib/rules/no-invalid-position-at-import-rule/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/rules/no-invalid-position-at-import-rule/README.md b/lib/rules/no-invalid-position-at-import-rule/README.md index fe7abfefe6..1ef52e6695 100644 --- a/lib/rules/no-invalid-position-at-import-rule/README.md +++ b/lib/rules/no-invalid-position-at-import-rule/README.md @@ -10,6 +10,8 @@ a {} * This @import */ ``` +Any `@import` rules must precede all other valid at-rules and style rules in a style sheet (ignoring `@charset`), or else the `@import` rule is invalid. + ## Options ### `true` From c2ff6b17ba6939b8cd5529259709dd2e20aba256 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Tue, 23 Mar 2021 23:05:37 +0400 Subject: [PATCH 09/10] use toLowerCase() for case insensitive string comparison --- lib/rules/no-invalid-position-at-import-rule/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/rules/no-invalid-position-at-import-rule/index.js b/lib/rules/no-invalid-position-at-import-rule/index.js index 12b6bd9fd0..810230fad6 100644 --- a/lib/rules/no-invalid-position-at-import-rule/index.js +++ b/lib/rules/no-invalid-position-at-import-rule/index.js @@ -23,11 +23,13 @@ function rule(actual) { let invalidPosition = false; root.walk((node) => { - if (node.type === 'comment' || (node.type === 'atrule' && /^charset$/i.test(node.name))) { + const nodeName = node.name && node.name.toLowerCase(); + + if (node.type === 'comment' || (node.type === 'atrule' && nodeName === 'charset')) { return; } - if (node.type === 'atrule' && /^import$/i.test(node.name)) { + if (node.type === 'atrule' && nodeName === 'import') { if (invalidPosition) { report({ message: messages.rejected, From 9eaee88c62d9996c9be196b7d32ad02f1f239658 Mon Sep 17 00:00:00 2001 From: Ilya Chudin Date: Tue, 23 Mar 2021 23:12:10 +0400 Subject: [PATCH 10/10] Update lib/rules/no-invalid-position-at-import-rule/README.md Co-authored-by: Masafumi Koba <473530+ybiquitous@users.noreply.github.com> --- lib/rules/no-invalid-position-at-import-rule/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/no-invalid-position-at-import-rule/README.md b/lib/rules/no-invalid-position-at-import-rule/README.md index 1ef52e6695..77cbe4546d 100644 --- a/lib/rules/no-invalid-position-at-import-rule/README.md +++ b/lib/rules/no-invalid-position-at-import-rule/README.md @@ -10,7 +10,7 @@ a {} * This @import */ ``` -Any `@import` rules must precede all other valid at-rules and style rules in a style sheet (ignoring `@charset`), or else the `@import` rule is invalid. +Any `@import` rules must precede all other valid at-rules and style rules in a stylesheet (ignoring `@charset`), or else the `@import` rule is invalid. ## Options