@rolandjlevy/css-ghost 1.0.4 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Roland Levy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, 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,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+ Standard MIT License text sourced from https://choosealicense.com/licenses/mit/
package/README.md CHANGED
@@ -1,16 +1,19 @@
1
1
  # šŸ‘» css-ghost
2
2
 
3
- Find orphaned CSS class selectors in your codebase — defined in style files but never referenced in your components.
3
+ Find and remove unused CSS selectors and orphaned CSS custom properties — selectors defined in your style files but never referenced in your components, across React, Vue, Svelte, SCSS, and CSS Modules
4
4
 
5
5
  ## What it does
6
6
 
7
7
  Scans one or more directories for style files, extracts every class selector defined, then cross-references them against usages in your component files. Anything defined but never used is reported as an orphan — with its line number and the actual CSS printed inline.
8
8
 
9
9
  **Supported style files:**
10
+
10
11
  - `.css`, `.module.css`, `.scss`, `.sass`, `.less`
11
- - `.js` / `.ts` files using `StyleSheet.create({})` or named style objects
12
+ - `.js` / `.ts` files using `StyleSheet.create({})`, `makeStyles({})` (MUI), or named style objects
13
+ - `.css.ts` / `.css.js` files using `style()` or `styleVariants()` (vanilla-extract)
12
14
 
13
15
  **Detected usage patterns:**
16
+
14
17
  - `className="foo"`
15
18
  - `className={styles.foo}`
16
19
  - `styles['foo']`
@@ -18,10 +21,37 @@ Scans one or more directories for style files, extracts every class selector def
18
21
  - `cx('foo')`, `clsx('foo')`, `classnames('foo')`
19
22
  - `cx({ active: isOn, disabled: true })` — object keys extracted
20
23
  - `cx(['foo', condition && 'bar'])` — array string literals extracted
24
+ - `classes.foo` — MUI `makeStyles` / `useStyles` convention
25
+ - `import { foo } from './styles.css'` — vanilla-extract named imports
21
26
 
22
27
  **Dynamic class detection:**
23
28
  Patterns where the class name is truly unknowable at parse time — `styles[variable]` or template literals containing `${}` — are flagged with a āš ļø warning. All statically resolvable patterns (string literals, ternaries, object keys) are analysed without warnings.
24
29
 
