diff --git a/.bin/test-tape.js b/.bin/test-tape.js index 43d99fa..8e72830 100644 --- a/.bin/test-tape.js +++ b/.bin/test-tape.js @@ -21,10 +21,8 @@ export default async function tape() { failures += await test('ignores invalid entries', { basename: 'ignore' }) failures += await test('supports complex entries', { basename: 'complex' }) failures += await test('supports all spec examples', { basename: 'spec-examples' }) - failures += await test('supports spec compliant mixing of nested rules and declarations', { basename: 'mixing-nested-rules-and-declarations-spec' }) - failures += await test('supports legacy mixing of nested rules and declarations', { basename: 'mixing-nested-rules-and-declarations-legacy', pluginOptions: { allowDeclarationsAfterNestedRules: true } }) - let mixinPlugin = () => { + let mixinPluginRule = () => { return { postcssPlugin: 'mixin', AtRule: { @@ -34,20 +32,35 @@ export default async function tape() { }, } } - mixinPlugin.postcss = true - failures += await test('supports other visitors', { basename: 'mixin' }, mixinPlugin) + + mixinPluginRule.postcss = true + failures += await test('supports other visitors (mixin rule)', { basename: 'mixin-rule' }, mixinPluginRule) + + let mixinPluginDeclaration = () => { + return { + postcssPlugin: 'mixin', + AtRule: { + mixin(node) { + node.replaceWith('color: blue;') + }, + }, + } + } + + mixinPluginDeclaration.postcss = true + failures += await test('supports other visitors (mixin declaration)', { basename: 'mixin-declaration' }, mixinPluginDeclaration) return failures === 0 } async function test(name, init, ...plugins) { - const { basename, pluginOptions } = Object(init) + const { basename } = Object(init) let sourceUrl = new URL(`test/${basename}.css`, workingUrl) let expectUrl = new URL(`test/${basename}.expect.css`, workingUrl) let resultUrl = new URL(`test/${basename}.result.css`, workingUrl) - plugins.unshift(plugin(pluginOptions)) + plugins.unshift(plugin()) let sourceCss = await fs.readFile(sourceUrl, 'utf8') let expectCss = await fs.readFile(expectUrl, 'utf8') diff --git a/README.md b/README.md index f90c941..039a14e 100644 --- a/README.md +++ b/README.md @@ -71,65 +71,6 @@ import postcssNesting from "https://deno.land/x/postcss_nesting/mod.js"; await postcss([postcssNesting]).process(YOUR_CSS /*, processOptions */); ``` -## Options - -### allowDeclarationsAfterNestedRules - -The [specification](https://www.w3.org/TR/css-nesting-1/#mixing) does not allow declarations after nested rules. -This was previously supported by this plugin and can be re-enabled with `allowDeclarationsAfterNestedRules`. - -Before : - -```css -a { - color: red; - - & b { - color: white; - } - - padding: 20px; -} -``` - -After **without** the option : - -```js -postcssNesting() -``` - -```css -a { - color: red; -} - -a b { - color: white; -} -``` - -After **with** the option : - -```js -postcssNesting({ - allowDeclarationsAfterNestedRules: true -}) -``` - -```css -a { - color: red; -} - -a b { - color: white; -} - -a { - padding: 20px; -} -``` - [cli-img]: https://img.shields.io/travis/csstools/postcss-nesting.svg [cli-url]: https://travis-ci.org/csstools/postcss-nesting [css-img]: https://cssdb.org/badge/nesting-rules.svg diff --git a/src/index.js b/src/index.js index e7c6a73..f984cac 100644 --- a/src/index.js +++ b/src/index.js @@ -1,19 +1,12 @@ -import ensureCorrectMixingOfNestingRulesAndDeclarations from './lib/mixing-nesting-rules-and-declarations.js' import walk from './lib/walk.js' /** - * @param {{allowDeclarationsAfterNestedRules?: boolean}} opts * @returns {import('postcss').Plugin} */ -export default function postcssNesting(opts) { - const allowDeclarationsAfterNestedRules = Object(opts).allowDeclarationsAfterNestedRules || false - +export default function postcssNesting() { return { postcssPlugin: 'postcss-nesting', Rule(rule) { - if (!allowDeclarationsAfterNestedRules) { - ensureCorrectMixingOfNestingRulesAndDeclarations(rule) - } walk(rule) }, } diff --git a/src/lib/mixing-nesting-rules-and-declarations.js b/src/lib/mixing-nesting-rules-and-declarations.js deleted file mode 100644 index ba8c7f9..0000000 --- a/src/lib/mixing-nesting-rules-and-declarations.js +++ /dev/null @@ -1,41 +0,0 @@ -// see : https://www.w3.org/TR/css-nesting-1/#mixing -export default function ensureCorrectMixingOfNestingRulesAndDeclarations(node) { - const hasNestedChildren = node.some((child) => { - return child.type === 'atrule' || child.type === 'rule' - }) - - if (!hasNestedChildren) { - return - } - - // Clone with only declarations - const clone = node.cloneBefore() - - let encounteredNestedRule = false - clone.each((child) => { - if (child.type === 'atrule' || child.type === 'rule') { - encounteredNestedRule = true - child.remove() - return - } - - if (encounteredNestedRule) { - // declarations after nesting rules are not allowed - child.remove() - return - } - }) - - if (clone.nodes.length === 0) { - clone.remove() - } - - // Remove all declarations and preserve nesting rules - node.each((child) => { - if (child.type === 'atrule' || child.type === 'rule') { - return - } - - child.remove() - }) -} diff --git a/test/basic.expect.css b/test/basic.expect.css index 0536704..b3e0eb0 100644 --- a/test/basic.expect.css +++ b/test/basic.expect.css @@ -24,6 +24,12 @@ a { } } +a { + + order: 5; + order: 6 +} + a b { order: 7; } @@ -37,6 +43,11 @@ a b { order: 9; } +a { + + order: 10 +} + body a { order: 11 } @@ -50,6 +61,11 @@ body a { order: 13 } +a { + + order: 14 +} + @media screen { a { diff --git a/test/direct.expect.css b/test/direct.expect.css index 56919d6..7af20b4 100644 --- a/test/direct.expect.css +++ b/test/direct.expect.css @@ -10,6 +10,9 @@ a, b { :is(a,b) c, :is(a,b) d { order: 4; } +a, b { + order: 5; +} a, b { order: 1; } @@ -22,3 +25,6 @@ a, b { :is(a,b) c, :is(a,b) d { order: 4; } +a, b { + order: 5; +} diff --git a/test/empty.expect.css b/test/empty.expect.css index 86e0b96..a23b4e2 100644 --- a/test/empty.expect.css +++ b/test/empty.expect.css @@ -11,6 +11,9 @@ d e { f g { order: 4; } +f { + order: 5; +} a b c { order: 1 } @@ -23,3 +26,6 @@ d e { f g { order: 4; } +f { + order: 5; +} diff --git a/test/ignore.expect.css b/test/ignore.expect.css index 2738441..13bdd8e 100644 --- a/test/ignore.expect.css +++ b/test/ignore.expect.css @@ -1,7 +1,5 @@ a, b { - order: 1 -} -a, b { + order: 1; c, d { order: 2; } @@ -13,9 +11,7 @@ f:is(g) { order: 5; } a, b { - order: 1 -} -a, b { + order: 1; @nest c, d { order: 2; } diff --git a/test/mixin-declaration.css b/test/mixin-declaration.css new file mode 100644 index 0000000..597a5ea --- /dev/null +++ b/test/mixin-declaration.css @@ -0,0 +1,13 @@ +/* prevent regressions : https://github.com/csstools/postcss-nesting/issues/95 */ +body { + @mixin; + + background: red; + font-size: 1rem; + + @media (min-width: 64em) { + background: green; + } + + margin: 0; +} diff --git a/test/mixin-declaration.expect.css b/test/mixin-declaration.expect.css new file mode 100644 index 0000000..01a3db4 --- /dev/null +++ b/test/mixin-declaration.expect.css @@ -0,0 +1,15 @@ +/* prevent regressions : https://github.com/csstools/postcss-nesting/issues/95 */ +body {color: blue; + + background: red; + font-size: 1rem; +} +@media (min-width: 64em) { +body { + background: green; +} + } +body { + + margin: 0; +} diff --git a/test/mixin.css b/test/mixin-rule.css similarity index 100% rename from test/mixin.css rename to test/mixin-rule.css diff --git a/test/mixin.expect.css b/test/mixin-rule.expect.css similarity index 100% rename from test/mixin.expect.css rename to test/mixin-rule.expect.css diff --git a/test/mixing-nested-rules-and-declarations-legacy.css b/test/mixing-nested-rules-and-declarations-legacy.css deleted file mode 100644 index 6b88ed4..0000000 --- a/test/mixing-nested-rules-and-declarations-legacy.css +++ /dev/null @@ -1,19 +0,0 @@ -a { - order: 1; - - & b { - order: 2; - } - - order: 3; -} - -a { - order: 4; - - @nest b & { - order: 5; - } - - order: 6; -} diff --git a/test/mixing-nested-rules-and-declarations-legacy.expect.css b/test/mixing-nested-rules-and-declarations-legacy.expect.css deleted file mode 100644 index 00cba8f..0000000 --- a/test/mixing-nested-rules-and-declarations-legacy.expect.css +++ /dev/null @@ -1,25 +0,0 @@ -a { - order: 1; -} - -a b { - order: 2; - } - -a { - - order: 3; -} - -a { - order: 4; -} - -b a { - order: 5; -} - -a { - - order: 6; -} diff --git a/test/mixing-nested-rules-and-declarations-spec.css b/test/mixing-nested-rules-and-declarations-spec.css deleted file mode 100644 index 6b88ed4..0000000 --- a/test/mixing-nested-rules-and-declarations-spec.css +++ /dev/null @@ -1,19 +0,0 @@ -a { - order: 1; - - & b { - order: 2; - } - - order: 3; -} - -a { - order: 4; - - @nest b & { - order: 5; - } - - order: 6; -} diff --git a/test/mixing-nested-rules-and-declarations-spec.expect.css b/test/mixing-nested-rules-and-declarations-spec.expect.css deleted file mode 100644 index d96af15..0000000 --- a/test/mixing-nested-rules-and-declarations-spec.expect.css +++ /dev/null @@ -1,15 +0,0 @@ -a { - order: 1; -} - -a b { - order: 2; - } - -a { - order: 4; -} - -b a { - order: 5; -} diff --git a/test/spec-examples.css b/test/spec-examples.css index 15dc8ba..05bf802 100644 --- a/test/spec-examples.css +++ b/test/spec-examples.css @@ -377,6 +377,10 @@ article { color: blue; } + /* + NOTE : We are more forgiving than the spec + This declaration is preserved + */ color: red; } @@ -387,6 +391,10 @@ article { color: blue; } + /* + NOTE : We are more forgiving than the spec + This declaration is preserved + */ color: red; &.foo { diff --git a/test/spec-examples.expect.css b/test/spec-examples.expect.css index 8f26d2c..7a888ab 100644 --- a/test/spec-examples.expect.css +++ b/test/spec-examples.expect.css @@ -158,9 +158,7 @@ figure>figcaption>p { /* No & at all */ .foo { - color: blue -} -.foo { + color: blue; .bar { color: red; @@ -169,9 +167,7 @@ figure>figcaption>p { /* & isn’t the first simple selector */ .foo { - color: blue -} -.foo { + color: blue; .bar& { color: red; @@ -181,10 +177,7 @@ figure>figcaption>p { /* & isn’t the first selector of every one in the list */ .foo, .bar { - color: blue -} -.foo, -.bar { + color: blue; &+.baz, .qux { @@ -232,10 +225,7 @@ figure>figcaption>p { */ .foo { - color: red -} - -.foo { + color: red; @nest .bar { color: blue; @@ -245,10 +235,7 @@ figure>figcaption>p { /* Invalid because there’s no nesting selector */ .foo { - color: red -} - -.foo { + color: red; @nest & .bar, .baz { @@ -357,10 +344,7 @@ figure>figcaption>p { contain a nesting selector */ .foo { - color: red -} - -.foo { + color: red; @nest @media (min-width: 480px) { & { @@ -378,6 +362,12 @@ article { } article { color: blue; + + /* + NOTE : We are more forgiving than the spec + This declaration is preserved + */ + color: red; } article { @@ -386,8 +376,19 @@ article { article { color: blue; + + /* + NOTE : We are more forgiving than the spec + This declaration is preserved + */ + color: red; } article.foo { color: yellow; } + +article { + + /* valid! */ + }