@rolandjlevy/css-ghost 1.2.0 → 1.3.0

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/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@ All notable changes to `@rolandjlevy/css-ghost` are documented here.
4
4
 
5
5
  ---
6
6
 
7
+ ## [1.3.0] — 2026-10-17
8
+
9
+ ### Added
10
+
11
+ - **Programmatic API** (`src/index.js`) — `scan()` and `generateReport()` are now exposed as the package's public entry point via the `exports` field. Other tools and build plugins can now depend on css-ghost directly.
12
+ - **TypeScript types** (`index.d.ts`) — hand-authored declarations for `ScanResult`, `OrphanedItem`, `GhostTrail`, and `ReportTotals`; no `@types/` package needed.
13
+ - **GitHub Actions CI** (`.github/workflows/ci.yml`) — runs the smoke test suite on Node 18, 20 and 22 on every push and pull request.
14
+ - **Smoke test runner** (`test/run.js`) — `npm test` now runs `scan()` against all 13 fixture directories and asserts result shapes; 13/13 pass.
15
+ - **README badges** — npm version, monthly downloads, CI status, Node version and licence badge at the top of the README.
16
+ - **Programmatic API docs** — new README section with install instructions, usage example, and TypeScript note.
17
+ - **Keywords expanded** — added `vite`, `webpack`, `postcss`, `css-variables`, `vanilla-extract`, `orphaned-selectors` for better npm discovery.
18
+
19
+ ---
20
+
7
21
  ## [1.2.0] — 2026-10-17
8
22
 
9
23
  ### Fixed
