/*
Canonical CSS value normalizer shared by biome.css.generate (codegen) and
biome.tokens.validate (drift detection). Whitespace collapsing, quote
normalisation, hex lowercasing, and trailing-zero stripping are applied in a
single deterministic order so that generated CSS and drift comparisons never
disagree on equality.
- Do not format CSS for emission — line-breaking is the caller's job.
- Do not parse CSS structure — this is a string-level transform only.
- RFC-1097: step 6 — compass.migrate codemod run
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.
- RFC-1097: sweep — werkstatt-engine clean
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.
*/
/**
* Normalize a CSS value string for stable comparison and emission.
*
* Applies (in order):
* 1. Whitespace collapse + trim (multi-line gradients become single-line)
* 2. Parenthesis spacing removal
* 3. Single → double quote conversion
* 4. Hex color lowercasing
* 5. Trailing decimal zero stripping
*/
export function normalizeCssValue(value: string): string {
return (
value
// Collapse all whitespace runs (handles multi-line gradient formatting)
.replace(/\s+/g, " ")
.trim()
// Remove spaces immediately after ( and before ) so gradient args align
.replace(/\(\s+/g, "(")
.replace(/\s+\)/g, ")")
// CSS strings: double quotes
.replace(/'([^']*)'/g, '"$1"')
// Hex colors: lowercase
.replace(/#([0-9A-Fa-f]+)/g, (_m, hex) => `#${hex.toLowerCase()}`)
// Strip trailing decimal zeros (e.g. 20.40px → 20.4px, 1.10 → 1.1)
.replace(/(\d+\.\d*[1-9])0+/g, "$1")
// Strip redundant .0 suffix (e.g. 1.0 → 1, 0.0 → 0)
.replace(/(\d+)\.0+(?!\d)/g, "$1")
);
}