From cbc6f3675b3cf5f33ed8f63eb58f436793845156 Mon Sep 17 00:00:00 2001 From: Jens Oliver Meiert Date: Wed, 12 Aug 2026 21:59:09 +0200 Subject: [PATCH 1/4] feat: rename positional argument to `path` in CLI Updated the CLI help output and README to rename the argument `file` to `path`, better reflecting its ability to handle both files and directories. Incremented the version to 1.12.1 in relevant metadata files. (This commit message was AI-generated.) Signed-off-by: Jens Oliver Meiert --- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- src/cli/options.js | 4 ++-- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7578d58..7ba5b88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to CSS Dedup are documented in this file, which is (mostly) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.12.1] - 2026-08-13 + +### Changed + +* Renamed the positional argument to `path` in the help output and the README, matching that it takes files as well as directories + ## [1.12.0] - 2026-08-12 ### Changed diff --git a/README.md b/README.md index adfbd8c..0142089 100644 --- a/README.md +++ b/README.md @@ -65,10 +65,10 @@ The two aren’t always aligned, though: Folding a declaration into a shared sel ### CLI ```shell -npx css-dedup [options] [file…] +npx css-dedup [options] [path…] ``` -Pass one or more files—each is analyzed (and, with `--fix`, rewritten) independently. Without a file, CSS Dedup analyzes the current directory. A directory is searched recursively for .css files (skipping node_modules and dotfolders); the result is unrolled into that same per-file list, so mixing files and directories works, too. Pass `-` instead of a file to read CSS from STDIN (can’t be combined with other file arguments); in `--fix` mode this prints the consolidated CSS to STDOUT, rather than writing a file, so it composes in a pipeline (status/summary output moves to STDERR in that case, keeping STDOUT pure CSS). +Pass one or more paths—each is analyzed (and, with `--fix`, rewritten) independently. Without a path, CSS Dedup analyzes the current directory. A directory is searched recursively for .css files (skipping node_modules and dotfolders); the result is unrolled into that same per-file list, so mixing files and directories works, too. Pass `-` instead of a file to read CSS from STDIN (can’t be combined with other file arguments); in `--fix` mode this prints the consolidated CSS to STDOUT, rather than writing a file, so it composes in a pipeline (status/summary output moves to STDERR in that case, keeping STDOUT pure CSS). The input is CSS. A preprocessor source named as an argument (.scss, .sass, .less, .styl) is skipped. Run CSS Dedup on the compiled style sheet instead—duplication in a preprocessor source is often deliberate (one mixin used in ten places), it only becomes real duplication after compilation, and the byte figures the report is built around describe what actually ships. The reason for skipping rather than trying: Constructs like `@include`, `@extend`, `#{…}`, and `@if` decide what a rule finally contains, which is exactly what the merge-safety checks would need to see to know whether moving a declaration across rules is safe. diff --git a/package-lock.json b/package-lock.json index 0ffa3fe..9e93a1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "css-dedup", - "version": "1.12.0", + "version": "1.12.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "css-dedup", - "version": "1.12.0", + "version": "1.12.1", "license": "MIT", "dependencies": { "postcss": "^8.5.26" diff --git a/package.json b/package.json index 018fc2a..d74906a 100644 --- a/package.json +++ b/package.json @@ -60,5 +60,5 @@ }, "type": "module", "types": "src/index.d.ts", - "version": "1.12.0" + "version": "1.12.1" } diff --git a/src/cli/options.js b/src/cli/options.js index 3df1bfa..88f300e 100644 --- a/src/cli/options.js +++ b/src/cli/options.js @@ -22,12 +22,12 @@ const OPTIONS_CONFIG = { help: { type: 'boolean', short: 'h', default: false }, }; -const HELP = `Usage: css-dedup [options] [file…] +const HELP = `Usage: css-dedup [options] [path…] Find (and optionally consolidate) duplicate CSS declarations. Arguments: - file One or more CSS files or directories to analyze, defaulting to the current directory (directories are searched recursively for .css files, skipping node_modules and dotfolders); pass \`-\` to read from STDIN instead. Preprocessor sources (.scss, .sass, .less, .styl) are skipped—run CSS Dedup on the compiled style sheet. + path One or more CSS files or directories to analyze, defaulting to the current directory (directories are searched recursively for .css files, skipping node_modules and dotfolders); pass \`-\` to read from STDIN instead. Preprocessor sources (.scss, .sass, .less, .styl) are skipped—run CSS Dedup on the compiled style sheet. Options: -f, --fix Consolidate declarations that are safe to merge automatically, rewriting each file in place (or printing to STDOUT for \`-\`) From f557f6aa8ff7788352f78b6bdb931a0c0ba3c988 Mon Sep 17 00:00:00 2001 From: Jens Oliver Meiert Date: Wed, 12 Aug 2026 22:20:32 +0200 Subject: [PATCH 2/4] chore: align comments Signed-off-by: Jens Oliver Meiert --- bin/css-dedup.js | 2 -- src/cli/options.js | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/bin/css-dedup.js b/bin/css-dedup.js index 1a05f63..09b03d5 100644 --- a/bin/css-dedup.js +++ b/bin/css-dedup.js @@ -166,8 +166,6 @@ async function main() { } main().catch(err => { - // A setup failure is the user’s to fix, so it gets the same message - // every other resolution error gets if (err.setupFailed) fail(styleText('red', err.message)); console.error(err); process.exit(1); diff --git a/src/cli/options.js b/src/cli/options.js index 88f300e..4cbb607 100644 --- a/src/cli/options.js +++ b/src/cli/options.js @@ -93,9 +93,7 @@ export function parseCliArgs(argv, { fail, showHelp }) { return { values, positionals: implicitTarget ? ['.'] : positionals, implicitTarget }; } -// Marks a failure as the user’s to fix (a bad pattern, an unloadable config) -// rather than a bug, so `bin/css-dedup.js` prints the message instead of a -// stack trace +// Marks a failure as the user’s to fix rather than a bug function setupError(message) { const err = new Error(message); err.setupFailed = true; From 36548cd4aefd3ffe37f325cff98996244e7e2c29 Mon Sep 17 00:00:00 2001 From: Jens Oliver Meiert Date: Wed, 12 Aug 2026 22:28:11 +0200 Subject: [PATCH 3/4] chore: align exit code formatting Signed-off-by: Jens Oliver Meiert --- CHANGELOG.md | 6 +++--- README.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ba5b88..f7f2c4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Changed -* Switched to analyzing the current directory when no file is given, instead of printing help and exiting “1” +* Switched to analyzing the current directory when no file is given, instead of printing help and exiting `1` * Changed to ask for confirmation before `--fix` rewrites a working directory nobody named; an explicit target (`css-dedup --fix .`) runs unprompted ## [1.11.0] - 2026-08-05 @@ -115,8 +115,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added -* Added `--exit-zero`/`-z` (and the `exitZero` config option) to exit “0” even when findings are skipped as unsafe to auto-merge or withheld by `--savings-only`, so a build pipeline doesn’t gate on them - - A file that fails to read or parse still exits “1” regardless of the flag. +* Added `--exit-zero`/`-z` (and the `exitZero` config option) to exit `0` even when findings are skipped as unsafe to auto-merge or withheld by `--savings-only`, so a build pipeline doesn’t gate on them + - A file that fails to read or parse still exits `1` regardless of the flag. * Added `--no-exit-zero`/`-e` to override `exitZero: true` from a config file for a run ## [1.5.0] - 2026-07-22 diff --git a/README.md b/README.md index 0142089..74811a9 100644 --- a/README.md +++ b/README.md @@ -88,9 +88,9 @@ The input is CSS. A preprocessor source named as an argument (.scss, .sass, .les `--ignore-selector` and `--ignore-path` are singular because they’re repeatable flags—each occurrence (`-i pattern1 -i pattern2`) adds one pattern. The corresponding config-file options, `ignoreSelectors` and `ignorePaths`, take an array. `--ignore-path` excludes whole files by path rather than by selector content, matched against each file’s path relative to the working directory—useful for keeping a directory scan out of a build output folder (`node_modules` and dotfolders are always skipped; nothing else is otherwise). -Without `--fix`, CSS Dedup only reports. Report mode still runs the same safety checks `--fix` would, though, so a finding that is considered unsafe to auto-merge (an intervening declaration on some other selector, say) is called out right there, alongside the byte estimate for whatever is safe—rather than the estimate silently going missing for that group. Exit code is “1” if default-mode rules find anything to report (or, with `--fix`, anything skipped as unsafe or withheld by `--savings-only`) in any of the given files—an aggressive-only finding that default rules wouldn’t otherwise report doesn’t, on its own, flip the exit code. +Without `--fix`, CSS Dedup only reports. Report mode still runs the same safety checks `--fix` would, though, so a finding that is considered unsafe to auto-merge (an intervening declaration on some other selector, say) is called out right there, alongside the byte estimate for whatever is safe—rather than the estimate silently going missing for that group. Exit code is `1` if default-mode rules find anything to report (or, with `--fix`, anything skipped as unsafe or withheld by `--savings-only`) in any of the given files—an aggressive-only finding that default rules wouldn’t otherwise report doesn’t, on its own, flip the exit code. -CSS Dedup only ever merges what it can prove safe: A duplicate group flagged unsafe to auto-merge is never merged, `--exit-zero` or not, and the finding still prints exactly the same either way—nothing about the flag changes what gets analyzed or reported, only what happens to the exit code. That’s for a build step that must otherwise succeed (e.g., a minification pipeline gating CI): `--fix` should not produce anything wrong (that would be a bug), so failing the build over a finding it just left on record for later is a separate call from whether the CSS itself is fine. Exit “1” still applies to a file that couldn’t be read or parsed. +CSS Dedup only ever merges what it can prove safe: A duplicate group flagged unsafe to auto-merge is never merged, `--exit-zero` or not, and the finding still prints exactly the same either way—nothing about the flag changes what gets analyzed or reported, only what happens to the exit code. That’s for a build step that must otherwise succeed (e.g., a minification pipeline gating CI): `--fix` should not produce anything wrong (that would be a bug), so failing the build over a finding it just left on record for later is a separate call from whether the CSS itself is fine. Exit `1` still applies to a file that couldn’t be read or parsed. A file that fails to parse—invalid CSS, or a non-standard dialect PostCSS doesn’t accept—doesn’t stop the run: Its error is reported and CSS Dedup moves on to the rest. From b7d3f651339d170b5b58a8f2be891356b6da1428 Mon Sep 17 00:00:00 2001 From: Jens Oliver Meiert Date: Thu, 13 Aug 2026 09:09:29 +0200 Subject: [PATCH 4/4] chore: ensure latest deps Signed-off-by: Jens Oliver Meiert --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9e93a1e..336c6b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "devDependencies": { "@eslint/js": "^10.0.1", "eslint": "^10.8.1", - "globals": "^17.10.0", + "globals": "^17.11.0", "typescript": "^7.0.2" }, "engines": { @@ -918,9 +918,9 @@ } }, "node_modules/globals": { - "version": "17.10.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.10.0.tgz", - "integrity": "sha512-V0kztuWST2k8A/VbxAY8+L+7+Rgo3fyA24IHRLrZp7HOzJjV0gHSaZUjK9lpP/IrBSNite2tZ1prhRkinRu1CA==", + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.11.0.tgz", + "integrity": "sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index d74906a..db0f58c 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "devDependencies": { "@eslint/js": "^10.0.1", "eslint": "^10.8.1", - "globals": "^17.10.0", + "globals": "^17.11.0", "typescript": "^7.0.2" }, "engines": {