diff --git a/__tests__/__snapshots__/index.test.js.md b/__tests__/__snapshots__/index.test.js.md index c5365df..38a94a4 100644 --- a/__tests__/__snapshots__/index.test.js.md +++ b/__tests__/__snapshots__/index.test.js.md @@ -161,6 +161,113 @@ Generated by [AVA](https://ava.li). `, ] +## deep-selectors + +> Snapshot 1 + + [ + `webpackJsonp([0],{␊ + ␊ + /***/ 18:␊ + /***/ (function(module, exports) {␊ + ␊ + module.exports = [{"type":"element","tag":"div","attrs":[{"type":"attribute","name":"class","value":"root"},{"type":"attribute","name":"data-r-2000be7d","value":""}],"children":[{"type":"text","text":"\\n deep selectors\\n"}]}]␊ + ␊ + /***/ }),␊ + ␊ + /***/ 19:␊ + /***/ (function(module, exports, __webpack_require__) {␊ + ␊ + "use strict";␊ + // ␊ + //␊ + // ␊ + //␊ + // ␊ + ␊ + ␊ + /***/ }),␊ + ␊ + /***/ 20:␊ + /***/ (function(module, exports) {␊ + ␊ + // removed by extract-text-webpack-plugin␊ + ␊ + /***/ }),␊ + ␊ + /***/ 22:␊ + /***/ (function(module, exports, __webpack_require__) {␊ + ␊ + var __regular_script__, __regular_template__;␊ + __webpack_require__(20)␊ + __regular_script__ = __webpack_require__(19)␊ + __regular_template__ = __webpack_require__(18)␊ + var Regular = __webpack_require__( 21 );␊ + ␊ + var __rs__ = __regular_script__ || {};␊ + if (__rs__.__esModule) __rs__ = __rs__["default"];␊ + if (Regular.__esModule) Regular = Regular["default"];␊ + ␊ + var __Component__, __cps__;␊ + if( typeof __rs__ === "object" ) {␊ + __rs__.template = __regular_template__;␊ + __Component__ = Regular.extend(__rs__);␊ + __cps__ = __rs__.components || __rs__.component;␊ + if( typeof __cps__ === "object" ) {␊ + for( var i in __cps__ ) {␊ + __Component__.component(i, __cps__[ i ]);␊ + }␊ + }␊ + } else if( typeof __rs__ === "function" && ( __rs__.prototype instanceof Regular ) ) {␊ + __rs__.prototype.template = __regular_template__;␊ + __Component__ = __rs__;␊ + }␊ + module.exports = __Component__;␊ + ␊ + /***/ })␊ + ␊ + },[22]);`, + `␊ + ␊ + ␊ + ␊ + ␊ + ␊ + ␊ + ␊ + ␊ + ␊ + .root[data-r-2000be7d] {␊ + color: red;␊ + }␊ + ␊ + .root .child[data-r-2000be7d] {␊ + color: yellow;␊ + }␊ + ␊ + .root[data-r-2000be7d] .child {␊ + color: blue;␊ + }␊ + `, + ] + ## multiple-css > Snapshot 1 diff --git a/__tests__/__snapshots__/index.test.js.snap b/__tests__/__snapshots__/index.test.js.snap index 6698bde..a812e2e 100644 Binary files a/__tests__/__snapshots__/index.test.js.snap and b/__tests__/__snapshots__/index.test.js.snap differ diff --git a/__tests__/fixtures/deep-selectors.rgl b/__tests__/fixtures/deep-selectors.rgl new file mode 100644 index 0000000..2032760 --- /dev/null +++ b/__tests__/fixtures/deep-selectors.rgl @@ -0,0 +1,22 @@ + + + + + diff --git a/__tests__/index.test.js b/__tests__/index.test.js index cd0b8d3..7f88fca 100644 --- a/__tests__/index.test.js +++ b/__tests__/index.test.js @@ -27,3 +27,7 @@ test.serial( 'preserve-whitespace', async t => { test.serial( 'scoped-css', async t => { t.snapshot( await bundle( 'scoped-css.rgl' ) ) } ) + +test.serial( 'deep-selectors', async t => { + t.snapshot( await bundle( 'deep-selectors.rgl' ) ) +} ) diff --git a/lib/postcss-plugins/add-scoped-id.js b/lib/postcss-plugins/add-scoped-id.js deleted file mode 100644 index 1bb0d7a..0000000 --- a/lib/postcss-plugins/add-scoped-id.js +++ /dev/null @@ -1,47 +0,0 @@ -const postcss = require( 'postcss' ) -const selectorParser = require( 'postcss-selector-parser' ) - -module.exports = postcss.plugin( 'add-id', function ( opts ) { - return function ( root ) { - root.each( function rewriteSelector( node ) { - if ( !node.selector ) { - // handle media queries - if ( node.type === 'atrule' && node.name === 'media' ) { - node.each( rewriteSelector ) - } - return - } - node.selector = selectorParser( function ( selectors ) { - selectors.each( function ( selector ) { - let firstNode = null - let node = null - - selector.each( function ( n, i ) { - if ( n.type !== 'pseudo' ) { - if ( i === 0 ) { - firstNode = n - } - node = n - } - } ) - - selector.insertAfter( - firstNode, - selectorParser.attribute( { - attribute: opts.id - } ) - ) - - if ( firstNode !== node ) { - selector.insertAfter( - node, - selectorParser.attribute( { - attribute: opts.id - } ) - ) - } - } ) - } ).process( node.selector ).result - } ) - } -} ) diff --git a/lib/postcss-plugins/scoped.js b/lib/postcss-plugins/scoped.js new file mode 100644 index 0000000..2f892d0 --- /dev/null +++ b/lib/postcss-plugins/scoped.js @@ -0,0 +1,95 @@ +const postcss = require( 'postcss' ) +const selectorParser = require( 'postcss-selector-parser' ) + +module.exports = postcss.plugin( 'add-id', options => root => { + const id = options.id + const keyframes = Object.create( null ) + + root.each( function rewriteSelector( node ) { + if ( !node.selector ) { + // handle media queries + if ( node.type === 'atrule' ) { + if ( node.name === 'media' || node.name === 'supports' ) { + node.each( rewriteSelector ) + } else if ( /-?keyframes$/.test( node.name ) ) { + // register keyframes + keyframes[ node.params ] = node.params = node.params + '-' + id + } + } + return + } + node.selector = selectorParser( selectors => { + selectors.each( selector => { + let node = null + + selector.each( n => { + // ">>>" combinator + if ( n.type === 'combinator' && n.value === '>>>' ) { + n.value = ' ' + n.spaces.before = n.spaces.after = '' + return false + } + // /deep/ alias for >>>, since >>> doesn't work in SASS + if ( n.type === 'tag' && n.value === '/deep/' ) { + const prev = n.prev() + if ( prev && prev.type === 'combinator' && prev.value === ' ' ) { + prev.remove() + } + n.remove() + return false + } + if ( n.type !== 'pseudo' && n.type !== 'combinator' ) { + node = n + } + } ) + + if ( node ) { + node.spaces.after = '' + } else { + // For deep selectors & standalone pseudo selectors, + // the attribute selectors are prepended rather than appended. + // So all leading spaces must be eliminated to avoid problems. + selector.first.spaces.before = '' + } + + selector.insertAfter( + node, + selectorParser.attribute( { + attribute: id + } ) + ) + } ) + } ).processSync( node.selector ) + } ) + + // If keyframes are found in this