Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ suspend fun getData(): Result<Data> = withContext(Dispatchers.IO) {
- ALWAYS remove unused code after refactors
- ALWAYS follow Material3 design guidelines for UI components
- When building from a Figma frame, reuse only scaffolding (sheet host, `SheetTopBar`, buttons, typography); NEVER swap a design-specific illustration/animation for a lookalike. Export the frame's assets via the Figma MCP and read animation timing/easing/direction from prototype reactions (`use_figma` → `node.reactions`)
- ALWAYS resolve a changed `*Screen.kt` to its Figma frame through `docs/screens-map.md` (`Flow › Frame` on the latest `Bitkit - Handoff vNN` page). When adding or removing a `*Screen.kt`, add or drop its row there (`todo` when the design does not exist yet); `ScreensMapTest` fails otherwise
- ALWAYS ensure proper error handling in coroutines
- ALWAYS acknowledge datastore async operations run synchronously in a suspend context
- NEVER use `runBlocking` in suspend functions
Expand Down
43 changes: 43 additions & 0 deletions app/src/test/java/to/bitkit/docs/ScreensMapTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package to.bitkit.docs

import org.junit.Test
import java.io.File
import kotlin.test.assertTrue

/**
* Keeps `docs/screens-map.md` in sync with the `*Screen.kt` files in `app/src/main/java`.
*/
class ScreensMapTest {
private val projectRoot = generateSequence(File("").absoluteFile) { it.parentFile }
.first { File(it, "docs/screens-map.md").isFile }
private val screensMap = File(projectRoot, "docs/screens-map.md")
private val sourceRoot = File(projectRoot, "app/src/main/java")

@Test
fun `every screen has a map entry and every entry has a screen`() {
val screens = sourceRoot.walkTopDown()
.filter { it.isFile && it.name.endsWith("Screen.kt") }
.map { it.name }
.toSet()
val entries = SCREEN_ENTRY.findAll(screensMap.readText())
.map { it.value }
.toSet()
Comment thread
ovitrif marked this conversation as resolved.

val missing = (screens - entries).sorted()
val stale = (entries - screens).sorted()

assertTrue(screens.isNotEmpty(), "No *Screen.kt files found under '$sourceRoot'")
assertTrue(
missing.isEmpty() && stale.isEmpty(),
buildString {
appendLine("docs/screens-map.md is out of sync with app/src/main/java.")
if (missing.isNotEmpty()) appendLine("Screens without a map entry: $missing")
if (stale.isNotEmpty()) appendLine("Map entries without a screen: $stale")
},
)
}

private companion object {
val SCREEN_ENTRY = Regex("""\b[A-Z]\w*Screen\.kt\b""")
}
}
Loading