@zealakit/css-doctor-cli 1.0.0 → 1.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zealamic
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.
package/README.md CHANGED
@@ -12,30 +12,382 @@
12
12
 
13
13
  ![css doctor](https://github.com/zealakit/css-doctor/blob/main/assets/images/css-doctor.jpg)
14
14
 
15
+ ## What it does
16
+
17
+ `css-doctor check` reads one or more CSS files, parses them with the native
18
+ LightningCSS engine, and prints a terminal report (or JSON for CI).
19
+
20
+ It is a **diagnostics** tool. It does **not** rewrite files, minify CSS, or
21
+ split stylesheets by page. Use the Vite / Next / Nuxt / Rsbuild / Remix adapters
22
+ for build-time optimization.
23
+
24
+ The CLI reports:
25
+
26
+ | Kind | Meaning |
27
+ | --- | --- |
28
+ | `syntax` | Parser / syntax warnings from LightningCSS |
29
+ | `empty-rule` | Rules with no declarations and no nested rules (dead-code candidates) |
30
+ | `duplicate-selector` | The same selector text appears in more than one rule |
31
+ | `threshold` | Selector count in a file exceeds `--threshold` |
32
+
33
+ ## Requirements
34
+
35
+ - Node.js **≥ 18**
36
+ - A supported `@zealakit/css-doctor-binding` native binary (downloaded with the
37
+ package on macOS / Linux / Windows x64 targets)
38
+
15
39
  ## Installation
16
40
 
41
+ ### One-off run (no install)
42
+
43
+ ```bash
44
+ npx @zealakit/css-doctor-cli check "src/**/*.css"
45
+ ```
46
+
47
+ ### Project dependency
48
+
17
49
  ```bash
18
50
  pnpm add -D @zealakit/css-doctor-cli
51
+
52
+ # or
53
+ npm install -D @zealakit/css-doctor-cli
54
+ yarn add -D @zealakit/css-doctor-cli
55
+ ```
56
+
57
+ After install, the `css-doctor` binary is available via:
58
+
59
+ ```bash
60
+ pnpm exec css-doctor --help
61
+ # npm
62
+ npx css-doctor --help
63
+ ```
64
+
65
+ ### package.json script
66
+
67
+ ```json
68
+ {
69
+ "scripts": {
70
+ "css:check": "css-doctor check \"src/**/*.css\"",
71
+ "css:check:ci": "css-doctor check \"src/**/*.css\" --json --threshold 500"
72
+ }
73
+ }
74
+ ```
75
+
76
+ ```bash
77
+ pnpm css:check
78
+ ```
79
+
80
+ ## Quick start
81
+
82
+ ```bash
83
+ # Help / version
84
+ css-doctor --help
85
+ css-doctor --version
86
+ css-doctor check --help
87
+ css-doctor health --help
88
+
89
+ # Single file
90
+ css-doctor check src/styles/app.css
91
+
92
+ # Multiple files
93
+ css-doctor check src/a.css src/b.css
94
+
95
+ # Glob — quote the pattern so the shell does not expand it first
96
+ css-doctor check "src/**/*.css"
97
+
98
+ # Mix paths and globs
99
+ css-doctor check styles/global.css "components/**/*.css"
100
+
101
+ # CSS Health Score (polished report)
102
+ css-doctor health "src/**/*.css"
103
+ css-doctor health "src/**/*.css" --json
104
+ css-doctor health "src/**/*.css" --fail-under 80
105
+ css-doctor check "src/**/*.css" --fail-under 85
106
+
107
+ # Baseline + regression
108
+ css-doctor baseline create "src/**/*.css"
109
+ css-doctor baseline show
110
+ css-doctor diff "src/**/*.css" --fail-on-regression
111
+
112
+ # Optimization intelligence
113
+ css-doctor optimize "src/**/*.css" --dry-run --explain --json
114
+ css-doctor split "src/**/*.css" --dry-run
115
+ css-doctor fix --list
116
+ css-doctor fix "src/**/*.css" --dry-run --rule dead.empty-rule
117
+ ```
118
+
119
+ ## Command: `check`
120
+
121
+ ```text
122
+ css-doctor check [patterns...] [options]
123
+ ```
124
+
125
+ | Argument / option | Description |
126
+ | --- | --- |
127
+ | `patterns...` | One or more CSS file paths or glob patterns. **Required.** |
128
+ | `-j, --json` | Print a structured `CheckReport` JSON document to stdout |
129
+ | `--threshold <n>` | Warn when a file has more than `<n>` selectors (`n` ≥ 0 integer) |
130
+ | `--fail-under <n>` | Exit `1` when overall Health Score is below `<n>` (0–100) |
131
+ | `-v, --version` | Print CLI version (global flag) |
132
+ | `-h, --help` | Print help |
133
+
134
+ ### Glob tips
135
+
136
+ - Quote globs: `"src/**/*.css"`. Unquoted `*` may be expanded by your shell
137
+ before css-doctor sees the pattern.
138
+ - `node_modules` and `.git` are ignored automatically.
139
+ - Literal paths that contain glob characters (for example `src/[slug].css`)
140
+ still work when passed as an existing file path.
141
+
142
+ ### Example terminal output
143
+
144
+ ```text
145
+ css-doctor v1.0.0 · check
146
+ patterns src/**/*.css
147
+ ────────────────────────────────────────────────────────────────
148
+ SUCCESS src/styles/app.css · 12.4 KB
149
+ selectors 184 · rules 132 · declarations 421
150
+ analysis 3.2 ms · read 0.8 ms · total 4.0 ms
151
+ Top selectors
152
+ #app .card:hover
153
+ .nav-link.is-active
154
+ …
155
+
156
+ WARNING src/legacy.css · 48.1 KB
157
+ selectors 612 · rules 540 · declarations 1 204
158
+ Diagnostics
159
+ • empty-rule — Rule ".unused" has no declarations…
160
+ • duplicate-selector — Selector ".btn" is defined in multiple rules…
161
+ ────────────────────────────────────────────────────────────────
162
+ files 2 · analyzed 2 · issues 2 · …
163
+ ```
164
+
165
+ Status badges:
166
+
167
+ | Status | When |
168
+ | --- | --- |
169
+ | `SUCCESS` | File analyzed; no issues |
170
+ | `WARNING` | File analyzed; has syntax / empty-rule / duplicate / threshold issues |
171
+ | `ERROR` | File could not be read or analyzed, or setup failed |
172
+
173
+ ## CI and JSON output
174
+
175
+ ```bash
176
+ css-doctor check "src/**/*.css" --json
177
+ css-doctor check "src/**/*.css" -j --threshold 500
19
178
  ```
20
179
 
21
- ## Usage
180
+ `--json` prints a stable `CheckReport` (`schemaVersion: 1`) with:
181
+
182
+ - `success` — `true` only when setup succeeded and every matched file was analyzed
183
+ - `errors` — fatal setup messages (no patterns, no matches, binding load failure, …)
184
+ - `files[]` — per-file path, size, timings, `issues`, and native `result` when `ok`
185
+ - `summary` — aggregated counters (files, selectors, warnings, timings, …)
186
+
187
+ Pipe or save the report:
22
188
 
23
189
  ```bash
24
- # Analyze files or quoted globs
25
- pnpm exec css-doctor check "src/**/*.css"
190
+ css-doctor check "src/**/*.css" --json > css-doctor-report.json
191
+ ```
192
+
193
+ ### Exit codes (`check`)
194
+
195
+ | Code | Meaning |
196
+ | --- | --- |
197
+ | `0` | Setup OK and every matched file was read + analyzed (warnings still allowed) |
198
+ | `1` | Fatal setup error, no matches, unloadable native binding, a file failed to read/analyze, or `--fail-under` failed |
199
+
200
+ Warnings and hints **do not** fail the process unless you also set
201
+ `--fail-under`. Use `--json` and inspect `summary.issues` / `files[].issues`
202
+ if you want CI gates on warnings.
203
+
204
+ `check --json` also includes an aggregated `health` field (CSS Health Score).
205
+
206
+ ## Command: `health`
207
+
208
+ ```text
209
+ css-doctor health [patterns...] [options]
210
+ ```
211
+
212
+ Evaluates a deterministic **CSS Health Score** (0–100) across five dimensions:
213
+
214
+ | Dimension | Weight | Measures |
215
+ | --- | ---: | --- |
216
+ | Selector Complexity | 20% | High specificity, deep combinators/nesting, long chains |
217
+ | Duplicate Rules | 20% | Repeated selectors / intra-rule duplicate declarations |
218
+ | CSS Size Efficiency | 20% | Large sheets, heavy rules, selector pressure |
219
+ | Dead CSS | 25% | Empty rules, recoverable syntax drops |
220
+ | Variable Consistency | 15% | Duplicate/`var()` usage gaps, naming mix (heuristic) |
221
+
222
+ Grades: **A** 90–100 · **B** 80–89 · **C** 70–79 · **D** 60–69 · **F** 0–59.
223
+
224
+ | Option | Description |
225
+ | --- | --- |
226
+ | `-j, --json` | Stable health JSON (`schemaVersion: 1`) |
227
+ | `--threshold <n>` | Maps to native `manySelectors` size pressure |
228
+ | `--fail-under <n>` | Exit `1` when overall score `< n` (CI gate) |
229
+
230
+ The score is **not** a guarantee of visual correctness. Unused-variable and
231
+ cross-file/`var()` findings are marked `heuristic` when static evidence is
232
+ incomplete. Page-usage dead CSS still requires adapters / `pageUsage`.
233
+
234
+ ### GitHub Actions sketch
235
+
236
+ ```yaml
237
+ - name: CSS diagnostics
238
+ run: pnpm exec css-doctor check "src/**/*.css" --json --threshold 800
239
+
240
+ - name: CSS health gate
241
+ run: pnpm exec css-doctor health "src/**/*.css" --fail-under 80
242
+
243
+ - name: CSS regression gate
244
+ run: pnpm exec css-doctor diff "src/**/*.css" --fail-on-regression --fail-on-new-errors
245
+ ```
246
+
247
+ Initialize and commit `.css-doctor/baseline.json` on the default branch before
248
+ enabling the regression gate.
249
+
250
+ ## Command: `baseline`
251
+
252
+ ```text
253
+ css-doctor baseline create|show|validate|remove [options]
254
+ ```
255
+
256
+ Creates a versioned JSON baseline (default `.css-doctor/baseline.json`) with:
26
257
 
27
- # Machine-readable CI output
28
- pnpm exec css-doctor check "src/**/*.css" --json
258
+ - schema / tool versions and creation timestamp;
259
+ - overall + dimension Health Scores;
260
+ - aggregate size / rule / declaration counters;
261
+ - per-file content fingerprints (no CSS source stored);
262
+ - diagnostic fingerprints that ignore line-number drift.
29
263
 
30
- # Warn when a file has more than 500 selectors
31
- pnpm exec css-doctor check "src/**/*.css" --threshold 500
264
+ | Subcommand | Purpose |
265
+ | --- | --- |
266
+ | `create [patterns...]` | Analyze CSS and write the baseline (`-o/--output` for custom path) |
267
+ | `show` | Print baseline metadata and scores |
268
+ | `validate` | Check schema compatibility (hard fail vs soft tool-version warning) |
269
+ | `remove` | Delete the baseline file |
270
+
271
+ ## Command: `diff`
272
+
273
+ ```text
274
+ css-doctor diff [patterns...] [options]
32
275
  ```
33
276
 
277
+ Compares the current analysis against a stored baseline and classifies status as
278
+ `healthy` | `improved` | `regressed` | `mixed` | `inconclusive`.
279
+
280
+ | Option | Description |
281
+ | --- | --- |
282
+ | `-b, --baseline <path>` | Baseline path (default `.css-doctor/baseline.json`) |
283
+ | `--fail-on-regression` | Exit `1` when status is `regressed` or `mixed` |
284
+ | `--fail-on-new-errors` | Exit `1` when new error diagnostics appear |
285
+ | `--fail-on-new-diagnostics` | Exit `1` when any new diagnostics appear |
286
+ | `--max-size-increase <n%>` | Fail when total CSS bytes grow beyond the percent |
287
+ | `--max-new-errors <n>` | Fail when new error count exceeds `<n>` |
288
+ | `--max-new-warnings <n>` | Fail when new warning count exceeds `<n>` |
289
+ | `--min-score <n>` | Fail when current overall score is below `<n>` |
290
+ | `--score-tolerance <n>` | Ignore score deltas within absolute tolerance |
291
+ | `-v, --verbose` | Longer file / diagnostic lists |
292
+ | `-j, --json` | Stable regression JSON (`schemaVersion: 1`) |
293
+
294
+ Diagnostic matching uses `code|path|selector|severity` fingerprints so inserting
295
+ lines near the top of a file does not mark every later finding as new.
296
+
297
+ ### Project config
298
+
299
+ Optional `.css-doctor/config.json`:
300
+
301
+ ```json
302
+ {
303
+ "baseline": ".css-doctor/baseline.json",
304
+ "patterns": ["src/**/*.css"],
305
+ "regression": {
306
+ "enabled": true,
307
+ "scoreTolerance": 1,
308
+ "sizeIncreasePercent": 10,
309
+ "maxNewErrors": 0,
310
+ "maxNewWarnings": 5
311
+ },
312
+ "qualityGates": {
313
+ "minScore": 85,
314
+ "maxSizeIncreasePercent": 10,
315
+ "failOnRegression": true
316
+ }
317
+ }
318
+ ```
319
+
320
+ **Precedence:** CLI flags > config file > built-in defaults.
321
+
322
+ ### Exit codes (`diff` / `baseline`)
323
+
324
+ | Code | Meaning |
325
+ | --- | --- |
326
+ | `0` | Command succeeded and configured quality gates passed |
327
+ | `1` | Missing/invalid baseline, analysis failure, or a quality gate failed |
328
+
329
+ ## Command: `optimize` / `split`
330
+
331
+ ```text
332
+ css-doctor optimize|split [patterns...] [options]
333
+ ```
334
+
335
+ Runs the native two-tier pipeline (page coverage → size budget) and prints an
336
+ **optimization report** with structured decisions.
337
+
338
+ | Option | Description |
339
+ | --- | --- |
340
+ | `--dry-run` | Preview only (default unless `--write`) |
341
+ | `--write --out-dir <dir>` | Emit chunk CSS files under `<dir>` |
342
+ | `--explain` / `-v` | Show more decision detail |
343
+ | `--diff` | Concise unified diff of source vs emitted CSS |
344
+ | `--page-usage <json>` | Route → class map for coverage / DCE |
345
+ | `--min-page-ratio <n>` | Common threshold (0–1) |
346
+ | `--max-chunk-size <bytes>` | Size budget |
347
+ | `--no-page-coverage` / `--no-size-budget` / `--no-isolate-variables` / `--no-minify` | Disable stages |
348
+ | `-j, --json` / `--report <path>` | Stable JSON (`schemaVersion: 1`) |
349
+
350
+ **Metrics:** `bytesEliminated` is measured against a reference payload (common /
351
+ minified equivalent). `redistributedBytes` accounts for split duplication — chunk
352
+ sum vs input is **not** claimed as savings.
353
+
354
+ ## Command: `fix`
355
+
356
+ ```text
357
+ css-doctor fix [patterns...] [options]
358
+ css-doctor fix --list
359
+ ```
360
+
361
+ | Option | Description |
362
+ | --- | --- |
363
+ | `--list` | Show fix catalog with safety levels |
364
+ | `--dry-run` | Preview (default unless `--write`) |
365
+ | `--write` | Atomically apply Safe fixes to source files |
366
+ | `--rule <id>` | Limit to selected rule ids (repeatable) |
367
+ | `--backup` | Write `.bak` before modifying |
368
+ | `--diff` | Unified diff preview |
369
+ | `-j, --json` | Stable JSON |
370
+
371
+ ### Autofix safety
372
+
373
+ | Level | Default | Examples |
374
+ | --- | --- | --- |
375
+ | Safe | Applied with `--write` | `dead.empty-rule`, `duplicate.declaration` |
376
+ | Review | Never silent | `duplicate.selector` |
377
+ | Unsafe | Never applied | `variable.unused-definition` |
378
+
379
+ Safe transforms use LightningCSS AST rewrites and preserve cascade under the
380
+ documented conditions.
381
+
34
382
  ## Safety and limitations
35
383
 
36
- - The binary is named css-doctor and is exposed through the package bin field.
37
- - --json emits a stable CheckReport schema with files, issues, and summary counters.
38
- - Exit code is non-zero for fatal setup/read/analysis failures; warnings remain visible in the report.
384
+ - Binary name: `css-doctor` (package `bin` field).
385
+ - The CLI **analyzes** and **scores** CSS. Page-coverage splitting, size budgets,
386
+ and variable isolation for production bundles belong to the framework adapters.
387
+ - CSS Modules / dynamic class usage are out of scope for static checks; those
388
+ matter for build plugins.
389
+ - Native binding must resolve for your platform; no Rust toolchain is required
390
+ when a prebuilt binary is available.
39
391
 
40
392
  ## Full documentation
41
393