diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1975edc --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,54 @@ +name: Release Package + +on: + workflow_dispatch: + inputs: + publish_type: + description: 'Choose publish type: dry-run, main' + required: true + default: 'dry-run' + type: choice + options: + - dry-run + - main + confirm_publish: + description: 'Type YES to confirm publishing (required for main release)' + required: false + default: '' + +permissions: + id-token: write + +jobs: + publish: + if: ${{ (github.event.inputs.publish_type == 'main' && github.event.inputs.confirm_publish == 'YES' && github.ref_name == 'main') || github.event.inputs.publish_type == 'dry-run' }} + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' + registry-url: 'https://registry.npmjs.org' + + - name: Set up pnpm + uses: pnpm/action-setup@v2 + with: + version: 8.9.2 + + - name: Install dependencies + run: pnpm i + + - name: Publish package (dry) + if: ${{github.event.inputs.publish_type == 'dry-run' }} + run: pnpm release:dry --no-git-checks + + - name: Publish package + if: ${{ github.event.inputs.publish_type == 'main' }} + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + REPOSITORY: ${{ github.repository }} + REF: ${{ github.ref }} + run: pnpm release:latest diff --git a/.gitignore b/.gitignore index b512c09..cc073a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -node_modules \ No newline at end of file +node_modules +dist +pnpm-lock.yaml +coverage diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..35fa266 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "trailingComma": "all", + "singleQuote": true, + "arrowParens": "avoid", + "endOfLine": "lf" +} diff --git a/README.md b/README.md index 85fd79a..5fb64bd 100644 --- a/README.md +++ b/README.md @@ -1,203 +1,260 @@ # [postcss][git_url]-remove-duplicate-values -[][npm_url] -[](https://opensource.org/licenses/MIT) +
-[PostCSS Remove Duplicate Values] is a plugin for [PostCSS] that removes duplicate CSS property values within rules, optimizing stylesheet size and improving maintainability. +> **Smart PostCSS plugin that removes duplicate CSS properties, reduces bundle size, and improves CSS maintainability.** -## Installation +## โจ What It Does? -You can install the plugin via npm, pnpm, or yarn: +Automatically removes duplicate CSS properties from your stylesheets while keeping the most important ones. Perfect for cleaning up CSS and improving performance. +### ๐ฏ Key Features +- **๐งน Removes duplicate properties** (keeps the last one) +- **โก Handles `!important` declarations** intelligently +- **๐จ Supports vendor prefixes** and modern CSS +- **๐ฏ Filters specific selectors** (optional) +- **๐๏ธ Cleans empty rules** (configurable) +- **๐ Zero configuration** needed + +## ๐ Quick Start + +### 1. Install ```bash npm install postcss-remove-duplicate-values --save-dev +# or pnpm add postcss-remove-duplicate-values -D +# or yarn add postcss-remove-duplicate-values -D ``` -## What does it do? - -This plugin identifies and removes duplicate CSS property values within rules, considering specificity and preserving `!important` declarations. When you have multiple declarations with the same property within a single rule, it retains only the last declaration, prioritizing `!important` values over non-`!important` values. - -### Examples: +### 2. Use in PostCSS +```js +// postcss.config.js +module.exports = { + plugins: [ + require('postcss-remove-duplicate-values') + ] +} +``` -Here are some CSS examples showcasing the behavior of the plugin: +### 3. That's it! ๐ +The plugin automatically removes duplicates from your CSS. -#### Example A: Without !important +## ๐ Examples +### Basic Duplicate Removal ```css -/* Input A */ +/* Before */ .button { color: red; color: blue; + margin: 10px; + margin: 20px; } -/* Output A */ +/* After */ .button { color: blue; + margin: 20px; } ``` -#### Example B: With !important - +### `!important` Handling ```css -/* Input B */ +/* Before */ .button { color: red !important; - color: yellow !important; color: blue; + font-weight: normal; + font-weight: bold !important; } -.card { - display: flex !important; - display: block; + +/* After */ +.button { + color: red !important; + font-weight: bold !important; } +``` -/* Output B */ +### Vendor Prefixes +```css +/* Before */ .button { - color: yellow !important; + transform: translateX(40px); + -webkit-transform: translateX(10px); + -moz-transform: translateX(10px); + transform: translateX(10px); } -.card { - display: flex !important; + +/* After */ +.button { + /* Plugin removes duplicate 'transform' properties, keeping the last one */ + /* Vendor prefixes are preserved */ + -webkit-transform: translateX(10px); + -moz-transform: translateX(10px); + transform: translateX(10px); } ``` -## Configuration +## โ๏ธ Configuration Options -Integrating [PostCSS Remove Duplicate Values] into your [PostCSS] configuration is straightforward. Add it to your list of plugins: - -```js -const postcss = require("postcss"); -const removeDuplicateValues = require("postcss-remove-duplicate-values"); +Before applying the plugin, you can configure the following options: -const css = ` -.button { - color: red; - color: blue; -}`; - -// Example 1: Using plugins array -postcss([ - removeDuplicateValues({ - // options here - }), -]) - .process(css, { from: undefined }) - .then((result) => { - console.log(result.css); - }); - -// Example 2: Using use() method -postcss() - .use( - removeDuplicateValues({ - /* options */ - }) - ) - .process(css, { from: undefined }) - .then((result) => { - console.log(result.css); - }); -``` +| Option | Type | Default | +| --------------------------------- | --------------------------------------------------- | ----------- | +| [`selector`](#selector) | `(selector: string) => boolean \| string \| RegExp` | `undefined` | +| [`preserveEmpty`](#preserveempty) | `boolean` | `false` | -If you are using `postcss.config.js`, you can include it as follows: +### selector +Filter which CSS selectors to process. ```js -module.exports = { - plugins: [require("postcss-remove-duplicate-values")], -}; +// Only process .button selectors +removeDuplicateValues({ + selector: '.button' +}) + +// Process selectors matching regex +removeDuplicateValues({ + selector: /^\.btn-/ +}) + +// Custom function +removeDuplicateValues({ + selector: (selector) => selector.includes('button') +}) ``` -For more customization, you can pass options to the plugin: +### preserveEmpty +Keep or remove empty CSS rules. ```js -const removeDuplicateValues = require("postcss-remove-duplicate-values"); -module.exports = { - plugins: [ - removeDuplicateValues({ - // options here - }), - ], -}; +// Remove empty rules (default) +removeDuplicateValues({ + preserveEmpty: false +}) + +// Keep empty rules +removeDuplicateValues({ + preserveEmpty: true +}) ``` -## Options +## ๐ง Advanced Usage -Before applying the plugin, you can configure the following options: - -| Option | Type | Default | -| --------------------------------- | --------------------------------------------------- | ----------- | -| [`selector`](#selector) | `(selector: string) => boolean \| string \| RegExp` | `undefined` | -| [`preserveEmpty`](#preserveempty) | `boolean` | `false` | +### With PostCSS API +```js +const postcss = require('postcss') +const removeDuplicateValues = require('postcss-remove-duplicate-values') -#### selector +const css = ` +.button { + color: red; + color: blue; +}` + +postcss([removeDuplicateValues()]) + .process(css) + .then(result => { + console.log(result.css) + // Output: .button { color: blue; } + }) +``` -The selector option specifies the selector to consider while removing duplicate values. This option allows you to target specific selectors for duplicate value removal. Default its undefined i.e. apply to all rules. Selector can be defined as: +### With Build Tools +```js +// webpack.config.js +module.exports = { + module: { + rules: [ + { + test: /\.css$/, + use: [ + 'style-loader', + 'css-loader', + { + loader: 'postcss-loader', + options: { + plugins: [ + require('postcss-remove-duplicate-values') + ] + } + } + ] + } + ] + } +} +``` -- **String**: A CSS selector string. Only rules matching this selector will have their duplicate values removed. -- **RegExp**: A regular expression. Rules with selectors matching this regular expression will have their duplicate values removed. -- **Function**: `(selector: string) => boolean` A function that takes a selector string as input and returns a boolean value indicating whether the selector should be considered for duplicate value removal. -**Example**: +## ๐ More Examples +### Selector Filtering ```css /* Input CSS */ .container { - display: block; color: red; color: blue; } - .button { - display: flex; - color: green; + margin: 10px; + margin: 20px; } -``` -If we set selector `.container`, only the properties within the .container selector will be considered for duplicate value removal. Similarly, you can use regular expressions or custom functions to match specific selectors for this operation. - -```css -/* Output CSS */ +/* With selector: '.container' */ .container { - display: block; color: blue; } - .button { - display: flex; - color: green; + margin: 10px; + margin: 20px; /* Not processed */ } ``` -### preserveEmpty - -The `preserveEmpty` option determines whether empty selectors should be preserved or removed during the process of removing duplicate values. An empty selector is a selector without any properties. - -**Example**: -Consider the following CSS: - +### Empty Rule Handling ```css /* Input CSS */ -.classA { +.empty-rule { } - -.classB { - /* some comment */ +.button { + color: blue; } +/* With preserveEmpty: false */ .button { - display: block; + color: blue; } -``` - -If `preserveEmpty` is set to false, the empty selector `.somecss` will be removed during the process. If set to true, the empty selector will be preserved in the output. +/* .empty-rule removed */ -```css -/* Output CSS */ +/* With preserveEmpty: true */ +.empty-rule { +} .button { - display: block; + color: blue; } ``` +## ๐ฎ Try It Live! + +**Test the plugin in real-time with our interactive playground:** + +[๐ฎ **Try the Playground** โ](https://xettri.github.io/postcss-remove-duplicate-values) + +### What You Can Do in the Playground: +- โจ **Test CSS processing** in real-time +- ๐ฏ **Experiment with options** (selector filtering, empty rule preservation) +- ๐ **Try pre-built examples** for common scenarios +- ๐ **See live statistics** of duplicate removal results +- ๐จ **Understand plugin behavior** through interactive examples + ++ Leave empty to process all selectors +
++ Remove empty rules by default +
++ Toggle to preserve empty rules +
+Select a test scenario to begin
++ Intelligently removes duplicate CSS properties while preserving + the last declaration +
++ Properly handles !important declarations with priority-based + logic +
++ Smart handling of vendor-prefixed properties and fallbacks +
++ Process only specific selectors using string, RegExp, or + function matching +
++ Optionally remove empty CSS rules for cleaner output +
++ Works out of the box with sensible defaults and optional + customization +
+