Exclude (scan scope)
exclude controls what the source scanner skips before extraction. It is part of core config shape, so it applies consistently across CLI commands and other clients that pass config to core.
Why use it
- Narrow scan scope to product code.
- Drop generated/vendor/test-heavy trees.
- Reduce dynamic-site noise and improve runtime performance.
Config shape
import { defineConfig, type I18nPruneConfig } from 'i18nprune/core/config';
export default defineConfig({
source: 'en',
localesDir: 'locales',
src: '.',
functions: ['t'],
exclude: {
preset: 'production',
dirs: ['fixtures'],
files: [/\.gen\./],
extensions: ['d.ts'],
patterns: [/^src\/generated\//],
useDefaultSkip: true,
},
} satisfies Partial<I18nPruneConfig>);Precedence (merge order)
When the scanner runs, rules are built in this order:
- Built-in directory skip list — applied when
useDefaultSkip !== false(e.g.node_modules,dist,build,.git, …). Turn off withuseDefaultSkip: falsein config. exclude.preset— expands to that preset’sdirs,files,extensions, andpatterns(see below).- Config file — your explicit
dirs,files,extensions, andpatternsare appended after the preset lists for each field (preset first, then config). - CLI globals —
--exclude a,bappends directory basenames toexclude.dirsafter the config file’s lists (deduped).
So: CLI overrides apply to default-skip and extra dirs; config extends preset lists; preset is the curated baseline.
Debug scan (global)
The scanner emits structured ScanDebugEvent objects (skip_directory | skip_file with relativePath, basename, reason). Core never writes to console — it only calls an optional listener so the package stays runtime-agnostic.
- CLI:
--debug-scanregistersRunOptions.onScanDebugfor the process; the CLI prints each event with the normal logger prefix as[i18nprune] [scan] skip dir|file …(same channel as[warn]). Suppressed when--silentor--jsonis set. - API: set
onScanDebugonRunOptions(viasetRunOptions) and/or passonScanDebugas the fourth argument tolistSourceFiles(per-call listener wins over the global one). Same field exists onscanProjectSourceFilesinput asscanDebug.
Use this to tune exclude.patterns, dirs, and --exclude without guessing which rule fired, or to pipe events into your own logger, UI, or tests.
Commands that combine literal key extraction + dynamic call-site scanning can still walk src/ more than once in a single run (for example buildProjectReportDocument intentionally runs scanProjectKeyObservations and scanProjectDynamicKeySites as separate passes — they answer different questions). i18nprune sync reuses one cached project-report build for both its reference context and dynamicSites, so you should not see the same file skip line repeated separately for buildKeyReferenceContext and again for resolveLocalesDynamicSites anymore.
Preset
Currently available:
production
production preset contents
Built-in defaults (merged before your explicit lists):
dirs:node_modules,dist,build,compiled,tests,benchfiles:pnpm-lock.yaml,package-lock.json,yarn.lockextensions:test.ts,test.tsx,spec.ts,spec.tsx,test.js,test.jsx,spec.js,spec.jsx— these match basename suffixes (e.g.foo.test.tsmatches thetest.tstoken), similar in intent to glob patterns like*.test.*/*.spec.*.
i18nprune init writes preset: 'production' in the starter config so new projects adopt this baseline in one line.
CLI merge behavior
Global --exclude <list> appends directory basenames to exclude.dirs from config.
- Config + CLI are combined before context is passed to core.
- Duplicates are removed in order for string rules.
- Use
exclude.useDefaultSkip: falsein config to disable built-in skips.
Examples:
i18nprune validate --exclude bench,compiled
i18nprune report --exclude testsRuntime impact
Narrowing the scan (especially src, preset: 'production', and extra dirs / patterns) reduces file counts and wall time.
Use cache diagnostics and cold/warm comparisons from:
Guidance
- Prefer
preset: 'production'as baseline, then add project-specific rules. - Keep
patternsfocused and anchored where possible. - If results look noisy, first tighten
src, then refineexclude.