Skip to content

Commit 5820378

Browse files
committed
docs: add C4 architecture diagrams (L1–L3) in Mermaid (#29)
Three new pages in docs/architecture/: - overview.md: C4 L1 System Context — Developer + github-code-search + GitHub REST API - containers.md: C4 L2 — CLI parser, API client, TUI, Output renderer, Upgrader, Team cache - components.md: C4 L3 — pure-function core (aggregate, group, rows, summary, filter stats, selection, highlight, output formatter) Each page includes a Mermaid C4 diagram and a prose table describing each actor/container/component with its source file(s) and key exports. VitePress nav and sidebar were already configured in feat/vitepress-docs.
1 parent 24dad06 commit 5820378

3 files changed

Lines changed: 147 additions & 0 deletions

File tree

docs/architecture/components.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Components (C4 L3)
2+
3+
This diagram zooms into the **pure-function core** — the modules that contain all
4+
business logic with no side effects. Every component here is fully unit-tested and
5+
takes in data structures defined in `src/types.ts`; none of them perform I/O.
6+
7+
The CLI parser (`github-code-search.ts`) and the TUI (`src/tui.ts`) call these
8+
components after fetching raw data from the API.
9+
10+
```mermaid
11+
C4Component
12+
title Components — pure-function core
13+
14+
Container_Boundary(core, "Pure-function core") {
15+
Component(aggregate, "Filter & aggregation", "src/aggregate.ts", "applyFiltersAndExclusions() — applies --exclude-repositories and --exclude-extracts, normalises org-prefixed names")
16+
Component(group, "Team grouping", "src/group.ts", "groupByTeamPrefix() / flattenTeamSections() — groups RepoGroups by team prefix, falls back to flat list")
17+
Component(rows, "Row builder", "src/render/rows.ts", "buildRows() — converts RepoGroups into terminal Row[], computes visibility and cursor position")
18+
Component(summary, "Summary builder", "src/render/summary.ts", "buildSummary() / buildSummaryFull() / buildSelectionSummary() — header and footer lines rendered in the TUI")
19+
Component(filter, "Filter stats", "src/render/filter.ts", "buildFilterStats() — counts visible vs total rows for the status bar")
20+
Component(selection, "Selection helpers", "src/render/selection.ts", "applySelectAll() / applySelectNone() — bulk selection mutations on Row[]")
21+
Component(highlight, "Syntax highlighter", "src/render/highlight.ts", "highlight() — detects language from filename, applies token-level ANSI colouring")
22+
Component(outputFn, "Output formatter", "src/output.ts", "buildOutput() — serialises selected RepoGroup[] to markdown or JSON")
23+
}
24+
25+
Container(tui, "TUI", "src/tui.ts", "Calls render components on every redraw")
26+
Container(cli, "CLI parser", "github-code-search.ts", "Calls aggregate + group, then TUI or output directly")
27+
28+
Rel(cli, aggregate, "Filters raw CodeMatch[]")
29+
Rel(cli, group, "Groups into TeamSection[]")
30+
Rel(cli, outputFn, "Formats selection (non-interactive mode)")
31+
Rel(tui, rows, "Builds terminal rows")
32+
Rel(tui, summary, "Builds header / footer lines")
33+
Rel(tui, filter, "Builds filter status bar")
34+
Rel(tui, selection, "Applies select-all / none")
35+
Rel(tui, highlight, "Highlights code extracts")
36+
Rel(tui, outputFn, "Formats selection on Enter")
37+
```
38+
39+
## Component descriptions
40+
41+
| Component | Source file | Key exports |
42+
| ------------------------ | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
43+
| **Filter & aggregation** | `src/aggregate.ts` | `applyFiltersAndExclusions()` — filters `CodeMatch[]` by repository and extract exclusion lists; normalises both `repoName` and `org/repoName` forms. |
44+
| **Team grouping** | `src/group.ts` | `groupByTeamPrefix()` — groups `RepoGroup[]` into `TeamSection[]` keyed by team slug; `flattenTeamSections()` — converts back to a flat list for the TUI row builder. |
45+
| **Row builder** | `src/render/rows.ts` | `buildRows()` — converts `RepoGroup[]` into `Row[]` with expanded/collapsed state; `rowTerminalLines()` — measures wrapped height; `isCursorVisible()` — viewport clipping. |
46+
| **Summary builder** | `src/render/summary.ts` | `buildSummary()` — compact header line; `buildSummaryFull()` — detailed counts; `buildSelectionSummary()` — "N files selected" footer. |
47+
| **Filter stats** | `src/render/filter.ts` | `buildFilterStats()` — produces the `FilterStats` object (visible count, total count, active filter string) used by the TUI status bar. |
48+
| **Selection helpers** | `src/render/selection.ts` | `applySelectAll()` — marks all visible rows as selected; `applySelectNone()` — deselects all. |
49+
| **Syntax highlighter** | `src/render/highlight.ts` | `highlight()` — maps file extension to a language token ruleset and applies ANSI escape sequences. Falls back to plain text for unknown extensions. |
50+
| **Output formatter** | `src/output.ts` | `buildOutput()` — entry point for both `--format markdown` and `--output-type json` serialisation of the confirmed selection. |
51+
52+
## Design principles
53+
54+
- **No I/O.** Every component in this layer is a pure function: given the same inputs it always returns the same outputs. This makes them straightforward to test with Bun's built-in test runner.
55+
- **Single responsibility.** Each component owns exactly one concern (rows, summary, selection, …). The TUI composes them at render time rather than duplicating logic.
56+
- **`types.ts` as the contract.** All components share the interfaces defined in `src/types.ts` (`TextMatchSegment`, `TextMatch`, `CodeMatch`, `RepoGroup`, `Row`, `TeamSection`, `OutputFormat`, `OutputType`). Changes to these types require updating all components.
57+
- **`render.ts` as façade.** External consumers import from `src/render.ts`, which re-exports all symbols from the `src/render/` sub-modules plus the top-level `renderGroups()` and `renderHelpOverlay()` functions.

docs/architecture/containers.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Containers (C4 L2)
2+
3+
This diagram zooms into `github-code-search` to show its internal processes and
4+
the boundaries between them. Each box represents one of the main source files and
5+
its primary responsibility. Arrows show the call direction at runtime.
6+
7+
```mermaid
8+
C4Container
9+
title Containers — github-code-search
10+
11+
Person(user, "Developer", "Runs the CLI from a terminal or CI pipeline")
12+
System_Ext(github, "GitHub REST API", "/search/code · /orgs/{org}/teams · /orgs/{org}/teams/{slug}/repos")
13+
14+
System_Boundary(tool, "github-code-search") {
15+
Container(cli, "CLI parser", "TypeScript / Commander", "Parses subcommands and flags, orchestrates the full flow — github-code-search.ts")
16+
Container(api, "API client", "TypeScript", "Authenticates with GitHub, paginates results, retries on rate limit — src/api.ts + src/api-utils.ts")
17+
Container(tui, "TUI", "TypeScript / raw TTY", "Reads keyboard input, renders the interactive result browser — src/tui.ts")
18+
Container(output, "Output renderer", "TypeScript", "Formats selected results as markdown or JSON — src/output.ts")
19+
Container(upgrade, "Upgrader", "TypeScript", "Fetches the latest release and replaces the running binary in-place — src/upgrade.ts")
20+
Container(cache, "Team cache", "TypeScript / disk", "Caches the org team list to avoid redundant API calls — src/cache.ts")
21+
}
22+
23+
Rel(user, cli, "Invokes", "argv / stdin")
24+
Rel(cli, api, "Calls to search and list teams")
25+
Rel(api, github, "HTTPS")
26+
Rel(api, cache, "Reads/writes team list")
27+
Rel(cli, tui, "Renders if interactive")
28+
Rel(tui, output, "Triggers on confirm")
29+
Rel(output, user, "Prints to stdout")
30+
Rel(cli, upgrade, "Triggers on upgrade subcommand")
31+
Rel(upgrade, github, "Fetches latest release assets", "HTTPS")
32+
```
33+
34+
## Container descriptions
35+
36+
| Container | Source file(s) | Responsibility |
37+
| ------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
38+
| **CLI parser** | `github-code-search.ts` | Entry point. Registers the `query` and `upgrade` Commander subcommands, resolves option defaults, and orchestrates the full search-display-output flow. |
39+
| **API client** | `src/api.ts` · `src/api-utils.ts` | The only layer allowed to make network calls. Handles authentication, pagination (`paginatedFetch`), exponential-backoff retry (`fetchWithRetry`), and team/repository listing. |
40+
| **TUI** | `src/tui.ts` | The only layer allowed to read raw stdin and write directly to the TTY. Manages the keyboard event loop, cursor position, filter mode, help overlay, and selection state. Disabled when `CI=true` or `--no-interactive` is passed. |
41+
| **Output renderer** | `src/output.ts` | Pure formatter. Converts the selected `RepoGroup[]` into a markdown document (`--format markdown`) or a JSON array (`--output-type json`). No I/O. |
42+
| **Upgrader** | `src/upgrade.ts` | Checks the latest GitHub release tag, downloads the matching binary asset, and atomically replaces the running executable. |
43+
| **Team cache** | `src/cache.ts` | Persists the org team list to disk (`~/.cache/github-code-search/` on Linux, `~/Library/Caches/` on macOS) to avoid hitting the `read:org` rate limit on every run. |
44+
45+
## Data flow — interactive query
46+
47+
1. **CLI parser** receives `query` subcommand → calls **API client**.
48+
2. **API client** queries `/search/code`, paginates, and returns `CodeMatch[]`.
49+
3. **CLI parser** calls pure functions (`aggregate.ts`, `group.ts`) to filter and group results.
50+
4. **TUI** receives `RepoGroup[]`, renders the browser, and waits for user input.
51+
5. On `Enter`, **TUI** returns the selection → **CLI parser** calls **Output renderer**.
52+
6. **Output renderer** prints markdown or JSON to stdout.

docs/architecture/overview.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# System context (C4 L1)
2+
3+
`github-code-search` is a self-contained command-line tool. It mediates between
4+
a developer and the GitHub REST API: the developer types a query, the tool
5+
searches GitHub on their behalf, displays an interactive result browser, and
6+
prints structured output so downstream tooling can consume it.
7+
8+
The diagram below shows the two actors and the single external dependency.
9+
10+
```mermaid
11+
C4Context
12+
title System Context — github-code-search
13+
14+
Person(user, "Developer", "Runs github-code-search from a terminal or CI pipeline")
15+
16+
System(cli, "github-code-search", "Interactive CLI — aggregates GitHub code search results, drives a keyboard-navigable TUI, and outputs markdown or JSON")
17+
18+
System_Ext(github, "GitHub REST API", "Code search endpoint (/search/code), organisation team listing (/orgs/{org}/teams) and team repository listing (/orgs/{org}/teams/{slug}/repos)")
19+
20+
Rel(user, cli, "Runs query, navigates TUI, confirms selection", "stdin / stdout")
21+
Rel(cli, github, "Searches code, lists org teams and team repos", "HTTPS")
22+
```
23+
24+
## Actors
25+
26+
| Actor | Description |
27+
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
28+
| **Developer** | The person (or CI job) that invokes the tool. Provides a `GITHUB_TOKEN` and a search query; receives markdown or JSON on stdout. |
29+
| **GitHub REST API** | The only external system the tool communicates with. The tool uses three endpoints: code search, org team list, and team repo list. All calls are authenticated with a personal access token. |
30+
31+
## Authentication
32+
33+
The tool reads `GITHUB_TOKEN` from the environment. The required OAuth scopes vary by feature:
34+
35+
- **Basic search**`public_repo` (public) or `repo` (private repos)
36+
- **Team grouping** (`--group-by-team-prefix`) — additionally requires `read:org`
37+
38+
See the [Environment variables](/reference/environment) reference for the full scope table.

0 commit comments

Comments
 (0)