diff --git a/plugin-packs/postcss-preset-env/.tape.mjs b/plugin-packs/postcss-preset-env/.tape.mjs index 02b429ea7..75c5d48ed 100644 --- a/plugin-packs/postcss-preset-env/.tape.mjs +++ b/plugin-packs/postcss-preset-env/.tape.mjs @@ -171,7 +171,7 @@ postcssTape(plugin)({ options: { stage: 0, browsers: '> 0%' - }, + } }, 'layers-basic:preserve:true': { message: 'supports layers usage with { preserve: true }', @@ -179,7 +179,7 @@ postcssTape(plugin)({ preserve: true, stage: 0, browsers: '> 0%' - }, + } }, 'client-side-polyfills:stage-1': { message: 'stable client side polyfill behavior', diff --git a/plugin-packs/postcss-preset-env/test/basic.ch88-ff78-saf10.expect.css b/plugin-packs/postcss-preset-env/test/basic.ch88-ff78-saf10.expect.css index 7b748514f..7fa0d9072 100644 --- a/plugin-packs/postcss-preset-env/test/basic.ch88-ff78-saf10.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.ch88-ff78-saf10.expect.css @@ -91,7 +91,27 @@ } } -h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors { +h1.test-custom-selectors { + order:12; +} + +h2.test-custom-selectors { + order:12; +} + +h3.test-custom-selectors { + order:12; +} + +h4.test-custom-selectors { + order:12; +} + +h5.test-custom-selectors { + order:12; +} + +h6.test-custom-selectors { order:12; } diff --git a/plugin-packs/postcss-preset-env/test/basic.ch88-ff78.expect.css b/plugin-packs/postcss-preset-env/test/basic.ch88-ff78.expect.css index 4f5bce961..ffe829c94 100644 --- a/plugin-packs/postcss-preset-env/test/basic.ch88-ff78.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.ch88-ff78.expect.css @@ -91,7 +91,27 @@ } } -h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors { +h1.test-custom-selectors { + order:12; +} + +h2.test-custom-selectors { + order:12; +} + +h3.test-custom-selectors { + order:12; +} + +h4.test-custom-selectors { + order:12; +} + +h5.test-custom-selectors { + order:12; +} + +h6.test-custom-selectors { order:12; } diff --git a/plugin-packs/postcss-preset-env/test/basic.ch88-ff78.no-is-pseudo.expect.css b/plugin-packs/postcss-preset-env/test/basic.ch88-ff78.no-is-pseudo.expect.css index 4f5bce961..ffe829c94 100644 --- a/plugin-packs/postcss-preset-env/test/basic.ch88-ff78.no-is-pseudo.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.ch88-ff78.no-is-pseudo.expect.css @@ -91,7 +91,27 @@ } } -h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors { +h1.test-custom-selectors { + order:12; +} + +h2.test-custom-selectors { + order:12; +} + +h3.test-custom-selectors { + order:12; +} + +h4.test-custom-selectors { + order:12; +} + +h5.test-custom-selectors { + order:12; +} + +h6.test-custom-selectors { order:12; } 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 15cb5fc49..0c8f97691 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 @@ -85,7 +85,27 @@ } } -h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors { +h1.test-custom-selectors { + order:12; +} + +h2.test-custom-selectors { + order:12; +} + +h3.test-custom-selectors { + order:12; +} + +h4.test-custom-selectors { + order:12; +} + +h5.test-custom-selectors { + order:12; +} + +h6.test-custom-selectors { order:12; } diff --git a/plugin-packs/postcss-preset-env/test/basic.op_mini.expect.css b/plugin-packs/postcss-preset-env/test/basic.op_mini.expect.css index 1a5bb8fc3..d700b8720 100644 --- a/plugin-packs/postcss-preset-env/test/basic.op_mini.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.op_mini.expect.css @@ -91,7 +91,27 @@ } } -h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors { +h1.test-custom-selectors { + order:12; +} + +h2.test-custom-selectors { + order:12; +} + +h3.test-custom-selectors { + order:12; +} + +h4.test-custom-selectors { + order:12; +} + +h5.test-custom-selectors { + order:12; +} + +h6.test-custom-selectors { order:12; } diff --git a/plugin-packs/postcss-preset-env/test/basic.preserve.true.expect.css b/plugin-packs/postcss-preset-env/test/basic.preserve.true.expect.css index ac8f97d25..cfe2b6ab9 100644 --- a/plugin-packs/postcss-preset-env/test/basic.preserve.true.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.preserve.true.expect.css @@ -187,7 +187,55 @@ @custom-selector :--heading h1, h2, h3, h4, h5, h6; -h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors { +h1.test-custom-selectors { + -webkit-box-ordinal-group:13; + -webkit-order:12; + -moz-box-ordinal-group:13; + -ms-flex-order:12; + order:12; +} + +h2.test-custom-selectors { + -webkit-box-ordinal-group:13; + -webkit-order:12; + -moz-box-ordinal-group:13; + -ms-flex-order:12; + order:12; +} + +h3.test-custom-selectors { + -webkit-box-ordinal-group:13; + -webkit-order:12; + -moz-box-ordinal-group:13; + -ms-flex-order:12; + order:12; +} + +h4.test-custom-selectors { + -webkit-box-ordinal-group:13; + -webkit-order:12; + -moz-box-ordinal-group:13; + -ms-flex-order:12; + order:12; +} + +h5.test-custom-selectors { + -webkit-box-ordinal-group:13; + -webkit-order:12; + -moz-box-ordinal-group:13; + -ms-flex-order:12; + order:12; +} + +h6.test-custom-selectors { + -webkit-box-ordinal-group:13; + -webkit-order:12; + -moz-box-ordinal-group:13; + -ms-flex-order:12; + order:12; +} + +.test-custom-selectors:is(h1, h2, h3, h4, h5, h6) { -webkit-box-ordinal-group:13; -webkit-order:12; -moz-box-ordinal-group:13; @@ -1015,6 +1063,10 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te background: red; } +:is([data-view-size=m]) .view { + background: red; +} + :--view-m .view { background: red; } diff --git a/plugin-packs/postcss-preset-env/test/basic.stage0-ff49.expect.css b/plugin-packs/postcss-preset-env/test/basic.stage0-ff49.expect.css index 647dadedb..74d3fdc4a 100644 --- a/plugin-packs/postcss-preset-env/test/basic.stage0-ff49.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.stage0-ff49.expect.css @@ -90,7 +90,27 @@ } } -h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors { +h1.test-custom-selectors { + order:12; +} + +h2.test-custom-selectors { + order:12; +} + +h3.test-custom-selectors { + order:12; +} + +h4.test-custom-selectors { + order:12; +} + +h5.test-custom-selectors { + order:12; +} + +h6.test-custom-selectors { order:12; } diff --git a/plugin-packs/postcss-preset-env/test/basic.stage0-ff66.expect.css b/plugin-packs/postcss-preset-env/test/basic.stage0-ff66.expect.css index 06f59ae6a..232f2671d 100644 --- a/plugin-packs/postcss-preset-env/test/basic.stage0-ff66.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.stage0-ff66.expect.css @@ -82,7 +82,27 @@ } } -h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors { +h1.test-custom-selectors { + order:12; +} + +h2.test-custom-selectors { + order:12; +} + +h3.test-custom-selectors { + order:12; +} + +h4.test-custom-selectors { + order:12; +} + +h5.test-custom-selectors { + order:12; +} + +h6.test-custom-selectors { order:12; } 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 2d6c84d9d..bd6b26d9d 100644 --- a/plugin-packs/postcss-preset-env/test/basic.stage0.expect.css +++ b/plugin-packs/postcss-preset-env/test/basic.stage0.expect.css @@ -92,7 +92,27 @@ } } -h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors { +h1.test-custom-selectors { + order:12; +} + +h2.test-custom-selectors { + order:12; +} + +h3.test-custom-selectors { + order:12; +} + +h4.test-custom-selectors { + order:12; +} + +h5.test-custom-selectors { + order:12; +} + +h6.test-custom-selectors { order:12; } diff --git a/plugins/postcss-custom-selectors/.tape.cjs b/plugins/postcss-custom-selectors/.tape.cjs deleted file mode 100644 index 5d857dd12..000000000 --- a/plugins/postcss-custom-selectors/.tape.cjs +++ /dev/null @@ -1,244 +0,0 @@ -const postcssTape = require('../../packages/postcss-tape/dist/index.cjs'); -const plugin = require('postcss-custom-selectors'); - -postcssTape(plugin)({ - 'basic': { - message: 'supports basic usage' - }, - 'basic:preserve': { - message: 'supports { preserve: true } usage', - options: { - preserve: true - } - }, - 'examples/example': { - message: 'minimal example', - }, - 'examples/example:preserve': { - message: 'minimal example', - options: { - preserve: true - } - }, - 'complex': { - message: 'supports complex usage' - }, - 'safety': { - message: 'supports safe tag ordering (.foo:--h1 becomes h1.foo instead of .fooh1)' - }, - 'basic-import': { - message: 'supports { importFrom: { customSelectors: { ... } } } usage', - options: { - importFrom: { - customSelectors: { - ':--heading': 'h1, h2, h3' - } - } - } - }, - 'basic-import:fn': { - message: 'supports { importFrom() } usage', - options: { - importFrom() { - return { - customSelectors: { - ':--heading': 'h1, h2, h3' - } - }; - } - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:fn-promise': { - message: 'supports { async importFrom() } usage', - options: { - importFrom() { - return new Promise(resolve => { - resolve({ - customSelectors: { - ':--heading': 'h1, h2, h3' - } - }) - }); - } - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:json': { - message: 'supports { importFrom: "test/import-selectors.json" } usage', - options: { - importFrom: 'test/import-selectors.json' - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:js': { - message: 'supports { importFrom: "test/import-selectors.js" } usage', - options: { - importFrom: 'test/import-selectors.js' - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:css': { - message: 'supports { importFrom: "test/import-selectors.css" } usage', - options: { - importFrom: 'test/import-selectors.css' - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:css-from': { - message: 'supports { importFrom: { from: "test/import-selectors.css" } } usage', - options: { - importFrom: { from: 'test/import-selectors.css' } - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:css-from-multiple-files': { - message: 'supports { importFrom: ["test/empty.css", "test/import-selectors.css"] } usage', - options: { - importFrom: ["test/empty.css", "test/import-selectors.css"] - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:css-from-type': { - message: 'supports { importFrom: [ { from: "test/import-selectors.css", type: "css" } ] } usage', - options: { - importFrom: [{ from: 'test/import-selectors.css', type: 'css' }] - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:empty': { - message: 'supports { importFrom: {} } usage', - options: { - importFrom: {} - } - }, - 'basic:export': { - message: 'supports { exportTo: { customSelectors: { ... } } } usage', - options: { - exportTo: (global.__exportSelectorObject = global.__exportSelectorObject || { - customSelectors: null - }) - }, - after() { - if (__exportSelectorObject.customSelectors[':--foo'] !== '.foo') { - throw new Error('The exportTo function failed'); - } - } - }, - 'basic:export-fn': { - message: 'supports { exportTo() } usage', - options: { - exportTo(customProperties) { - if (customProperties[':--foo'] !== '.foo') { - throw new Error('The exportTo function failed'); - } - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-fn-promise': { - message: 'supports { async exportTo() } usage', - options: { - exportTo(customProperties) { - return new Promise((resolve, reject) => { - if (customProperties[':--foo'] !== '.foo') { - reject('The exportTo function failed'); - } else { - resolve(); - } - }); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-json': { - message: 'supports { exportTo: "test/export-selectors.json" } usage', - options: { - exportTo: 'test/export-selectors.json' - }, - before() { - global.__exportSelectorsString = require('fs').readFileSync('test/export-selectors.json', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== require('fs').readFileSync('test/export-selectors.json', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-js': { - message: 'supports { exportTo: "test/export-selectors.js" } usage', - options: { - exportTo: 'test/export-selectors.js' - }, - before() { - global.__exportSelectorsString = require('fs').readFileSync('test/export-selectors.js', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== require('fs').readFileSync('test/export-selectors.js', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-mjs': { - message: 'supports { exportTo: "test/export-selectors.mjs" } usage', - options: { - exportTo: 'test/export-selectors.mjs' - }, - before() { - global.__exportSelectorsString = require('fs').readFileSync('test/export-selectors.mjs', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== require('fs').readFileSync('test/export-selectors.mjs', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-css': { - message: 'supports { exportTo: "test/export-selectors.css" } usage', - options: { - exportTo: 'test/export-selectors.css' - }, - before() { - global.__exportSelectorsString = require('fs').readFileSync('test/export-selectors.css', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== require('fs').readFileSync('test/export-selectors.css', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-css-to': { - message: 'supports { exportTo: { to: "test/export-selectors.css" } } usage', - options: { - exportTo: { to: 'test/export-selectors.css' } - }, - before() { - global.__exportSelectorsString = require('fs').readFileSync('test/export-selectors.css', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== require('fs').readFileSync('test/export-selectors.css', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-css-to-type': { - message: 'supports { exportTo: { to: "test/export-selectors.css", type: "css" } } usage', - options: { - exportTo: { to: 'test/export-selectors.css', type: 'css' } - }, - before() { - global.__exportSelectorsString = require('fs').readFileSync('test/export-selectors.css', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== require('fs').readFileSync('test/export-selectors.css', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - } -}); diff --git a/plugins/postcss-custom-selectors/.tape.mjs b/plugins/postcss-custom-selectors/.tape.mjs index 79664b78e..2c5c971f5 100644 --- a/plugins/postcss-custom-selectors/.tape.mjs +++ b/plugins/postcss-custom-selectors/.tape.mjs @@ -1,6 +1,5 @@ import postcssTape from '../../packages/postcss-tape/dist/index.mjs'; import plugin from 'postcss-custom-selectors'; -import fs from 'fs'; postcssTape(plugin)({ 'basic': { @@ -12,6 +11,9 @@ postcssTape(plugin)({ preserve: true } }, + 'conditionals': { + message: 'handles conditional rules' + }, 'examples/example': { message: 'minimal example', }, @@ -27,220 +29,4 @@ postcssTape(plugin)({ 'safety': { message: 'supports safe tag ordering (.foo:--h1 becomes h1.foo instead of .fooh1)' }, - 'basic-import': { - message: 'supports { importFrom: { customSelectors: { ... } } } usage', - options: { - importFrom: { - customSelectors: { - ':--heading': 'h1, h2, h3' - } - } - } - }, - 'basic-import:fn': { - message: 'supports { importFrom() } usage', - options: { - importFrom() { - return { - customSelectors: { - ':--heading': 'h1, h2, h3' - } - }; - } - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:fn-promise': { - message: 'supports { async importFrom() } usage', - options: { - importFrom() { - return new Promise(resolve => { - resolve({ - customSelectors: { - ':--heading': 'h1, h2, h3' - } - }) - }); - } - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:json': { - message: 'supports { importFrom: "test/import-selectors.json" } usage', - options: { - importFrom: 'test/import-selectors.json' - }, - expect: 'basic-import.expect.css' - }, - // ⚠️ Importing CJS in MJS does not work ⚠️ - // 'basic-import:js': { - // message: 'supports { importFrom: "test/import-selectors.js" } usage', - // options: { - // importFrom: 'test/import-selectors.js' - // }, - // expect: 'basic-import.expect.css' - // }, - 'basic-import:css': { - message: 'supports { importFrom: "test/import-selectors.css" } usage', - options: { - importFrom: 'test/import-selectors.css' - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:css-from': { - message: 'supports { importFrom: { from: "test/import-selectors.css" } } usage', - options: { - importFrom: { from: 'test/import-selectors.css' } - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:css-from-multiple-files': { - message: 'supports { importFrom: ["test/empty.css", "test/import-selectors.css"] } usage', - options: { - importFrom: ["test/empty.css", "test/import-selectors.css"] - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:css-from-type': { - message: 'supports { importFrom: [ { from: "test/import-selectors.css", type: "css" } ] } usage', - options: { - importFrom: [{ from: 'test/import-selectors.css', type: 'css' }] - }, - expect: 'basic-import.expect.css' - }, - 'basic-import:empty': { - message: 'supports { importFrom: {} } usage', - options: { - importFrom: {} - } - }, - 'basic:export': { - message: 'supports { exportTo: { customSelectors: { ... } } } usage', - options: { - exportTo: (global.__exportSelectorObject = global.__exportSelectorObject || { - customSelectors: null - }) - }, - after() { - if (__exportSelectorObject.customSelectors[':--foo'] !== '.foo') { - throw new Error('The exportTo function failed'); - } - } - }, - 'basic:export-fn': { - message: 'supports { exportTo() } usage', - options: { - exportTo(customProperties) { - if (customProperties[':--foo'] !== '.foo') { - throw new Error('The exportTo function failed'); - } - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-fn-promise': { - message: 'supports { async exportTo() } usage', - options: { - exportTo(customProperties) { - return new Promise((resolve, reject) => { - if (customProperties[':--foo'] !== '.foo') { - reject('The exportTo function failed'); - } else { - resolve(); - } - }); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-json': { - message: 'supports { exportTo: "test/export-selectors.json" } usage', - options: { - exportTo: 'test/export-selectors.json' - }, - before() { - global.__exportSelectorsString = fs.readFileSync('test/export-selectors.json', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== fs.readFileSync('test/export-selectors.json', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-js': { - message: 'supports { exportTo: "test/export-selectors.js" } usage', - options: { - exportTo: 'test/export-selectors.js' - }, - before() { - global.__exportSelectorsString = fs.readFileSync('test/export-selectors.js', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== fs.readFileSync('test/export-selectors.js', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-mjs': { - message: 'supports { exportTo: "test/export-selectors.mjs" } usage', - options: { - exportTo: 'test/export-selectors.mjs' - }, - before() { - global.__exportSelectorsString = fs.readFileSync('test/export-selectors.mjs', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== fs.readFileSync('test/export-selectors.mjs', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-css': { - message: 'supports { exportTo: "test/export-selectors.css" } usage', - options: { - exportTo: 'test/export-selectors.css' - }, - before() { - global.__exportSelectorsString = fs.readFileSync('test/export-selectors.css', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== fs.readFileSync('test/export-selectors.css', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-css-to': { - message: 'supports { exportTo: { to: "test/export-selectors.css" } } usage', - options: { - exportTo: { to: 'test/export-selectors.css' } - }, - before() { - global.__exportSelectorsString = fs.readFileSync('test/export-selectors.css', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== fs.readFileSync('test/export-selectors.css', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - }, - 'basic:export-css-to-type': { - message: 'supports { exportTo: { to: "test/export-selectors.css", type: "css" } } usage', - options: { - exportTo: { to: 'test/export-selectors.css', type: 'css' } - }, - before() { - global.__exportSelectorsString = fs.readFileSync('test/export-selectors.css', 'utf8'); - }, - after() { - if (global.__exportSelectorsString !== fs.readFileSync('test/export-selectors.css', 'utf8')) { - throw new Error('The original file did not match the freshly exported copy'); - } - }, - expect: 'basic.expect.css' - } }); diff --git a/plugins/postcss-custom-selectors/CHANGELOG.md b/plugins/postcss-custom-selectors/CHANGELOG.md index 9853a7b5d..8f0e94010 100644 --- a/plugins/postcss-custom-selectors/CHANGELOG.md +++ b/plugins/postcss-custom-selectors/CHANGELOG.md @@ -3,10 +3,29 @@ ### Unreleased (major) - Updated: Support for Node v14+ (major). +- Removed: `importFrom` feature (breaking). +- Removed: `exportTo` feature (breaking). +- Fixed: follow the specification and use `:is()` in transformed selectors (breaking). +- Added: Support for `@scope` and `@container` as parent rules of `@custom-selector`. + +```diff +@custom-selector :--heading h1, h2, h3; + +article :--heading + p { + margin-top: 0; +} + +/* becomes */ + +- article h1 + p,article h2 + p,article h3 + p { ++ article :is(h1, h2, h3) + p { + margin-top: 0; +} +``` ### 6.0.3 (June 4, 2022) -- Fixed: allow any valid ident in custom media (`@custom-selector :--🧑🏾‍🎤 .singer`) +- Fixed: allow any valid ident in custom selectors (`@custom-selector :--🧑🏾‍🎤 .singer`) ### 6.0.2 (June 3, 2022) diff --git a/plugins/postcss-custom-selectors/README.md b/plugins/postcss-custom-selectors/README.md index 5b57aeeb0..4b0ca4f2d 100644 --- a/plugins/postcss-custom-selectors/README.md +++ b/plugins/postcss-custom-selectors/README.md @@ -13,7 +13,7 @@ article :--heading + p { /* becomes */ -article h1 + p,article h2 + p,article h3 + p { +article :is(h1, h2, h3) + p { margin-top: 0; } ``` @@ -65,7 +65,7 @@ article :--heading + p { @custom-selector :--heading h1, h2, h3; -article h1 + p,article h2 + p,article h3 + p { +article :is(h1, h2, h3) + p { margin-top: 0; } @@ -74,85 +74,6 @@ article :--heading + p { } ``` -### importFrom - -The `importFrom` option specifies sources where custom selectors can be -imported from, which might be CSS, JS, and JSON files, functions, and directly -passed objects. - -```js -postcssCustomSelectors({ - importFrom: 'path/to/file.css' // => @custom-selector :--heading h1, h2, h3; -}); -``` - -```pcss -article :--heading + p { - margin-top: 0; -} - -/* becomes */ - -article h1 + p, article h2 + p, article h3 + p {} -``` - -Multiple sources can be passed into this option, and they will be parsed in the -order they are received. JavaScript files, JSON files, functions, and objects -will need to namespace custom selectors using the `customProperties` or -`custom-properties` key. - -```js -postcssCustomSelectors({ - importFrom: [ - 'path/to/file.css', - 'and/then/this.js', - 'and/then/that.json', - { - customSelectors: { ':--heading': 'h1, h2, h3' } - }, - () => { - const customProperties = { ':--heading': 'h1, h2, h3' }; - - return { customProperties }; - } - ] -}); -``` - -### exportTo - -The `exportTo` option specifies destinations where custom selectors can be -exported to, which might be CSS, JS, and JSON files, functions, and directly -passed objects. - -```js -postcssCustomSelectors({ - exportTo: 'path/to/file.css' // @custom-selector :--heading h1, h2, h3; -}); -``` - -Multiple destinations can be passed into this option, and they will be parsed -in the order they are received. JavaScript files, JSON files, and objects will -need to namespace custom selectors using the `customProperties` or -`custom-properties` key. - -```js -const cachedObject = { customSelectors: {} }; - -postcssCustomSelectors({ - exportTo: [ - 'path/to/file.css', // @custom-selector :--heading h1, h2, h3; - 'and/then/this.js', // module.exports = { customSelectors: { ':--heading': 'h1, h2, h3' } } - 'and/then/this.mjs', // export const customSelectors = { ':--heading': 'h1, h2, h3' } } - 'and/then/that.json', // { "custom-selectors": { ":--heading": "h1, h2, h3" } } - cachedObject, - customProperties => { - customProperties // { ':--heading': 'h1, h2, h3' } - } - ] -}); -``` - [cli-url]: https://github.com/csstools/postcss-plugins/actions/workflows/test.yml?query=workflow/test [css-url]: https://cssdb.org/#custom-selectors [discord]: https://discord.gg/bUadyRwkJS diff --git a/plugins/postcss-custom-selectors/docs/README.md b/plugins/postcss-custom-selectors/docs/README.md index 94e7d6e0f..9537100ca 100644 --- a/plugins/postcss-custom-selectors/docs/README.md +++ b/plugins/postcss-custom-selectors/docs/README.md @@ -49,84 +49,5 @@ is preserved. By default, it is not preserved. ``` -### importFrom - -The `importFrom` option specifies sources where custom selectors can be -imported from, which might be CSS, JS, and JSON files, functions, and directly -passed objects. - -```js -({ - importFrom: 'path/to/file.css' // => @custom-selector :--heading h1, h2, h3; -}); -``` - -```pcss -article :--heading + p { - margin-top: 0; -} - -/* becomes */ - -article h1 + p, article h2 + p, article h3 + p {} -``` - -Multiple sources can be passed into this option, and they will be parsed in the -order they are received. JavaScript files, JSON files, functions, and objects -will need to namespace custom selectors using the `customProperties` or -`custom-properties` key. - -```js -({ - importFrom: [ - 'path/to/file.css', - 'and/then/this.js', - 'and/then/that.json', - { - customSelectors: { ':--heading': 'h1, h2, h3' } - }, - () => { - const customProperties = { ':--heading': 'h1, h2, h3' }; - - return { customProperties }; - } - ] -}); -``` - -### exportTo - -The `exportTo` option specifies destinations where custom selectors can be -exported to, which might be CSS, JS, and JSON files, functions, and directly -passed objects. - -```js -({ - exportTo: 'path/to/file.css' // @custom-selector :--heading h1, h2, h3; -}); -``` - -Multiple destinations can be passed into this option, and they will be parsed -in the order they are received. JavaScript files, JSON files, and objects will -need to namespace custom selectors using the `customProperties` or -`custom-properties` key. - -```js -const cachedObject = { customSelectors: {} }; - -({ - exportTo: [ - 'path/to/file.css', // @custom-selector :--heading h1, h2, h3; - 'and/then/this.js', // module.exports = { customSelectors: { ':--heading': 'h1, h2, h3' } } - 'and/then/this.mjs', // export const customSelectors = { ':--heading': 'h1, h2, h3' } } - 'and/then/that.json', // { "custom-selectors": { ":--heading": "h1, h2, h3" } } - cachedObject, - customProperties => { - customProperties // { ':--heading': 'h1, h2, h3' } - } - ] -}); -``` - [Custom Selectors Specification]: diff --git a/plugins/postcss-custom-selectors/package.json b/plugins/postcss-custom-selectors/package.json index e0fac66e3..250029316 100644 --- a/plugins/postcss-custom-selectors/package.json +++ b/plugins/postcss-custom-selectors/package.json @@ -33,6 +33,7 @@ }, "main": "dist/index.cjs", "module": "dist/index.mjs", + "types": "dist/index.d.ts", "exports": { ".": { "import": "./dist/index.mjs", @@ -60,9 +61,9 @@ "lint:eslint": "eslint ./src --ext .js --ext .ts --ext .mjs --no-error-on-unmatched-pattern", "lint:package-json": "node ../../.github/bin/format-package-json.mjs", "prepublishOnly": "npm run clean && npm run build && npm run test", - "test": "node .tape.cjs && node .tape.mjs && npm run test:exports", + "test": "node .tape.mjs && npm run test:exports", "test:exports": "node ./test/_import.mjs && node ./test/_require.cjs", - "test:rewrite-expects": "REWRITE_EXPECTS=true node .tape.mjs && REWRITE_EXPECTS=true node .tape.cjs" + "test:rewrite-expects": "REWRITE_EXPECTS=true node .tape.mjs" }, "homepage": "https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-custom-selectors#readme", "repository": { diff --git a/plugins/postcss-custom-selectors/src/custom-selectors-from-root.js b/plugins/postcss-custom-selectors/src/custom-selectors-from-root.js deleted file mode 100644 index 3a9b70cb3..000000000 --- a/plugins/postcss-custom-selectors/src/custom-selectors-from-root.js +++ /dev/null @@ -1,38 +0,0 @@ -import parser from 'postcss-selector-parser'; - -// return custom selectors from the css root, conditionally removing them -export default (root, opts) => { - // initialize custom selectors - const customSelectors = {}; - - // for each custom selector atrule that is a child of the css root - root.nodes.slice().forEach(node => { - if (node.type !== 'atrule' || node.name !== 'custom-selector') { - return; - } - - if (!node.params || !node.params.includes(':--')) { - return; - } - - const source = node.params.trim(); - - const selectorAST = parser().astSync(source); - const nameNode = selectorAST?.nodes?.[0]?.nodes?.[0]; - if (!nameNode || nameNode.type !== 'pseudo' || !nameNode.value.startsWith(':--')) { - return; - } - - const name = nameNode.toString(); - - // re-parsing is important to obtain the correct AST shape - customSelectors[name] = parser().astSync(source.slice(name.length).trim()); - - // conditionally remove the custom selector atrule - if (!Object(opts).preserve) { - node.remove(); - } - }); - - return customSelectors; -}; diff --git a/plugins/postcss-custom-selectors/src/custom-selectors-from-root.ts b/plugins/postcss-custom-selectors/src/custom-selectors-from-root.ts new file mode 100644 index 000000000..1e0161f05 --- /dev/null +++ b/plugins/postcss-custom-selectors/src/custom-selectors-from-root.ts @@ -0,0 +1,52 @@ +import type { ChildNode, Container, Document, Root as PostCSSRoot } from 'postcss'; +import type { Root as SelectorRoot } from 'postcss-selector-parser'; +import parser from 'postcss-selector-parser'; +import { isProcessableCustomSelectorRule } from './is-processable-custom-selector-rule'; + +// return custom selectors from the css root, conditionally removing them +export default function getCustomSelectors(root: PostCSSRoot, opts: { preserve?: boolean }): Map { + // initialize custom selectors + const customSelectors = new Map(); + + root.walkAtRules((atRule) => { + if (!isProcessableCustomSelectorRule(atRule)) { + return; + } + + const source = atRule.params.trim(); + + const selectorAST = parser().astSync(source); + const nameNode = selectorAST?.nodes?.[0]?.nodes?.[0]; + if (!nameNode || nameNode.type !== 'pseudo' || !nameNode.value.startsWith(':--')) { + return; + } + + const name = nameNode.toString(); + + // re-parsing is important to obtain the correct AST shape + customSelectors.set(name, parser().astSync(source.slice(name.length).trim())); + + if (!opts.preserve) { + const parent = atRule.parent; + atRule.remove(); + + removeEmptyAncestorBlocks(parent); + } + }); + + return customSelectors; +} + +function removeEmptyAncestorBlocks(block: Container) { + let currentNode: Document | Container = block; + + while (currentNode) { + if (currentNode.nodes && currentNode.nodes.length > 0) { + return; + } + + const parent = currentNode.parent; + currentNode.remove(); + currentNode = parent; + } +} diff --git a/plugins/postcss-custom-selectors/src/export-to.js b/plugins/postcss-custom-selectors/src/export-to.js deleted file mode 100644 index 3420fe074..000000000 --- a/plugins/postcss-custom-selectors/src/export-to.js +++ /dev/null @@ -1,129 +0,0 @@ -import fs from 'fs'; -import path from 'path'; - -/* Import Custom Selectors from CSS File -/* ========================================================================== */ - -async function exportCustomSelectorsToCssFile(to, customSelectors) { - const cssContent = Object.keys(customSelectors).reduce((cssLines, name) => { - cssLines.push(`@custom-selector ${name} ${customSelectors[name]};`); - - return cssLines; - }, []).join('\n'); - const css = `${cssContent}\n`; - - await writeFile(to, css); -} - -/* Import Custom Selectors from JSON file -/* ========================================================================== */ - -async function exportCustomSelectorsToJsonFile(to, customSelectors) { - const jsonContent = JSON.stringify({ - 'custom-selectors': customSelectors, - }, null, '\t'); - const json = `${jsonContent}\n`; - - await writeFile(to, json); -} - -/* Import Custom Selectors from Common JS file -/* ========================================================================== */ - -async function exportCustomSelectorsToCjsFile(to, customSelectors) { - const jsContents = Object.keys(customSelectors).reduce((jsLines, name) => { - jsLines.push(`\t\t'${escapeForJS(name)}': '${escapeForJS(customSelectors[name])}'`); - - return jsLines; - }, []).join(',\n'); - const js = `module.exports = {\n\tcustomSelectors: {\n${jsContents}\n\t}\n};\n`; - - await writeFile(to, js); -} - -/* Import Custom Selectors from Module JS file -/* ========================================================================== */ - -async function exportCustomSelectorsToMjsFile(to, customSelectors) { - const mjsContents = Object.keys(customSelectors).reduce((mjsLines, name) => { - mjsLines.push(`\t'${escapeForJS(name)}': '${escapeForJS(customSelectors[name])}'`); - - return mjsLines; - }, []).join(',\n'); - const mjs = `export const customSelectors = {\n${mjsContents}\n};\n`; - - await writeFile(to, mjs); -} - -/* Export Custom Selectors to Destinations -/* ========================================================================== */ - -export default function exportCustomSelectorsToDestinations(customSelectors, destinations) { - return Promise.all(destinations.map(async destination => { - if (destination instanceof Function) { - await destination(defaultCustomSelectorsToJSON(customSelectors)); - } else { - // read the destination as an object - const opts = destination === Object(destination) ? destination : { to: String(destination) }; - - // transformer for custom selectors into a JSON-compatible object - const toJSON = opts.toJSON || defaultCustomSelectorsToJSON; - - if ('customSelectors' in opts) { - // write directly to an object as customSelectors - opts.customSelectors = toJSON(customSelectors); - } else if ('custom-selectors' in opts) { - // write directly to an object as custom-selectors - opts['custom-selectors'] = toJSON(customSelectors); - } else { - // destination pathname - const to = String(opts.to || ''); - - // type of file being written to - const type = (opts.type || path.extname(opts.to).slice(1)).toLowerCase(); - - // transformed custom selectors - const customSelectorsJSON = toJSON(customSelectors); - - if (type === 'css') { - await exportCustomSelectorsToCssFile(to, customSelectorsJSON); - } - - if (type === 'js') { - await exportCustomSelectorsToCjsFile(to, customSelectorsJSON); - } - - if (type === 'json') { - await exportCustomSelectorsToJsonFile(to, customSelectorsJSON); - } - - if (type === 'mjs') { - await exportCustomSelectorsToMjsFile(to, customSelectorsJSON); - } - } - } - })); -} - -/* Helper utilities -/* ========================================================================== */ - -const defaultCustomSelectorsToJSON = customSelectors => { - return Object.keys(customSelectors).reduce((customSelectorsJSON, key) => { - customSelectorsJSON[key] = String(customSelectors[key]); - - return customSelectorsJSON; - }, {}); -}; - -const writeFile = (to, text) => new Promise((resolve, reject) => { - fs.writeFile(to, text, error => { - if (error) { - reject(error); - } else { - resolve(); - } - }); -}); - -const escapeForJS = string => string.replace(/\\([\s\S])|(')/g, '\\$1$2').replace(/\n/g, '\\n').replace(/\r/g, '\\r'); diff --git a/plugins/postcss-custom-selectors/src/import-from.js b/plugins/postcss-custom-selectors/src/import-from.js deleted file mode 100644 index 61c8fb522..000000000 --- a/plugins/postcss-custom-selectors/src/import-from.js +++ /dev/null @@ -1,121 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import postcss from 'postcss'; -import parser from 'postcss-selector-parser'; -import getCustomSelectors from './custom-selectors-from-root'; - -/* Import Custom Selectors from CSS AST -/* ========================================================================== */ - -function importCustomSelectorsFromCSSAST(root) { - return getCustomSelectors(root); -} - -/* Import Custom Selectors from CSS File -/* ========================================================================== */ - -async function importCustomSelectorsFromCSSFile(from) { - const css = await readFile(path.resolve(from)); - const root = postcss.parse(css, { from: path.resolve(from) }); - - return importCustomSelectorsFromCSSAST(root); -} - -/* Import Custom Selectors from Object -/* ========================================================================== */ - -function importCustomSelectorsFromObject(object) { - const customSelectors = Object.assign( - {}, - Object(object).customSelectors || Object(object)['custom-selectors'], - ); - - for (const key in customSelectors) { - customSelectors[key] = parser().astSync(customSelectors[key]); - } - - return customSelectors; -} - -/* Import Custom Selectors from JSON file -/* ========================================================================== */ - -async function importCustomSelectorsFromJSONFile(from) { - const object = await readJSON(path.resolve(from)); - - return importCustomSelectorsFromObject(object); -} - -/* Import Custom Selectors from JS file -/* ========================================================================== */ - -async function importCustomSelectorsFromJSFile(from) { - const object = await import(path.resolve(from)); - - return importCustomSelectorsFromObject(object); -} - -/* Import Custom Selectors from Sources -/* ========================================================================== */ - -export default function importCustomSelectorsFromSources(sources) { - return sources.map(source => { - if (source instanceof Promise) { - return source; - } else if (source instanceof Function) { - return source(); - } - - // read the source as an object - const opts = source === Object(source) ? source : { from: String(source) }; - - // skip objects with custom selectors - if (Object(opts).customSelectors || Object(opts)['custom-selectors']) { - return opts; - } - - // source pathname - const from = String(opts.from || ''); - - // type of file being read from - const type = (opts.type || path.extname(from).slice(1)).toLowerCase(); - - return { type, from }; - }).reduce(async (customSelectorsPromise, source) => { - const customSelectors = await customSelectorsPromise; - const { type, from } = await source; - - if (type === 'ast') { - return Object.assign(customSelectors, importCustomSelectorsFromCSSAST(from)); - } - - if (type === 'css') { - return Object.assign(customSelectors, await importCustomSelectorsFromCSSFile(from)); - } - - if (type === 'js') { - return Object.assign(customSelectors, await importCustomSelectorsFromJSFile(from)); - } - - if (type === 'json') { - return Object.assign(customSelectors, await importCustomSelectorsFromJSONFile(from)); - } - - return Object.assign(customSelectors, importCustomSelectorsFromObject(await source)); - }, Promise.resolve({})); -} - -/* Helper utilities -/* ========================================================================== */ - -const readFile = from => new Promise((resolve, reject) => { - fs.readFile(from, 'utf8', (error, result) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); -}); - -const readJSON = async from => JSON.parse(await readFile(from)); diff --git a/plugins/postcss-custom-selectors/src/index.js b/plugins/postcss-custom-selectors/src/index.js deleted file mode 100644 index 156000b8c..000000000 --- a/plugins/postcss-custom-selectors/src/index.js +++ /dev/null @@ -1,45 +0,0 @@ -import getCustomSelectors from './custom-selectors-from-root'; -import transformRule from './transform-rule'; -import importCustomSelectorsFromSources from './import-from'; -import exportCustomSelectorsToDestinations from './export-to'; - -const creator = (opts) => { - // whether to preserve custom selectors and rules using them - const preserve = Boolean(Object(opts).preserve); - - // sources to import custom selectors from - const importFrom = [].concat(Object(opts).importFrom || []); - - // destinations to export custom selectors to - const exportTo = [].concat(Object(opts).exportTo || []); - - // promise any custom selectors are imported - const customSelectorsPromise = importCustomSelectorsFromSources(importFrom); - - const customSelectorHelperKey = Symbol('customSelectorHelper'); - - return { - postcssPlugin: 'postcss-custom-selectors', - Once: async (root, helpers) => { - helpers[customSelectorHelperKey] = Object.assign( - await customSelectorsPromise, - getCustomSelectors(root, { preserve }), - ); - - await exportCustomSelectorsToDestinations(helpers[customSelectorHelperKey], exportTo); - }, - Rule: (rule, helpers) => { - if (!rule.selector.includes(':--')) { - return; - } - - transformRule(rule, helpers[customSelectorHelperKey], { preserve }); - }, - }; -}; - -creator.postcss = true; - -export default creator; - - diff --git a/plugins/postcss-custom-selectors/src/index.ts b/plugins/postcss-custom-selectors/src/index.ts new file mode 100644 index 000000000..f450f7c1f --- /dev/null +++ b/plugins/postcss-custom-selectors/src/index.ts @@ -0,0 +1,45 @@ +import type { PluginCreator } from 'postcss'; +import getCustomSelectors from './custom-selectors-from-root'; +import transformRule from './transform-rule'; + +export interface PluginOptions { + /** Determines whether Custom Selectors and selectors using custom selectors should be preserved in their original form. */ + preserve?: boolean +} + +const creator: PluginCreator = (opts?: PluginOptions) => { + // whether to preserve custom selectors and rules using them + const preserve = Boolean(Object(opts).preserve); + + if ('importFrom' in Object(opts)) { + throw new Error('[postcss-custom-selectors] "importFrom" is no longer supported'); + } + + if ('exportTo' in Object(opts)) { + throw new Error('[postcss-custom-selectors] "exportTo" is no longer supported'); + } + + return { + postcssPlugin: 'postcss-custom-selectors', + prepare() { + let customSelectors = new Map(); + + return { + Once: (root) => { + customSelectors = getCustomSelectors(root, { preserve: preserve }); + }, + Rule: (rule) => { + if (!rule.selector.includes(':--')) { + return; + } + + transformRule(rule, customSelectors, { preserve: preserve }); + }, + }; + }, + }; +}; + +creator.postcss = true; + +export default creator; diff --git a/plugins/postcss-custom-selectors/src/is-processable-custom-selector-rule.ts b/plugins/postcss-custom-selectors/src/is-processable-custom-selector-rule.ts new file mode 100644 index 000000000..e54ddf042 --- /dev/null +++ b/plugins/postcss-custom-selectors/src/is-processable-custom-selector-rule.ts @@ -0,0 +1,36 @@ +import type { AtRule, ChildNode, Container, Document } from 'postcss'; + +const allowedParentAtRules = new Set(['scope', 'container']); + +export function isProcessableCustomSelectorRule(atRule: AtRule): boolean { + if (atRule.type !== 'atrule') { + return false; + } + + if (atRule.name.toLowerCase() !== 'custom-selector') { + return false; + } + + if (!atRule.params || !atRule.params.includes(':--')) { + return false; + } + + if (atRule.nodes && atRule.nodes.length > 0) { + return false; + } + + let parent: Container | Document = atRule.parent; + while (parent) { + if (parent.type === 'rule') { + return false; + } + + if (parent.type === 'atrule' && !allowedParentAtRules.has((parent as AtRule).name.toLowerCase())) { + return false; + } + + parent = parent.parent; + } + + return true; +} diff --git a/plugins/postcss-custom-selectors/src/transform-rule.js b/plugins/postcss-custom-selectors/src/transform-rule.js deleted file mode 100644 index 0f9eeb0c3..000000000 --- a/plugins/postcss-custom-selectors/src/transform-rule.js +++ /dev/null @@ -1,19 +0,0 @@ -import parser from 'postcss-selector-parser'; -import transformSelectorsByCustomSelectors from './transform-selectors-by-custom-selectors'; - -// transform custom pseudo selectors with custom selectors -export default (rule, customSelectors, opts) => { - const selector = parser(selectors => { - transformSelectorsByCustomSelectors(selectors, customSelectors, opts); - }).processSync(rule.selector); - - if (selector === rule.selector) { - return; - } - - rule.cloneBefore({ selector: selector }); - - if (!opts.preserve) { - rule.remove(); - } -}; diff --git a/plugins/postcss-custom-selectors/src/transform-rule.ts b/plugins/postcss-custom-selectors/src/transform-rule.ts new file mode 100644 index 000000000..d3b37f4d7 --- /dev/null +++ b/plugins/postcss-custom-selectors/src/transform-rule.ts @@ -0,0 +1,36 @@ +import type { Root, Selector } from 'postcss-selector-parser'; +import parser from 'postcss-selector-parser'; + +// transform custom pseudo selectors with custom selectors +export default (rule, customSelectors: Map, opts: { preserve?: boolean }) => { + const selector = parser(selectors => { + selectors.walkPseudos((pseudo) => { + if (!customSelectors.has(pseudo.value)) { + return; + } + + const isWrapper = parser.pseudo({ + value: ':is', + nodes: [], + }); + + const base = customSelectors.get(pseudo.value); + base.each((node) => { + isWrapper.append(node.clone({}) as Selector); + }); + + pseudo.replaceWith(isWrapper); + + }); + }).processSync(rule.selector); + + if (selector === rule.selector) { + return; + } + + rule.cloneBefore({ selector: selector }); + + if (!opts.preserve) { + rule.remove(); + } +}; diff --git a/plugins/postcss-custom-selectors/src/transform-selectors-by-custom-selectors.js b/plugins/postcss-custom-selectors/src/transform-selectors-by-custom-selectors.js deleted file mode 100644 index 37e32d5e6..000000000 --- a/plugins/postcss-custom-selectors/src/transform-selectors-by-custom-selectors.js +++ /dev/null @@ -1,99 +0,0 @@ -// return transformed selectors, replacing custom pseudo selectors with custom selectors -export default function transformSelectorList(selectorList, customSelectors) { - let index = selectorList.nodes.length - 1; - - while (index >= 0) { - const transformedSelectors = transformSelector(selectorList.nodes[index], customSelectors); - - if (transformedSelectors.length) { - selectorList.nodes.splice(index, 1, ...transformedSelectors); - } - - --index; - } - - return selectorList; -} - -// return custom pseudo selectors replaced with custom selectors -function transformSelector(selector, customSelectors) { - const transpiledSelectors = []; - - for (const index in selector.nodes) { - const { value, nodes } = selector.nodes[index]; - - if (value in customSelectors) { - for (const replacementSelector of customSelectors[value].nodes) { - const selectorClone = selector.clone(); - - const replacementSelectorNodes = replacementSelector.clone().nodes; - - selectorClone.nodes.splice(index, 1, ...replacementSelectorNodes.map((node, index) => { - if (node.type === 'selector') { - // use spacing from the current usage - node.spaces = { ...selector.nodes[index].spaces }; - } - - if (index === 0 && node.spaces) { - node.spaces.before = ''; - } - - if (index === (replacementSelectorNodes.length - 1) && node.spaces) { - node.spaces.after = ''; - } - - return node; - })); - - const retranspiledSelectors = transformSelector(selectorClone, customSelectors); - - adjustNodesBySelectorEnds(selectorClone.nodes, Number(index)); - - if (retranspiledSelectors.length) { - transpiledSelectors.push(...retranspiledSelectors); - } else { - transpiledSelectors.push(selectorClone); - } - } - - return transpiledSelectors; - } else if (nodes && nodes.length) { - transformSelectorList(selector.nodes[index], customSelectors); - } - } - - return transpiledSelectors; -} - -// match selectors by difficult-to-separate ends -const withoutSelectorStartMatch = /^(tag|universal)$/; -const withoutSelectorEndMatch = /^(class|id|pseudo|tag|universal)$/; - -const isWithoutSelectorStart = node => withoutSelectorStartMatch.test(Object(node).type); -const isWithoutSelectorEnd = node => withoutSelectorEndMatch.test(Object(node).type); - -// adjust nodes by selector ends (so that .class:--h1 becomes h1.class rather than .classh1) -const adjustNodesBySelectorEnds = (nodes, index) => { - if (index && isWithoutSelectorStart(nodes[index]) && isWithoutSelectorEnd(nodes[index - 1])) { - let safeIndex = index - 1; - - while (safeIndex && isWithoutSelectorEnd(nodes[safeIndex])) { - --safeIndex; - } - - if (safeIndex < index) { - const node = nodes.splice(index, 1)[0]; - - nodes.splice(safeIndex, 0, node); - - nodes[safeIndex].spaces.before = nodes[safeIndex + 1].spaces.before; - nodes[safeIndex + 1].spaces.before = ''; - - if (nodes[index]) { - nodes[index].spaces.after = nodes[safeIndex].spaces.after; - nodes[safeIndex].spaces.after = ''; - } - } - } -}; - diff --git a/plugins/postcss-custom-selectors/test/basic-import.css b/plugins/postcss-custom-selectors/test/basic-import.css deleted file mode 100644 index 23fdd405c..000000000 --- a/plugins/postcss-custom-selectors/test/basic-import.css +++ /dev/null @@ -1,3 +0,0 @@ -article :--heading+p { - margin-top: 0; -} diff --git a/plugins/postcss-custom-selectors/test/basic-import.empty.expect.css b/plugins/postcss-custom-selectors/test/basic-import.empty.expect.css deleted file mode 100644 index 23fdd405c..000000000 --- a/plugins/postcss-custom-selectors/test/basic-import.empty.expect.css +++ /dev/null @@ -1,3 +0,0 @@ -article :--heading+p { - margin-top: 0; -} diff --git a/plugins/postcss-custom-selectors/test/basic-import.expect.css b/plugins/postcss-custom-selectors/test/basic-import.expect.css deleted file mode 100644 index 51a7130f9..000000000 --- a/plugins/postcss-custom-selectors/test/basic-import.expect.css +++ /dev/null @@ -1,3 +0,0 @@ -article h1+p,article h2+p,article h3+p { - margin-top: 0; -} diff --git a/plugins/postcss-custom-selectors/test/basic.expect.css b/plugins/postcss-custom-selectors/test/basic.expect.css index 1a6918335..858b928a5 100644 --- a/plugins/postcss-custom-selectors/test/basic.expect.css +++ b/plugins/postcss-custom-selectors/test/basic.expect.css @@ -1,34 +1,43 @@ -.foo.foo { +.foo:is(.foo) { margin-top: 16px; } -h1 + p,h2 + p,h3 + p,h4 + p,h5 + p,h6 + p {} +:is(h1, h2, h3, h4, h5, h6) + p {} -.foo > .baz {} -.fizz > .foo,.buzz > .foo {} -.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active {} +:is(.foo) > :is(.baz) {} +:is(.fizz, .buzz) > :is(.foo) {} +:is(.btn-primary, + .btn-success, + .btn-info, + .btn-warning, + .btn-danger),:is(.btn-primary, + .btn-success, + .btn-info, + .btn-warning, + .btn-danger):active {} -.foo + p,.bar > .baz + p { +:is(.foo, + .bar > .baz) + p { display: block; } -.foo > a::before img,.foo > a::after img { +.foo > a:is(::before, ::after) img { display: block; } -.foo,.foo.bar { +:is(.foo),:is(.foo).bar { color: white; } -.foo .foo:hover { +:is(.foo) :is(.foo):hover { color: white; } -.fo--oo > h1,.fo--oo > h2,.fo--oo > h3 { +.fo--oo > :is(h1, h2, h3) { margin: auto; } -h4:hover .ba--z,h5:hover .ba--z,h6:hover .ba--z { +:is(h4, h5, h6):hover .ba--z { display: block; } @@ -38,48 +47,49 @@ article :--heading + p { margin-top: 0; } -.foo,.bar > .baz { +:is(.foo, + .bar > .baz) { display: block; } /* should works with collapsed custom selectors */ -button:hover,button:focus,.button:hover,.button:focus {} +:is(button, .button):is(:hover, :focus) {} -.foo h1,.bar h1 { +:is(.foo, .bar) h1 { margin-top: 16px; } -main .foo + p { +main :is(.foo) + p { margin-top: 16px; } -.foo { +:is(.foo) { order: 1000; } -a,.foo { +a,:is(.foo) { order: 1001; } -b,.foo { +b,:is(.foo) { order: 1002; } -.foo.baz { +:is(.foo.baz) { order: 1010; } -a,.foo.baz { +a,:is(.foo.baz) { order: 1011; } -b,.foo.baz { +b,:is(.foo.baz) { order: 1012; } -.foo .baz { +:is(.foo .baz) { order: 1020; } -a,.foo .baz { +a,:is(.foo .baz) { order: 1021; } -b,.foo .baz { +b,:is(.foo .baz) { order: 1022; } diff --git a/plugins/postcss-custom-selectors/test/basic.export.expect.css b/plugins/postcss-custom-selectors/test/basic.export.expect.css deleted file mode 100644 index 1a6918335..000000000 --- a/plugins/postcss-custom-selectors/test/basic.export.expect.css +++ /dev/null @@ -1,85 +0,0 @@ -.foo.foo { - margin-top: 16px; -} - -h1 + p,h2 + p,h3 + p,h4 + p,h5 + p,h6 + p {} - -.foo > .baz {} -.fizz > .foo,.buzz > .foo {} -.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active {} - -.foo + p,.bar > .baz + p { - display: block; -} - -.foo > a::before img,.foo > a::after img { - display: block; -} - -.foo,.foo.bar { - color: white; -} - -.foo .foo:hover { - color: white; -} - -.fo--oo > h1,.fo--oo > h2,.fo--oo > h3 { - margin: auto; -} - -h4:hover .ba--z,h5:hover .ba--z,h6:hover .ba--z { - display: block; -} - -/* comment */ - -article :--heading + p { - margin-top: 0; -} - -.foo,.bar > .baz { - display: block; -} - -/* should works with collapsed custom selectors */ - -button:hover,button:focus,.button:hover,.button:focus {} - -.foo h1,.bar h1 { - margin-top: 16px; -} - -main .foo + p { - margin-top: 16px; -} - -.foo { - order: 1000; -} -a,.foo { - order: 1001; -} -b,.foo { - order: 1002; -} - -.foo.baz { - order: 1010; -} -a,.foo.baz { - order: 1011; -} -b,.foo.baz { - order: 1012; -} - -.foo .baz { - order: 1020; -} -a,.foo .baz { - order: 1021; -} -b,.foo .baz { - order: 1022; -} diff --git a/plugins/postcss-custom-selectors/test/basic.preserve.expect.css b/plugins/postcss-custom-selectors/test/basic.preserve.expect.css index e5a03c4b0..953cb9de2 100644 --- a/plugins/postcss-custom-selectors/test/basic.preserve.expect.css +++ b/plugins/postcss-custom-selectors/test/basic.preserve.expect.css @@ -1,6 +1,6 @@ @custom-selector :--foo .bar, .baz; -.foo.foo { +.foo:is(.foo) { margin-top: 16px; } @@ -10,7 +10,7 @@ @custom-selector :--any-heading h1, h2, h3, h4, h5, h6; -h1 + p,h2 + p,h3 + p,h4 + p,h5 + p,h6 + p {} +:is(h1, h2, h3, h4, h5, h6) + p {} :--any-heading + p {} @@ -24,12 +24,20 @@ h1 + p,h2 + p,h3 + p,h4 + p,h5 + p,h6 + p {} .btn-warning, .btn-danger; -.foo > .baz {} +:is(.foo) > :is(.baz) {} :--foobar > :--baz {} -.fizz > .foo,.buzz > .foo {} +:is(.fizz, .buzz) > :is(.foo) {} :--fizzbuzz > :--foobar {} -.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active {} +:is(.btn-primary, + .btn-success, + .btn-info, + .btn-warning, + .btn-danger),:is(.btn-primary, + .btn-success, + .btn-info, + .btn-warning, + .btn-danger):active {} :--button-types, :--button-types:active {} @custom-selector :--commented-foo @@ -37,7 +45,8 @@ h1 + p,h2 + p,h3 + p,h4 + p,h5 + p,h6 + p {} .foo, .bar > .baz; -.foo + p,.bar > .baz + p { +:is(.foo, + .bar > .baz) + p { display: block; } @@ -47,7 +56,7 @@ h1 + p,h2 + p,h3 + p,h4 + p,h5 + p,h6 + p {} @custom-selector :--pseudo ::before, ::after; -.foo > a::before img,.foo > a::after img { +.foo > a:is(::before, ::after) img { display: block; } @@ -57,7 +66,7 @@ h1 + p,h2 + p,h3 + p,h4 + p,h5 + p,h6 + p {} @custom-selector :--foo .foo; -.foo,.foo.bar { +:is(.foo),:is(.foo).bar { color: white; } @@ -65,7 +74,7 @@ h1 + p,h2 + p,h3 + p,h4 + p,h5 + p,h6 + p {} color: white; } -.foo .foo:hover { +:is(.foo) :is(.foo):hover { color: white; } @@ -76,7 +85,7 @@ h1 + p,h2 + p,h3 + p,h4 + p,h5 + p,h6 + p {} @custom-selector :--fo-----o h1, h2, h3; @custom-selector :--ba-----r h4, h5, h6; -.fo--oo > h1,.fo--oo > h2,.fo--oo > h3 { +.fo--oo > :is(h1, h2, h3) { margin: auto; } @@ -84,7 +93,7 @@ h1 + p,h2 + p,h3 + p,h4 + p,h5 + p,h6 + p {} margin: auto; } -h4:hover .ba--z,h5:hover .ba--z,h6:hover .ba--z { +:is(h4, h5, h6):hover .ba--z { display: block; } @@ -102,7 +111,8 @@ article :--heading + p { .foo, .bar > .baz; -.foo,.bar > .baz { +:is(.foo, + .bar > .baz) { display: block; } @@ -115,13 +125,13 @@ article :--heading + p { @custom-selector :--button button, .button; @custom-selector :--enter :hover, :focus; -button:hover,button:focus,.button:hover,.button:focus {} +:is(button, .button):is(:hover, :focus) {} :--button:--enter {} @custom-selector :--any-foobar .foo, .bar; -.foo h1,.bar h1 { +:is(.foo, .bar) h1 { margin-top: 16px; } @@ -129,7 +139,7 @@ button:hover,button:focus,.button:hover,.button:focus {} margin-top: 16px; } -main .foo + p { +main :is(.foo) + p { margin-top: 16px; } @@ -139,20 +149,20 @@ main :--foo + p { @custom-selector :--foobar .foo; -.foo { +:is(.foo) { order: 1000; } :--foobar { order: 1000; } -a,.foo { +a,:is(.foo) { order: 1001; } a, :--foobar { order: 1001; } -b,.foo { +b,:is(.foo) { order: 1002; } b,:--foobar { @@ -161,20 +171,20 @@ b,:--foobar { @custom-selector :--foobaz .foo.baz; -.foo.baz { +:is(.foo.baz) { order: 1010; } :--foobaz { order: 1010; } -a,.foo.baz { +a,:is(.foo.baz) { order: 1011; } a, :--foobaz { order: 1011; } -b,.foo.baz { +b,:is(.foo.baz) { order: 1012; } b,:--foobaz { @@ -183,20 +193,20 @@ b,:--foobaz { @custom-selector :--foobazz .foo .baz; -.foo .baz { +:is(.foo .baz) { order: 1020; } :--foobazz { order: 1020; } -a,.foo .baz { +a,:is(.foo .baz) { order: 1021; } a, :--foobazz { order: 1021; } -b,.foo .baz { +b,:is(.foo .baz) { order: 1022; } b,:--foobazz { diff --git a/plugins/postcss-custom-selectors/test/complex.expect.css b/plugins/postcss-custom-selectors/test/complex.expect.css index 971fe5f2e..d5fa08a9e 100644 --- a/plugins/postcss-custom-selectors/test/complex.expect.css +++ b/plugins/postcss-custom-selectors/test/complex.expect.css @@ -1,11 +1,11 @@ -.xl3 { +:is(.xl3) { order: 1; } -.singer { +:is(.singer) { order: 2; } -.dash { +:is(.dash) { order: 3; } diff --git a/plugins/postcss-custom-selectors/test/conditionals.css b/plugins/postcss-custom-selectors/test/conditionals.css new file mode 100644 index 000000000..078d4e661 --- /dev/null +++ b/plugins/postcss-custom-selectors/test/conditionals.css @@ -0,0 +1,57 @@ +@custom-selector :--a .a; + +@media screen { + @custom-selector :--a .a.media; +} + +:--a { + order: 1; +} + +@custom-selector :--b .b; + +@supports (display: grid) { + @custom-selector :--b .b.supports; +} + +:--b { + order: 2; +} + +@custom-selector :--c .c; + +@container (min-width: 500px) { + @custom-selector :--c .c.container; +} + +@media screen { + @container (min-width: 500px) { + @custom-selector : --c .c.container.screen; + } +} + +:--c { + order: 3; +} + +@custom-selector :--d .d; + +@scope (.foo) to (.bar) { + @custom-selector :--d .d.scope; +} + +@media screen { + @scope (.foo) to (.bar) { + @custom-selector : --d .d.scope.screen; + } +} + +@scope (.foo) to (.bar) { + @media screen { + @custom-selector : --d .d.screen.scope; + } +} + +:--d { + order: 4; +} diff --git a/plugins/postcss-custom-selectors/test/conditionals.expect.css b/plugins/postcss-custom-selectors/test/conditionals.expect.css new file mode 100644 index 000000000..70550d282 --- /dev/null +++ b/plugins/postcss-custom-selectors/test/conditionals.expect.css @@ -0,0 +1,41 @@ +@media screen { + @custom-selector :--a .a.media; +} + +:is(.a) { + order: 1; +} + +@supports (display: grid) { + @custom-selector :--b .b.supports; +} + +:is(.b) { + order: 2; +} + +@media screen { + @container (min-width: 500px) { + @custom-selector : --c .c.container.screen; + } +} + +:is(.c.container) { + order: 3; +} + +@media screen { + @scope (.foo) to (.bar) { + @custom-selector : --d .d.scope.screen; + } +} + +@scope (.foo) to (.bar) { + @media screen { + @custom-selector : --d .d.screen.scope; + } +} + +:is(.d.scope) { + order: 4; +} diff --git a/plugins/postcss-custom-selectors/test/empty.css b/plugins/postcss-custom-selectors/test/empty.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/plugins/postcss-custom-selectors/test/examples/example.expect.css b/plugins/postcss-custom-selectors/test/examples/example.expect.css index 5cdcf01f4..857c8ee51 100644 --- a/plugins/postcss-custom-selectors/test/examples/example.expect.css +++ b/plugins/postcss-custom-selectors/test/examples/example.expect.css @@ -1,3 +1,3 @@ -article h1 + p,article h2 + p,article h3 + p { +article :is(h1, h2, h3) + p { margin-top: 0; } diff --git a/plugins/postcss-custom-selectors/test/examples/example.preserve.expect.css b/plugins/postcss-custom-selectors/test/examples/example.preserve.expect.css index 00738e691..e1e64c88d 100644 --- a/plugins/postcss-custom-selectors/test/examples/example.preserve.expect.css +++ b/plugins/postcss-custom-selectors/test/examples/example.preserve.expect.css @@ -1,6 +1,6 @@ @custom-selector :--heading h1, h2, h3; -article h1 + p,article h2 + p,article h3 + p { +article :is(h1, h2, h3) + p { margin-top: 0; } diff --git a/plugins/postcss-custom-selectors/test/export-selectors.css b/plugins/postcss-custom-selectors/test/export-selectors.css deleted file mode 100644 index b129f1329..000000000 --- a/plugins/postcss-custom-selectors/test/export-selectors.css +++ /dev/null @@ -1,22 +0,0 @@ -@custom-selector :--foo .foo; -@custom-selector :--any-heading h1, h2, h3, h4, h5, h6; -@custom-selector :--foobar .foo; -@custom-selector :--baz .baz; -@custom-selector :--fizzbuzz .fizz, .buzz; -@custom-selector :--button-types .btn-primary, - .btn-success, - .btn-info, - .btn-warning, - .btn-danger; -@custom-selector :--commented-foo .foo, - .bar > .baz; -@custom-selector :--pseudo ::before, ::after; -@custom-selector :--fo-----o h1, h2, h3; -@custom-selector :--ba-----r h4, h5, h6; -@custom-selector :--multiline .foo, - .bar > .baz; -@custom-selector :--button button, .button; -@custom-selector :--enter :hover, :focus; -@custom-selector :--any-foobar .foo, .bar; -@custom-selector :--foobaz .foo.baz; -@custom-selector :--foobazz .foo .baz; diff --git a/plugins/postcss-custom-selectors/test/export-selectors.js b/plugins/postcss-custom-selectors/test/export-selectors.js deleted file mode 100644 index 060a3658a..000000000 --- a/plugins/postcss-custom-selectors/test/export-selectors.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - customSelectors: { - ':--foo': '.foo', - ':--any-heading': 'h1, h2, h3, h4, h5, h6', - ':--foobar': '.foo', - ':--baz': '.baz', - ':--fizzbuzz': '.fizz, .buzz', - ':--button-types': '.btn-primary,\n .btn-success,\n .btn-info,\n .btn-warning,\n .btn-danger', - ':--commented-foo': '.foo,\n .bar > .baz', - ':--pseudo': '::before, ::after', - ':--fo-----o': 'h1, h2, h3', - ':--ba-----r': 'h4, h5, h6', - ':--multiline': '.foo,\n .bar > .baz', - ':--button': 'button, .button', - ':--enter': ':hover, :focus', - ':--any-foobar': '.foo, .bar', - ':--foobaz': '.foo.baz', - ':--foobazz': '.foo .baz' - } -}; diff --git a/plugins/postcss-custom-selectors/test/export-selectors.json b/plugins/postcss-custom-selectors/test/export-selectors.json deleted file mode 100644 index c7967c5e9..000000000 --- a/plugins/postcss-custom-selectors/test/export-selectors.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "custom-selectors": { - ":--foo": ".foo", - ":--any-heading": "h1, h2, h3, h4, h5, h6", - ":--foobar": ".foo", - ":--baz": ".baz", - ":--fizzbuzz": ".fizz, .buzz", - ":--button-types": ".btn-primary,\n\t.btn-success,\n\t.btn-info,\n\t.btn-warning,\n\t.btn-danger", - ":--commented-foo": ".foo,\n\t.bar > .baz", - ":--pseudo": "::before, ::after", - ":--fo-----o": "h1, h2, h3", - ":--ba-----r": "h4, h5, h6", - ":--multiline": ".foo,\n\t.bar > .baz", - ":--button": "button, .button", - ":--enter": ":hover, :focus", - ":--any-foobar": ".foo, .bar", - ":--foobaz": ".foo.baz", - ":--foobazz": ".foo .baz" - } -} diff --git a/plugins/postcss-custom-selectors/test/export-selectors.mjs b/plugins/postcss-custom-selectors/test/export-selectors.mjs deleted file mode 100644 index a73ac9bc5..000000000 --- a/plugins/postcss-custom-selectors/test/export-selectors.mjs +++ /dev/null @@ -1,18 +0,0 @@ -export const customSelectors = { - ':--foo': '.foo', - ':--any-heading': 'h1, h2, h3, h4, h5, h6', - ':--foobar': '.foo', - ':--baz': '.baz', - ':--fizzbuzz': '.fizz, .buzz', - ':--button-types': '.btn-primary,\n .btn-success,\n .btn-info,\n .btn-warning,\n .btn-danger', - ':--commented-foo': '.foo,\n .bar > .baz', - ':--pseudo': '::before, ::after', - ':--fo-----o': 'h1, h2, h3', - ':--ba-----r': 'h4, h5, h6', - ':--multiline': '.foo,\n .bar > .baz', - ':--button': 'button, .button', - ':--enter': ':hover, :focus', - ':--any-foobar': '.foo, .bar', - ':--foobaz': '.foo.baz', - ':--foobazz': '.foo .baz' -}; diff --git a/plugins/postcss-custom-selectors/test/import-selectors.css b/plugins/postcss-custom-selectors/test/import-selectors.css deleted file mode 100644 index 6926002c1..000000000 --- a/plugins/postcss-custom-selectors/test/import-selectors.css +++ /dev/null @@ -1 +0,0 @@ -@custom-selector :--heading h1, h2, h3; diff --git a/plugins/postcss-custom-selectors/test/import-selectors.js b/plugins/postcss-custom-selectors/test/import-selectors.js deleted file mode 100644 index d64592668..000000000 --- a/plugins/postcss-custom-selectors/test/import-selectors.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - customSelectors: { - ':--heading': 'h1, h2, h3', - }, -}; diff --git a/plugins/postcss-custom-selectors/test/import-selectors.json b/plugins/postcss-custom-selectors/test/import-selectors.json deleted file mode 100644 index 1416489f7..000000000 --- a/plugins/postcss-custom-selectors/test/import-selectors.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "custom-selectors": { - ":--heading": "h1, h2, h3" - } -} diff --git a/plugins/postcss-custom-selectors/test/safety.expect.css b/plugins/postcss-custom-selectors/test/safety.expect.css index a79db5165..f90988ab9 100644 --- a/plugins/postcss-custom-selectors/test/safety.expect.css +++ b/plugins/postcss-custom-selectors/test/safety.expect.css @@ -1,11 +1,11 @@ -h1.class, h1#id, h1::before, h1* { +.class:is(h1), #id:is(h1), ::before:is(h1), *:is(h1) { order: 1; } -h1.foo.class, h1.foo#id, h1.foo::before { +.foo.class:is(h1), .foo#id:is(h1), .foo::before:is(h1) { order: 2; } -h1.foo.class, h1.foo#id, h1.foo::before { +.foo.class:is(h1), .foo#id:is(h1), .foo::before:is(h1) { order: 3; } diff --git a/plugins/postcss-custom-selectors/tsconfig.json b/plugins/postcss-custom-selectors/tsconfig.json new file mode 100644 index 000000000..2e428a8c2 --- /dev/null +++ b/plugins/postcss-custom-selectors/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "declarationDir": ".", + "module": "es2020" + }, + "include": ["./src/**/*"], + "exclude": ["dist"], +}