Skip to content

Commit 796b469

Browse files
chenglouclaude
andcommitted
Add knip dead-code scan to check
Wires knip into `bun run check` and removes the three exports it flagged on the first run: `getSegmentGraphemeWidths` (no callers), `walkPreparedLines` plus its `InternalLayoutLine` type (only the test used it, and only as a pass-through to `walkPreparedLinesRaw`), and `unicodeBidiDataVersion` from the generated bidi data and its generator (Unicode version is already in the file header). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 18770ad commit 796b469

9 files changed

Lines changed: 168 additions & 54 deletions

File tree

DEVELOPMENT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ bun install
1010

1111
- `bun start` — stable local page server at <http://localhost:3000>
1212
- `bun run start:windows` — Windows-friendly fallback without automatic port cleanup
13-
- `bun run check` — typecheck plus lint
13+
- `bun run check` — typecheck, lint, and dead-code scan (`knip`)
1414
- `bun test` — small durable invariant suite
1515

1616
### Packaging And Release Confidence

bun.lock

Lines changed: 131 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

knip.config.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { KnipConfig } from 'knip'
2+
3+
// Test files are in `ignore` so their imports don't count as "usage", flagging exports used only by test files as unused.
4+
// Tradeoff: dead code & exports within test files won't be detected. See: https://github.com/webpro-nl/knip/issues/1374. This is acceptable
5+
const config: KnipConfig = {
6+
entry: [
7+
// Library entry points — match the `exports` field in package.json
8+
'src/layout.ts',
9+
'src/rich-inline.ts',
10+
// Scripts invoked via package.json
11+
'scripts/**/*.ts',
12+
// Browser pages and demos — each `pages/**/*.ts` is the target of a `<script type="module" src="…">` in a sibling `.html`
13+
'pages/**/*.ts',
14+
],
15+
ignore: [
16+
'src/layout.test.ts', // Exclude tests so their imports don't count as "usage"
17+
],
18+
ignoreDependencies: [
19+
'tsgolint', // Type-aware checker invoked by `oxlint --type-aware` via oxlint-tsgolint
20+
],
21+
ignoreBinaries: [
22+
// Used in package.json scripts
23+
'lsof',
24+
],
25+
// slightly confusing config. We detect dead code just fine
26+
// this one's just to silence exported types and values that aren't used elsewhere but that are still used within their file
27+
// yelling on unnecessary exports is a bit noisy so we turn it off
28+
ignoreExportsUsedInFile: true,
29+
}
30+
31+
export default config

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"benchmark-check": "bun run scripts/benchmark-check.ts",
5656
"benchmark-check:safari": "BENCHMARK_CHECK_BROWSER=safari bun run scripts/benchmark-check.ts",
5757
"build:package": "rm -rf dist && tsc -p tsconfig.build.json",
58-
"check": "tsc && oxlint --type-aware src",
58+
"check": "tsc && oxlint --type-aware src && knip",
5959
"corpus-check": "bun run scripts/corpus-check.ts",
6060
"corpus-check:safari": "CORPUS_CHECK_BROWSER=safari bun run scripts/corpus-check.ts",
6161
"corpus-font-matrix": "bun run scripts/corpus-font-matrix.ts",
@@ -82,6 +82,7 @@
8282
},
8383
"devDependencies": {
8484
"@types/bun": "latest",
85+
"knip": "^6.14.2",
8586
"marked": "^17.0.5",
8687
"oxlint": "^1.51.0",
8788
"oxlint-tsgolint": "^0.15.0",

scripts/generate-bidi-data.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,6 @@ export type GeneratedBidiType =
198198
| 'WS'
199199
| 'NSM'
200200
201-
export const unicodeBidiDataVersion = '${payload.unicodeVersion}'
202-
203201
export const latin1BidiTypes: readonly GeneratedBidiType[] = [
204202
${latin1Rows},
205203
]

src/generated/bidi-data.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ export type GeneratedBidiType =
1919
| 'WS'
2020
| 'NSM'
2121

22-
export const unicodeBidiDataVersion = '17.0.0'
23-
2422
export const latin1BidiTypes: readonly GeneratedBidiType[] = [
2523
'BN',
2624
'BN',

src/layout.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ let setLocale: LayoutModule['setLocale']
3030
let countPreparedLines: LineBreakModule['countPreparedLines']
3131
let measurePreparedLineGeometry: LineBreakModule['measurePreparedLineGeometry']
3232
let stepPreparedLineGeometry: LineBreakModule['stepPreparedLineGeometry']
33-
let walkPreparedLines: LineBreakModule['walkPreparedLines']
33+
let walkPreparedLinesRaw: LineBreakModule['walkPreparedLinesRaw']
3434
let getSegmentBreakableFitAdvances: MeasurementModule['getSegmentBreakableFitAdvances']
3535
let prepareRichInline: RichInlineModule['prepareRichInline']
3636
let layoutNextRichInlineLineRange: RichInlineModule['layoutNextRichInlineLineRange']
@@ -290,7 +290,7 @@ beforeAll(async () => {
290290
clearCache,
291291
setLocale,
292292
} = mod)
293-
;({ countPreparedLines, measurePreparedLineGeometry, stepPreparedLineGeometry, walkPreparedLines } = lineBreakMod)
293+
;({ countPreparedLines, measurePreparedLineGeometry, stepPreparedLineGeometry, walkPreparedLinesRaw } = lineBreakMod)
294294
;({ getSegmentBreakableFitAdvances } = measurementMod)
295295
;({ prepareRichInline, layoutNextRichInlineLineRange, materializeRichInlineLineRange, measureRichInlineStats, walkRichInlineLineRanges } = richInlineMod)
296296
})
@@ -1673,7 +1673,7 @@ describe('layout invariants', () => {
16731673
for (let widthIndex = 0; widthIndex < widths.length; widthIndex++) {
16741674
const width = widths[widthIndex]!
16751675
const counted = countPreparedLines(prepared, width)
1676-
const walked = walkPreparedLines(prepared, width)
1676+
const walked = walkPreparedLinesRaw(prepared, width)
16771677
expect(counted).toBe(walked)
16781678
}
16791679
}

src/line-break.ts

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,6 @@ export type PreparedLineBreakData = {
2525
}[]
2626
}
2727

