Merge remote-tracking branch 'upstream/main'

This commit is contained in:
2026-08-26 09:31:34 +08:00
parent 9b8c4bfab6
commit 394eb0285d
34137 changed files with 3589424 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015-2017 Jonathan Ong me@jongleberry.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+207
View File
@@ -0,0 +1,207 @@
# postcss-prefix-selector
[![NPM version][npm-image]][npm-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![License][license-image]][license-url]
[![Downloads][downloads-image]][downloads-url]
[![Gitpod ready-to-code][gitpod-image]][gitpod-url]
> Prefix every CSS selector with a custom namespace `.a => .prefix .a`
## Table of Contents
- [Install](#install)
- [Usage with PostCSS](#usage-with-postcss)
- [Usage with Webpack](#usage-with-webpack)
- [Usage with Vite](#usage-with-vite)
- [Options](#options)
- [Maintainer](#maintainer)
- [Contribute](#contribute)
- [License](#license)
## Install
```console
$ npm install postcss-prefix-selector
```
## Usage with PostCSS
```js
const prefixer = require('postcss-prefix-selector')
// css to be processed
const css = fs.readFileSync("input.css", "utf8")
const out = postcss().use(prefixer({
prefix: '.some-selector',
exclude: ['.c'],
// Optional transform callback for case-by-case overrides
transform: function (prefix, selector, prefixedSelector, filePath, rule) {
if (selector === 'body') {
return 'body' + prefix;
} else {
return prefixedSelector;
}
}
})).process(css).css
```
Using the options above and the CSS below...
```css
body {
background: red;
}
.a, .b {
color: aqua;
}
.c {
color: coral;
}
```
You will get the following output
```css
body.some-selector {
background: red;
}
.some-selector .a, .some-selector .b {
color: aqua;
}
.c {
color: coral;
}
```
## Usage with webpack
Use it like you'd use any other PostCSS plugin. If you also have `autoprefixer` in your webpack config then make sure that `postcss-prefix-selector` is called first. This is needed to avoid running the prefixer twice on both standard selectors and vendor specific ones (ex: `@keyframes` and `@webkit-keyframes`).
```js
module: {
rules: [{
test: /\.css$/,
use: [
require.resolve('style-loader'),
require.resolve('css-loader'),
{
loader: require.resolve('postcss-loader'),
options: {
postcssOptions: {
plugins: {
"postcss-prefix-selector": {
prefix: '.my-prefix',
transform(prefix, selector, prefixedSelector, filePath, rule) {
if (selector.match(/^(html|body)/)) {
return selector.replace(/^([^\s]*)/, `$1 ${prefix}`);
}
if (filePath.match(/node_modules/)) {
return selector; // Do not prefix styles imported from node_modules
}
const annotation = rule.prev();
if (annotation?.type === 'comment' && annotation.text.trim() === 'no-prefix') {
return selector; // Do not prefix style rules that are preceded by: /* no-prefix */
}
return prefixedSelector;
},
},
autoprefixer: {
browsers: ['last 4 versions']
}
}
}
}
}
]
}]
}
```
## Usage with Vite
Following the same way of Webpack but for Vite:
```js
import prefixer from 'postcss-prefix-selector';
import autoprefixer from 'autoprefixer';
...
export default defineConfig({
...
css: {
postcss: {
plugins: [
prefixer({
prefix: '.my-prefix',
transform(prefix, selector, prefixedSelector, filePath, rule) {
if (selector.match(/^(html|body)/)) {
return selector.replace(/^([^\s]*)/, `$1 ${prefix}`);
}
if (filePath.match(/node_modules/)) {
return selector; // Do not prefix styles imported from node_modules
}
const annotation = rule.prev();
if (annotation?.type === 'comment' && annotation.text.trim() === 'no-prefix') {
return selector; // Do not prefix style rules that are preceded by: /* no-prefix */
}
return prefixedSelector;
},
}),
autoprefixer({}) // add options if needed
],
}
},
...
});
```
## Options
| Name | Type | Description |
|-|-|-|
| `prefix` | `string` | This string is added before every CSS selector |
| `exclude` | `string[]` or `RegExp[]` | It's possible to avoid prefixing some selectors by passing an array of selectors |
| `transform` | `Function` | 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` | `string[]` or `RegExp[]` | List of ignored files for processing |
| `includeFiles` | `string[]` or `RegExp[]` | List of included files for processing |
## Maintainer
This project was originally created by [@jongleberry](https://github.com/jonathanong) and is being maintained by [@RadValentin](https://github.com/RadValentin). If you have any questions, feel free to ping the latter.
## Contribute
Please contribute! If you have any questions or bugs, [open an issue](https://github.com/RadValentin/postcss-prefix-selector/issues/new). Or, open a pull request with a fix.
This project uses Mocha. If you submit a PR, please add appropriate tests and make sure that everything is green for your branch.
## License
[MIT](LICENSE) © 2015-2022 Jonathan Ong.
[gitpod-image]: https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod
[gitpod-url]: https://gitpod.io/#https://github.com/RadValentin/postcss-prefix-selector
[npm-image]: https://img.shields.io/npm/v/postcss-prefix-selector.svg?style=flat-square
[npm-url]: https://npmjs.org/package/postcss-prefix-selector
[coveralls-image]: https://img.shields.io/coveralls/jonathanong/postcss-prefix-selector.svg?style=flat-square
[coveralls-url]: https://coveralls.io/r/jonathanong/postcss-prefix-selector
[license-image]: http://img.shields.io/npm/l/postcss-prefix-selector.svg?style=flat-square
[license-url]: LICENSE
[downloads-image]: http://img.shields.io/npm/dm/postcss-prefix-selector.svg?style=flat-square
[downloads-url]: https://npmjs.org/package/postcss-prefix-selector
+77
View File
@@ -0,0 +1,77 @@
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 &&
isFileInArray(root.source.input.file, ignoreFiles)
) {
return;
}
if (
includeFiles.length &&
root.source.input.file &&
!isFileInArray(root.source.input.file, includeFiles)
) {
return;
}
root.walkRules((rule) => {
const keyframeRules = [
'keyframes',
'-webkit-keyframes',
'-moz-keyframes',
'-o-keyframes',
'-ms-keyframes',
];
if (rule.parent && keyframeRules.includes(rule.parent.name)) {
return;
}
rule.selectors = rule.selectors.map((selector) => {
if (options.exclude && excludeSelector(selector, options.exclude)) {
return selector;
}
if (options.transform) {
return options.transform(
prefix,
selector,
prefixWithSpace + selector,
root.source.input.file,
rule
);
}
return prefixWithSpace + selector;
});
});
};
};
function isFileInArray(file, arr) {
return arr.some((ruleOrString) => {
if (ruleOrString instanceof RegExp) {
return ruleOrString.test(file);
}
return file.includes(ruleOrString);
});
}
function excludeSelector(selector, excludeArr) {
return excludeArr.some((excludeRule) => {
if (excludeRule instanceof RegExp) {
return excludeRule.test(selector);
}
return selector === excludeRule;
});
}
+57
View File
@@ -0,0 +1,57 @@
{
"name": "postcss-prefix-selector",
"description": "Prefix all CSS rules with a selector",
"version": "1.16.1",
"author": "Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)",
"contributors": [
"Valentin Radulescu <hi@valentin.io> (https://valentin.io)"
],
"license": "MIT",
"repository": "RadValentin/postcss-prefix-selector",
"bugs": "https://github.com/RadValentin/postcss-prefix-selector/issues",
"homepage": "https://github.com/RadValentin/postcss-prefix-selector",
"peerDependencies": {
"postcss": ">4 <9"
},
"devDependencies": {
"husky": "^8.0.3",
"istanbul": "~0.4.5",
"lint-staged": "^13.2.1",
"mocha": "^9.2.2",
"postcss": "^8.0.0",
"postcss-nested": "^5.0.6",
"prettier": "^2.0.0"
},
"scripts": {
"test": "mocha",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter dot",
"lint": "prettier --write '**/*.{js,css}'"
},
"lint-staged": {
"*.js": [
"prettier --write"
]
},
"prettier": {
"printWidth": 80,
"singleQuote": true
},
"keywords": [
"postcss",
"prefix",
"selectors",
"postcss-plugin",
"css",
"selector",
"plugin"
],
"files": [
"index.js"
],
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
}
}