summaryrefslogtreecommitdiff
path: root/config/detekt/detekt.yml
blob: baea31858780db3b130630fb46793f5ba1d3454e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# Builds on detekt's default ruleset (see app/build.gradle.kts: buildUponDefaultConfig = true).
# Only overrides/additions relative to the defaults belong here -- keep this file small so
# upgrading detekt pulls in sane new defaults automatically instead of us silently diverging.

style:
  MagicNumber:
    ignorePropertyDeclaration: true # assigning a literal to a named property IS the fix this
    # rule asks for -- `private val SPEEDS = listOf(1.0f, 1.25f, ...)` is named data, and
    # exploding each element into its own constant would make it less readable, not more.
  ReturnCount:
    max: 5 # the feed parser is guard-clause heavy on purpose -- an enclosure with no URL, no
    # type, or a non-playable type each bail out early. Forcing those into nested conditionals
    # to satisfy a limit of 2 would make the code harder to read, not easier.
  MaxLineLength:
    maxLineLength: 140 # several files carry long, deliberate rationale comments (see
    # ReaderExtractor.kt) -- 120 (detekt's default) wrapped mid-explanation too aggressively.
  ForbiddenComment:
    active: false # this codebase deliberately doesn't use TODO/FIXME markers (see CLAUDE.md
    # "why these checks") -- nothing to forbid.
  UnusedImports:
    active: true # off in detekt's defaults, which is how 71 dead imports accumulated across
    # nine files -- EpisodeActions.kt was eleven lines of data class under forty of them,
    # Scaffold and SnackbarHost and LazyColumn included, left behind when the screens were
    # split per file. An import list is the first thing read to work out what a file does, so a
    # stale one actively misleads. Kotlin only warns, so nothing enforced it.

complexity:
  TooManyFunctions:
    thresholdInInterfaces: 22 # Room DAOs are broad by nature -- each query is a method, and
    # splitting one table's access across several interfaces to satisfy a count would make the
    # data layer harder to follow, not easier. Raised from 20 when EpisodeDao picked up
    # downloadedFromServer (the skip-refresh filter): one more genuinely distinct query, not
    # scope creep. Raised again to 22 for waitingForServer, which cannot reuse queuedDownloads:
    # a bounded retry must go newest first, or episodes the server has aged out of its newest-8
    # window would starve the ones it still has.
    thresholdInClasses: 21 # same for the view model: it is a flat list of one-line user actions
    # (enqueue, download, mark played), and splitting it by count rather than by meaning would
    # scatter related behaviour across types for no gain. 21 with downloadFromPublisher, the
    # explicit choice the episode screen offers a waiting download.

naming:
  FunctionNaming:
    ignoreAnnotated: ["Composable"] # Jetpack Compose's own naming convention is PascalCase for
    # composable functions -- that's the correct style here, not a violation.