@ivanalbizu/astro-contrast 0.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 +21 -0
- package/README.md +436 -0
- package/bin/cli.mjs +2 -0
- package/dist/chunk-APMEU7CT.js +366 -0
- package/dist/chunk-G7ROW3VC.js +1869 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +247 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +12 -0
- package/dist/integration-xZSIPB3d.d.ts +112 -0
- package/dist/integration.d.ts +2 -0
- package/dist/integration.js +7 -0
- package/package.json +83 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ivanalbizu
|
|
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
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
# astro-contrast
|
|
2
|
+
|
|
3
|
+
WCAG color contrast analyzer for Astro components. Checks your `.astro` files for color contrast issues at build time, dev time, or on demand via CLI.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Parses `.astro` files and extracts color pairs (text color + background)
|
|
8
|
+
- Calculates WCAG 2.1 contrast ratios
|
|
9
|
+
- Supports hex, rgb, hsl, oklch, oklab, lab, lch, and named CSS colors (including alpha channels)
|
|
10
|
+
- **Large text detection** — applies lower WCAG thresholds for headings, large fonts, and bold text
|
|
11
|
+
- **Tailwind CSS support** — resolves `text-*` and `bg-*` utility classes
|
|
12
|
+
- Resolves CSS custom properties (`var(--color)`) from `:root`
|
|
13
|
+
- **Auto-detects external CSS** — `<link rel="stylesheet">` and `@import` are loaded automatically
|
|
14
|
+
- Reads external design tokens (Style Dictionary, Cobalt UI, Terrazzo)
|
|
15
|
+
- Ignore specific elements or rules with comments
|
|
16
|
+
- **GitHub Actions annotations** — contrast failures appear inline in PR diffs automatically
|
|
17
|
+
- **Dev dashboard** — visual contrast report in the browser during development
|
|
18
|
+
- Works as **CLI**, **Astro integration**, or **programmatic API**
|
|
19
|
+
- Watch mode for real-time analysis during development
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm install @ivanalbizu/astro-contrast
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### CLI
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
# Analyze all .astro files
|
|
33
|
+
astro-contrast "src/**/*.astro"
|
|
34
|
+
|
|
35
|
+
# With WCAG AAA level
|
|
36
|
+
astro-contrast "src/**/*.astro" --level aaa
|
|
37
|
+
|
|
38
|
+
# Show all pairs, not just failures
|
|
39
|
+
astro-contrast "src/**/*.astro" --verbose
|
|
40
|
+
|
|
41
|
+
# Watch mode
|
|
42
|
+
astro-contrast "src/**/*.astro" --watch
|
|
43
|
+
|
|
44
|
+
# With design tokens
|
|
45
|
+
astro-contrast "src/**/*.astro" --tokens tokens/colors.json
|
|
46
|
+
astro-contrast "src/**/*.astro" --tokens primitives.json --tokens semantic.json
|
|
47
|
+
|
|
48
|
+
# With external/global CSS
|
|
49
|
+
astro-contrast "src/**/*.astro" --css src/styles/global.css
|
|
50
|
+
astro-contrast "src/**/*.astro" --css variables.css --css theme.css
|
|
51
|
+
|
|
52
|
+
# JSON output
|
|
53
|
+
astro-contrast "src/**/*.astro" --json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### CLI Options
|
|
57
|
+
|
|
58
|
+
| Option | Description |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `--level aa\|aaa` | WCAG level to check (default: `aa`) |
|
|
61
|
+
| `--verbose`, `-v` | Show all pairs, not just failures |
|
|
62
|
+
| `--watch`, `-w` | Watch for file changes and re-analyze |
|
|
63
|
+
| `--tokens <file>` | Token file (JSON/YAML/CSS). Repeatable |
|
|
64
|
+
| `--css <file>` | External CSS file. Repeatable |
|
|
65
|
+
| `--ignore-color <val>` | Color to ignore globally. Repeatable |
|
|
66
|
+
| `--ignore-pair <val>` | Color pair to ignore (`fg:bg`). Repeatable |
|
|
67
|
+
| `--ignore-selector <sel>` | Selector to ignore (`.class`, `#id`, `tag`, `.prefix-*`). Repeatable |
|
|
68
|
+
| `--json` | Output results as JSON |
|
|
69
|
+
| `--help`, `-h` | Show help |
|
|
70
|
+
| `--version` | Show version |
|
|
71
|
+
|
|
72
|
+
#### Exit codes
|
|
73
|
+
|
|
74
|
+
| Code | Meaning |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `0` | All pairs pass the required level |
|
|
77
|
+
| `1` | At least one pair fails |
|
|
78
|
+
| `2` | Error during analysis |
|
|
79
|
+
|
|
80
|
+
### Astro Integration
|
|
81
|
+
|
|
82
|
+
Add `@ivanalbizu/astro-contrast` to your `astro.config.mjs`:
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
import { defineConfig } from 'astro/config';
|
|
86
|
+
import astroContrast from '@ivanalbizu/astro-contrast';
|
|
87
|
+
|
|
88
|
+
export default defineConfig({
|
|
89
|
+
integrations: [
|
|
90
|
+
astroContrast({
|
|
91
|
+
level: 'aa',
|
|
92
|
+
verbose: true,
|
|
93
|
+
css: ['src/styles/global.css'],
|
|
94
|
+
}),
|
|
95
|
+
],
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This runs contrast analysis automatically during `astro dev` (with file watching) and `astro build`.
|
|
100
|
+
|
|
101
|
+
#### Integration Options
|
|
102
|
+
|
|
103
|
+
| Option | Type | Default | Description |
|
|
104
|
+
|---|---|---|---|
|
|
105
|
+
| `level` | `'aa' \| 'aaa'` | `'aa'` | WCAG level to check |
|
|
106
|
+
| `verbose` | `boolean` | `false` | Show all pairs, not just failures |
|
|
107
|
+
| `failOnError` | `boolean` | `false` | Fail the build if contrast issues are found |
|
|
108
|
+
| `tokens` | `string[]` | `[]` | Paths to token files |
|
|
109
|
+
| `css` | `string[]` | `[]` | Paths to external CSS files |
|
|
110
|
+
| `ignore` | `IgnoreConfig` | `undefined` | Global ignore rules (see below) |
|
|
111
|
+
| `dashboard` | `boolean \| string` | `false` | Dev dashboard URL. `true` = `/_contrast`, string = custom path |
|
|
112
|
+
|
|
113
|
+
### Dev Dashboard
|
|
114
|
+
|
|
115
|
+
Enable the dashboard to view contrast results in the browser during development:
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
astroContrast({
|
|
119
|
+
dashboard: true, // available at http://localhost:4321/_contrast
|
|
120
|
+
})
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Or with a custom URL:
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
astroContrast({
|
|
127
|
+
dashboard: '/debug-astro-contrast',
|
|
128
|
+
})
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The dashboard shows all analyzed files with their color pairs, contrast ratios, and pass/fail status. It auto-refreshes every 2 seconds when you edit `.astro` files — no need to reload the page.
|
|
132
|
+
|
|
133
|
+
A JSON API is also available at `{dashboardUrl}/api` for programmatic access.
|
|
134
|
+
|
|
135
|
+
### Programmatic API
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { analyzeFile, analyzeFiles } from '@ivanalbizu/astro-contrast';
|
|
139
|
+
|
|
140
|
+
const result = await analyzeFile('src/components/Button.astro');
|
|
141
|
+
|
|
142
|
+
console.log(result.stats);
|
|
143
|
+
// { elementsAnalyzed: 2, pairsChecked: 2, passing: 1, aaFailing: 1, ... }
|
|
144
|
+
|
|
145
|
+
for (const cr of result.results) {
|
|
146
|
+
console.log(`${cr.element.tagName} — ${cr.ratio}:1 — ${cr.meetsAA ? 'PASS' : 'FAIL'}`);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
With external tokens:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { analyzeFiles } from '@ivanalbizu/astro-contrast';
|
|
154
|
+
import { readTokenFiles } from 'astro-contrast/dist/chunk-HPYGY3PW.js'; // internal
|
|
155
|
+
|
|
156
|
+
const tokens = await readTokenFiles(['tokens/colors.json']);
|
|
157
|
+
const results = await analyzeFiles(files, { externalTokens: tokens });
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Design Tokens
|
|
161
|
+
|
|
162
|
+
astro-contrast can read external design token files and resolve `var()` references against them. Supported formats:
|
|
163
|
+
|
|
164
|
+
### JSON — W3C DTCG / Style Dictionary
|
|
165
|
+
|
|
166
|
+
Compatible with [W3C Design Token Community Group](https://tr.designtokens.org/format/) format, used by Cobalt UI, Terrazzo, and Style Dictionary v4:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"color": {
|
|
171
|
+
"$type": "color",
|
|
172
|
+
"primary": {
|
|
173
|
+
"$value": "#1a5276"
|
|
174
|
+
},
|
|
175
|
+
"danger": {
|
|
176
|
+
"$value": "#e74c3c"
|
|
177
|
+
},
|
|
178
|
+
"info": {
|
|
179
|
+
"$value": "{color.primary}"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Also supports Style Dictionary v3 format (`value`/`type` without `$` prefix).
|
|
186
|
+
|
|
187
|
+
### YAML
|
|
188
|
+
|
|
189
|
+
Same structure as JSON, with `.yaml` or `.yml` extension:
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
color:
|
|
193
|
+
$type: color
|
|
194
|
+
primary:
|
|
195
|
+
$value: "#1a5276"
|
|
196
|
+
danger:
|
|
197
|
+
$value: "#e74c3c"
|
|
198
|
+
info:
|
|
199
|
+
$value: "{color.primary}"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### CSS
|
|
203
|
+
|
|
204
|
+
Plain CSS files with `:root` declarations:
|
|
205
|
+
|
|
206
|
+
```css
|
|
207
|
+
:root {
|
|
208
|
+
--color-primary: #1a5276;
|
|
209
|
+
--color-danger: #e74c3c;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### How tokens are mapped
|
|
214
|
+
|
|
215
|
+
Token paths are converted to CSS custom properties:
|
|
216
|
+
|
|
217
|
+
| Token path | CSS variable |
|
|
218
|
+
|---|---|
|
|
219
|
+
| `color.primary` | `--color-primary` |
|
|
220
|
+
| `color.primitives.blue.500` | `--color-primitives-blue-500` |
|
|
221
|
+
|
|
222
|
+
Token references (`{color.primary}`) are resolved recursively before mapping.
|
|
223
|
+
|
|
224
|
+
When a `.astro` file defines the same custom property in its `<style>` block, the in-file value takes priority over the external token.
|
|
225
|
+
|
|
226
|
+
## External / Global CSS
|
|
227
|
+
|
|
228
|
+
### Auto-detection
|
|
229
|
+
|
|
230
|
+
astro-contrast automatically detects and loads external CSS referenced in your `.astro` files via:
|
|
231
|
+
|
|
232
|
+
- **`import "./styles.css"`** — in the frontmatter (component script)
|
|
233
|
+
- **`<link rel="stylesheet" href="./styles.css">`** — in the HTML template
|
|
234
|
+
- **`@import './tokens.css'`** — inside `<style>` blocks
|
|
235
|
+
|
|
236
|
+
This works recursively: if `a.css` imports `b.css` which imports `c.css`, all three are loaded. Circular imports are handled safely.
|
|
237
|
+
|
|
238
|
+
Only relative paths (`./`, `../`) are resolved. Absolute URLs (`http://`, `https://`) and package imports are skipped.
|
|
239
|
+
|
|
240
|
+
### Manual `--css` flag
|
|
241
|
+
|
|
242
|
+
For CSS files that aren't referenced directly in `.astro` files (e.g. injected by a build tool), use `--css` (CLI) or `css` (integration):
|
|
243
|
+
|
|
244
|
+
```sh
|
|
245
|
+
astro-contrast "src/**/*.astro" --css src/styles/global.css --css src/styles/variables.css
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
External CSS files provide:
|
|
249
|
+
- **CSS rules** — selectors and declarations (e.g. `.heading { color: #1a5276; }`)
|
|
250
|
+
- **Custom properties** — `:root` variables (e.g. `--color-primary: #1a5276`)
|
|
251
|
+
|
|
252
|
+
**Priority order**: external tokens < auto-detected CSS < manual `--css` < in-file `:root` / `<style>`. In-file styles always win at equal specificity.
|
|
253
|
+
|
|
254
|
+
## Tailwind CSS
|
|
255
|
+
|
|
256
|
+
astro-contrast detects Tailwind utility classes and resolves them to colors using the default Tailwind v3 palette. No configuration needed.
|
|
257
|
+
|
|
258
|
+
**Supported patterns:**
|
|
259
|
+
|
|
260
|
+
```astro
|
|
261
|
+
<!-- Standard palette colors -->
|
|
262
|
+
<button class="text-white bg-blue-700">Submit</button>
|
|
263
|
+
|
|
264
|
+
<!-- Arbitrary values -->
|
|
265
|
+
<p class="text-[#1a5276] bg-[#d4e6f1]">Custom colors</p>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
| Pattern | Example | Resolves to |
|
|
269
|
+
|---|---|---|
|
|
270
|
+
| `text-{color}-{shade}` | `text-blue-500` | `color: #3b82f6` |
|
|
271
|
+
| `bg-{color}-{shade}` | `bg-red-600` | `background-color: #dc2626` |
|
|
272
|
+
| `text-white` / `text-black` | `text-white` | `color: #ffffff` |
|
|
273
|
+
| `text-[value]` | `text-[#1a5276]` | `color: #1a5276` |
|
|
274
|
+
| `bg-[value]` | `bg-[rgb(26,82,118)]` | `background-color: rgb(26,82,118)` |
|
|
275
|
+
|
|
276
|
+
**Priority order**: inline styles > Tailwind classes > CSS rules > defaults.
|
|
277
|
+
|
|
278
|
+
**Not yet supported**: responsive variants (`md:text-white`), state variants (`hover:bg-blue-500`), opacity modifiers (`text-blue-500/50`), custom Tailwind config.
|
|
279
|
+
|
|
280
|
+
## Ignoring Elements
|
|
281
|
+
|
|
282
|
+
You can skip specific elements or CSS rules from contrast analysis using ignore comments.
|
|
283
|
+
|
|
284
|
+
### HTML comment
|
|
285
|
+
|
|
286
|
+
Place `<!-- astro-contrast-ignore -->` before the element to skip:
|
|
287
|
+
|
|
288
|
+
```astro
|
|
289
|
+
<p class="decorative">This is checked</p>
|
|
290
|
+
<!-- astro-contrast-ignore -->
|
|
291
|
+
<p class="decorative">This is skipped</p>
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### HTML attribute
|
|
295
|
+
|
|
296
|
+
Add `data-contrast-ignore` to the element:
|
|
297
|
+
|
|
298
|
+
```astro
|
|
299
|
+
<span class="badge" data-contrast-ignore>Decorative badge</span>
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### CSS comment
|
|
303
|
+
|
|
304
|
+
Place `/* astro-contrast-ignore */` before a CSS rule to skip it:
|
|
305
|
+
|
|
306
|
+
```css
|
|
307
|
+
.alert {
|
|
308
|
+
color: #fff;
|
|
309
|
+
background-color: #e74c3c;
|
|
310
|
+
}
|
|
311
|
+
/* astro-contrast-ignore */
|
|
312
|
+
.decorative {
|
|
313
|
+
color: #ccc;
|
|
314
|
+
background-color: #ddd;
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Global Ignore Rules
|
|
319
|
+
|
|
320
|
+
For repetitive patterns like brand colors that intentionally fail contrast, use global ignore rules instead of per-element comments.
|
|
321
|
+
|
|
322
|
+
#### Astro Integration
|
|
323
|
+
|
|
324
|
+
```js
|
|
325
|
+
astroContrast({
|
|
326
|
+
ignore: {
|
|
327
|
+
colors: ['#e74c3c'], // ignore this color everywhere
|
|
328
|
+
pairs: [{ foreground: '#ffffff', background: '#e74c3c' }], // ignore this exact pair
|
|
329
|
+
selectors: ['.brand-badge', '.alert-*'], // ignore matching elements
|
|
330
|
+
}
|
|
331
|
+
})
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
#### CLI
|
|
335
|
+
|
|
336
|
+
```sh
|
|
337
|
+
# Ignore a color globally (repeatable)
|
|
338
|
+
astro-contrast "src/**/*.astro" --ignore-color "#e74c3c"
|
|
339
|
+
|
|
340
|
+
# Ignore a specific foreground:background pair (repeatable)
|
|
341
|
+
astro-contrast "src/**/*.astro" --ignore-pair "#ffffff:#e74c3c"
|
|
342
|
+
|
|
343
|
+
# Ignore elements by selector, supports * wildcards (repeatable)
|
|
344
|
+
astro-contrast "src/**/*.astro" --ignore-selector ".brand-badge" --ignore-selector ".alert-*"
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
| Rule type | What it does |
|
|
348
|
+
|---|---|
|
|
349
|
+
| `colors` | Ignores any pair where the color appears as foreground **or** background |
|
|
350
|
+
| `pairs` | Ignores only when both foreground and background match exactly |
|
|
351
|
+
| `selectors` | Ignores elements matching `.class`, `#id`, `tag`, or wildcard patterns like `.prefix-*` |
|
|
352
|
+
|
|
353
|
+
Colors are compared by their resolved RGB value — `#e74c3c` and `rgb(231, 76, 60)` are treated as the same color.
|
|
354
|
+
|
|
355
|
+
## CI / GitHub Actions
|
|
356
|
+
|
|
357
|
+
When running in GitHub Actions, astro-contrast automatically emits annotations that appear inline in pull request diffs. No configuration needed — it detects the `GITHUB_ACTIONS` environment variable.
|
|
358
|
+
|
|
359
|
+
Contrast failures appear as error annotations on the exact line of the failing element.
|
|
360
|
+
|
|
361
|
+
**Example workflow:**
|
|
362
|
+
|
|
363
|
+
```yaml
|
|
364
|
+
- name: Check contrast
|
|
365
|
+
run: astro-contrast "src/**/*.astro"
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
If the check fails (exit code 1), the PR will show annotations like:
|
|
369
|
+
|
|
370
|
+
> **Error** src/components/Card.astro#L7
|
|
371
|
+
> Contrast 2.8:1 fails AA (requires 4.5:1) — #999999 on #ffffff (.card-meta)
|
|
372
|
+
|
|
373
|
+
When using `--level aaa`, pairs that pass AA but fail AAA appear as warnings instead of errors.
|
|
374
|
+
|
|
375
|
+
## How It Works
|
|
376
|
+
|
|
377
|
+
1. **Parse** — Reads `.astro` files using `@astrojs/compiler` and extracts HTML elements, `<style>` blocks, `<link>` hrefs, and `@import` references
|
|
378
|
+
2. **Extract CSS** — Parses style blocks with PostCSS to get selectors, color declarations, and `:root` custom properties. Auto-loads CSS from `<link>` and `@import` recursively
|
|
379
|
+
3. **Resolve** — Resolves `var()` references using custom properties from `:root`, auto-detected CSS, external CSS files, and/or design tokens
|
|
380
|
+
4. **Match** — Matches HTML elements to CSS rules by selector (type, class, ID, compound) and resolves Tailwind utility classes
|
|
381
|
+
5. **Evaluate** — Calculates WCAG 2.1 contrast ratio for each foreground/background pair
|
|
382
|
+
6. **Report** — Outputs results with pass/fail status for AA and AAA levels
|
|
383
|
+
|
|
384
|
+
## WCAG 2.1 Contrast Requirements
|
|
385
|
+
|
|
386
|
+
| Level | Normal text | Large text |
|
|
387
|
+
|---|---|---|
|
|
388
|
+
| **AA** | 4.5:1 | 3:1 |
|
|
389
|
+
| **AAA** | 7:1 | 4.5:1 |
|
|
390
|
+
|
|
391
|
+
> **Large text** is defined as ≥ 18px, or ≥ 14px bold (font-weight ≥ 700). astro-contrast detects font size from inline styles, CSS rules, Tailwind classes (`text-xl`, `font-bold`, etc.), and HTML heading defaults (`<h1>`–`<h4>`).
|
|
392
|
+
>
|
|
393
|
+
> Viewport-dependent values (`vw`, `vh`) and CSS functions (`clamp()`, `min()`, `max()`, `calc()`) cannot be resolved statically. When the font size cannot be determined, astro-contrast defaults to **normal text** thresholds — the stricter requirement — to avoid false passes.
|
|
394
|
+
|
|
395
|
+
## Example Output
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
src/components/atoms/Button.astro
|
|
399
|
+
PASS .btn-primary L5 #ffffff on #1a5276 → 8.4:1 (AA ✓ AAA ✓)
|
|
400
|
+
PASS .btn-danger L6 #ffffff on #514f4f → 8.1:1 (AA ✓ AAA ✓)
|
|
401
|
+
|
|
402
|
+
src/components/molecules/Card.astro
|
|
403
|
+
PASS .card-title L6 #1a1a1a on #ffffff → 17.4:1 (AA ✓ AAA ✓) [large]
|
|
404
|
+
FAIL .card-meta L7 #999999 on #ffffff → 2.8:1 (AA requires 4.5:1)
|
|
405
|
+
PASS .card-body L8 #333333 on #ffffff → 12.6:1 (AA ✓ AAA ✓)
|
|
406
|
+
|
|
407
|
+
Summary:
|
|
408
|
+
Files analyzed: 2
|
|
409
|
+
Color pairs checked: 5
|
|
410
|
+
Passing: 4 | Failing: 1
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## Development Scripts
|
|
414
|
+
|
|
415
|
+
| Script | Description |
|
|
416
|
+
|---|---|
|
|
417
|
+
| `npm run build` | Build with tsup |
|
|
418
|
+
| `npm run dev` | Build in watch mode |
|
|
419
|
+
| `npm test` | Run tests |
|
|
420
|
+
| `npm run test:watch` | Tests in watch mode |
|
|
421
|
+
| `npm run typecheck` | TypeScript check (`tsc --noEmit`) |
|
|
422
|
+
| `npm run prepublishOnly` | Runs typecheck + test + build (auto on `npm publish`) |
|
|
423
|
+
|
|
424
|
+
## Current Limitations
|
|
425
|
+
|
|
426
|
+
- **Background inheritance (same file)** — Child elements inherit `background-color` from ancestor elements within the same `.astro` file (inline styles, Tailwind classes, and CSS rules). Cross-file inheritance (e.g. layout → page) requires `--css`
|
|
427
|
+
- **No pseudo-classes** — `:hover`, `:focus`, `:active` states are not analyzed. Only base-state selectors are matched (planned for a future release)
|
|
428
|
+
- **Simple selectors only** — Supports type, class, ID, and compound selectors. No combinators or media queries
|
|
429
|
+
- **No dynamic font sizes** — `clamp()`, `min()`, `max()`, `calc()`, and viewport units (`vw`, `vh`) cannot be resolved; text is treated as normal size (stricter threshold)
|
|
430
|
+
- **No SCSS/SASS/Less** — Only plain CSS in `<style>` blocks is supported. Preprocessor syntax (`$variables`, nesting, `@mixin`) is not parsed. Colors defined via preprocessors can still be analyzed if compiled to CSS custom properties and loaded with `--css`
|
|
431
|
+
- **Partial alpha compositing** — Foreground colors with alpha (`rgba`, `hsla`, hex8) are composited onto the background. Background alpha, CSS `opacity`, and nested opacity require CSS inheritance and are not supported
|
|
432
|
+
- **No dark mode / theme scopes** — Only `:root` and `html` custom properties are extracted. Variables under `[data-theme="dark"]`, `.dark`, or `@media (prefers-color-scheme: dark)` are not resolved. Workaround: use separate CSS files per theme and run with `--css themes/light.css` or `--css themes/dark.css`
|
|
433
|
+
|
|
434
|
+
## License
|
|
435
|
+
|
|
436
|
+
MIT
|
package/bin/cli.mjs
ADDED