diff --git a/README.md b/README.md index c35dfae..51494f8 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,13 @@ module: { postcssOptions: { plugins: { "postcss-prefix-selector": { - prefix: '.my-prefix' + prefix: '.my-prefix', + transform(prefix, selector, prefixedSelector) { + if (selector.match(/^(html|body)/)) { + return selector.replace(/^([^\s]*)/, `$1 ${prefix}`); + } + return prefixedSelector; + }, }, autoprefixer: { browsers: ['last 4 versions'] @@ -118,6 +124,7 @@ module: { - `exclude` - It's possible to avoid prefixing some selectors by passing an array of selectors (strings or regular expressions). - `transform` - In cases where you may want to use the prefix differently for different selectors, it is possible to pass in a custom transform method. - `ignoreFiles` - List of ignored files for processing. +- `includeFiles` - List of included files for processing. ## Maintainer diff --git a/index.js b/index.js index 30eded1..f994a88 100644 --- a/index.js +++ b/index.js @@ -2,14 +2,25 @@ module.exports = function postcssPrefixSelector(options) { const prefix = options.prefix; const prefixWithSpace = /\s+$/.test(prefix) ? prefix : `${prefix} `; const ignoreFiles = options.ignoreFiles ? [].concat(options.ignoreFiles) : []; + const includeFiles = options.includeFiles + ? [].concat(options.includeFiles) + : []; return function (root) { if ( + ignoreFiles.length && root.source.input.file && ignoreFiles.some((file) => root.source.input.file.includes(file)) ) { return; } + if ( + includeFiles.length && + root.source.input.file && + !includeFiles.find((file) => root.source.input.file.includes(file)) + ) { + return; + } root.walkRules((rule) => { const keyframeRules = [ diff --git a/test/fixtures/between-symbol-selector.css b/test/fixtures/between-symbol-selector.css new file mode 100644 index 0000000..12da16e --- /dev/null +++ b/test/fixtures/between-symbol-selector.css @@ -0,0 +1,7 @@ +.a { + color: coral; +} + +.b { + color: deepskyblue; +} diff --git a/test/fixtures/between-symbol-selector.expected.css b/test/fixtures/between-symbol-selector.expected.css new file mode 100644 index 0000000..85dba3c --- /dev/null +++ b/test/fixtures/between-symbol-selector.expected.css @@ -0,0 +1,7 @@ +.hello.a { + color: coral; +} + +.hello.b { + color: deepskyblue; +} diff --git a/test/fixtures/include-files.css b/test/fixtures/include-files.css new file mode 100644 index 0000000..12da16e --- /dev/null +++ b/test/fixtures/include-files.css @@ -0,0 +1,7 @@ +.a { + color: coral; +} + +.b { + color: deepskyblue; +} diff --git a/test/fixtures/include-files.expected.css b/test/fixtures/include-files.expected.css new file mode 100644 index 0000000..3b4570b --- /dev/null +++ b/test/fixtures/include-files.expected.css @@ -0,0 +1,7 @@ +.hello .a { + color: coral; +} + +.hello .b { + color: deepskyblue; +} diff --git a/test/fixtures/single-long-selector.css b/test/fixtures/single-long-selector.css new file mode 100644 index 0000000..12da16e --- /dev/null +++ b/test/fixtures/single-long-selector.css @@ -0,0 +1,7 @@ +.a { + color: coral; +} + +.b { + color: deepskyblue; +} diff --git a/test/fixtures/single-long-selector.expected.css b/test/fixtures/single-long-selector.expected.css new file mode 100644 index 0000000..5c03ae1 --- /dev/null +++ b/test/fixtures/single-long-selector.expected.css @@ -0,0 +1,7 @@ +.hello .world .a { + color: coral; +} + +.hello .world .b { + color: deepskyblue; +} diff --git a/test/test.js b/test/test.js index 0744d8a..8bc9ab5 100644 --- a/test/test.js +++ b/test/test.js @@ -115,6 +115,109 @@ it('should prefix selectors in unignored files', () => { assert.equal(out, expected); }); +it('should prefix selectors in included file', () => { + const out = postcss() + .use( + prefixer({ + prefix: '.hello ', + includeFiles: ['include-files.css'], + }) + ) + .process(getFixtureContents('include-files.css'), { + from: 'include-files.css', + }).css; + + const expected = getFixtureContents('include-files.expected.css'); + + assert.equal(out, expected); +}); + +it('should work as expected when included array is empty', () => { + const out = postcss() + .use( + prefixer({ + prefix: '.hello ', + includeFiles: [], + }) + ) + .process(getFixtureContents('include-files.css'), { + from: 'include-files.css', + }).css; + + const expected = getFixtureContents('include-files.expected.css'); + + assert.equal(out, expected); +}); + +it('should work as expected when included two items and mmore in array', () => { + const out = postcss() + .use( + prefixer({ + prefix: '.hello ', + includeFiles: [ + 'include-files.css', + 'single-selector.css', + 'undefined.css', + ], + }) + ) + .process(getFixtureContents('include-files.css'), { + from: 'include-files.css', + }).css; + + const expected = getFixtureContents('include-files.expected.css'); + + assert.equal(out, expected); +}); + +it('should not prefix selectors in unincluded files', () => { + const out = postcss() + .use( + prefixer({ + prefix: '.hello ', + includeFiles: ['include-files.css'], + }) + ) + .process(getFixtureContents('single-selector.css'), { + from: 'single-selector.css', + }).css; + + const expected = getFixtureContents('single-selector.css'); + + assert.equal(out, expected); +}); + +it('should use custom symbol between prefix and selector. Use empty to glue', () => { + const out = postcss() + .use( + prefixer({ + prefix: '.hello', + transform(prefix, selector) { + return prefix + selector; + }, + }) + ) + .process(getFixtureContents('between-symbol-selector.css')).css; + + const expected = getFixtureContents('between-symbol-selector.expected.css'); + + assert.equal(out, expected); +}); + +it('should prefix a selector. Use ".hello .world"', () => { + const out = postcss() + .use( + prefixer({ + prefix: '.hello .world', + }) + ) + .process(getFixtureContents('single-long-selector.css')).css; + + const expected = getFixtureContents('single-long-selector.expected.css'); + + assert.equal(out, expected); +}); + function getFixtureContents(name) { return fs.readFileSync(`test/fixtures/${name}`, 'utf8').trim(); }