package/README.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # 👻 css-ghost
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@rolandjlevy/css-ghost.svg)](https://www.npmjs.com/package/@rolandjlevy/css-ghost)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@rolandjlevy/css-ghost.svg)](https://www.npmjs.com/package/@rolandjlevy/css-ghost)
5
+ [![CI](https://github.com/rolandjlevy/css-ghost/actions/workflows/ci.yml/badge.svg)](https://github.com/rolandjlevy/css-ghost/actions/workflows/ci.yml)
6
+ [![Node.js >=18](https://img.shields.io/node/v/@rolandjlevy/css-ghost.svg)](https://nodejs.org/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+
3
9
  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
10
 
5
11
  ## What it does
@@ -158,6 +164,34 @@ css-ghost ./src --ai # with AI summary
158
164
  css-ghost ./src --output ./reports/audit.md
159
165
  ```
160
166
 
167
+ ## Programmatic API
168
+
169
+ Use css-ghost as a library inside your own build tools, Vite plugins, or scripts:
170
+
171
+ ```bash
172
+ npm install @rolandjlevy/css-ghost
173
+ ```
174
+
175
+ ```js
176
+ import { scan, generateReport } from '@rolandjlevy/css-ghost';
177
+ import { resolve } from 'path';
178
+
179
+ // Scan one or more directories
180
+ const results = scan([resolve(process.cwd(), 'src')]);
181
+
182
+ // Optional: write a Markdown report and get the orphan totals
183
+ const { totalAllOrphans } = generateReport(results, 'orphan-report.md');
184
+
185
+ // Use in CI: fail the build if any orphans are found
186
+ if (totalAllOrphans > 0) process.exit(1);
187
+ ```
188
+
189
+ TypeScript types are included — no `@types/` package needed.
190
+
191
+ **`scan(dirs: string[])`** — returns a `ScanResult[]` array, one entry per style file. Each entry includes `filePath`, `orphaned` selectors, `orphanedVars` (CSS custom properties), `hasDynamic` flag, and more.
192
+
193
+ **`generateReport(results, outputPath?, aiSummary?)`** — writes a Markdown report and prints a colour summary to the terminal. Returns `{ totalOrphaned, totalVarsOrphaned, totalAllOrphans }`.
194
+
161
195
  ## Using with npm scripts
162
196
 
163
197
  ```json
package/index.d.ts ADDED
@@ -0,0 +1,108 @@
1
+ /**
2
+ * TypeScript declarations for @rolandjlevy/css-ghost
3
+ * Import from the package root to get `scan` and `generateReport`.
4
+ */
5
+
6
+ /** A single orphaned class selector or CSS variable. */
7
+ export interface OrphanedItem {
8
+ /** The selector name (without leading `.`) or CSS variable name (with `--` prefix). */
9
+ name: string;
10
+ /** Line number in the source style file. */
11
+ line: number;
12
+ /** The raw CSS rule text, if available. */
13
+ rule?: string;
14
+ }
15
+
16
+ /** Git blame info for a single orphaned item (--ghost-trail mode). */
17
+ export interface GhostTrail {
18
+ /** Short commit hash. */
19
+ hash: string;
20
+ /** Commit author name. */
21
+ author: string;
22
+ /** Human-readable date/time of the commit. */
23
+ when: string;
24
+ /** Commit subject line. */
25
+ subject: string;
26
+ }
27
+
28
+ /**
29
+ * Per-file result returned by `scan()`.
30
+ * One entry per style file processed.
31
+ */
32
+ export interface ScanResult {
33
+ /** Absolute path to the style file. */
34
+ filePath: string;
35
+ /** Total number of class selectors defined in the file. */
36
+ total: number;
37
+ /** Class selectors that are defined but never referenced in component files. */
38
+ orphaned: OrphanedItem[];
39
+ /** CSS custom properties (`--foo`) defined but never used via `var()`. */
40
+ orphanedVars: OrphanedItem[];
41
+ /** Total number of CSS custom properties defined in the file. */
42
+ totalVars: number;
43
+ /**
44
+ * `true` when the co-located component files use dynamic class access
45
+ * (`styles[variable]`, template literals) — results may be incomplete.
46
+ */
47
+ hasDynamic: boolean;
48
+ /** Absolute paths of component files that contain dynamic class references. */
49
+ dynamicFiles: string[];
50
+ /**
51
+ * Ghost-trail git blame data for orphaned selectors, keyed by selector name.
52
+ * Only present when `--ghost-trail` is active or you call the git module directly.
53
+ */
54
+ trails?: Record<string, GhostTrail>;
55
+ /**
56
+ * Ghost-trail git blame data for orphaned CSS variables, keyed by variable name.
57
+ * Only present when `--ghost-trail` is active or you call the git module directly.
58
+ */
59
+ varTrails?: Record<string, GhostTrail>;
60
+ }
61
+
62
+ /** Totals returned by `generateReport()`. Useful for CI / strict-mode checks. */
63
+ export interface ReportTotals {
64
+ /** Number of orphaned class selectors across all scanned files. */
65
+ totalOrphaned: number;
66
+ /** Number of orphaned CSS variables across all scanned files. */
67
+ totalVarsOrphaned: number;
68
+ /** Sum of `totalOrphaned` and `totalVarsOrphaned`. */
69
+ totalAllOrphans: number;
70
+ }
71
+
72
+ /**
73
+ * Scan one or more directories for orphaned CSS selectors and CSS custom properties.
74
+ *
75
+ * @param dirs - Absolute paths to the directories you want to scan.
76
+ * @returns An array of per-file results — one entry per style file found.
77
+ *
78
+ * @example
79
+ * import { scan } from '@rolandjlevy/css-ghost';
80
+ * import { resolve } from 'path';
81
+ *
82
+ * const results = scan([resolve(process.cwd(), 'src')]);
83
+ * const totalOrphans = results.reduce((n, r) => n + r.orphaned.length + r.orphanedVars.length, 0);
84
+ * console.log(`Found ${totalOrphans} orphan(s).`);
85
+ */
86
+ export function scan(dirs: string[]): ScanResult[];
87
+
88
+ /**
89
+ * Generate a Markdown report file and print a summary to stdout.
90
+ *
91
+ * @param results - Output from `scan()`.
92
+ * @param outputPath - Where to write the `.md` report. Defaults to `'orphan-report.md'`.
93
+ * @param aiSummary - Optional AI-generated summary string to embed in the report.
94
+ * @returns Totals you can use for CI gates or `--strict` mode.
95
+ *
96
+ * @example
97
+ * import { scan, generateReport } from '@rolandjlevy/css-ghost';
98
+ * import { resolve } from 'path';
99
+ *
100
+ * const results = scan([resolve(process.cwd(), 'src')]);
101
+ * const { totalAllOrphans } = generateReport(results, 'orphan-report.md');
102
+ * if (totalAllOrphans > 0) process.exit(1);
103
+ */
104
+ export function generateReport(
105
+ results: ScanResult[],
106
+ outputPath?: string,
107
+ aiSummary?: string | null
108
+ ): ReportTotals;
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@rolandjlevy/css-ghost",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
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
+ "exports": {
7
+ ".": "./src/index.js"
8
+ },
9
+ "main": "./src/index.js",
10
+ "types": "./index.d.ts",
6
11
  "bin": {
7
12
  "css-ghost": "bin/css-ghost.js"
8
13
  },
@@ -12,11 +17,13 @@
12
17
  "scan:trail": "node bin/css-ghost.js ./test --ghost-trail",
13
18
  "delete": "node bin/css-ghost.js ./test --delete",
14
19
  "delete:yes": "node bin/css-ghost.js ./test --delete --yes",
15
- "setup": "node bin/css-ghost.js --setup"
20
+ "setup": "node bin/css-ghost.js --setup",
21
+ "test": "node test/run.js"
16
22
  },
17
23
  "files": [
18
24
  "bin",
19
25
  "src",
26
+ "index.d.ts",
20
27
  "README.md",
21
28
  "CHANGELOG.md",
22
29
  "LICENSE"
@@ -25,6 +32,7 @@
25
32
  "css",
26
33
  "unused",
27
34
  "orphan",
35
+ "orphaned-selectors",
28
36
  "selectors",
29
37
  "dead-code",
30
38
  "cleanup",
@@ -33,20 +41,29 @@
33
41
  "audit",
34
42
  "tree-shaking",
35
43
  "custom-properties",
44
+ "css-variables",
36
45
  "react",
37
46
  "vue",
38
47
  "svelte",
39
48
  "scss",
40
49
  "css-modules",
41
- "purgecss"
50
+ "purgecss",
51
+ "vite",
52
+ "webpack",
53
+ "postcss",
54
+ "vanilla-extract",
55
+ "style-audit"
42
56
  ],
43
57
  "author": "Roland Levy",
44
58
  "license": "MIT",
45
59
  "repository": {
46
60
  "type": "git",
47
- "url": "https://github.com/rolandjlevy/css-ghost.git"
61
+ "url": "git+https://github.com/rolandjlevy/css-ghost.git"
48
62
  },
49
63
  "homepage": "https://github.com/rolandjlevy/css-ghost#readme",
64
+ "bugs": {
65
+ "url": "https://github.com/rolandjlevy/css-ghost/issues"
66
+ },
50
67
  "engines": {
51
68
  "node": ">=18"
52
69
  },
package/src/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @rolandjlevy/css-ghost — Programmatic API
3
+ *
4
+ * Use this when integrating css-ghost into build tools, scripts, or plugins
5
+ * rather than running it as a CLI.
6
+ *
7
+ * @example
8
+ * import { scan, generateReport } from '@rolandjlevy/css-ghost';
9
+ *
10
+ * const results = scan(['/absolute/path/to/src']);
11
+ * const { totalAllOrphans } = generateReport(results, 'orphan-report.md');
12
+ * if (totalAllOrphans > 0) process.exit(1);
13
+ */
14
+
15
+ export { scan } from './scanner.js';
16
+ export { generateReport } from './reporter.js';