30
+ ## How is this different from PurgeCSS?
31
+
32
+ [PurgeCSS](https://www.npmjs.com/package/purgecss) is a **build-time bundler** — it hooks into webpack, PostCSS, or Gulp to strip unused CSS from your production output. It's designed for removing large framework utility classes (Bootstrap, Tailwind) that you never use.
33
+
34
+ css-ghost is a **source code auditor** — it finds dead selectors in your actual codebase, with no build step and no config file required. Just point it at a folder:
35
+
36
+ ```bash
37
+ npx @rolandjlevy/css-ghost ./src
38
+ ```
39
+
40
+ | | PurgeCSS | css-ghost |
41
+ |---|---|---|
42
+ | Works on source files | āŒ Build output only | āœ… |
43
+ | Zero config, no build step | āŒ Requires webpack / PostCSS | āœ… |
44
+ | CSS custom property orphans | āŒ | āœ… |
45
+ | Git history per orphan | āŒ | āœ… |
46
+ | Pre-commit hook | āŒ | āœ… |
47
+ | Deletes dead code for you | āŒ | āœ… |
48
+ | MUI / vanilla-extract aware | āŒ | āœ… |
49
+ | Safe with dynamic classes | āŒ Silently removes them | āœ… Flags with āš ļø |
50
+
51
+ The two tools are complementary: PurgeCSS for trimming framework output at build time; css-ghost for auditing your own hand-written CSS throughout development.
52
+
53
+ ---
54
+
25
55
  ## To enable AI features
26
56
 
27
57
  css-ghost can generate a plain English summary of your orphaned selectors using a free [OpenRouter](https://openrouter.ai) API key. Run the setup wizard once:
@@ -53,24 +83,177 @@ npx @rolandjlevy/css-ghost ./src
53
83
  ## Usage
54
84
 
55
85
  ```bash
56
- css-ghost <directory> [directory2] ... [options]
86
+ css-ghost [directory] [directory2] ... [options]
57
87
  ```
58
88
 
59
89
  **Options:**
60
90
 
61
- | Flag | Description | Default |
62
- | --- | --- | --- |
63
- | `--output <file>` | Output report file path | `orphan-report.md` |
64
- | `--ai` | Append an AI-generated summary (requires setup) | off |
65
- | `--setup` | Save your OpenRouter API key for `--ai` | — |
66
- | `-h, --help` | Show help | — |
91
+ | Flag | Description | Default |
92
+ | ----------------- | ---------------------------------------------------- | ------------------ |
93
+ | `--output <file>` | Output report file path | `orphan-report.md` |
94
+ | `--delete` | Delete all orphaned selectors from source files | off |
95
+ | `--yes` | Skip the deletion confirmation prompt | off |
96
+ | `--strict` | Exit with code 1 when any orphans are found (CI use) | off |
97
+ | `--ghost-trail` | Show the last git commit that touched each orphan | off |
98
+ | `--install-hook` | Write a pre-commit hook to `.git/hooks/pre-commit` | — |
99
+ | `--ai` | Append an AI-generated summary (requires setup) | off |
100
+ | `--setup` | Save your OpenRouter API key for `--ai` | — |
101
+ | `-h, --help` | Show help | — |
102
+
103
+ ## CSS variable orphan detection
104
+
105
+ css-ghost also catches **orphaned CSS custom properties** — variables defined with `--my-token: value` but never consumed anywhere via `var(--my-token)`.
106
+
107
+ Usages are detected across all file types: CSS, SCSS, JS, TS, JSX, TSX, Vue, Svelte, HTML. A variable defined in `variables.css` and used in a React component is correctly seen as _used_.
108
+
109
+ ```
110
+ šŸ”® --colour-danger-hover (line 8)
111
+ --colour-danger-hover: #dc2626;
112
+
113
+ šŸ”® --spacing-xl (line 26)
114
+ --spacing-xl: 64px;
115
+ ```
116
+
117
+ Orphaned variables appear under a separate **šŸ”® Orphaned CSS variables** section in both the terminal output and the markdown report.
118
+
119
+ ---
120
+
121
+ ## Ghost trail — git history for orphans
122
+
123
+ Pass `--ghost-trail` to fetch the last git commit that changed each orphan's occurrence count in the codebase. For class-name orphans the search is limited to component file types (`.tsx`, `.jsx`, `.ts`, `.js`, etc.) so the result reflects _usage_ history rather than the style-file definition.
124
+
125
+ ```bash
126
+ css-ghost ./src --ghost-trail
127
+ ```
128
+
129
+ ```
130
+ šŸ‘» .iconRight (line 28)
131
+ šŸ•µļø b5c6efb Ā· Roland Levy Ā· 3 weeks ago — "Refactor Button component"
132
+ .iconRight {
133
+ margin-left: 6px;
134
+ }
135
+ ```
136
+
137
+ For CSS variables the search looks for `var(--name` across all file types.
138
+
139
+ > **Note:** ghost trail runs one `git log -S` per orphan in parallel. On large histories with many orphans it may take a few seconds.
140
+
141
+ ---
142
+
143
+ ## Pre-commit hook
144
+
145
+ Install a hook that blocks commits when orphaned selectors are present:
146
+
147
+ ```bash
148
+ css-ghost --install-hook ./src
149
+ ```
150
+
151
+ This writes `.git/hooks/pre-commit` (executable, `chmod 755`) containing:
152
+
153
+ ```sh
154
+ #!/bin/sh
155
+ echo "šŸ‘» css-ghost — checking for orphaned CSS selectors..."
156
+ npx --yes @rolandjlevy/css-ghost ./src --strict --output /tmp/css-ghost-hook-report.md
157
+
158
+ if [ $? -ne 0 ]; then
159
+ echo "āŒ Commit blocked: orphaned CSS selectors found"
160
+ echo " Run 'css-ghost ./src --delete' to remove them"
161
+ echo " Or skip: git commit --no-verify"
162
+ exit 1
163
+ fi
164
+ ```
165
+
166
+ Pass multiple directories to the hook installer the same way you would to a normal scan:
167
+
168
+ ```bash
169
+ css-ghost --install-hook ./src ./components ./pages
170
+ ```
171
+
172
+ To uninstall: `rm .git/hooks/pre-commit`
173
+
174
+ ### `--strict` flag
175
+
176
+ `--strict` makes css-ghost exit with code 1 when any orphans are found — the mechanism the hook depends on, but also useful in CI workflows independently:
177
+
178
+ ```bash
179
+ # In CI: fail the build if orphans exist
180
+ css-ghost ./src --strict
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Interactive folder picker
186
+
187
+ Run `css-ghost` with no arguments and an arrow-key picker opens in your terminal:
188
+
189
+ ```
190
+ šŸ“‚ Directory picker — navigate into a folder, then press [a] to add it
191
+
192
+ šŸ“ /home/user/my-project
193
+
194
+ šŸ“ components
195
+ ā–¶ šŸ“ src
196
+ šŸ“ styles
197
+
198
+ āœ… Added to scan:
199
+ /home/user/my-project/src
200
+
201
+ [↑↓/jk] navigate [↵/→] enter [←] parent [a] add current dir [d] done [^C] quit
202
+ ```
203
+
204
+ | Key | Action |
205
+ | ---------------------- | --------------------------------------- |
206
+ | `↑` / `↓` or `k` / `j` | Move up and down the folder list |
207
+ | `↵` or `→` | Enter the highlighted folder |
208
+ | `←` or Backspace | Go up to the parent folder |
209
+ | `a` | Add the current folder to the scan list |
210
+ | `d` | Done — start the scan |
211
+ | `Ctrl+C` | Quit without scanning |
212
+
213
+ You can add **multiple folders** before pressing `d` — just navigate to each one and press `a`. If you press `d` without adding anything, the folder you're currently browsing is used.
214
+
215
+ ## Deleting orphans
216
+
217
+ Pass `--delete` after a scan to remove every flagged selector directly from its source file:
218
+
219
+ ```bash
220
+ css-ghost ./src --delete
221
+ ```
222
+
223
+ css-ghost prints the full report first, then lists what will be deleted and asks for confirmation before touching anything. Pass `--yes` to skip the prompt (useful in CI or scripts):
224
+
225
+ ```bash
226
+ css-ghost ./src --delete --yes
227
+ ```
228
+
229
+ Works across all supported file types — `.css`, `.scss`, `.less`, MUI `makeStyles`, and vanilla-extract exports.
230
+
231
+ > **Tip:** commit or stash your work before running `--delete`. There is no undo.
67
232
 
68
233
  ## Examples
69
234
 
70
235
  ```bash
236
+ # Interactive folder picker (no args)
237
+ css-ghost
238
+
71
239
  # Scan your src folder
72
240
  css-ghost ./src
73
241
 
242
+ # Show git history for each orphan
243
+ css-ghost ./src --ghost-trail
244
+
245
+ # Fail with exit code 1 when orphans exist (CI)
246
+ css-ghost ./src --strict
247
+
248
+ # Install a pre-commit hook that scans ./src
249
+ css-ghost --install-hook ./src
250
+
251
+ # Scan and delete all orphans (with confirmation prompt)
252
+ css-ghost ./src --delete
253
+
254
+ # Scan and delete without prompting
255
+ css-ghost ./src --delete --yes
256
+
74
257
  # Scan multiple directories
75
258
  css-ghost ./src ./components ./pages
76
259
 
@@ -108,9 +291,11 @@ Running `css-ghost ./src` prints a live summary to your terminal:
108
291
  }
109
292
 
110
293
  šŸ“ 1 style file scanned
294
+ šŸ’¾ Potential savings: 3 selectors removed
111
295
  ```
112
296
 
113
297
  Each orphan shows:
298
+
114
299
  - the selector name and the **exact line number** where it's defined
115
300
  - the **full CSS rule** so you can see what it does before deciding to delete it
116
301
 
@@ -160,39 +345,58 @@ npm run scan
160
345
  npm run scan -- --output ./reports/audit.md
161
346
  ```
162
347
 
163
- ## No dependencies
348
+ ## Troubleshooting
349
+
350
+ ### `css-ghost: command not found` after global install
164
351
 
165
- Built with Node.js built-ins only (`fs`, `path`). No npm packages required.
352
+ Your npm global bin directory may not be on your PATH. Run:
353
+
354
+ ```bash
355
+ npm bin -g
356
+ ```
357
+
358
+ Then add that path to your shell config (`~/.zshrc`, `~/.bashrc`, etc.):
359
+
360
+ ```bash
361
+ export PATH="$(npm bin -g):$PATH"
362
+ ```
363
+
364
+ Reload with `source ~/.zshrc`. This is a one-time fix — it won't be needed again after that.
365
+
366
+ > This is common when Node was installed via the official installer rather than nvm or Homebrew.
367
+
368
+ ## Dependencies
369
+
370
+ One runtime dependency: [`picocolors`](https://github.com/alexeyraspopov/picocolors) for terminal colours. Everything else uses Node.js built-ins (`fs`, `path`, `readline`).
166
371
 
167
372
  ## Origin — built with OpenRouter free models via Claude Code
168
373
 
169
374
  This tool was created as a test project to explore [using OpenRouter's free model tier with Claude Code](https://www.mindstudio.ai/blog/open-router-free-models-claude-code-cost-reduction) as a way to cut AI development costs.
170
375
 
171
- Claude Code normally calls Anthropic's API directly. By overriding two environment variables you can route it through OpenRouter's free tier instead — meaning you can run agentic coding sessions at no cost using models like Llama 3.3 70B or Deepseek R1.
172
-
173
- ### Setup
376
+ Claude Code normally calls Anthropic's API directly. By overriding two environment variables you can route it through OpenRouter's free tier instead — meaning you can run agentic coding sessions at no cost.
174
377
 
175
- Get a free API key at [openrouter.ai/keys](https://openrouter.ai/keys), then add these aliases to your `~/.zshrc`:
378
+ If you've already run `css-ghost --setup`, you have an OpenRouter key. You can also export it as an environment variable — css-ghost picks it up automatically, so you don't even need `--setup`:
176
379
 
177
380
  ```bash
178
- # Store your key once
179
381
  export OPENROUTER_API_KEY="sk-or-v1-YOUR_KEY"
382
+ ```
383
+
384
+ And you can reuse the same key with Claude Code by adding these aliases to your `~/.zshrc`:
180
385
 
181
- # Llama 3.3 70B — fast, capable, free
386
+ ```bash
182
387
  alias claude-free='ANTHROPIC_BASE_URL="https://openrouter.ai/api/v1" \
183
388
  ANTHROPIC_API_KEY="$OPENROUTER_API_KEY" \
184
- claude --model "meta-llama/llama-3.3-70b-instruct:free"'
389
+ claude --model "nvidia/nemotron-3.5-lightning:free"'
185
390
 
186
- # Deepseek R1 — strongest free option for reasoning and debugging
187
391
  alias claude-r1='ANTHROPIC_BASE_URL="https://openrouter.ai/api/v1" \
188
392
  ANTHROPIC_API_KEY="$OPENROUTER_API_KEY" \
189
- claude --model "deepseek/deepseek-r1:free"'
393
+ claude --model "qwen/qwen3.8-27b:free"'
190
394
  ```
191
395
 
192
396
  Then `source ~/.zshrc`. Use `claude-free` or `claude-r1` in place of `claude` to start a free session.
193
397
 
194
- > **Note:** Free tier models handle Claude Code's tool call format well in practice, but run a quick agentic task first to confirm file read/edit/bash loops work end to end in your environment before committing to it for serious work.
398
+ > **Note:** Free model availability changes frequently. Browse current options at [openrouter.ai/models](https://openrouter.ai/models?q=free) — filter by `:free`.
195
399
 
196
400
  ## License
197
401
 
198
- MIT
402
+ [MIT](./LICENSE)
package/bin/css-ghost.js CHANGED
@@ -4,6 +4,7 @@ import { resolve } from 'path';
4
4
  import { existsSync as fsExists } from 'fs';
5
5
  import { scan } from '../src/scanner.js';
6
6
  import { generateReport } from '../src/reporter.js';
7
+ import { deleteOrphans } from '../src/deleter.js';
7
8
  import { runSetup } from '../src/setup.js';
8
9
  import { getAiSummary } from '../src/ai.js';
9
10
 
@@ -15,22 +16,44 @@ if (args.includes('--setup')) {
15
16
  process.exit(0);
16
17
  }
17
18
 
18
- if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
19
+ // --install-hook [dirs...]
20
+ if (args.includes('--install-hook')) {
21
+ const { installHook } = await import('../src/hook.js');
22
+ // Any positional args become the directories the hook will scan
23
+ const hookDirs = args.filter(a => !a.startsWith('-'));
24
+ installHook(hookDirs, process.cwd());
25
+ process.exit(0);
26
+ }
27
+
28
+ if (args.includes('--help') || args.includes('-h')) {
19
29
  console.log(`
20
- šŸ‘» css-ghost — Find orphaned CSS class selectors
30
+ šŸ‘» css-ghost — Find orphaned CSS class selectors and custom properties
21
31
 
22
32
  Usage:
23
- css-ghost <directory> [directory2] ... [options]
33
+ css-ghost [directory] [directory2] ... [options]
34
+
35
+ When no directory is given, an interactive folder picker opens.
24
36
 
25
37
  Options:
26
- --output <file> Output report file path (default: orphan-report.md)
27
- --ai Append an AI-generated summary to the report
28
- --setup Save your OpenRouter API key for use with --ai
29
- -h, --help Show this help message
38
+ --output <file> Output report file path (default: orphan-report.md)
39
+ --delete Delete all orphaned selectors from source files (prompts first)
40
+ --yes Skip the deletion confirmation prompt (use with --delete)
41
+ --strict Exit with code 1 when orphans are found (useful in CI)
42
+ --ghost-trail Show the last git commit that touched each orphan
43
+ --install-hook Write a pre-commit hook to .git/hooks/pre-commit
44
+ --ai Append an AI-generated summary to the report
45
+ --setup Save your OpenRouter API key for use with --ai
46
+ -h, --help Show this help message
30
47
 
31
48
  Examples:
49
+ css-ghost # interactive folder picker
32
50
  css-ghost ./src
33
51
  css-ghost ./src ./components
52
+ css-ghost ./src --ghost-trail # show git history for each orphan
53
+ css-ghost ./src --strict # exit 1 when orphans found (CI mode)
54
+ css-ghost ./src --delete
55
+ css-ghost ./src --delete --yes
56
+ css-ghost --install-hook ./src # install pre-commit hook for ./src
34
57
  css-ghost ./src --ai
35
58
  css-ghost ./src --output ./reports/css-audit.md
36
59
  `);
@@ -38,34 +61,41 @@ Examples:
38
61
  }
39
62
 
40
63
  // Parse flags
41
- const useAi = args.includes('--ai');
42
- const outputIdx = args.indexOf('--output');
43
- const outputPath = outputIdx !== -1 ? args[outputIdx + 1] : 'orphan-report.md';
64
+ const useAi = args.includes('--ai');
65
+ const doDelete = args.includes('--delete');
66
+ const skipConfirm = args.includes('--yes') || args.includes('-y');
67
+ const strict = args.includes('--strict');
68
+ const ghostTrail = args.includes('--ghost-trail');
69
+ const outputIdx = args.indexOf('--output');
70
+ const outputPath = outputIdx !== -1 ? args[outputIdx + 1] : 'orphan-report.md';
44
71
 
45
72
  if (outputIdx !== -1 && !outputPath) {
46
73
  console.error('āŒ --output requires a file path');
47
74
  process.exit(1);
48
75
  }
49
76
 
50
- // Remaining args are directories (strip flags and their values)
77
+ // Remaining positional args are directories (strip flags and their values)
51
78
  const rawDirs = args.filter((a, i) =>
52
- !a.startsWith('--') && (outputIdx === -1 || i !== outputIdx + 1)
79
+ !a.startsWith('-') && (outputIdx === -1 || i !== outputIdx + 1)
53
80
  );
54
81
 
82
+ // No directories given → launch interactive picker
83
+ let dirs;
55
84
  if (rawDirs.length === 0) {
56
- console.error('āŒ At least one directory is required');
57
- process.exit(1);
58
- }
59
-
60
- // Validate directories exist
61
- const dirs = [];
62
- for (const d of rawDirs) {
63
- const resolved = resolve(d);
64
- if (!fsExists(resolved)) {
65
- console.error(`āŒ Directory not found: ${d}`);
66
- process.exit(1);
85
+ const { pickDirectories } = await import('../src/picker.js');
86
+ dirs = await pickDirectories();
87
+ console.log('');
88
+ } else {
89
+ // Validate provided directories exist
90
+ dirs = [];
91
+ for (const d of rawDirs) {
92
+ const resolved = resolve(d);
93
+ if (!fsExists(resolved)) {
94
+ console.error(`āŒ Directory not found: ${d}`);
95
+ process.exit(1);
96
+ }
97
+ dirs.push(resolved);
67
98
  }
68
- dirs.push(resolved);
69
99
  }
70
100
 
71
101
  console.log(`\nšŸ‘» css-ghost scanning ${dirs.length} director${dirs.length === 1 ? 'y' : 'ies'}...`);
@@ -79,7 +109,40 @@ if (results.length === 0) {
79
109
  process.exit(0);
80
110
  }
81
111
 
112
+ // Ghost trail — fetch git history for each orphan (opt-in, runs before report)
113
+ if (ghostTrail) {
114
+ const { isGitRepo, getGhostTrails } = await import('../src/git.js');
115
+ if (!isGitRepo(process.cwd())) {
116
+ console.warn('āš ļø --ghost-trail: not a git repository — skipping git history.\n');
117
+ } else {
118
+ const totalOrphans = results.reduce(
119
+ (n, r) => n + r.orphaned.length + (r.orphanedVars?.length ?? 0), 0
120
+ );
121
+ if (totalOrphans > 0) {
122
+ process.stdout.write(`šŸ” Fetching git history for ${totalOrphans} orphan${totalOrphans !== 1 ? 's' : ''}...`);
123
+ for (const result of results) {
124
+ if (result.orphaned.length > 0) {
125
+ result.trails = await getGhostTrails(result.orphaned, process.cwd());
126
+ }
127
+ if ((result.orphanedVars?.length ?? 0) > 0) {
128
+ result.varTrails = await getGhostTrails(result.orphanedVars, process.cwd(), { isVar: true });
129
+ }
130
+ }
131
+ process.stdout.write(' done\n\n');
132
+ }
133
+ }
134
+ }
135
+
82
136
  // Get AI summary before writing report (so it can be included in the .md)
83
137
  const aiSummary = useAi ? await getAiSummary(results) : null;
84
138
 
85
- generateReport(results, outputPath, aiSummary);
139
+ const { totalAllOrphans } = generateReport(results, outputPath, aiSummary);
140
+
141
+ if (doDelete) {
142
+ await deleteOrphans(results, { yes: skipConfirm });
143
+ }
144
+
145
+ // --strict: exit 1 if any orphans were found (for CI / pre-commit hooks)
146
+ if (strict && totalAllOrphans > 0) {
147
+ process.exit(1);
148
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rolandjlevy/css-ghost",
3
- "version": "1.0.4",
4
- "description": "Find orphaned CSS class selectors in your codebase",
3
+ "version": "1.1.2",
4
+ "description": "Find and remove unused CSS selectors and orphaned CSS custom properties — a CLI linter and auditor for React, Vue, Svelte, SCSS, and CSS Modules",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "css-ghost": "bin/css-ghost.js"
@@ -9,24 +9,35 @@
9
9
  "scripts": {
10
10
  "start": "node bin/css-ghost.js",
11
11
  "scan": "node bin/css-ghost.js ./test",
12
+ "scan:trail": "node bin/css-ghost.js ./test --ghost-trail",
13
+ "delete": "node bin/css-ghost.js ./test --delete",
14
+ "delete:yes": "node bin/css-ghost.js ./test --delete --yes",
12
15
  "setup": "node bin/css-ghost.js --setup"
13
16
  },
14
17
  "files": [
15
18
  "bin",
16
19
  "src",
17
- "README.md"
20
+ "README.md",
21
+ "LICENSE"
18
22
  ],
19
23
  "keywords": [
20
24
  "css",
21
- "orphan",
22
25
  "unused",
26
+ "orphan",
23
27
  "selectors",
28
+ "dead-code",
29
+ "cleanup",
24
30
  "cli",
25
31
  "linter",
32
+ "audit",
33
+ "tree-shaking",
34
+ "custom-properties",
26
35
  "react",
36
+ "vue",
37
+ "svelte",
27
38
  "scss",
28
- "stylesheet",
29
- "audit"
39
+ "css-modules",
40
+ "purgecss"
30
41
  ],
31
42
  "author": "Roland Levy",
32
43
  "license": "MIT",
@@ -37,5 +48,8 @@
37
48
  "homepage": "https://github.com/rolandjlevy/css-ghost#readme",
38
49
  "engines": {
39
50
  "node": ">=18"
51
+ },
52
+ "dependencies": {
53
+ "picocolors": "^1.1.1"
40
54
  }
41
55
  }