├── .editorconfig ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── index.js ├── index.test.js ├── package-lock.json ├── package.json └── src └── index.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | yarn-error.log 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .npmignore 2 | .gitignore 3 | .editorconfig 4 | 5 | node_modules/ 6 | npm-debug.log 7 | yarn.lock 8 | 9 | *.test.js 10 | .travis.yml 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: yarn 3 | node_js: 4 | - node 5 | - "10" 6 | - "8" 7 | - "6" 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | This project adheres to [Semantic Versioning](http://semver.org/). 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2019 ymrdf <837856276@qq.com> 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PostCSS Plugin Namespace [![Build Status][ci-img]][ci][![npm](https://img.shields.io/npm/v/postcss-plugin-namespace.svg)](https://www.npmjs.com/package/postcss-plugin-namespace)[![npm](https://img.shields.io/npm/dm/postcss-plugin-namespace.svg)](https://www.npmjs.com/package/postcss-plugin-namespace) 2 | 3 | [PostCSS] A PostCSS plugin that could add css selector before all selectors,so that the styles will not affect other projects. 4 | 5 | [PostCSS]: https://github.com/postcss/postcss 6 | [ci-img]: https://travis-ci.org/ymrdf/postcss-plugin-namespace.svg 7 | [ci]: https://travis-ci.org/ymrdf/postcss-plugin-namespace 8 | 9 | ## Usage 10 | passed a css selector as the first argument; 11 | 12 | ```js 13 | postcss([ require('postcss-plugin-namespace')('.insert-selector') ]) 14 | ``` 15 | 16 | ### input 17 | ```css 18 | .foo { 19 | /* Input example */ 20 | } 21 | ``` 22 | ### output 23 | ```css 24 | .insert-selector .foo { 25 | /* Output example */ 26 | } 27 | ``` 28 | 29 | ### Options 30 | 31 | Pass an options object as the second argument. 32 | 33 | #### options.ignore 34 | 35 | Don't prefix specific classes or classes that match a regex. 36 | 37 | ```js 38 | var css = postcss([namespace('.test', { ignore: [ /body/, ".icon" ] })]) 39 | .process(inputCSS) 40 | .then(results => {results.toString()}); 41 | ``` 42 | 43 | See [PostCSS] docs for examples for your environment. 44 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var postcss = require('postcss') 2 | var plugin = require('./src/index.js') 3 | 4 | module.exports = postcss.plugin('postcss-plugin-namespace', plugin) 5 | -------------------------------------------------------------------------------- /index.test.js: -------------------------------------------------------------------------------- 1 | var postcss = require('postcss') 2 | 3 | var plugin = require('./') 4 | 5 | function run (input, output, selector, opts) { 6 | return postcss([plugin(selector, opts)]) 7 | .process(input) 8 | .then(function (result) { 9 | expect(result.css).toEqual(output) 10 | expect(result.warnings()).toHaveLength(0) 11 | }) 12 | } 13 | 14 | it('add selector correctly', function () { 15 | return run('a{ }', '.test a{ }', '.test') 16 | }) 17 | 18 | describe('do not add anything when the arguments were wrong', function () { 19 | it('do not have arguments ', function () { 20 | return run('a{ }', 'a{ }') 21 | }) 22 | 23 | it('selector type is error', function () { 24 | return run('a{ }', 'a{ }', {}, {}) 25 | }) 26 | 27 | it('opts type is error', function () { 28 | return run('a{ }', '.ss a{ }', '.ss', 'string') 29 | }) 30 | }) 31 | 32 | describe('ignore option will work correctly', function () { 33 | it('single ignore', function () { 34 | return run('a{ }', 'a{ }', '.test', { ignore: /a/ }) 35 | }) 36 | 37 | it('multiple ignore', function () { 38 | return run('a{ } body{ }', 'a{ } body{ }', '.test', { 39 | ignore: [/a/, /body/] 40 | }) 41 | }) 42 | 43 | it('string type ignore', function () { 44 | return run('a{ } body{ }', '.test a{ } body{ }', '.test', { 45 | ignore: 'body' 46 | }) 47 | }) 48 | }) 49 | 50 | describe('work correctly when there has a "@" ', function () { 51 | it('it should be correct when add selector inside @media', 52 | function () { 53 | return run( 54 | '@media (min-width: 900px) {div { display: flex; } }', 55 | '@media (min-width: 900px) {.test div { display: flex; } }', 56 | '.test' 57 | ) 58 | }) 59 | it('it should be correct when add selector inside @suport', 60 | function () { 61 | return run( 62 | '@supports (display: flex) { div { display: flex; }}', 63 | '@supports (display: flex) { .test div { display: flex; }}', 64 | '.test' 65 | ) 66 | }) 67 | it('do not add selector which rule is inside @keyframes', 68 | function () { 69 | return run( 70 | '@keyframes slidein { from { width: 300%; } to { width: 100%; } }', 71 | '@keyframes slidein { from { width: 300%; } to { width: 100%; } }', 72 | '.test' 73 | ) 74 | }) 75 | it('do not add selector which rule is inside @-webkit-keyframes', 76 | function () { 77 | return run( 78 | '@-webkit-keyframes in { from { width: 300%; } to { width: 100%; } }', 79 | '@-webkit-keyframes in { from { width: 300%; } to { width: 100%; } }', 80 | '.test' 81 | ) 82 | }) 83 | }) 84 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-plugin-namespace", 3 | "version": "0.0.3", 4 | "description": "A PostCSS plugin that could add css selector before all selectors,so that the styles will not affect other projects.", 5 | "keywords": [ 6 | "postcss", 7 | "css", 8 | "postcss-plugin", 9 | "namespace", 10 | "selectors" 11 | ], 12 | "main": "index.js", 13 | "scripts": { 14 | "test": "jest && eslint *.js" 15 | }, 16 | "author": "ymrdf <837856276@qq.com>", 17 | "license": "MIT", 18 | "repository": "ymrdf/postcss-plugin-namespace", 19 | "bugs": { 20 | "url": "https://github.com/ymrdf/postcss-plugin-namespace/issues" 21 | }, 22 | "homepage": "https://github.com/ymrdf/postcss-plugin-namespace", 23 | "dependencies": { 24 | "postcss": "^7.0.6" 25 | }, 26 | "devDependencies": { 27 | "@logux/eslint-config": "^27.0.0", 28 | "eslint": "^5.10.0", 29 | "eslint-config-postcss": "^3.0.7", 30 | "eslint-config-standard": "^12.0.0", 31 | "eslint-plugin-es5": "^1.3.1", 32 | "eslint-plugin-import": "^2.14.0", 33 | "eslint-plugin-jest": "^22.1.2", 34 | "eslint-plugin-node": "^8.0.0", 35 | "eslint-plugin-promise": "^4.0.1", 36 | "eslint-plugin-security": "^1.4.0", 37 | "eslint-plugin-standard": "^4.0.0", 38 | "jest": "^23.6.0" 39 | }, 40 | "eslintConfig": { 41 | "extends": "eslint-config-postcss/es5" 42 | }, 43 | "jest": { 44 | "testEnvironment": "node", 45 | "transform": {} 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * main function 3 | * @param {string} prefix the css selector want to add 4 | * @param {object | null} options configs 5 | * @returns {function} return a function 6 | */ 7 | function plugin (prefix, options) { 8 | options = options || {} 9 | 10 | return function (root) { 11 | if (!prefix || typeof prefix !== 'string') { 12 | return 13 | } 14 | 15 | root.walkRules(function (rule) { 16 | if (!rule.selectors) { 17 | return rule 18 | } 19 | 20 | if (specailTest(rule)) { 21 | return rule 22 | } 23 | 24 | rule.selectors = rule.selectors.map(function (selector) { 25 | if ( 26 | classMatchesTest(selector, options.ignore) || 27 | selector.trim().length === 0 28 | ) { 29 | return selector 30 | } 31 | return prefix.trim() + ' ' + selector 32 | }) 33 | return rule 34 | }) 35 | } 36 | } 37 | 38 | /** 39 | * Determine if class passes test 40 | * 41 | * @param {string} clss selector 42 | * @param {string} test reg or string 43 | * @return {boolean} if class selector 44 | */ 45 | function classMatchesTest (clss, test) { 46 | if (!test) { 47 | return false 48 | } 49 | 50 | clss = clss.trim() 51 | 52 | if (test instanceof RegExp) { 53 | return test.exec(clss) 54 | } 55 | 56 | if (Array.isArray(test)) { 57 | var tests = test 58 | 59 | return tests.some(function (testItem) { 60 | if (testItem instanceof RegExp) { 61 | return testItem.exec(clss) 62 | } else { 63 | return clss === testItem 64 | } 65 | }) 66 | } 67 | 68 | return clss === test 69 | } 70 | 71 | /** 72 | * Determine if the selector couldn't be added namespace 73 | * 74 | * @param {object} rule css rule 75 | * @return {boolean} if the selector couldn't be added namespace 76 | */ 77 | function specailTest (rule) { 78 | if ( 79 | rule.parent && 80 | rule.parent.name && 81 | rule.parent.name.indexOf('keyframes') > -1 82 | ) { 83 | return true 84 | } 85 | return false 86 | } 87 | 88 | module.exports = plugin 89 | --------------------------------------------------------------------------------