28-
export type InternalLayoutLine = {
29-
startSegmentIndex: number
30-
startGraphemeIndex: number
31-
endSegmentIndex: number
32-
endGraphemeIndex: number
33-
width: number
34-
}
35-
3628
type InternalLineVisitor = (
3729
width: number,
3830
startSegmentIndex: number,
@@ -792,28 +784,6 @@ export function walkPreparedLinesRaw(
792784
return lineCount
793785
}
794786

795-
export function walkPreparedLines(
796-
prepared: PreparedLineBreakData,
797-
maxWidth: number,
798-
onLine?: (line: InternalLayoutLine) => void,
799-
): number {
800-
if (onLine === undefined) return walkPreparedLinesRaw(prepared, maxWidth)
801-
802-
return walkPreparedLinesRaw(
803-
prepared,
804-
maxWidth,
805-
(width, startSegmentIndex, startGraphemeIndex, endSegmentIndex, endGraphemeIndex) => {
806-
onLine({
807-
startSegmentIndex,
808-
startGraphemeIndex,
809-
endSegmentIndex,
810-
endGraphemeIndex,
811-
width,
812-
})
813-
},
814-
)
815-
}
816-
817787
function stepPreparedChunkLineGeometry(
818788
prepared: PreparedLineBreakData,
819789
cursor: LineBreakCursor,

src/measurement.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -182,21 +182,6 @@ export function getCorrectedSegmentWidth(seg: string, metrics: SegmentMetrics, e
182182
return metrics.width - getEmojiCount(seg, metrics) * emojiCorrection
183183
}
184184

185-
export function getSegmentGraphemeWidths(
186-
seg: string,
187-
cache: Map<string, SegmentMetrics>,
188-
emojiCorrection: number,
189-
): number[] | null {
190-
const widths: number[] = []
191-
const graphemeSegmenter = getSharedGraphemeSegmenter()
192-
for (const gs of graphemeSegmenter.segment(seg)) {
193-
const graphemeMetrics = getSegmentMetrics(gs.segment, cache)
194-
widths.push(getCorrectedSegmentWidth(gs.segment, graphemeMetrics, emojiCorrection))
195-
}
196-
197-
return widths.length > 1 ? widths : null
198-
}
199-
200185
export function getSegmentBreakableFitAdvances(
201186
seg: string,
202187
metrics: SegmentMetrics,

0 commit comments

Comments
 (0)