From 1bc1fa9c629fd4f92b1f0191984f4f3c404df64f Mon Sep 17 00:00:00 2001 From: kimulaco Date: Tue, 31 Jan 2023 20:01:43 +0900 Subject: [PATCH 1/7] Add test case --- .../keyframe-selector-notation/__tests__/index.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/rules/keyframe-selector-notation/__tests__/index.js b/lib/rules/keyframe-selector-notation/__tests__/index.js index 7b5e73a2c3..eb8c157522 100644 --- a/lib/rules/keyframe-selector-notation/__tests__/index.js +++ b/lib/rules/keyframe-selector-notation/__tests__/index.js @@ -29,6 +29,10 @@ testRule({ code: '@keyframes foo { from, to {} }', description: 'selector lists', }, + { + code: '@keyframes foo { enter 0% {} enter 100% {} }', + description: 'timeline-range-name', + }, ], reject: [ @@ -166,6 +170,10 @@ testRule({ code: '@keyframes foo { 0%, 100% {} }', description: 'selector lists', }, + { + code: '@keyframes foo { enter 0% {} enter 100% {} }', + description: 'timeline-range-name', + }, ], reject: [ @@ -301,6 +309,10 @@ testRule({ { code: '@keyframes foo { from,to {} }', }, + { + code: '@keyframes foo { enter 0% {} enter 100% {} }', + description: 'timeline-range-name', + }, ], reject: [ From bef0f272f394853a83b41e44a416300e13b87336 Mon Sep 17 00:00:00 2001 From: kimulaco Date: Tue, 31 Jan 2023 20:05:27 +0900 Subject: [PATCH 2/7] Ignore if the selector has multiple tags --- lib/rules/keyframe-selector-notation/index.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/rules/keyframe-selector-notation/index.js b/lib/rules/keyframe-selector-notation/index.js index b83301935c..73bbbc8de2 100644 --- a/lib/rules/keyframe-selector-notation/index.js +++ b/lib/rules/keyframe-selector-notation/index.js @@ -73,6 +73,10 @@ const rule = (primary, _, context) => { atRuleKeyframes.walkRules((keyframeRule) => { transformSelector(result, keyframeRule, (selectors) => { + if (hasMultipleTags(selectors)) { + return; + } + selectors.walkTags((selectorTag) => { checkSelector( selectorTag.value, @@ -148,6 +152,24 @@ function getSelectorsInBlock(atRule) { return selectors; } +/** + * @param {import('postcss-selector-parser').Root} selectors + * @returns boolean + */ +function hasMultipleTags(selectors) { + for (const selectorNode of Array.from(selectors.nodes)) { + const tagNodes = selectorNode.nodes.filter((node) => { + return node.type === 'tag'; + }); + + if (tagNodes.length >= 2) { + return true; + } + } + + return false; +} + rule.ruleName = ruleName; rule.messages = messages; rule.meta = meta; From 10832deecd2299847e6ba53e96e13f3b01266e84 Mon Sep 17 00:00:00 2001 From: kimulaco Date: Tue, 31 Jan 2023 20:08:36 +0900 Subject: [PATCH 3/7] Add changeset --- .changeset/spotty-baboons-train.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/spotty-baboons-train.md diff --git a/.changeset/spotty-baboons-train.md b/.changeset/spotty-baboons-train.md new file mode 100644 index 0000000000..870126130d --- /dev/null +++ b/.changeset/spotty-baboons-train.md @@ -0,0 +1,5 @@ +--- +"stylelint": patch +--- + +Fixed: `keyframe-selector-notation` false positives for named timeline ranges From d0b97095a4d61981f378a39ba4f5e3eeefbc76cc Mon Sep 17 00:00:00 2001 From: kimulaco Date: Wed, 1 Feb 2023 00:24:46 +0900 Subject: [PATCH 4/7] Fix to ignore when using named timeline ranges --- .../__tests__/index.js | 54 +++++++++++++++++-- lib/rules/keyframe-selector-notation/index.js | 11 ++-- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/lib/rules/keyframe-selector-notation/__tests__/index.js b/lib/rules/keyframe-selector-notation/__tests__/index.js index eb8c157522..113056d539 100644 --- a/lib/rules/keyframe-selector-notation/__tests__/index.js +++ b/lib/rules/keyframe-selector-notation/__tests__/index.js @@ -29,9 +29,25 @@ testRule({ code: '@keyframes foo { from, to {} }', description: 'selector lists', }, + { + code: '@keyframes foo { cover 0% {} cover 100% {} }', + description: 'timeline-range-name cover', + }, + { + code: '@keyframes foo { contain 0% {} contain 100% {} }', + description: 'timeline-range-name contain', + }, + { + code: '@keyframes foo { entry 0% {} entry 100% {} }', + description: 'timeline-range-name entry', + }, { code: '@keyframes foo { enter 0% {} enter 100% {} }', - description: 'timeline-range-name', + description: 'timeline-range-name enter', + }, + { + code: '@keyframes foo { exit 0% {} exit 100% {} }', + description: 'timeline-range-name exit', }, ], @@ -170,9 +186,25 @@ testRule({ code: '@keyframes foo { 0%, 100% {} }', description: 'selector lists', }, + { + code: '@keyframes foo { cover 0% {} cover 100% {} }', + description: 'timeline-range-name cover', + }, + { + code: '@keyframes foo { contain 0% {} contain 100% {} }', + description: 'timeline-range-name contain', + }, + { + code: '@keyframes foo { entry 0% {} entry 100% {} }', + description: 'timeline-range-name entry', + }, { code: '@keyframes foo { enter 0% {} enter 100% {} }', - description: 'timeline-range-name', + description: 'timeline-range-name enter', + }, + { + code: '@keyframes foo { exit 0% {} exit 100% {} }', + description: 'timeline-range-name exit', }, ], @@ -309,9 +341,25 @@ testRule({ { code: '@keyframes foo { from,to {} }', }, + { + code: '@keyframes foo { cover 0% {} cover 100% {} }', + description: 'timeline-range-name cover', + }, + { + code: '@keyframes foo { contain 0% {} contain 100% {} }', + description: 'timeline-range-name contain', + }, + { + code: '@keyframes foo { entry 0% {} entry 100% {} }', + description: 'timeline-range-name entry', + }, { code: '@keyframes foo { enter 0% {} enter 100% {} }', - description: 'timeline-range-name', + description: 'timeline-range-name enter', + }, + { + code: '@keyframes foo { exit 0% {} exit 100% {} }', + description: 'timeline-range-name exit', }, ], diff --git a/lib/rules/keyframe-selector-notation/index.js b/lib/rules/keyframe-selector-notation/index.js index 73bbbc8de2..78ddcd151d 100644 --- a/lib/rules/keyframe-selector-notation/index.js +++ b/lib/rules/keyframe-selector-notation/index.js @@ -19,6 +19,7 @@ const meta = { const PERCENTAGE_SELECTORS = new Set(['0%', '100%']); const KEYWORD_SELECTORS = new Set(['from', 'to']); +const NAMED_TIMELINE_RABGE_SELECTORS = new Set(['cover', 'contain', 'entry', 'enter', 'exit']); const PERCENTAGE_TO_KEYWORD = new Map([ ['0%', 'from'], ['100%', 'to'], @@ -73,7 +74,7 @@ const rule = (primary, _, context) => { atRuleKeyframes.walkRules((keyframeRule) => { transformSelector(result, keyframeRule, (selectors) => { - if (hasMultipleTags(selectors)) { + if (isNamedTimelineRange(selectors)) { return; } @@ -156,13 +157,11 @@ function getSelectorsInBlock(atRule) { * @param {import('postcss-selector-parser').Root} selectors * @returns boolean */ -function hasMultipleTags(selectors) { +function isNamedTimelineRange(selectors) { for (const selectorNode of Array.from(selectors.nodes)) { - const tagNodes = selectorNode.nodes.filter((node) => { - return node.type === 'tag'; - }); + const firstTagNode = selectorNode.nodes.filter((node) => node.type === 'tag')[0]; - if (tagNodes.length >= 2) { + if (firstTagNode?.value && NAMED_TIMELINE_RABGE_SELECTORS.has(firstTagNode.value)) { return true; } } From 05fddbcf4a8b0df260edfaee7cfa181bc2f3ab9f Mon Sep 17 00:00:00 2001 From: kimulaco Date: Wed, 1 Feb 2023 00:41:08 +0900 Subject: [PATCH 5/7] Fix error when node12 --- lib/rules/keyframe-selector-notation/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/rules/keyframe-selector-notation/index.js b/lib/rules/keyframe-selector-notation/index.js index 78ddcd151d..d2767de5ef 100644 --- a/lib/rules/keyframe-selector-notation/index.js +++ b/lib/rules/keyframe-selector-notation/index.js @@ -160,8 +160,9 @@ function getSelectorsInBlock(atRule) { function isNamedTimelineRange(selectors) { for (const selectorNode of Array.from(selectors.nodes)) { const firstTagNode = selectorNode.nodes.filter((node) => node.type === 'tag')[0]; + const firstTagValue = firstTagNode && firstTagNode.value ? firstTagNode.value : ''; - if (firstTagNode?.value && NAMED_TIMELINE_RABGE_SELECTORS.has(firstTagNode.value)) { + if (firstTagValue && NAMED_TIMELINE_RABGE_SELECTORS.has(firstTagValue)) { return true; } } From 80a8351c20c1c14d6dfebd7dfc2580296d2e567a Mon Sep 17 00:00:00 2001 From: kimulaco Date: Sat, 4 Feb 2023 00:05:24 +0900 Subject: [PATCH 6/7] Fix check named-timeline-range and typo --- lib/rules/keyframe-selector-notation/index.js | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/lib/rules/keyframe-selector-notation/index.js b/lib/rules/keyframe-selector-notation/index.js index d2767de5ef..9854e40eec 100644 --- a/lib/rules/keyframe-selector-notation/index.js +++ b/lib/rules/keyframe-selector-notation/index.js @@ -19,7 +19,7 @@ const meta = { const PERCENTAGE_SELECTORS = new Set(['0%', '100%']); const KEYWORD_SELECTORS = new Set(['from', 'to']); -const NAMED_TIMELINE_RABGE_SELECTORS = new Set(['cover', 'contain', 'entry', 'enter', 'exit']); +const NAMED_TIMELINE_RANGE_SELECTORS = new Set(['cover', 'contain', 'entry', 'enter', 'exit']); const PERCENTAGE_TO_KEYWORD = new Map([ ['0%', 'from'], ['100%', 'to'], @@ -74,11 +74,15 @@ const rule = (primary, _, context) => { atRuleKeyframes.walkRules((keyframeRule) => { transformSelector(result, keyframeRule, (selectors) => { - if (isNamedTimelineRange(selectors)) { - return; - } + let first = true; selectors.walkTags((selectorTag) => { + if (first && NAMED_TIMELINE_RANGE_SELECTORS.has(selectorTag.value)) { + return false; + } + + first = false; + checkSelector( selectorTag.value, optionFuncs[primary], @@ -153,23 +157,6 @@ function getSelectorsInBlock(atRule) { return selectors; } -/** - * @param {import('postcss-selector-parser').Root} selectors - * @returns boolean - */ -function isNamedTimelineRange(selectors) { - for (const selectorNode of Array.from(selectors.nodes)) { - const firstTagNode = selectorNode.nodes.filter((node) => node.type === 'tag')[0]; - const firstTagValue = firstTagNode && firstTagNode.value ? firstTagNode.value : ''; - - if (firstTagValue && NAMED_TIMELINE_RABGE_SELECTORS.has(firstTagValue)) { - return true; - } - } - - return false; -} - rule.ruleName = ruleName; rule.messages = messages; rule.meta = meta; From ca57baf4ed0404f8202514eff9e19e5bd7cca5ae Mon Sep 17 00:00:00 2001 From: kimulaco Date: Sat, 4 Feb 2023 00:16:00 +0900 Subject: [PATCH 7/7] Fix to commonize duplicated test cases --- .../__tests__/index.js | 86 ++++++------------- 1 file changed, 26 insertions(+), 60 deletions(-) diff --git a/lib/rules/keyframe-selector-notation/__tests__/index.js b/lib/rules/keyframe-selector-notation/__tests__/index.js index 113056d539..1066dd5fbc 100644 --- a/lib/rules/keyframe-selector-notation/__tests__/index.js +++ b/lib/rules/keyframe-selector-notation/__tests__/index.js @@ -2,6 +2,29 @@ const { messages, ruleName } = require('..'); +const ACCEPT_TIMELINE_RANGE_NAME_TEST_CASES = [ + { + code: '@keyframes foo { cover 0% {} cover 100% {} }', + description: 'timeline-range-name cover', + }, + { + code: '@keyframes foo { contain 0% {} contain 100% {} }', + description: 'timeline-range-name contain', + }, + { + code: '@keyframes foo { entry 0% {} entry 100% {} }', + description: 'timeline-range-name entry', + }, + { + code: '@keyframes foo { enter 0% {} enter 100% {} }', + description: 'timeline-range-name enter', + }, + { + code: '@keyframes foo { exit 0% {} exit 100% {} }', + description: 'timeline-range-name exit', + }, +]; + testRule({ ruleName, config: ['keyword'], @@ -29,26 +52,7 @@ testRule({ code: '@keyframes foo { from, to {} }', description: 'selector lists', }, - { - code: '@keyframes foo { cover 0% {} cover 100% {} }', - description: 'timeline-range-name cover', - }, - { - code: '@keyframes foo { contain 0% {} contain 100% {} }', - description: 'timeline-range-name contain', - }, - { - code: '@keyframes foo { entry 0% {} entry 100% {} }', - description: 'timeline-range-name entry', - }, - { - code: '@keyframes foo { enter 0% {} enter 100% {} }', - description: 'timeline-range-name enter', - }, - { - code: '@keyframes foo { exit 0% {} exit 100% {} }', - description: 'timeline-range-name exit', - }, + ...ACCEPT_TIMELINE_RANGE_NAME_TEST_CASES, ], reject: [ @@ -186,26 +190,7 @@ testRule({ code: '@keyframes foo { 0%, 100% {} }', description: 'selector lists', }, - { - code: '@keyframes foo { cover 0% {} cover 100% {} }', - description: 'timeline-range-name cover', - }, - { - code: '@keyframes foo { contain 0% {} contain 100% {} }', - description: 'timeline-range-name contain', - }, - { - code: '@keyframes foo { entry 0% {} entry 100% {} }', - description: 'timeline-range-name entry', - }, - { - code: '@keyframes foo { enter 0% {} enter 100% {} }', - description: 'timeline-range-name enter', - }, - { - code: '@keyframes foo { exit 0% {} exit 100% {} }', - description: 'timeline-range-name exit', - }, + ...ACCEPT_TIMELINE_RANGE_NAME_TEST_CASES, ], reject: [ @@ -341,26 +326,7 @@ testRule({ { code: '@keyframes foo { from,to {} }', }, - { - code: '@keyframes foo { cover 0% {} cover 100% {} }', - description: 'timeline-range-name cover', - }, - { - code: '@keyframes foo { contain 0% {} contain 100% {} }', - description: 'timeline-range-name contain', - }, - { - code: '@keyframes foo { entry 0% {} entry 100% {} }', - description: 'timeline-range-name entry', - }, - { - code: '@keyframes foo { enter 0% {} enter 100% {} }', - description: 'timeline-range-name enter', - }, - { - code: '@keyframes foo { exit 0% {} exit 100% {} }', - description: 'timeline-range-name exit', - }, + ...ACCEPT_TIMELINE_RANGE_NAME_TEST_CASES, ], reject: [