diff --git a/.github/labeler.yml b/.github/labeler.yml index 1be04be84..c9341f7c6 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,5 +1,6 @@ "common-tools": - packages/base-cli/** + - packages/postcss-tape/** - plugins/postcss-base-plugin/** - rollup/** diff --git a/package-lock.json b/package-lock.json index 3ddaf2002..3bab89bc1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6753,10 +6753,6 @@ "dependencies": { "postcss-selector-parser": "^6.0.8" }, - "devDependencies": { - "postcss": "^8.3.6", - "postcss-tape": "^6.0.1" - }, "engines": { "node": "^12 || ^14 || >=16" }, @@ -10601,9 +10597,7 @@ "postcss-pseudo-class-any-link": { "version": "file:plugins/postcss-pseudo-class-any-link", "requires": { - "postcss": "^8.3.6", - "postcss-selector-parser": "^6.0.8", - "postcss-tape": "^6.0.1" + "postcss-selector-parser": "^6.0.8" } }, "postcss-replace-overflow-wrap": { diff --git a/packages/postcss-tape/src/index.ts b/packages/postcss-tape/src/index.ts index 8fc1d7849..3bc49bf83 100644 --- a/packages/postcss-tape/src/index.ts +++ b/packages/postcss-tape/src/index.ts @@ -131,6 +131,8 @@ export default function runner(currentPlugin: PluginCreator) { // Test cases return async (options: Record) => { + const failureSummary = new Set(); + for (const testCaseLabel in options) { const testCaseOptions = options[testCaseLabel]; @@ -172,12 +174,14 @@ export default function runner(currentPlugin: PluginCreator) { { file: testFilePath, line: 1, col: 1 }, )); } else { + failureSummary.add(testCaseLabel); console.error(`\n${testCaseLabel}\n\nmissing or broken "expect" file: "${path.parse(expectFilePath).base}"\n\n${dashesSeparator}`); } } let result: Result; + let sawException = false; try { result = await postcss(plugins).process(input, { from: testFilePath, @@ -188,6 +192,7 @@ export default function runner(currentPlugin: PluginCreator) { }, }); } catch (err) { + sawException = true; if (testCaseOptions.exception && testCaseOptions.exception.test(err.message)) { // expected an exception and got one. continue; @@ -197,6 +202,21 @@ export default function runner(currentPlugin: PluginCreator) { throw err; } + if (!sawException && testCaseOptions.exception) { + hasErrors = true; + + if (emitGitHubAnnotations) { + console.log(formatGitHubActionAnnotation( + `${testCaseLabel}\n\nexpected an exception but got none`, + 'error', + { file: testFilePath, line: 1, col: 1 }, + )); + } else { + failureSummary.add(testCaseLabel); + console.error(`\n${testCaseLabel}\n\nexpected an exception but got none\n\n${dashesSeparator}`); + } + } + // Try to write the result file, even if further checks fails. // This helps writing new tests for plugins. // Taking the result file as a starting point for the expect file. @@ -225,6 +245,7 @@ export default function runner(currentPlugin: PluginCreator) { { file: normalizeFilePathForGithubAnnotation(expectFilePath), line: 1, col: 1 }, )); } else { + failureSummary.add(testCaseLabel); console.error(formatCSSAssertError(testCaseLabel, testCaseOptions, err)); } } @@ -246,6 +267,7 @@ export default function runner(currentPlugin: PluginCreator) { { file: testFilePath, line: 1, col: 1 }, )); } else { + failureSummary.add(testCaseLabel); console.error(`\n${testCaseLabel}\n\nbroken source map: ${JSON.stringify(result.map.toJSON().sources)}\n\n${dashesSeparator}`); } } @@ -282,6 +304,7 @@ export default function runner(currentPlugin: PluginCreator) { { file: expectFilePath, line: 1, col: 1 }, )); } else { + failureSummary.add(testCaseLabel); console.error(`\n${testCaseLabel}\n\nresult was not parsable with PostCSS.\n\n${dashesSeparator}`); } } @@ -317,6 +340,7 @@ export default function runner(currentPlugin: PluginCreator) { { file: normalizeFilePathForGithubAnnotation(expectFilePath), line: 1, col: 1 }, )); } else { + failureSummary.add(testCaseLabel); console.error('testing older PostCSS:\n' + formatCSSAssertError(testCaseLabel, testCaseOptions, err)); } } @@ -338,12 +362,20 @@ export default function runner(currentPlugin: PluginCreator) { { file: normalizeFilePathForGithubAnnotation(expectFilePath), line: 1, col: 1 }, )); } else { + failureSummary.add(testCaseLabel); console.error(formatWarningsAssertError(testCaseLabel, testCaseOptions, result.warnings().length, testCaseOptions.warnings)); } } } } + if (failureSummary.size) { + console.error('\nunexpected failures:'); + for (const label of failureSummary.values()) { + console.error(' - ' + label); + } + } + if (hasErrors) { process.exit(1); } diff --git a/packages/postcss-tape/test-self/basic.break-css.expect.log b/packages/postcss-tape/test-self/basic.break-css.expect.log index d50ea9f1c..ac614bab7 100644 --- a/packages/postcss-tape/test-self/basic.break-css.expect.log +++ b/packages/postcss-tape/test-self/basic.break-css.expect.log @@ -4,3 +4,6 @@ basic:break-css result was not parsable with PostCSS. ---------------------------------------- + +unexpected failures: + - basic:break-css diff --git a/packages/postcss-tape/test-self/basic.broken-sourcemap.expect.log b/packages/postcss-tape/test-self/basic.broken-sourcemap.expect.log index 0f3afcb3b..c3a94ee30 100644 --- a/packages/postcss-tape/test-self/basic.broken-sourcemap.expect.log +++ b/packages/postcss-tape/test-self/basic.broken-sourcemap.expect.log @@ -4,3 +4,6 @@ basic:broken-sourcemap broken source map: ["basic.css",""] ---------------------------------------- + +unexpected failures: + - basic:broken-sourcemap diff --git a/packages/postcss-tape/test-self/basic.postcss-8-3.expect.log b/packages/postcss-tape/test-self/basic.postcss-8-3.expect.log index f22b29868..3ba4ebe01 100644 --- a/packages/postcss-tape/test-self/basic.postcss-8-3.expect.log +++ b/packages/postcss-tape/test-self/basic.postcss-8-3.expect.log @@ -19,3 +19,6 @@ output changed : ^ ---------------------------------------- + +unexpected failures: + - basic:postcss-8-3 diff --git a/packages/postcss-tape/test-self/basic.with-diff-in-expect.expect.log b/packages/postcss-tape/test-self/basic.with-diff-in-expect.expect.log index 453442a96..1eb8f910d 100644 --- a/packages/postcss-tape/test-self/basic.with-diff-in-expect.expect.log +++ b/packages/postcss-tape/test-self/basic.with-diff-in-expect.expect.log @@ -12,3 +12,6 @@ output changed : ^ ---------------------------------------- + +unexpected failures: + - basic:with-diff-in-expect diff --git a/packages/postcss-tape/test-self/basic.with-warnings.expect.log b/packages/postcss-tape/test-self/basic.with-warnings.expect.log index 228b8a0cf..d30915f02 100644 --- a/packages/postcss-tape/test-self/basic.with-warnings.expect.log +++ b/packages/postcss-tape/test-self/basic.with-warnings.expect.log @@ -31,3 +31,8 @@ unexpected or missing warnings : - expected 7 ---------------------------------------- + +unexpected failures: + - basic:with-one-missing-warning + - basic:with-one-unexpected-warning + - basic:with-multiple-warnings diff --git a/packages/postcss-tape/test-self/basic.without-expect.expect.log b/packages/postcss-tape/test-self/basic.without-expect.expect.log index 1558b84bc..47750e7cd 100644 --- a/packages/postcss-tape/test-self/basic.without-expect.expect.log +++ b/packages/postcss-tape/test-self/basic.without-expect.expect.log @@ -4,3 +4,6 @@ basic:without-expect missing or broken "expect" file: "basic.without-expect.expect.css" ---------------------------------------- + +unexpected failures: + - basic:without-expect diff --git a/plugin-packs/postcss-preset-env/.tape.mjs b/plugin-packs/postcss-preset-env/.tape.mjs index 0fcd6de73..5747be165 100644 --- a/plugin-packs/postcss-preset-env/.tape.mjs +++ b/plugin-packs/postcss-preset-env/.tape.mjs @@ -38,6 +38,12 @@ postcssTape(plugin)({ browsers: 'chrome >= 38' } }, + 'basic:ie10': { + message: 'supports { browsers: "ie >= 10" } usage', + options: { + browsers: 'ie >= 10' + } + }, 'basic:ch88-ff78': { message: 'uses :is pseudo for nesting with modern browsers { browsers: "chrome >= 88, firefox >= 78", stage: 0 }', options: { diff --git a/plugin-packs/postcss-preset-env/src/lib/get-options-for-browsers-by-feature.js b/plugin-packs/postcss-preset-env/src/lib/get-options-for-browsers-by-feature.js index af7c5f788..3acdeaf9a 100644 --- a/plugin-packs/postcss-preset-env/src/lib/get-options-for-browsers-by-feature.js +++ b/plugin-packs/postcss-preset-env/src/lib/get-options-for-browsers-by-feature.js @@ -24,6 +24,24 @@ export default function getOptionsForBrowsersByFeature(browsers, feature, cssdb) return {}; + case 'any-link-pseudo-class': + { + const hasIEOrEdge = supportedBrowsers.find((browserslistEntry) => { + return browserslistEntry.startsWith('ie ') || browserslistEntry.startsWith('edge '); + }); + + if (hasIEOrEdge) { + log('Adding area[href] fallbacks for ":any-link" support in Edge and IE.'); + return { + subFeatures: { + areaHrefNeedsFixing: true, + }, + }; + } + } + + return {}; + default: return {}; } diff --git a/plugin-packs/postcss-preset-env/test/basic.autoprefixer.expect.css b/plugin-packs/postcss-preset-env/test/basic.autoprefixer.expect.css index 73da9bc94..44b0c6604 100644 --- a/plugin-packs/postcss-preset-env/test/basic.autoprefixer.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.autoprefixer.expect.css @@ -216,7 +216,7 @@ order: 22; } -.test-any-link-pseudo-class:link,.test-any-link-pseudo-class:visited { +.test-any-link-pseudo-class:link, .test-any-link-pseudo-class:visited, area.test-any-link-pseudo-class[href] { order: 23; } diff --git a/plugin-packs/postcss-preset-env/test/basic.autoprefixer.false.expect.css b/plugin-packs/postcss-preset-env/test/basic.autoprefixer.false.expect.css index 73da9bc94..44b0c6604 100644 --- a/plugin-packs/postcss-preset-env/test/basic.autoprefixer.false.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.autoprefixer.false.expect.css @@ -216,7 +216,7 @@ order: 22; } -.test-any-link-pseudo-class:link,.test-any-link-pseudo-class:visited { +.test-any-link-pseudo-class:link, .test-any-link-pseudo-class:visited, area.test-any-link-pseudo-class[href] { order: 23; } diff --git a/plugin-packs/postcss-preset-env/test/basic.expect.css b/plugin-packs/postcss-preset-env/test/basic.expect.css index dcf13bfea..79b4e9721 100644 --- a/plugin-packs/postcss-preset-env/test/basic.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.expect.css @@ -232,7 +232,7 @@ order: 22; } -.test-any-link-pseudo-class:link,.test-any-link-pseudo-class:visited { +.test-any-link-pseudo-class:link, .test-any-link-pseudo-class:visited, area.test-any-link-pseudo-class[href] { order: 23; } diff --git a/plugin-packs/postcss-preset-env/test/basic.ie10.expect.css b/plugin-packs/postcss-preset-env/test/basic.ie10.expect.css new file mode 100644 index 000000000..509e612b8 --- /dev/null +++ b/plugin-packs/postcss-preset-env/test/basic.ie10.expect.css @@ -0,0 +1,311 @@ +:root { + --order: 1; +} + +.test-custom-properties { + -ms-flex-order: 1; + order: 1; + -ms-flex-order: var(--order); + order: var(--order); +} + +.test-image-set-function { + background-image: url(img/test.png); + background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x); + -ms-flex-order: 2; + order: 2; +} + +@media (min-resolution: 192dpi) { + +.test-image-set-function { + background-image: url(img/test-2x.png); +} +} + +[dir="ltr"] .test-logical-properties-and-values { + margin: 1px 4px 3px 2px; +} + +[dir="rtl"] .test-logical-properties-and-values { + margin: 1px 2px 3px 4px; +} + +.test-logical-properties-and-values { + -ms-flex-order: 3; + order: 3; + padding-top: 5px; + padding-bottom: 5px; +} + +.test-nesting-rules { + -ms-flex-order: 4; + order: 4; + + & p { + -ms-flex-order: 5; + order: 5; + } + + -ms-flex-order: 6; + + order: 6; +} + +.test-nesting-rules, +#test-is-pseudo { + -ms-flex-order: 7; + order: 7; + + & + p { + -ms-flex-order: 8; + order: 8; + } + + -ms-flex-order: 9; + + order: 9; +} + +@custom-media --narrow-window (max-width: 30em); + +@media (--narrow-window) { + .test-custom-media-queries { + -ms-flex-order: 10; + order: 10; + } +} + +@media (min-width: 480px) and (max-width: 767px) { + .test-media-query-ranges { + -ms-flex-order: 11; + order: 11; + } +} + +@custom-media --dark-mode (prefers-color-scheme: dark); + +@media (--dark-mode) { + body { + background-color: black; + color: white; + } +} + +@custom-selector :--heading h1, h2, h3, h4, h5, h6; + +.test-custom-selectors:--heading { + -ms-flex-order:12; + order:12; +} + +.test-case-insensitive-attributes[frame=hsides],.test-case-insensitive-attributes[frame=Hsides],.test-case-insensitive-attributes[frame=hSides],.test-case-insensitive-attributes[frame=HSides],.test-case-insensitive-attributes[frame=hsIdes],.test-case-insensitive-attributes[frame=HsIdes],.test-case-insensitive-attributes[frame=hSIdes],.test-case-insensitive-attributes[frame=HSIdes],.test-case-insensitive-attributes[frame=hsiDes],.test-case-insensitive-attributes[frame=HsiDes],.test-case-insensitive-attributes[frame=hSiDes],.test-case-insensitive-attributes[frame=HSiDes],.test-case-insensitive-attributes[frame=hsIDes],.test-case-insensitive-attributes[frame=HsIDes],.test-case-insensitive-attributes[frame=hSIDes],.test-case-insensitive-attributes[frame=HSIDes],.test-case-insensitive-attributes[frame=hsidEs],.test-case-insensitive-attributes[frame=HsidEs],.test-case-insensitive-attributes[frame=hSidEs],.test-case-insensitive-attributes[frame=HSidEs],.test-case-insensitive-attributes[frame=hsIdEs],.test-case-insensitive-attributes[frame=HsIdEs],.test-case-insensitive-attributes[frame=hSIdEs],.test-case-insensitive-attributes[frame=HSIdEs],.test-case-insensitive-attributes[frame=hsiDEs],.test-case-insensitive-attributes[frame=HsiDEs],.test-case-insensitive-attributes[frame=hSiDEs],.test-case-insensitive-attributes[frame=HSiDEs],.test-case-insensitive-attributes[frame=hsIDEs],.test-case-insensitive-attributes[frame=HsIDEs],.test-case-insensitive-attributes[frame=hSIDEs],.test-case-insensitive-attributes[frame=HSIDEs],.test-case-insensitive-attributes[frame=hsideS],.test-case-insensitive-attributes[frame=HsideS],.test-case-insensitive-attributes[frame=hSideS],.test-case-insensitive-attributes[frame=HSideS],.test-case-insensitive-attributes[frame=hsIdeS],.test-case-insensitive-attributes[frame=HsIdeS],.test-case-insensitive-attributes[frame=hSIdeS],.test-case-insensitive-attributes[frame=HSIdeS],.test-case-insensitive-attributes[frame=hsiDeS],.test-case-insensitive-attributes[frame=HsiDeS],.test-case-insensitive-attributes[frame=hSiDeS],.test-case-insensitive-attributes[frame=HSiDeS],.test-case-insensitive-attributes[frame=hsIDeS],.test-case-insensitive-attributes[frame=HsIDeS],.test-case-insensitive-attributes[frame=hSIDeS],.test-case-insensitive-attributes[frame=HSIDeS],.test-case-insensitive-attributes[frame=hsidES],.test-case-insensitive-attributes[frame=HsidES],.test-case-insensitive-attributes[frame=hSidES],.test-case-insensitive-attributes[frame=HSidES],.test-case-insensitive-attributes[frame=hsIdES],.test-case-insensitive-attributes[frame=HsIdES],.test-case-insensitive-attributes[frame=hSIdES],.test-case-insensitive-attributes[frame=HSIdES],.test-case-insensitive-attributes[frame=hsiDES],.test-case-insensitive-attributes[frame=HsiDES],.test-case-insensitive-attributes[frame=hSiDES],.test-case-insensitive-attributes[frame=HSiDES],.test-case-insensitive-attributes[frame=hsIDES],.test-case-insensitive-attributes[frame=HsIDES],.test-case-insensitive-attributes[frame=hSIDES],.test-case-insensitive-attributes[frame=HSIDES] { + -ms-flex-order: 13; + order: 13; +} + +.test-rebeccapurple-color { + color: #639; + -ms-flex-order: 14; + order: 14; +} + +.test-hexadecimal-alpha-notation { + background-color: rgba(243,243,243,0.95294); + color: rgba(0,0,0,0.2); + -ms-flex-order: 15; + order: 15; +} + +.test-color-functional-notation { + color: rgb(70% 13.5% 13.5% / 50%); + -ms-flex-order: 16; + order: 16; +} + +.test-lab-function { + background-color: rgb(179, 35, 35); + color: rgba(179, 34, 35, 0.5); + -ms-flex-order: 17; + order: 17; +} + +.test-system-ui-font-family { + font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif; + -ms-flex-order: 18; + order: 18; +} + +.test-font-variant-property { + font-feature-settings: "smcp"; + font-variant-caps: small-caps; + -ms-flex-order: 19; + order: 19; +} + +.test-all-property { + animation: none 0s ease 0s 1 normal none running; + backface-visibility: visible; + background: transparent none repeat 0 0 / auto auto padding-box border-box scroll; + border: medium none currentColor; + border-collapse: separate; + border-image: none; + border-radius: 0; + border-spacing: 0; + bottom: auto; + box-shadow: none; + box-sizing: content-box; + caption-side: top; + clear: none; + clip: auto; + color: #000; + columns: auto; + column-count: auto; + column-fill: balance; + column-gap: normal; + column-rule: medium none currentColor; + column-span: 1; + column-width: auto; + content: normal; + counter-increment: none; + counter-reset: none; + cursor: auto; + direction: ltr; + display: inline; + empty-cells: show; + float: none; + font-family: serif; + font-size: medium; + font-style: normal; + font-variant: normal; + font-weight: normal; + font-stretch: normal; + line-height: normal; + height: auto; + -ms-hyphens: none; + hyphens: none; + left: auto; + letter-spacing: normal; + list-style: disc outside none; + margin: 0; + max-height: none; + max-width: none; + min-height: 0; + min-width: 0; + opacity: 1; + orphans: 2; + outline: medium none invert; + overflow: visible; + overflow-x: visible; + overflow-y: visible; + padding: 0; + page-break-after: auto; + page-break-before: auto; + page-break-inside: auto; + perspective: none; + perspective-origin: 50% 50%; + position: static; + right: auto; + tab-size: 8; + table-layout: auto; + text-align: left; + text-align-last: auto; + text-decoration: none; + text-indent: 0; + text-shadow: none; + text-transform: none; + top: auto; + transform: none; + transform-origin: 50% 50% 0; + transform-style: flat; + transition: none 0s ease 0s; + unicode-bidi: normal; + vertical-align: baseline; + visibility: visible; + white-space: normal; + widows: 2; + width: auto; + word-spacing: normal; + z-index: auto; + all: initial; + -ms-flex-order: 20; + order: 20; +} + +.test-matches-pseudo-class:matches(:first-child, .special) { + -ms-flex-order: 21; + order: 21; +} + +.test-not-pseudo-class:not(:first-child):not(.special) { + -ms-flex-order: 22; + order: 22; +} + +.test-any-link-pseudo-class:link, .test-any-link-pseudo-class:visited, area.test-any-link-pseudo-class[href] { + -ms-flex-order: 23; + order: 23; +} + +.test-any-link-pseudo-class:any-link { + -ms-flex-order: 23; + order: 23; +} + +[dir="rtl"] .test-dir-pseudo-class { + -ms-flex-order: 24; + order: 24; +} + +.test-overflow-wrap-property { + -ms-flex-order: 25; + order: 25; + word-wrap: break-word; +} + +.test-focus-visible-pseudo-class.focus-visible { + -ms-flex-order: 26; + order: 26; +} + +.test-focus-visible-pseudo-class:focus-visible { + -ms-flex-order: 26; + order: 26; +} + +.test-double-position-gradients { + background-image: conic-gradient(yellowgreen 40%, gold 0deg,gold 75%, #f06 0deg); + background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg); +} + +.test-blank-pseudo-class:blank { + background-color: yellow; +} + +.test-has-pseudo-class[\:has\(.inner-class\)] { + background-color: yellow; +} + +.test-has-pseudo-class:has(.inner-class) { + background-color: yellow; +} + +.a:focus { + -ms-flex-order: 27; + order: 27; +} + +.a:hover { + -ms-flex-order: 27; + order: 27; +} + +.b:focus { + -ms-flex-order: 27; + order: 27; +} + +.b:hover { + -ms-flex-order: 27; + order: 27; +} diff --git a/plugin-packs/postcss-preset-env/test/basic.nesting.false.expect.css b/plugin-packs/postcss-preset-env/test/basic.nesting.false.expect.css index 5c67b8305..5d0ef9fd4 100644 --- a/plugin-packs/postcss-preset-env/test/basic.nesting.false.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.nesting.false.expect.css @@ -240,7 +240,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te order: 22; } -.test-any-link-pseudo-class:link,.test-any-link-pseudo-class:visited { +.test-any-link-pseudo-class:link, .test-any-link-pseudo-class:visited, area.test-any-link-pseudo-class[href] { order: 23; } diff --git a/plugin-packs/postcss-preset-env/test/basic.stage0.expect.css b/plugin-packs/postcss-preset-env/test/basic.stage0.expect.css index 56b998e3c..0fc409ecb 100644 --- a/plugin-packs/postcss-preset-env/test/basic.stage0.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.stage0.expect.css @@ -247,7 +247,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te order: 22; } -.test-any-link-pseudo-class:link,.test-any-link-pseudo-class:visited { +.test-any-link-pseudo-class:link, .test-any-link-pseudo-class:visited, area.test-any-link-pseudo-class[href] { order: 23; } diff --git a/plugins/postcss-pseudo-class-any-link/.tape.js b/plugins/postcss-pseudo-class-any-link/.tape.js deleted file mode 100644 index ebf17143e..000000000 --- a/plugins/postcss-pseudo-class-any-link/.tape.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - 'basic': { - message: 'supports basic usage' - }, - 'basic:preserve-false': { - message: 'supports { preserve: false } usage', - options: { - preserve: false - } - }, - 'generated-selector-cases': { - message: 'correctly handles generated cases', - warnings: 1, - options: { - preserve: false - } - }, -}; diff --git a/plugins/postcss-pseudo-class-any-link/.tape.mjs b/plugins/postcss-pseudo-class-any-link/.tape.mjs new file mode 100644 index 000000000..f599102f4 --- /dev/null +++ b/plugins/postcss-pseudo-class-any-link/.tape.mjs @@ -0,0 +1,39 @@ +import postcssTape from '../../packages/postcss-tape/dist/index.mjs'; +import plugin from 'postcss-pseudo-class-any-link'; + +postcssTape(plugin)({ + 'basic': { + message: 'supports basic usage' + }, + 'basic:preserve-false': { + message: 'supports { preserve: false } usage', + options: { + preserve: false + } + }, + 'basic:sub-features-area-href': { + message: 'supports { subFeatures: { areaHrefNeedsFixing: true } } usage', + options: { + subFeatures: { + areaHrefNeedsFixing: true + } + } + }, + 'generated-selector-cases': { + message: 'correctly handles generated cases', + warnings: 1, + options: { + preserve: false + } + }, + 'generated-selector-cases:sub-features-area-href': { + message: 'correctly handles generated cases with areaHrefNeedsFixing: true', + warnings: 1, + options: { + preserve: false, + subFeatures: { + areaHrefNeedsFixing: true + } + } + }, +}); diff --git a/plugins/postcss-pseudo-class-any-link/CHANGELOG.md b/plugins/postcss-pseudo-class-any-link/CHANGELOG.md index 97f61b144..67a8a7240 100644 --- a/plugins/postcss-pseudo-class-any-link/CHANGELOG.md +++ b/plugins/postcss-pseudo-class-any-link/CHANGELOG.md @@ -1,5 +1,20 @@ # Changes to PostCSS Pseudo Class Any Link +### Unreleased + +- Add support in IE and Edge for the `` element +- Add support for `:any-link` in pseudo class functions (`:not(:any-link)`) + +To support matching `:any-link` in IE and Edge on `` you need to set the `subFeatures.areaHrefNeedsFixing` option to `true`: + +```js +postcssPseudoClassAnyLink({ + subFeatures: { + areaHrefNeedsFixing: true + } +}) +``` + ### 7.0.2 (January 2, 2022) - Removed Sourcemaps from package tarball. diff --git a/plugins/postcss-pseudo-class-any-link/README.md b/plugins/postcss-pseudo-class-any-link/README.md index 86ad8b7e2..8e12bfbc6 100644 --- a/plugins/postcss-pseudo-class-any-link/README.md +++ b/plugins/postcss-pseudo-class-any-link/README.md @@ -80,6 +80,35 @@ nav :link > span, nav :visited > span { } ``` +### subFeatures + +#### areaHrefNeedsFixing + +The `subFeatures.areaHrefNeedsFixing` option determines if `` elements should match `:any-link` pseudo-class.
+In IE and Edge these do not match `:link` or `:visited`. + +_This increased CSS bundle size and is disabled by default._ + +```js +postcssPseudoClassAnyLink({ + subFeatures: { + areaHrefNeedsFixing: true + } +}) +``` + +```pcss +nav :any-link > span { + background-color: yellow; +} + +/* becomes */ + +nav :link > span, nav :visited > span, area[href] > span { + background-color: yellow; +} +``` + [cli-img]: https://github.com/csstools/postcss-plugins/workflows/test/badge.svg [cli-url]: https://github.com/csstools/postcss-plugins/actions/workflows/test.yml?query=workflow/test [css-img]: https://cssdb.org/images/badges/any-link-pseudo-class.svg diff --git a/plugins/postcss-pseudo-class-any-link/package.json b/plugins/postcss-pseudo-class-any-link/package.json index c976d5846..123a85650 100644 --- a/plugins/postcss-pseudo-class-any-link/package.json +++ b/plugins/postcss-pseudo-class-any-link/package.json @@ -20,7 +20,7 @@ "lint": "eslint ./src --ext .js --ext .ts --ext .mjs --no-error-on-unmatched-pattern", "prepublishOnly": "npm run clean && npm run build && npm run test", "stryker": "stryker run --logLevel error", - "test": "postcss-tape --ci && npm run test:exports", + "test": "node .tape.mjs && npm run test:exports", "test:exports": "node ./test/_import.mjs && node ./test/_require.cjs" }, "engines": { @@ -29,10 +29,6 @@ "dependencies": { "postcss-selector-parser": "^6.0.8" }, - "devDependencies": { - "postcss": "^8.3.6", - "postcss-tape": "^6.0.1" - }, "peerDependencies": { "postcss": "^8.3" }, diff --git a/plugins/postcss-pseudo-class-any-link/src/compound-selector-order.js b/plugins/postcss-pseudo-class-any-link/src/compound-selector-order.js new file mode 100644 index 000000000..d19d5b25c --- /dev/null +++ b/plugins/postcss-pseudo-class-any-link/src/compound-selector-order.js @@ -0,0 +1,117 @@ +import parser from 'postcss-selector-parser'; + +export function sortCompoundSelectorsInsideComplexSelector(node) { + if (!node || !node.nodes) { + return; + } + + let compound = []; + const nodes = [...node.nodes]; + + for (let i = 0; i < (nodes.length+1); i++) { + const child = nodes[i]; + if (!child || child.type === 'combinator') { + if (compound.length > 1) { + const compoundSelector = parser.selector({value:''}); + compound[0].replaceWith(compoundSelector); + + compound.slice(1).forEach((compoundPart) => { + compoundPart.remove(); + }); + + compound.forEach((compoundPart) => { + compoundSelector.append(compoundPart); + }); + + sortCompoundSelector(compoundSelector); + compoundSelector.replaceWith(...(compoundSelector.nodes)); + } + + compound = []; + continue; + } + + compound.push(child); + } +} + +export function sortCompoundSelector(node) { + if (!node || !node.nodes) { + return; + } + // compound selectors with nesting can be written with tag selectors as later parts. + // for example : `&h1` + // + // simply concating with parent selectors can lead to : + // `.fooh1` + // + // applying a sort where tag selectors are first will result in : + // `h1.foo` + + node.nodes.sort((a, b) => { + if (a.type === 'selector' && b.type === 'selector' && a.nodes.length && b.nodes.length) { + if (a.nodes[0].type === b.nodes[0].type) { + return 0; + } + + if (selectorTypeOrder[a.nodes[0].type] < selectorTypeOrder[b.nodes[0].type]) { + return -1; + } + + if (selectorTypeOrder[a.nodes[0].type] > selectorTypeOrder[b.nodes[0].type]) { + return 1; + } + } + + if (a.type === 'selector' && a.nodes.length) { + if (a.nodes[0].type === b.type) { + return 0; + } + + if (selectorTypeOrder[a.nodes[0].type] < selectorTypeOrder[b.type]) { + return -1; + } + + if (selectorTypeOrder[a.nodes[0].type] > selectorTypeOrder[b.type]) { + return 1; + } + } + + if (b.type === 'selector' && b.nodes.length) { + if (a.type === b.nodes[0].type) { + return 0; + } + + if (selectorTypeOrder[a.type] < selectorTypeOrder[b.nodes[0].type]) { + return -1; + } + + if (selectorTypeOrder[a.type] > selectorTypeOrder[b.nodes[0].type]) { + return 1; + } + } + + if (a.type === b.type) { + return 0; + } + + if (selectorTypeOrder[a.type] < selectorTypeOrder[b.type]) { + return -1; + } + + return 1; + }); +} + +const selectorTypeOrder = { + universal: 0, + tag: 1, + id: 2, + class: 3, + attribute: 4, + pseudo: 5, + selector: 7, + string: 8, + root : 9, + comment: 10, +}; diff --git a/plugins/postcss-pseudo-class-any-link/src/index.js b/plugins/postcss-pseudo-class-any-link/src/index.js index 671789d7f..c5795455a 100644 --- a/plugins/postcss-pseudo-class-any-link/src/index.js +++ b/plugins/postcss-pseudo-class-any-link/src/index.js @@ -1,13 +1,21 @@ -import parser from 'postcss-selector-parser'; +import { replaceAnyLink } from './replace-any-link'; const anyAnyLinkMatch = /:any-link/; /** - * @param {{preserve?: boolean}} opts + * @param {{preserve?: boolean, subFeatures?: { areaHrefNeedsFixing?: boolean }}} opts * @returns {import('postcss').Plugin} */ function creator(opts) { - const preserve = 'preserve' in Object(opts) ? Boolean(opts.preserve) : true; + const options = { + preserve: true, + ...opts, + }; + + const subFeatures = { + areaHrefNeedsFixing: false, + ...Object(options.subFeatures), + }; return { postcssPlugin: 'postcss-pseudo-class-any-link', @@ -23,73 +31,7 @@ function creator(opts) { return; } - let updatedSelector; - - try { - // update the selector - updatedSelector = parser(selectors => { - // cache variables - let node; - let nodeIndex; - let selector; - let selectorLink; - let selectorVisited; - - // cache the selector index - let selectorIndex = -1; - - // for each selector - selector = selectors.nodes[++selectorIndex]; - while (selector) { - // reset the node index - nodeIndex = -1; - - // for each node - node = selector.nodes[++nodeIndex]; - while (node) { - // if the node value matches the any-link value - if (node.value !== ':any-link' || node.type !== 'pseudo' || (node.nodes && node.nodes.length)) { - node = selector.nodes[++nodeIndex]; - continue; - } - - // clone the selector - selectorLink = selector.clone(); - selectorVisited = selector.clone(); - - // update the matching clone values - selectorLink.nodes[nodeIndex].value = ':link'; - selectorVisited.nodes[nodeIndex].value = ':visited'; - - // replace the selector with the clones and roll back the selector index - selectors.nodes.splice(selectorIndex--, 1, selectorLink, selectorVisited); - - break; - } - - selector = selectors.nodes[++selectorIndex]; - } - }).processSync(rawSelector); - } catch (_) { - rule.warn(result, `Failed to parse selector : ${rule.selector}`); - return; - } - - if (typeof updatedSelector === 'undefined') { - return; - } - - if (updatedSelector === rawSelector) { - return; - } - - if (preserve) { - rule.cloneBefore({ - selector: updatedSelector, - }); - } else { - rule.selector = updatedSelector; - } + replaceAnyLink(rule, result, options.preserve, subFeatures.areaHrefNeedsFixing); }, }; } diff --git a/plugins/postcss-pseudo-class-any-link/src/replace-any-link.js b/plugins/postcss-pseudo-class-any-link/src/replace-any-link.js new file mode 100644 index 000000000..88fd069dc --- /dev/null +++ b/plugins/postcss-pseudo-class-any-link/src/replace-any-link.js @@ -0,0 +1,123 @@ +import parser from 'postcss-selector-parser'; +import { sortCompoundSelectorsInsideComplexSelector } from './compound-selector-order'; + +const linkAST = parser().astSync(':link').nodes[0]; +const visitedAST = parser().astSync(':visited').nodes[0]; +const areaHrefAST = parser().astSync('area[href]').nodes[0]; + +export function replaceAnyLink(rule, result, preserve, areaHrefNeedsFixing) { + let updatedSelectors = []; + let untouchedSelectors = []; + + try { + for (let i = 0; i < rule.selectors.length; i++) { + const selector = rule.selectors[i]; + + const updated = modifiedSelector(selector, areaHrefNeedsFixing); + if (updated.length) { + updatedSelectors.push(...updated); + } else { + untouchedSelectors.push(selector); + } + } + } catch (_) { + rule.warn(result, `Failed to parse selector : ${rule.selector}`); + return; + } + + if (!updatedSelectors.length) { + return; + } + + rule.cloneBefore({ + selectors: updatedSelectors, + }); + + if (preserve) { + if (untouchedSelectors.length) { + rule.cloneBefore({ + selectors: untouchedSelectors, + }); + } + } else { + if (untouchedSelectors.length) { + rule.selectors = untouchedSelectors; + } else { + rule.remove(); + } + } +} + +function modifiedSelector(selector, areaHrefNeedsFixing) { + let out = []; + + // update the selector + parser((selectorsAST) => { + let anyLinkCount = 0; + selectorsAST.walkPseudos((pseudo) => { + if (pseudo.value !== ':any-link' || (pseudo.nodes && pseudo.nodes.length)) { + return; + } + + anyLinkCount++; + }); + + if (!anyLinkCount) { + return; + } + + let replacements = []; + for (let i = 0; i < anyLinkCount; i++) { + if (areaHrefNeedsFixing) { + replacements.push([linkAST.clone(), visitedAST.clone(), areaHrefAST.clone()]); + } else { + replacements.push([linkAST.clone(), visitedAST.clone()]); + } + } + + let replacementsCartesianProduct = cartesianProduct(...replacements); + + replacementsCartesianProduct.forEach((replacement) => { + const clone = selectorsAST.clone(); + clone.walkPseudos((pseudo) => { + if (pseudo.value !== ':any-link' || (pseudo.nodes && pseudo.nodes.length)) { + return; + } + + pseudo.replaceWith(...replacement.shift().nodes); + }); + + clone.walk((node) => { + if ('nodes' in node) { + node.nodes.forEach((child) => { + sortCompoundSelectorsInsideComplexSelector(child); + }); + sortCompoundSelectorsInsideComplexSelector(node); + } + }); + + out.push(clone.toString()); + }); + }).processSync(selector); + + return out; +} + +function cartesianProduct(...args) { + const r = []; + const max = args.length - 1; + + function helper(arr, i) { + for (let j = 0, l = args[i].length; j < l; j++) { + const a = arr.slice(0); + a.push(args[i][j]); + if (i == max) { + r.push(a); + } else { + helper(a, i + 1); + } + } + } + helper([], 0); + return r; +} diff --git a/plugins/postcss-pseudo-class-any-link/test/basic.css b/plugins/postcss-pseudo-class-any-link/test/basic.css index a336bf1dc..5d00a801d 100644 --- a/plugins/postcss-pseudo-class-any-link/test/basic.css +++ b/plugins/postcss-pseudo-class-any-link/test/basic.css @@ -1,17 +1,28 @@ :any-link { - background: blue; + order: 1; } :any-link, ul a:any-link > span { - background: blue; + order: 2; } :any-link :any-link { - background: blue; + order: 3; } - :any-link(.ignore) { - background: red; + order: 4; +} + +div :any-link { + order: 5; +} + +div:any-link { + order: 6; +} + +div:is(:any-link) { + order: 7; } diff --git a/plugins/postcss-pseudo-class-any-link/test/basic.expect.css b/plugins/postcss-pseudo-class-any-link/test/basic.expect.css index 9877ef5ee..ff5650d40 100644 --- a/plugins/postcss-pseudo-class-any-link/test/basic.expect.css +++ b/plugins/postcss-pseudo-class-any-link/test/basic.expect.css @@ -1,31 +1,55 @@ -:link,:visited { - background: blue; +:link, :visited { + order: 1; } :any-link { - background: blue; + order: 1; } -:link,:visited, +:link, +:visited, ul a:link > span, ul a:visited > span { - background: blue; + order: 2; } :any-link, ul a:any-link > span { - background: blue; + order: 2; } -:link :link,:link :visited,:visited :link,:visited :visited { - background: blue; +:link :link, :link :visited, :visited :link, :visited :visited { + order: 3; } :any-link :any-link { - background: blue; + order: 3; } - :any-link(.ignore) { - background: red; + order: 4; +} + +div :link, div :visited { + order: 5; +} + +div :any-link { + order: 5; +} + +div:link, div:visited { + order: 6; +} + +div:any-link { + order: 6; +} + +div:is(:link), div:is(:visited) { + order: 7; +} + +div:is(:any-link) { + order: 7; } diff --git a/plugins/postcss-pseudo-class-any-link/test/basic.preserve-false.expect.css b/plugins/postcss-pseudo-class-any-link/test/basic.preserve-false.expect.css index 57baccbbb..c199714a2 100644 --- a/plugins/postcss-pseudo-class-any-link/test/basic.preserve-false.expect.css +++ b/plugins/postcss-pseudo-class-any-link/test/basic.preserve-false.expect.css @@ -1,18 +1,30 @@ -:link,:visited { - background: blue; +:link, :visited { + order: 1; } -:link,:visited, +:link, +:visited, ul a:link > span, ul a:visited > span { - background: blue; + order: 2; } -:link :link,:link :visited,:visited :link,:visited :visited { - background: blue; +:link :link, :link :visited, :visited :link, :visited :visited { + order: 3; } - :any-link(.ignore) { - background: red; + order: 4; +} + +div :link, div :visited { + order: 5; +} + +div:link, div:visited { + order: 6; +} + +div:is(:link), div:is(:visited) { + order: 7; } diff --git a/plugins/postcss-pseudo-class-any-link/test/basic.sub-features-area-href.expect.css b/plugins/postcss-pseudo-class-any-link/test/basic.sub-features-area-href.expect.css new file mode 100644 index 000000000..17bc5a5d3 --- /dev/null +++ b/plugins/postcss-pseudo-class-any-link/test/basic.sub-features-area-href.expect.css @@ -0,0 +1,57 @@ +:link, :visited, area[href] { + order: 1; +} + +:any-link { + order: 1; +} + +:link, +:visited, +area[href], +ul a:link > span, +ul a:visited > span, +ul aarea[href] > span { + order: 2; +} + +:any-link, +ul a:any-link > span { + order: 2; +} + +:link :link, :link :visited, :link area[href], :visited :link, :visited :visited, :visited area[href], area[href] :link, area[href] :visited, area[href] area[href] { + order: 3; +} + +:any-link :any-link { + order: 3; +} + +:any-link(.ignore) { + order: 4; +} + +div :link, div :visited, div area[href] { + order: 5; +} + +div :any-link { + order: 5; +} + +div:link, div:visited, divarea[href] { + order: 6; +} + +div:any-link { + order: 6; +} + +div:is(:link), div:is(:visited), div:is(area[href]) { + order: 7; +} + +div:is(:any-link) { + order: 7; +} diff --git a/plugins/postcss-pseudo-class-any-link/test/generated-selector-cases.expect.css b/plugins/postcss-pseudo-class-any-link/test/generated-selector-cases.expect.css index 2970030e2..688ddb435 100644 --- a/plugins/postcss-pseudo-class-any-link/test/generated-selector-cases.expect.css +++ b/plugins/postcss-pseudo-class-any-link/test/generated-selector-cases.expect.css @@ -1,84 +1,84 @@ -:link:link,:link:visited,:visited:link,:visited:visited { +:link:link, :link:visited, :visited:link, :visited:visited { order: 0; } -:link:link,:link:visited,:visited:link,:visited:visited { +:link:link, :link:visited, :visited:link, :visited:visited { order: 1; } -:link :link,:link :visited,:visited :link,:visited :visited { +:link :link, :link :visited, :visited :link, :visited :visited { order: 2; } -:link :link,:link :visited,:visited :link,:visited :visited { +:link :link, :link :visited, :visited :link, :visited :visited { order: 3; } -:link :link,:link :visited,:visited :link,:visited :visited { +:link :link, :link :visited, :visited :link, :visited :visited { order: 4; } -:link :link,:link :visited,:visited :link,:visited :visited { +:link :link, :link :visited, :visited :link, :visited :visited { order: 5; } -:link+:link,:link+:visited,:visited+:link,:visited+:visited { +:link+:link, :link+:visited, :visited+:link, :visited+:visited { order: 6; } -:link+:link,:link+:visited,:visited+:link,:visited+:visited { +:link+:link, :link+:visited, :visited+:link, :visited+:visited { order: 7; } -:link + :link,:link + :visited,:visited + :link,:visited + :visited { +:link + :link, :link + :visited, :visited + :link, :visited + :visited { order: 8; } -:link + :link,:link + :visited,:visited + :link,:visited + :visited { +:link + :link, :link + :visited, :visited + :link, :visited + :visited { order: 9; } -:link~:link,:link~:visited,:visited~:link,:visited~:visited { +:link~:link, :link~:visited, :visited~:link, :visited~:visited { order: 10; } -:link~:link,:link~:visited,:visited~:link,:visited~:visited { +:link~:link, :link~:visited, :visited~:link, :visited~:visited { order: 11; } -:link ~ :link,:link ~ :visited,:visited ~ :link,:visited ~ :visited { +:link ~ :link, :link ~ :visited, :visited ~ :link, :visited ~ :visited { order: 12; } -:link ~ :link,:link ~ :visited,:visited ~ :link,:visited ~ :visited { +:link ~ :link, :link ~ :visited, :visited ~ :link, :visited ~ :visited { order: 13; } -:link>:link,:link>:visited,:visited>:link,:visited>:visited { +:link>:link, :link>:visited, :visited>:link, :visited>:visited { order: 14; } -:link>:link,:link>:visited,:visited>:link,:visited>:visited { +:link>:link, :link>:visited, :visited>:link, :visited>:visited { order: 15; } -:link > :link,:link > :visited,:visited > :link,:visited > :visited { +:link > :link, :link > :visited, :visited > :link, :visited > :visited { order: 16; } -:link > :link,:link > :visited,:visited > :link,:visited > :visited { +:link > :link, :link > :visited, :visited > :link, :visited > :visited { order: 17; } -:link,:visited, :link, :visited { +:link, :visited, :link, :visited { order: 18; } -:link,:visited, :link, :visited { +:link, :visited, :link, :visited { order: 19; } -button:link,button:visited { +button:link, button:visited { order: 20; } @@ -86,319 +86,351 @@ button:link,button:visited { order: 21; } -button :link,button :visited { +button :link, button :visited { order: 22; } -:link button,:visited button { +:link button, :visited button { order: 23; } -button :link,button :visited { +button :link, button :visited { order: 24; } -:link button,:visited button { +:link button, :visited button { order: 25; } -button+:link,button+:visited { +button+:link, button+:visited { order: 26; } -:link+button,:visited+button { +:link+button, :visited+button { order: 27; } -button + :link,button + :visited { +button + :link, button + :visited { order: 28; } -:link + button,:visited + button { +:link + button, :visited + button { order: 29; } -button~:link,button~:visited { +button~:link, button~:visited { order: 30; } -:link~button,:visited~button { +:link~button, :visited~button { order: 31; } -button ~ :link,button ~ :visited { +button ~ :link, button ~ :visited { order: 32; } -:link ~ button,:visited ~ button { +:link ~ button, :visited ~ button { order: 33; } -button>:link,button>:visited { +button>:link, button>:visited { order: 34; } -:link>button,:visited>button { +:link>button, :visited>button { order: 35; } -button > :link,button > :visited { +button > :link, button > :visited { order: 36; } -:link > button,:visited > button { +:link > button, :visited > button { order: 37; } -button, :link, :visited { +:link, :visited { order: 38; } -:link,:visited, button { +button { + order: 38; +} + +:link, :visited { + order: 39; +} + +button { order: 39; } -.🧑🏾‍🎤:link,.🧑🏾‍🎤:visited { +.🧑🏾‍🎤:link, .🧑🏾‍🎤:visited { order: 40; } -:link.🧑🏾‍🎤,:visited.🧑🏾‍🎤 { +.🧑🏾‍🎤:link, .🧑🏾‍🎤:visited { order: 41; } -.🧑🏾‍🎤 :link,.🧑🏾‍🎤 :visited { +.🧑🏾‍🎤 :link, .🧑🏾‍🎤 :visited { order: 42; } -:link .🧑🏾‍🎤,:visited .🧑🏾‍🎤 { +:link .🧑🏾‍🎤, :visited .🧑🏾‍🎤 { order: 43; } -.🧑🏾‍🎤 :link,.🧑🏾‍🎤 :visited { +.🧑🏾‍🎤 :link, .🧑🏾‍🎤 :visited { order: 44; } -:link .🧑🏾‍🎤,:visited .🧑🏾‍🎤 { +:link .🧑🏾‍🎤, :visited .🧑🏾‍🎤 { order: 45; } -.🧑🏾‍🎤+:link,.🧑🏾‍🎤+:visited { +.🧑🏾‍🎤+:link, .🧑🏾‍🎤+:visited { order: 46; } -:link+.🧑🏾‍🎤,:visited+.🧑🏾‍🎤 { +:link+.🧑🏾‍🎤, :visited+.🧑🏾‍🎤 { order: 47; } -.🧑🏾‍🎤 + :link,.🧑🏾‍🎤 + :visited { +.🧑🏾‍🎤 + :link, .🧑🏾‍🎤 + :visited { order: 48; } -:link + .🧑🏾‍🎤,:visited + .🧑🏾‍🎤 { +:link + .🧑🏾‍🎤, :visited + .🧑🏾‍🎤 { order: 49; } -.🧑🏾‍🎤~:link,.🧑🏾‍🎤~:visited { +.🧑🏾‍🎤~:link, .🧑🏾‍🎤~:visited { order: 50; } -:link~.🧑🏾‍🎤,:visited~.🧑🏾‍🎤 { +:link~.🧑🏾‍🎤, :visited~.🧑🏾‍🎤 { order: 51; } -.🧑🏾‍🎤 ~ :link,.🧑🏾‍🎤 ~ :visited { +.🧑🏾‍🎤 ~ :link, .🧑🏾‍🎤 ~ :visited { order: 52; } -:link ~ .🧑🏾‍🎤,:visited ~ .🧑🏾‍🎤 { +:link ~ .🧑🏾‍🎤, :visited ~ .🧑🏾‍🎤 { order: 53; } -.🧑🏾‍🎤>:link,.🧑🏾‍🎤>:visited { +.🧑🏾‍🎤>:link, .🧑🏾‍🎤>:visited { order: 54; } -:link>.🧑🏾‍🎤,:visited>.🧑🏾‍🎤 { +:link>.🧑🏾‍🎤, :visited>.🧑🏾‍🎤 { order: 55; } -.🧑🏾‍🎤 > :link,.🧑🏾‍🎤 > :visited { +.🧑🏾‍🎤 > :link, .🧑🏾‍🎤 > :visited { order: 56; } -:link > .🧑🏾‍🎤,:visited > .🧑🏾‍🎤 { +:link > .🧑🏾‍🎤, :visited > .🧑🏾‍🎤 { order: 57; } -.🧑🏾‍🎤, :link, :visited { +:link, :visited { order: 58; } -:link,:visited, .🧑🏾‍🎤 { +.🧑🏾‍🎤 { + order: 58; +} + +:link, :visited { + order: 59; +} + +.🧑🏾‍🎤 { order: 59; } -.foo:link,.foo:visited { +.foo:link, .foo:visited { order: 60; } -:link.foo,:visited.foo { +.foo:link, .foo:visited { order: 61; } -.foo :link,.foo :visited { +.foo :link, .foo :visited { order: 62; } -:link .foo,:visited .foo { +:link .foo, :visited .foo { order: 63; } -.foo :link,.foo :visited { +.foo :link, .foo :visited { order: 64; } -:link .foo,:visited .foo { +:link .foo, :visited .foo { order: 65; } -.foo+:link,.foo+:visited { +.foo+:link, .foo+:visited { order: 66; } -:link+.foo,:visited+.foo { +:link+.foo, :visited+.foo { order: 67; } -.foo + :link,.foo + :visited { +.foo + :link, .foo + :visited { order: 68; } -:link + .foo,:visited + .foo { +:link + .foo, :visited + .foo { order: 69; } -.foo~:link,.foo~:visited { +.foo~:link, .foo~:visited { order: 70; } -:link~.foo,:visited~.foo { +:link~.foo, :visited~.foo { order: 71; } -.foo ~ :link,.foo ~ :visited { +.foo ~ :link, .foo ~ :visited { order: 72; } -:link ~ .foo,:visited ~ .foo { +:link ~ .foo, :visited ~ .foo { order: 73; } -.foo>:link,.foo>:visited { +.foo>:link, .foo>:visited { order: 74; } -:link>.foo,:visited>.foo { +:link>.foo, :visited>.foo { order: 75; } -.foo > :link,.foo > :visited { +.foo > :link, .foo > :visited { order: 76; } -:link > .foo,:visited > .foo { +:link > .foo, :visited > .foo { order: 77; } -.foo, :link, :visited { +:link, :visited { + order: 78; +} + +.foo { order: 78; } -:link,:visited, .foo { +:link, :visited { order: 79; } -#foo:link,#foo:visited { +.foo { + order: 79; +} + +#foo:link, #foo:visited { order: 80; } -:link#foo,:visited#foo { +#foo:link, #foo:visited { order: 81; } -#foo :link,#foo :visited { +#foo :link, #foo :visited { order: 82; } -:link #foo,:visited #foo { +:link #foo, :visited #foo { order: 83; } -#foo :link,#foo :visited { +#foo :link, #foo :visited { order: 84; } -:link #foo,:visited #foo { +:link #foo, :visited #foo { order: 85; } -#foo+:link,#foo+:visited { +#foo+:link, #foo+:visited { order: 86; } -:link+#foo,:visited+#foo { +:link+#foo, :visited+#foo { order: 87; } -#foo + :link,#foo + :visited { +#foo + :link, #foo + :visited { order: 88; } -:link + #foo,:visited + #foo { +:link + #foo, :visited + #foo { order: 89; } -#foo~:link,#foo~:visited { +#foo~:link, #foo~:visited { order: 90; } -:link~#foo,:visited~#foo { +:link~#foo, :visited~#foo { order: 91; } -#foo ~ :link,#foo ~ :visited { +#foo ~ :link, #foo ~ :visited { order: 92; } -:link ~ #foo,:visited ~ #foo { +:link ~ #foo, :visited ~ #foo { order: 93; } -#foo>:link,#foo>:visited { +#foo>:link, #foo>:visited { order: 94; } -:link>#foo,:visited>#foo { +:link>#foo, :visited>#foo { order: 95; } -#foo > :link,#foo > :visited { +#foo > :link, #foo > :visited { order: 96; } -:link > #foo,:visited > #foo { +:link > #foo, :visited > #foo { order: 97; } -#foo, :link, :visited { +:link, :visited { + order: 98; +} + +#foo { order: 98; } -:link,:visited, #foo { +:link, :visited { order: 99; } -__foo:link,__foo:visited { +#foo { + order: 99; +} + +__foo:link, __foo:visited { order: 100; } @@ -406,475 +438,523 @@ __foo:link,__foo:visited { order: 101; } -__foo :link,__foo :visited { +__foo :link, __foo :visited { order: 102; } -:link __foo,:visited __foo { +:link __foo, :visited __foo { order: 103; } -__foo :link,__foo :visited { +__foo :link, __foo :visited { order: 104; } -:link __foo,:visited __foo { +:link __foo, :visited __foo { order: 105; } -__foo+:link,__foo+:visited { +__foo+:link, __foo+:visited { order: 106; } -:link+__foo,:visited+__foo { +:link+__foo, :visited+__foo { order: 107; } -__foo + :link,__foo + :visited { +__foo + :link, __foo + :visited { order: 108; } -:link + __foo,:visited + __foo { +:link + __foo, :visited + __foo { order: 109; } -__foo~:link,__foo~:visited { +__foo~:link, __foo~:visited { order: 110; } -:link~__foo,:visited~__foo { +:link~__foo, :visited~__foo { order: 111; } -__foo ~ :link,__foo ~ :visited { +__foo ~ :link, __foo ~ :visited { order: 112; } -:link ~ __foo,:visited ~ __foo { +:link ~ __foo, :visited ~ __foo { order: 113; } -__foo>:link,__foo>:visited { +__foo>:link, __foo>:visited { order: 114; } -:link>__foo,:visited>__foo { +:link>__foo, :visited>__foo { order: 115; } -__foo > :link,__foo > :visited { +__foo > :link, __foo > :visited { order: 116; } -:link > __foo,:visited > __foo { +:link > __foo, :visited > __foo { order: 117; } -__foo, :link, :visited { +:link, :visited { + order: 118; +} + +__foo { order: 118; } -:link,:visited, __foo { +:link, :visited { + order: 119; +} + +__foo { order: 119; } -:--foo:link,:--foo:visited { +:--foo:link, :--foo:visited { order: 120; } -:link:--foo,:visited:--foo { +:link:--foo, :visited:--foo { order: 121; } -:--foo :link,:--foo :visited { +:--foo :link, :--foo :visited { order: 122; } -:link :--foo,:visited :--foo { +:link :--foo, :visited :--foo { order: 123; } -:--foo :link,:--foo :visited { +:--foo :link, :--foo :visited { order: 124; } -:link :--foo,:visited :--foo { +:link :--foo, :visited :--foo { order: 125; } -:--foo+:link,:--foo+:visited { +:--foo+:link, :--foo+:visited { order: 126; } -:link+:--foo,:visited+:--foo { +:link+:--foo, :visited+:--foo { order: 127; } -:--foo + :link,:--foo + :visited { +:--foo + :link, :--foo + :visited { order: 128; } -:link + :--foo,:visited + :--foo { +:link + :--foo, :visited + :--foo { order: 129; } -:--foo~:link,:--foo~:visited { +:--foo~:link, :--foo~:visited { order: 130; } -:link~:--foo,:visited~:--foo { +:link~:--foo, :visited~:--foo { order: 131; } -:--foo ~ :link,:--foo ~ :visited { +:--foo ~ :link, :--foo ~ :visited { order: 132; } -:link ~ :--foo,:visited ~ :--foo { +:link ~ :--foo, :visited ~ :--foo { order: 133; } -:--foo>:link,:--foo>:visited { +:--foo>:link, :--foo>:visited { order: 134; } -:link>:--foo,:visited>:--foo { +:link>:--foo, :visited>:--foo { order: 135; } -:--foo > :link,:--foo > :visited { +:--foo > :link, :--foo > :visited { order: 136; } -:link > :--foo,:visited > :--foo { +:link > :--foo, :visited > :--foo { order: 137; } -:--foo, :link, :visited { +:link, :visited { order: 138; } -:link,:visited, :--foo { +:--foo { + order: 138; +} + +:link, :visited { + order: 139; +} + +:--foo { order: 139; } -[foo="baz"]:link,[foo="baz"]:visited { +[foo="baz"]:link, [foo="baz"]:visited { order: 140; } -:link[foo="baz"],:visited[foo="baz"] { +[foo="baz"]:link, [foo="baz"]:visited { order: 141; } -[foo="baz"] :link,[foo="baz"] :visited { +[foo="baz"] :link, [foo="baz"] :visited { order: 142; } -:link [foo="baz"],:visited [foo="baz"] { +:link [foo="baz"], :visited [foo="baz"] { order: 143; } -[foo="baz"] :link,[foo="baz"] :visited { +[foo="baz"] :link, [foo="baz"] :visited { order: 144; } -:link [foo="baz"],:visited [foo="baz"] { +:link [foo="baz"], :visited [foo="baz"] { order: 145; } -[foo="baz"]+:link,[foo="baz"]+:visited { +[foo="baz"]+:link, [foo="baz"]+:visited { order: 146; } -:link+[foo="baz"],:visited+[foo="baz"] { +:link+[foo="baz"], :visited+[foo="baz"] { order: 147; } -[foo="baz"] + :link,[foo="baz"] + :visited { +[foo="baz"] + :link, [foo="baz"] + :visited { order: 148; } -:link + [foo="baz"],:visited + [foo="baz"] { +:link + [foo="baz"], :visited + [foo="baz"] { order: 149; } -[foo="baz"]~:link,[foo="baz"]~:visited { +[foo="baz"]~:link, [foo="baz"]~:visited { order: 150; } -:link~[foo="baz"],:visited~[foo="baz"] { +:link~[foo="baz"], :visited~[foo="baz"] { order: 151; } -[foo="baz"] ~ :link,[foo="baz"] ~ :visited { +[foo="baz"] ~ :link, [foo="baz"] ~ :visited { order: 152; } -:link ~ [foo="baz"],:visited ~ [foo="baz"] { +:link ~ [foo="baz"], :visited ~ [foo="baz"] { order: 153; } -[foo="baz"]>:link,[foo="baz"]>:visited { +[foo="baz"]>:link, [foo="baz"]>:visited { order: 154; } -:link>[foo="baz"],:visited>[foo="baz"] { +:link>[foo="baz"], :visited>[foo="baz"] { order: 155; } -[foo="baz"] > :link,[foo="baz"] > :visited { +[foo="baz"] > :link, [foo="baz"] > :visited { order: 156; } -:link > [foo="baz"],:visited > [foo="baz"] { +:link > [foo="baz"], :visited > [foo="baz"] { order: 157; } -[foo="baz"], :link, :visited { +:link, :visited { order: 158; } -:link,:visited, [foo="baz"] { +[foo="baz"] { + order: 158; +} + +:link, :visited { + order: 159; +} + +[foo="baz"] { order: 159; } -*:link,*:visited { +*:link, *:visited { order: 160; } -:link*,:visited* { +*:link, *:visited { order: 161; } -* :link,* :visited { +* :link, * :visited { order: 162; } -:link *,:visited * { +:link *, :visited * { order: 163; } -* :link,* :visited { +* :link, * :visited { order: 164; } -:link *,:visited * { +:link *, :visited * { order: 165; } -*+:link,*+:visited { +*+:link, *+:visited { order: 166; } -:link+*,:visited+* { +:link+*, :visited+* { order: 167; } -* + :link,* + :visited { +* + :link, * + :visited { order: 168; } -:link + *,:visited + * { +:link + *, :visited + * { order: 169; } -*~:link,*~:visited { +*~:link, *~:visited { order: 170; } -:link~*,:visited~* { +:link~*, :visited~* { order: 171; } -* ~ :link,* ~ :visited { +* ~ :link, * ~ :visited { order: 172; } -:link ~ *,:visited ~ * { +:link ~ *, :visited ~ * { order: 173; } -*>:link,*>:visited { +*>:link, *>:visited { order: 174; } -:link>*,:visited>* { +:link>*, :visited>* { order: 175; } -* > :link,* > :visited { +* > :link, * > :visited { order: 176; } -:link > *,:visited > * { +:link > *, :visited > * { order: 177; } -*, :link, :visited { +:link, :visited { + order: 178; +} + +* { order: 178; } -:link,:visited, * { +:link, :visited { order: 179; } -:hover:link,:hover:visited { +* { + order: 179; +} + +:hover:link, :hover:visited { order: 180; } -:link:hover,:visited:hover { +:link:hover, :visited:hover { order: 181; } -:hover :link,:hover :visited { +:hover :link, :hover :visited { order: 182; } -:link :hover,:visited :hover { +:link :hover, :visited :hover { order: 183; } -:hover :link,:hover :visited { +:hover :link, :hover :visited { order: 184; } -:link :hover,:visited :hover { +:link :hover, :visited :hover { order: 185; } -:hover+:link,:hover+:visited { +:hover+:link, :hover+:visited { order: 186; } -:link+:hover,:visited+:hover { +:link+:hover, :visited+:hover { order: 187; } -:hover + :link,:hover + :visited { +:hover + :link, :hover + :visited { order: 188; } -:link + :hover,:visited + :hover { +:link + :hover, :visited + :hover { order: 189; } -:hover~:link,:hover~:visited { +:hover~:link, :hover~:visited { order: 190; } -:link~:hover,:visited~:hover { +:link~:hover, :visited~:hover { order: 191; } -:hover ~ :link,:hover ~ :visited { +:hover ~ :link, :hover ~ :visited { order: 192; } -:link ~ :hover,:visited ~ :hover { +:link ~ :hover, :visited ~ :hover { order: 193; } -:hover>:link,:hover>:visited { +:hover>:link, :hover>:visited { order: 194; } -:link>:hover,:visited>:hover { +:link>:hover, :visited>:hover { order: 195; } -:hover > :link,:hover > :visited { +:hover > :link, :hover > :visited { order: 196; } -:link > :hover,:visited > :hover { +:link > :hover, :visited > :hover { order: 197; } -:hover, :link, :visited { +:link, :visited { + order: 198; +} + +:hover { order: 198; } -:link,:visited, :hover { +:link, :visited { order: 199; } -::before:link,::before:visited { +:hover { + order: 199; +} + +::before:link, ::before:visited { order: 200; } -:link::before,:visited::before { +:link::before, :visited::before { order: 201; } -::before :link,::before :visited { +::before :link, ::before :visited { order: 202; } -:link ::before,:visited ::before { +:link ::before, :visited ::before { order: 203; } -::before :link,::before :visited { +::before :link, ::before :visited { order: 204; } -:link ::before,:visited ::before { +:link ::before, :visited ::before { order: 205; } -::before+:link,::before+:visited { +::before+:link, ::before+:visited { order: 206; } -:link+::before,:visited+::before { +:link+::before, :visited+::before { order: 207; } -::before + :link,::before + :visited { +::before + :link, ::before + :visited { order: 208; } -:link + ::before,:visited + ::before { +:link + ::before, :visited + ::before { order: 209; } -::before~:link,::before~:visited { +::before~:link, ::before~:visited { order: 210; } -:link~::before,:visited~::before { +:link~::before, :visited~::before { order: 211; } -::before ~ :link,::before ~ :visited { +::before ~ :link, ::before ~ :visited { order: 212; } -:link ~ ::before,:visited ~ ::before { +:link ~ ::before, :visited ~ ::before { order: 213; } -::before>:link,::before>:visited { +::before>:link, ::before>:visited { order: 214; } -:link>::before,:visited>::before { +:link>::before, :visited>::before { order: 215; } -::before > :link,::before > :visited { +::before > :link, ::before > :visited { order: 216; } -:link > ::before,:visited > ::before { +:link > ::before, :visited > ::before { order: 217; } -::before, :link, :visited { +:link, :visited { + order: 218; +} + +::before { order: 218; } -:link,:visited, ::before { +:link, :visited { + order: 219; +} + +::before { order: 219; } @@ -886,7 +966,7 @@ foo[baz=":any-link"] { order: 221; } -:not(:any-link) { +:not(:link), :not(:visited) { order: 222; } @@ -894,11 +974,11 @@ foo[baz=":any-link"] { order: 223; } -:--:link,:--:visited { +:--:link, :--:visited { order: 224; } -__:link,__:visited { +__:link, __:visited { order: 225; } diff --git a/plugins/postcss-pseudo-class-any-link/test/generated-selector-cases.sub-features-area-href.expect.css b/plugins/postcss-pseudo-class-any-link/test/generated-selector-cases.sub-features-area-href.expect.css new file mode 100644 index 000000000..c6f58721f --- /dev/null +++ b/plugins/postcss-pseudo-class-any-link/test/generated-selector-cases.sub-features-area-href.expect.css @@ -0,0 +1,985 @@ +:link:link, :link:visited, area[href]:link, :visited:link, :visited:visited, area[href]:visited, area[href]:link, area[href]:visited, areaarea[href][href] { + order: 0; +} + +:link:link, :link:visited, area[href]:link, :visited:link, :visited:visited, area[href]:visited, area[href]:link, area[href]:visited, areaarea[href][href] { + order: 1; +} + +:link :link, :link :visited, :link area[href], :visited :link, :visited :visited, :visited area[href], area[href] :link, area[href] :visited, area[href] area[href] { + order: 2; +} + +:link :link, :link :visited, :link area[href], :visited :link, :visited :visited, :visited area[href], area[href] :link, area[href] :visited, area[href] area[href] { + order: 3; +} + +:link :link, :link :visited, :link area[href], :visited :link, :visited :visited, :visited area[href], area[href] :link, area[href] :visited, area[href] area[href] { + order: 4; +} + +:link :link, :link :visited, :link area[href], :visited :link, :visited :visited, :visited area[href], area[href] :link, area[href] :visited, area[href] area[href] { + order: 5; +} + +:link+:link, :link+:visited, :link+area[href], :visited+:link, :visited+:visited, :visited+area[href], area[href]+:link, area[href]+:visited, area[href]+area[href] { + order: 6; +} + +:link+:link, :link+:visited, :link+area[href], :visited+:link, :visited+:visited, :visited+area[href], area[href]+:link, area[href]+:visited, area[href]+area[href] { + order: 7; +} + +:link + :link, :link + :visited, :link + area[href], :visited + :link, :visited + :visited, :visited + area[href], area[href] + :link, area[href] + :visited, area[href] + area[href] { + order: 8; +} + +:link + :link, :link + :visited, :link + area[href], :visited + :link, :visited + :visited, :visited + area[href], area[href] + :link, area[href] + :visited, area[href] + area[href] { + order: 9; +} + +:link~:link, :link~:visited, :link~area[href], :visited~:link, :visited~:visited, :visited~area[href], area[href]~:link, area[href]~:visited, area[href]~area[href] { + order: 10; +} + +:link~:link, :link~:visited, :link~area[href], :visited~:link, :visited~:visited, :visited~area[href], area[href]~:link, area[href]~:visited, area[href]~area[href] { + order: 11; +} + +:link ~ :link, :link ~ :visited, :link ~ area[href], :visited ~ :link, :visited ~ :visited, :visited ~ area[href], area[href] ~ :link, area[href] ~ :visited, area[href] ~ area[href] { + order: 12; +} + +:link ~ :link, :link ~ :visited, :link ~ area[href], :visited ~ :link, :visited ~ :visited, :visited ~ area[href], area[href] ~ :link, area[href] ~ :visited, area[href] ~ area[href] { + order: 13; +} + +:link>:link, :link>:visited, :link>area[href], :visited>:link, :visited>:visited, :visited>area[href], area[href]>:link, area[href]>:visited, area[href]>area[href] { + order: 14; +} + +:link>:link, :link>:visited, :link>area[href], :visited>:link, :visited>:visited, :visited>area[href], area[href]>:link, area[href]>:visited, area[href]>area[href] { + order: 15; +} + +:link > :link, :link > :visited, :link > area[href], :visited > :link, :visited > :visited, :visited > area[href], area[href] > :link, area[href] > :visited, area[href] > area[href] { + order: 16; +} + +:link > :link, :link > :visited, :link > area[href], :visited > :link, :visited > :visited, :visited > area[href], area[href] > :link, area[href] > :visited, area[href] > area[href] { + order: 17; +} + +:link, :visited, area[href], :link, :visited, area[href] { + order: 18; +} + +:link, :visited, area[href], :link, :visited, area[href] { + order: 19; +} + +button:link, button:visited, buttonarea[href] { + order: 20; +} + +:any-linkbutton { + order: 21; +} + +button :link, button :visited, button area[href] { + order: 22; +} + +:link button, :visited button, area[href] button { + order: 23; +} + +button :link, button :visited, button area[href] { + order: 24; +} + +:link button, :visited button, area[href] button { + order: 25; +} + +button+:link, button+:visited, button+area[href] { + order: 26; +} + +:link+button, :visited+button, area[href]+button { + order: 27; +} + +button + :link, button + :visited, button + area[href] { + order: 28; +} + +:link + button, :visited + button, area[href] + button { + order: 29; +} + +button~:link, button~:visited, button~area[href] { + order: 30; +} + +:link~button, :visited~button, area[href]~button { + order: 31; +} + +button ~ :link, button ~ :visited, button ~ area[href] { + order: 32; +} + +:link ~ button, :visited ~ button, area[href] ~ button { + order: 33; +} + +button>:link, button>:visited, button>area[href] { + order: 34; +} + +:link>button, :visited>button, area[href]>button { + order: 35; +} + +button > :link, button > :visited, button > area[href] { + order: 36; +} + +:link > button, :visited > button, area[href] > button { + order: 37; +} + +:link, :visited, area[href] { + order: 38; +} + +button { + order: 38; +} + +:link, :visited, area[href] { + order: 39; +} + +button { + order: 39; +} + +.🧑🏾‍🎤:link, .🧑🏾‍🎤:visited, area.🧑🏾‍🎤[href] { + order: 40; +} + +.🧑🏾‍🎤:link, .🧑🏾‍🎤:visited, area.🧑🏾‍🎤[href] { + order: 41; +} + +.🧑🏾‍🎤 :link, .🧑🏾‍🎤 :visited, .🧑🏾‍🎤 area[href] { + order: 42; +} + +:link .🧑🏾‍🎤, :visited .🧑🏾‍🎤, area[href] .🧑🏾‍🎤 { + order: 43; +} + +.🧑🏾‍🎤 :link, .🧑🏾‍🎤 :visited, .🧑🏾‍🎤 area[href] { + order: 44; +} + +:link .🧑🏾‍🎤, :visited .🧑🏾‍🎤, area[href] .🧑🏾‍🎤 { + order: 45; +} + +.🧑🏾‍🎤+:link, .🧑🏾‍🎤+:visited, .🧑🏾‍🎤+area[href] { + order: 46; +} + +:link+.🧑🏾‍🎤, :visited+.🧑🏾‍🎤, area[href]+.🧑🏾‍🎤 { + order: 47; +} + +.🧑🏾‍🎤 + :link, .🧑🏾‍🎤 + :visited, .🧑🏾‍🎤 + area[href] { + order: 48; +} + +:link + .🧑🏾‍🎤, :visited + .🧑🏾‍🎤, area[href] + .🧑🏾‍🎤 { + order: 49; +} + +.🧑🏾‍🎤~:link, .🧑🏾‍🎤~:visited, .🧑🏾‍🎤~area[href] { + order: 50; +} + +:link~.🧑🏾‍🎤, :visited~.🧑🏾‍🎤, area[href]~.🧑🏾‍🎤 { + order: 51; +} + +.🧑🏾‍🎤 ~ :link, .🧑🏾‍🎤 ~ :visited, .🧑🏾‍🎤 ~ area[href] { + order: 52; +} + +:link ~ .🧑🏾‍🎤, :visited ~ .🧑🏾‍🎤, area[href] ~ .🧑🏾‍🎤 { + order: 53; +} + +.🧑🏾‍🎤>:link, .🧑🏾‍🎤>:visited, .🧑🏾‍🎤>area[href] { + order: 54; +} + +:link>.🧑🏾‍🎤, :visited>.🧑🏾‍🎤, area[href]>.🧑🏾‍🎤 { + order: 55; +} + +.🧑🏾‍🎤 > :link, .🧑🏾‍🎤 > :visited, .🧑🏾‍🎤 > area[href] { + order: 56; +} + +:link > .🧑🏾‍🎤, :visited > .🧑🏾‍🎤, area[href] > .🧑🏾‍🎤 { + order: 57; +} + +:link, :visited, area[href] { + order: 58; +} + +.🧑🏾‍🎤 { + order: 58; +} + +:link, :visited, area[href] { + order: 59; +} + +.🧑🏾‍🎤 { + order: 59; +} + +.foo:link, .foo:visited, area.foo[href] { + order: 60; +} + +.foo:link, .foo:visited, area.foo[href] { + order: 61; +} + +.foo :link, .foo :visited, .foo area[href] { + order: 62; +} + +:link .foo, :visited .foo, area[href] .foo { + order: 63; +} + +.foo :link, .foo :visited, .foo area[href] { + order: 64; +} + +:link .foo, :visited .foo, area[href] .foo { + order: 65; +} + +.foo+:link, .foo+:visited, .foo+area[href] { + order: 66; +} + +:link+.foo, :visited+.foo, area[href]+.foo { + order: 67; +} + +.foo + :link, .foo + :visited, .foo + area[href] { + order: 68; +} + +:link + .foo, :visited + .foo, area[href] + .foo { + order: 69; +} + +.foo~:link, .foo~:visited, .foo~area[href] { + order: 70; +} + +:link~.foo, :visited~.foo, area[href]~.foo { + order: 71; +} + +.foo ~ :link, .foo ~ :visited, .foo ~ area[href] { + order: 72; +} + +:link ~ .foo, :visited ~ .foo, area[href] ~ .foo { + order: 73; +} + +.foo>:link, .foo>:visited, .foo>area[href] { + order: 74; +} + +:link>.foo, :visited>.foo, area[href]>.foo { + order: 75; +} + +.foo > :link, .foo > :visited, .foo > area[href] { + order: 76; +} + +:link > .foo, :visited > .foo, area[href] > .foo { + order: 77; +} + +:link, :visited, area[href] { + order: 78; +} + +.foo { + order: 78; +} + +:link, :visited, area[href] { + order: 79; +} + +.foo { + order: 79; +} + +#foo:link, #foo:visited, area#foo[href] { + order: 80; +} + +#foo:link, #foo:visited, area#foo[href] { + order: 81; +} + +#foo :link, #foo :visited, #foo area[href] { + order: 82; +} + +:link #foo, :visited #foo, area[href] #foo { + order: 83; +} + +#foo :link, #foo :visited, #foo area[href] { + order: 84; +} + +:link #foo, :visited #foo, area[href] #foo { + order: 85; +} + +#foo+:link, #foo+:visited, #foo+area[href] { + order: 86; +} + +:link+#foo, :visited+#foo, area[href]+#foo { + order: 87; +} + +#foo + :link, #foo + :visited, #foo + area[href] { + order: 88; +} + +:link + #foo, :visited + #foo, area[href] + #foo { + order: 89; +} + +#foo~:link, #foo~:visited, #foo~area[href] { + order: 90; +} + +:link~#foo, :visited~#foo, area[href]~#foo { + order: 91; +} + +#foo ~ :link, #foo ~ :visited, #foo ~ area[href] { + order: 92; +} + +:link ~ #foo, :visited ~ #foo, area[href] ~ #foo { + order: 93; +} + +#foo>:link, #foo>:visited, #foo>area[href] { + order: 94; +} + +:link>#foo, :visited>#foo, area[href]>#foo { + order: 95; +} + +#foo > :link, #foo > :visited, #foo > area[href] { + order: 96; +} + +:link > #foo, :visited > #foo, area[href] > #foo { + order: 97; +} + +:link, :visited, area[href] { + order: 98; +} + +#foo { + order: 98; +} + +:link, :visited, area[href] { + order: 99; +} + +#foo { + order: 99; +} + +__foo:link, __foo:visited, __fooarea[href] { + order: 100; +} + +:any-link__foo { + order: 101; +} + +__foo :link, __foo :visited, __foo area[href] { + order: 102; +} + +:link __foo, :visited __foo, area[href] __foo { + order: 103; +} + +__foo :link, __foo :visited, __foo area[href] { + order: 104; +} + +:link __foo, :visited __foo, area[href] __foo { + order: 105; +} + +__foo+:link, __foo+:visited, __foo+area[href] { + order: 106; +} + +:link+__foo, :visited+__foo, area[href]+__foo { + order: 107; +} + +__foo + :link, __foo + :visited, __foo + area[href] { + order: 108; +} + +:link + __foo, :visited + __foo, area[href] + __foo { + order: 109; +} + +__foo~:link, __foo~:visited, __foo~area[href] { + order: 110; +} + +:link~__foo, :visited~__foo, area[href]~__foo { + order: 111; +} + +__foo ~ :link, __foo ~ :visited, __foo ~ area[href] { + order: 112; +} + +:link ~ __foo, :visited ~ __foo, area[href] ~ __foo { + order: 113; +} + +__foo>:link, __foo>:visited, __foo>area[href] { + order: 114; +} + +:link>__foo, :visited>__foo, area[href]>__foo { + order: 115; +} + +__foo > :link, __foo > :visited, __foo > area[href] { + order: 116; +} + +:link > __foo, :visited > __foo, area[href] > __foo { + order: 117; +} + +:link, :visited, area[href] { + order: 118; +} + +__foo { + order: 118; +} + +:link, :visited, area[href] { + order: 119; +} + +__foo { + order: 119; +} + +:--foo:link, :--foo:visited, area[href]:--foo { + order: 120; +} + +:link:--foo, :visited:--foo, area[href]:--foo { + order: 121; +} + +:--foo :link, :--foo :visited, :--foo area[href] { + order: 122; +} + +:link :--foo, :visited :--foo, area[href] :--foo { + order: 123; +} + +:--foo :link, :--foo :visited, :--foo area[href] { + order: 124; +} + +:link :--foo, :visited :--foo, area[href] :--foo { + order: 125; +} + +:--foo+:link, :--foo+:visited, :--foo+area[href] { + order: 126; +} + +:link+:--foo, :visited+:--foo, area[href]+:--foo { + order: 127; +} + +:--foo + :link, :--foo + :visited, :--foo + area[href] { + order: 128; +} + +:link + :--foo, :visited + :--foo, area[href] + :--foo { + order: 129; +} + +:--foo~:link, :--foo~:visited, :--foo~area[href] { + order: 130; +} + +:link~:--foo, :visited~:--foo, area[href]~:--foo { + order: 131; +} + +:--foo ~ :link, :--foo ~ :visited, :--foo ~ area[href] { + order: 132; +} + +:link ~ :--foo, :visited ~ :--foo, area[href] ~ :--foo { + order: 133; +} + +:--foo>:link, :--foo>:visited, :--foo>area[href] { + order: 134; +} + +:link>:--foo, :visited>:--foo, area[href]>:--foo { + order: 135; +} + +:--foo > :link, :--foo > :visited, :--foo > area[href] { + order: 136; +} + +:link > :--foo, :visited > :--foo, area[href] > :--foo { + order: 137; +} + +:link, :visited, area[href] { + order: 138; +} + +:--foo { + order: 138; +} + +:link, :visited, area[href] { + order: 139; +} + +:--foo { + order: 139; +} + +[foo="baz"]:link, [foo="baz"]:visited, area[foo="baz"][href] { + order: 140; +} + +[foo="baz"]:link, [foo="baz"]:visited, area[href][foo="baz"] { + order: 141; +} + +[foo="baz"] :link, [foo="baz"] :visited, [foo="baz"] area[href] { + order: 142; +} + +:link [foo="baz"], :visited [foo="baz"], area[href] [foo="baz"] { + order: 143; +} + +[foo="baz"] :link, [foo="baz"] :visited, [foo="baz"] area[href] { + order: 144; +} + +:link [foo="baz"], :visited [foo="baz"], area[href] [foo="baz"] { + order: 145; +} + +[foo="baz"]+:link, [foo="baz"]+:visited, [foo="baz"]+area[href] { + order: 146; +} + +:link+[foo="baz"], :visited+[foo="baz"], area[href]+[foo="baz"] { + order: 147; +} + +[foo="baz"] + :link, [foo="baz"] + :visited, [foo="baz"] + area[href] { + order: 148; +} + +:link + [foo="baz"], :visited + [foo="baz"], area[href] + [foo="baz"] { + order: 149; +} + +[foo="baz"]~:link, [foo="baz"]~:visited, [foo="baz"]~area[href] { + order: 150; +} + +:link~[foo="baz"], :visited~[foo="baz"], area[href]~[foo="baz"] { + order: 151; +} + +[foo="baz"] ~ :link, [foo="baz"] ~ :visited, [foo="baz"] ~ area[href] { + order: 152; +} + +:link ~ [foo="baz"], :visited ~ [foo="baz"], area[href] ~ [foo="baz"] { + order: 153; +} + +[foo="baz"]>:link, [foo="baz"]>:visited, [foo="baz"]>area[href] { + order: 154; +} + +:link>[foo="baz"], :visited>[foo="baz"], area[href]>[foo="baz"] { + order: 155; +} + +[foo="baz"] > :link, [foo="baz"] > :visited, [foo="baz"] > area[href] { + order: 156; +} + +:link > [foo="baz"], :visited > [foo="baz"], area[href] > [foo="baz"] { + order: 157; +} + +:link, :visited, area[href] { + order: 158; +} + +[foo="baz"] { + order: 158; +} + +:link, :visited, area[href] { + order: 159; +} + +[foo="baz"] { + order: 159; +} + +*:link, *:visited, *area[href] { + order: 160; +} + +*:link, *:visited, *area[href] { + order: 161; +} + +* :link, * :visited, * area[href] { + order: 162; +} + +:link *, :visited *, area[href] * { + order: 163; +} + +* :link, * :visited, * area[href] { + order: 164; +} + +:link *, :visited *, area[href] * { + order: 165; +} + +*+:link, *+:visited, *+area[href] { + order: 166; +} + +:link+*, :visited+*, area[href]+* { + order: 167; +} + +* + :link, * + :visited, * + area[href] { + order: 168; +} + +:link + *, :visited + *, area[href] + * { + order: 169; +} + +*~:link, *~:visited, *~area[href] { + order: 170; +} + +:link~*, :visited~*, area[href]~* { + order: 171; +} + +* ~ :link, * ~ :visited, * ~ area[href] { + order: 172; +} + +:link ~ *, :visited ~ *, area[href] ~ * { + order: 173; +} + +*>:link, *>:visited, *>area[href] { + order: 174; +} + +:link>*, :visited>*, area[href]>* { + order: 175; +} + +* > :link, * > :visited, * > area[href] { + order: 176; +} + +:link > *, :visited > *, area[href] > * { + order: 177; +} + +:link, :visited, area[href] { + order: 178; +} + +* { + order: 178; +} + +:link, :visited, area[href] { + order: 179; +} + +* { + order: 179; +} + +:hover:link, :hover:visited, area[href]:hover { + order: 180; +} + +:link:hover, :visited:hover, area[href]:hover { + order: 181; +} + +:hover :link, :hover :visited, :hover area[href] { + order: 182; +} + +:link :hover, :visited :hover, area[href] :hover { + order: 183; +} + +:hover :link, :hover :visited, :hover area[href] { + order: 184; +} + +:link :hover, :visited :hover, area[href] :hover { + order: 185; +} + +:hover+:link, :hover+:visited, :hover+area[href] { + order: 186; +} + +:link+:hover, :visited+:hover, area[href]+:hover { + order: 187; +} + +:hover + :link, :hover + :visited, :hover + area[href] { + order: 188; +} + +:link + :hover, :visited + :hover, area[href] + :hover { + order: 189; +} + +:hover~:link, :hover~:visited, :hover~area[href] { + order: 190; +} + +:link~:hover, :visited~:hover, area[href]~:hover { + order: 191; +} + +:hover ~ :link, :hover ~ :visited, :hover ~ area[href] { + order: 192; +} + +:link ~ :hover, :visited ~ :hover, area[href] ~ :hover { + order: 193; +} + +:hover>:link, :hover>:visited, :hover>area[href] { + order: 194; +} + +:link>:hover, :visited>:hover, area[href]>:hover { + order: 195; +} + +:hover > :link, :hover > :visited, :hover > area[href] { + order: 196; +} + +:link > :hover, :visited > :hover, area[href] > :hover { + order: 197; +} + +:link, :visited, area[href] { + order: 198; +} + +:hover { + order: 198; +} + +:link, :visited, area[href] { + order: 199; +} + +:hover { + order: 199; +} + +::before:link, ::before:visited, area[href]::before { + order: 200; +} + +:link::before, :visited::before, area[href]::before { + order: 201; +} + +::before :link, ::before :visited, ::before area[href] { + order: 202; +} + +:link ::before, :visited ::before, area[href] ::before { + order: 203; +} + +::before :link, ::before :visited, ::before area[href] { + order: 204; +} + +:link ::before, :visited ::before, area[href] ::before { + order: 205; +} + +::before+:link, ::before+:visited, ::before+area[href] { + order: 206; +} + +:link+::before, :visited+::before, area[href]+::before { + order: 207; +} + +::before + :link, ::before + :visited, ::before + area[href] { + order: 208; +} + +:link + ::before, :visited + ::before, area[href] + ::before { + order: 209; +} + +::before~:link, ::before~:visited, ::before~area[href] { + order: 210; +} + +:link~::before, :visited~::before, area[href]~::before { + order: 211; +} + +::before ~ :link, ::before ~ :visited, ::before ~ area[href] { + order: 212; +} + +:link ~ ::before, :visited ~ ::before, area[href] ~ ::before { + order: 213; +} + +::before>:link, ::before>:visited, ::before>area[href] { + order: 214; +} + +:link>::before, :visited>::before, area[href]>::before { + order: 215; +} + +::before > :link, ::before > :visited, ::before > area[href] { + order: 216; +} + +:link > ::before, :visited > ::before, area[href] > ::before { + order: 217; +} + +:link, :visited, area[href] { + order: 218; +} + +::before { + order: 218; +} + +:link, :visited, area[href] { + order: 219; +} + +::before { + order: 219; +} + +foo[:any-link] { + order: 220; +} + +foo[baz=":any-link"] { + order: 221; +} + +:not(:link), :not(:visited), :not(area[href]) { + order: 222; +} + +::any-link { + order: 223; +} + +:--:link, :--:visited, area[href]:-- { + order: 224; +} + +__:link, __:visited, __area[href] { + order: 225; +} + +/* :any-link */