Skip to content

Commit 9ac5bbe

Browse files
committed
fix(icons): make precision exceptions local
1 parent 7de9cbb commit 9ac5bbe

5 files changed

Lines changed: 337 additions & 304 deletions

File tree

.github/workflows/test-build.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,16 @@ jobs:
123123
- name: Repo audits
124124
run: bun run check:audits
125125

126+
- name: Check SVG icon path precision
127+
run: |
128+
if [ "${{ github.event_name }}" = "pull_request" ]; then
129+
BASE_REF="origin/${{ github.base_ref }}"
130+
git fetch --depth=1 origin "${{ github.base_ref }}" 2>/dev/null || true
131+
else
132+
BASE_REF="HEAD~1"
133+
fi
134+
bun run check:icon-path-precision "$BASE_REF"
135+
126136
- name: Migration safety (zero-downtime) audit
127137
run: |
128138
if [ "${{ github.event_name }}" = "pull_request" ]; then

scripts/check-icon-path-precision.baseline.json

Lines changed: 0 additions & 160 deletions
This file was deleted.

scripts/check-icon-path-precision.test.ts

Lines changed: 72 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { describe, expect, it } from 'vitest'
22
import {
3-
comparePrecisionBaseline,
4-
createPrecisionBaseline,
3+
analyzeIconSource,
54
effectiveFractionDigits,
5+
findNewPrecisionCandidates,
66
findPrecisionCandidates,
77
} from './check-icon-path-precision'
88

@@ -23,7 +23,10 @@ describe('icon path precision audit', () => {
2323
}
2424
`
2525

26-
expect(findPrecisionCandidates(source, FIXTURE_PATH)).toEqual([])
26+
expect(analyzeIconSource(source, FIXTURE_PATH)).toEqual({
27+
candidates: [],
28+
invalidExceptions: [],
29+
})
2730
})
2831

2932
it('finds ordinary decimals and exponents finer than a hundredth', () => {
@@ -58,59 +61,90 @@ describe('icon path precision audit', () => {
5861
expect(findPrecisionCandidates(source, FIXTURE_PATH)).toHaveLength(2)
5962
})
6063

61-
it('ratchets exact legacy paths and rejects new duplicates', () => {
62-
const original = `
63-
export function LegacyIcon() {
64-
return <svg><path d='M0.123 1' /></svg>
64+
it('accepts a reasoned TSDoc exception on the immediately following path', () => {
65+
const source = `
66+
export function PreciseBrandIcon() {
67+
return (
68+
<svg>
69+
{/**
70+
* svg-path-precision-exception: Rounding visibly distorts the provider-authored mark.
71+
*/}
72+
<path d='M0.1234 1' />
73+
</svg>
74+
)
6575
}
6676
`
67-
const originalCandidates = findPrecisionCandidates(original, FIXTURE_PATH)
68-
const baseline = createPrecisionBaseline(originalCandidates)
6977

70-
expect(comparePrecisionBaseline(originalCandidates, baseline)).toEqual({
71-
unbaselined: [],
72-
staleBaseline: [],
78+
expect(analyzeIconSource(source, FIXTURE_PATH)).toEqual({
79+
candidates: [],
80+
invalidExceptions: [],
7381
})
82+
})
7483

75-
const duplicate = `
76-
export function LegacyIcon() {
77-
return <svg><path d='M0.123 1' /><path d='M0.123 1' /></svg>
84+
it('rejects exceptions without a reason and exceptions on already-clean paths', () => {
85+
const missingReason = `
86+
export function PreciseIcon() {
87+
return <svg>{/** svg-path-precision-exception: */}<path d='M0.123 1' /></svg>
7888
}
7989
`
80-
const comparison = comparePrecisionBaseline(
81-
findPrecisionCandidates(duplicate, FIXTURE_PATH),
82-
baseline
83-
)
84-
expect(comparison.unbaselined).toHaveLength(1)
85-
expect(comparison.staleBaseline).toEqual([])
90+
const unnecessary = `
91+
export function CleanIcon() {
92+
return <svg>{/** svg-path-precision-exception: Keep detail. */}<path d='M0.12 1' /></svg>
93+
}
94+
`
95+
96+
const missingReasonAnalysis = analyzeIconSource(missingReason, FIXTURE_PATH)
97+
expect(missingReasonAnalysis.candidates).toHaveLength(1)
98+
expect(missingReasonAnalysis.invalidExceptions[0]?.message).toContain('specific reason')
99+
100+
const unnecessaryAnalysis = analyzeIconSource(unnecessary, FIXTURE_PATH)
101+
expect(unnecessaryAnalysis.candidates).toEqual([])
102+
expect(unnecessaryAnalysis.invalidExceptions[0]?.message).toContain('unnecessary')
86103
})
87104

88-
it('makes the baseline stale when legacy debt is changed or removed', () => {
89-
const original = `
105+
it('grandfathers exact paths from the target branch but rejects additions and edits', () => {
106+
const base = `
90107
export function LegacyIcon() {
91108
return <svg><path d='M0.123 1' /></svg>
92109
}
93110
`
94-
const baseline = createPrecisionBaseline(findPrecisionCandidates(original, FIXTURE_PATH))
95-
const changed = `
111+
const unchanged = findPrecisionCandidates(base, FIXTURE_PATH)
112+
expect(findNewPrecisionCandidates(unchanged, unchanged)).toEqual([])
113+
114+
const duplicate = `
96115
export function LegacyIcon() {
97-
return <svg><path d='M0.1234 1' /></svg>
116+
return <svg><path d='M0.123 1' /><path d='M0.123 1' /></svg>
98117
}
99118
`
119+
expect(
120+
findNewPrecisionCandidates(findPrecisionCandidates(duplicate, FIXTURE_PATH), unchanged)
121+
).toHaveLength(1)
100122

101-
const changedComparison = comparePrecisionBaseline(
102-
findPrecisionCandidates(changed, FIXTURE_PATH),
103-
baseline
104-
)
105-
expect(changedComparison.unbaselined).toHaveLength(1)
106-
expect(changedComparison.staleBaseline).toHaveLength(1)
123+
const changed = base.replace('0.123', '0.1234')
124+
expect(
125+
findNewPrecisionCandidates(findPrecisionCandidates(changed, FIXTURE_PATH), unchanged)
126+
).toHaveLength(1)
127+
})
107128

108-
const cleaned = original.replace('0.123', '0.12')
109-
const cleanedComparison = comparePrecisionBaseline(
110-
findPrecisionCandidates(cleaned, FIXTURE_PATH),
111-
baseline
129+
it('requires a committed exception to remain while its precise path remains', () => {
130+
const excepted = `
131+
export function PreciseBrandIcon() {
132+
return (
133+
<svg>
134+
{/** svg-path-precision-exception: Rounding visibly distorts the brand mark. */}
135+
<path d='M0.1234 1' />
136+
</svg>
137+
)
138+
}
139+
`
140+
const exceptionRemoved = excepted.replace(
141+
'{/** svg-path-precision-exception: Rounding visibly distorts the brand mark. */}',
142+
''
112143
)
113-
expect(cleanedComparison.unbaselined).toEqual([])
114-
expect(cleanedComparison.staleBaseline).toHaveLength(1)
144+
145+
expect(findPrecisionCandidates(excepted, FIXTURE_PATH)).toEqual([])
146+
expect(
147+
findNewPrecisionCandidates(findPrecisionCandidates(exceptionRemoved, FIXTURE_PATH), [])
148+
).toHaveLength(1)
115149
})
116150
})

0 commit comments

Comments
 (0)