github-mobile-reader 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +504 -0
- package/action.yml +24 -0
- package/dist/action.js +348 -0
- package/dist/index.d.mts +62 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +257 -0
- package/dist/index.mjs +224 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
# 📖 github-mobile-reader
|
|
2
|
+
|
|
3
|
+
> **Stop squinting at code on your phone.**
|
|
4
|
+
> `github-mobile-reader` transforms raw git diffs into clean, vertically-scrollable Markdown — no more pinch-zooming or swiping left and right to read a single line.
|
|
5
|
+
|
|
6
|
+
[](https://www.npmjs.com/package/github-mobile-reader)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://nodejs.org)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## The Problem
|
|
13
|
+
|
|
14
|
+
GitHub's mobile web view renders code in a fixed-width monospace block. Long lines require horizontal scrolling, deeply nested logic is invisible at a glance, and reviewing a PR on a commute is practically impossible.
|
|
15
|
+
|
|
16
|
+
## The Solution
|
|
17
|
+
|
|
18
|
+
`github-mobile-reader` parses a git diff and produces a **Logical Flow** — a compact tree that shows *what the code does*, not just what characters changed. The result is a Markdown document that reads top-to-bottom on any screen width.
|
|
19
|
+
|
|
20
|
+
**Before** (raw diff, mobile web):
|
|
21
|
+
```
|
|
22
|
+
← swipe → swipe → swipe →
|
|
23
|
+
+ const result = data.map(item => item.value).filter(v => v > 10).reduce((a,b) => a+b, 0)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**After** (Reader Markdown):
|
|
27
|
+
```
|
|
28
|
+
data
|
|
29
|
+
└─ map(item → value)
|
|
30
|
+
└─ filter(callback)
|
|
31
|
+
└─ reduce(callback)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- **Zero-dependency core** — the parser runs anywhere Node.js ≥ 18 is available
|
|
39
|
+
- **Dual output format** — CJS (`require`) and ESM (`import`) with full TypeScript types
|
|
40
|
+
- **GitHub Action** — drop one YAML block into any repo and get auto-generated Reader docs on every PR
|
|
41
|
+
- **Tracks both sides of a diff** — shows added *and* removed code in separate sections
|
|
42
|
+
- **Conservative by design** — when a pattern is ambiguous, the library shows less rather than showing something wrong
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Table of Contents
|
|
47
|
+
|
|
48
|
+
1. [Quick Start](#quick-start)
|
|
49
|
+
2. [Language Support](#language-support)
|
|
50
|
+
3. [GitHub Action (recommended)](#github-action-recommended)
|
|
51
|
+
4. [npm Library Usage](#npm-library-usage)
|
|
52
|
+
5. [Output Format](#output-format)
|
|
53
|
+
6. [API Reference](#api-reference)
|
|
54
|
+
7. [How the Parser Works](#how-the-parser-works)
|
|
55
|
+
8. [Contributing](#contributing)
|
|
56
|
+
9. [License](#license)
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Language Support
|
|
61
|
+
|
|
62
|
+
The parser is built on regex-based pattern matching, so it can technically receive a diff from any language. However, the detection patterns are tuned to JavaScript/TypeScript syntax, which means the **quality of the Logical Flow output varies by language**.
|
|
63
|
+
|
|
64
|
+
### Current support (v0.1)
|
|
65
|
+
|
|
66
|
+
| Language | Extensions | Flow Quality | Notes |
|
|
67
|
+
|----------|-----------|:------------:|-------|
|
|
68
|
+
| **JavaScript** | `.js` `.mjs` `.cjs` | ✅ Full | Baseline target language |
|
|
69
|
+
| **TypeScript** | `.ts` | ✅ Full | JS superset — all patterns apply |
|
|
70
|
+
| **React JSX** | `.jsx` | ✅ Full | Same syntax as JS |
|
|
71
|
+
| **React TSX** | `.tsx` | ✅ Full | Same syntax as TS |
|
|
72
|
+
| **Next.js** | `.js` `.ts` `.jsx` `.tsx` | ✅ Full | Framework on top of JS/TS |
|
|
73
|
+
| **Java** | `.java` | ⚠️ Partial (~55%) | `if/for/while` and dot-chaining work; function declarations missed (no `const/let/var`) |
|
|
74
|
+
| **C#** | `.cs` | ⚠️ Partial (~35%) | LINQ chaining (`.Where().Select()`) works; `using`/`namespace`/`class` not detected |
|
|
75
|
+
| **C** | `.c` `.h` | ❌ Minimal (~15%) | No matching keywords; pointer syntax (`->`, `*`) not understood |
|
|
76
|
+
| **Python, Go, Rust, etc.** | — | 🔜 Planned | See roadmap below |
|
|
77
|
+
|
|
78
|
+
> **Note:** Java, C#, and C files are not processed by the GitHub Action by default.
|
|
79
|
+
> The Action only scans `.js .jsx .ts .tsx .mjs .cjs` files ([`src/action.ts` line 66](src/action.ts)).
|
|
80
|
+
> To process other languages you would need a custom adapter (see [Contributing](#contributing)).
|
|
81
|
+
|
|
82
|
+
### Why JS/TS/React/Next.js work fully
|
|
83
|
+
|
|
84
|
+
All four share the same underlying syntax. The parser recognises:
|
|
85
|
+
|
|
86
|
+
- **Method chaining** — line starting with `.` after a line ending with `)` or `}`
|
|
87
|
+
```ts
|
|
88
|
+
data
|
|
89
|
+
.filter(item => item.active) // detected as P1 chain
|
|
90
|
+
.map(item => item.value) // detected as P1 chain
|
|
91
|
+
```
|
|
92
|
+
- **Function declarations** — `const`, `let`, `var`, `function`, `async`
|
|
93
|
+
- **Conditionals** — `if / else / switch`
|
|
94
|
+
- **Loops** — `for / while`
|
|
95
|
+
- **Noise filtering** — `import`, `export`, `type`, `interface`, `console.log` are silently dropped
|
|
96
|
+
|
|
97
|
+
### Why C / C# / Java are limited
|
|
98
|
+
|
|
99
|
+
These languages use different conventions for the patterns above:
|
|
100
|
+
|
|
101
|
+
| Concept | JS/TS (✅ detected) | Java / C# / C (❌ missed) |
|
|
102
|
+
|---------|---------------------|--------------------------|
|
|
103
|
+
| Variable declaration | `const x = …` | `int x = …` / `String x = …` |
|
|
104
|
+
| Arrow callbacks | `x => x.value` | Lambdas differ per language |
|
|
105
|
+
| Noise imports | `import` / `export` | `using` / `#include` / `package` |
|
|
106
|
+
| Async functions | `async function foo()` | `async Task<T> Foo()` |
|
|
107
|
+
|
|
108
|
+
### Roadmap — Language Adapter system (v0.2)
|
|
109
|
+
|
|
110
|
+
To support additional languages, a **Language Adapter** architecture is planned:
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
src/languages/
|
|
114
|
+
├── base.adapter.ts ← shared interface
|
|
115
|
+
├── js-ts.adapter.ts ← current logic (promoted from parser.ts)
|
|
116
|
+
├── java.adapter.ts ← public/private/void declarations, Stream chaining
|
|
117
|
+
└── csharp.adapter.ts ← using/namespace, LINQ chaining
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Each adapter will declare:
|
|
121
|
+
- Supported file extensions
|
|
122
|
+
- Function-declaration detection pattern
|
|
123
|
+
- Keywords to ignore (noise list)
|
|
124
|
+
- Chaining notation (dot vs. arrow `->`)
|
|
125
|
+
|
|
126
|
+
If you'd like to contribute an adapter for your language, see [Contributing](#contributing).
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Quick Start
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npm install github-mobile-reader
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { generateReaderMarkdown } from 'github-mobile-reader'
|
|
138
|
+
import { execSync } from 'child_process'
|
|
139
|
+
|
|
140
|
+
const diff = execSync('git diff HEAD~1', { encoding: 'utf8' })
|
|
141
|
+
const markdown = generateReaderMarkdown(diff, { file: 'src/utils.ts' })
|
|
142
|
+
|
|
143
|
+
console.log(markdown)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## GitHub Action (recommended)
|
|
149
|
+
|
|
150
|
+
The easiest way to use this library is as a GitHub Action. On every pull request it will:
|
|
151
|
+
|
|
152
|
+
1. Parse the diff of all changed `.js` / `.ts` files
|
|
153
|
+
2. Write a Reader Markdown file to `docs/reader/pr-<number>.md` inside your repo
|
|
154
|
+
3. Post a summary comment directly on the PR
|
|
155
|
+
|
|
156
|
+
### Step 1 — Add the workflow file
|
|
157
|
+
|
|
158
|
+
Create `.github/workflows/mobile-reader.yml` in your repository:
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
name: 📖 Mobile Reader
|
|
162
|
+
|
|
163
|
+
on:
|
|
164
|
+
pull_request:
|
|
165
|
+
types: [opened, synchronize, reopened]
|
|
166
|
+
|
|
167
|
+
permissions:
|
|
168
|
+
contents: write # commit the generated .md file
|
|
169
|
+
pull-requests: write # post the PR comment
|
|
170
|
+
|
|
171
|
+
jobs:
|
|
172
|
+
generate-reader:
|
|
173
|
+
name: Generate Mobile Reader View
|
|
174
|
+
runs-on: ubuntu-latest
|
|
175
|
+
|
|
176
|
+
steps:
|
|
177
|
+
- name: Checkout
|
|
178
|
+
uses: actions/checkout@v4
|
|
179
|
+
with:
|
|
180
|
+
fetch-depth: 0 # full history required for git diff
|
|
181
|
+
|
|
182
|
+
- name: Generate Reader Markdown
|
|
183
|
+
uses: 3rdflr/github-mobile-reader@v1
|
|
184
|
+
with:
|
|
185
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
186
|
+
base_branch: ${{ github.base_ref }}
|
|
187
|
+
output_dir: docs/reader
|
|
188
|
+
env:
|
|
189
|
+
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
190
|
+
|
|
191
|
+
- name: Commit Reader Markdown
|
|
192
|
+
run: |
|
|
193
|
+
git config user.name "github-actions[bot]"
|
|
194
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
195
|
+
git add docs/reader/
|
|
196
|
+
if git diff --cached --quiet; then
|
|
197
|
+
echo "No changes to commit"
|
|
198
|
+
else
|
|
199
|
+
git commit -m "docs(reader): update mobile reader for PR #${{ github.event.pull_request.number }} [skip ci]"
|
|
200
|
+
git push
|
|
201
|
+
fi
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Step 2 — Open a PR
|
|
205
|
+
|
|
206
|
+
That's it. Every subsequent PR will automatically get:
|
|
207
|
+
|
|
208
|
+
- A Reader Markdown file at `docs/reader/pr-<number>.md`
|
|
209
|
+
- A comment on the PR linking to the generated file
|
|
210
|
+
|
|
211
|
+
### Action Inputs
|
|
212
|
+
|
|
213
|
+
| Input | Required | Default | Description |
|
|
214
|
+
|-------|----------|---------|-------------|
|
|
215
|
+
| `github_token` | ✅ | — | Use `${{ secrets.GITHUB_TOKEN }}` |
|
|
216
|
+
| `base_branch` | ❌ | `main` | The branch the PR is merging into |
|
|
217
|
+
| `output_dir` | ❌ | `docs/reader` | Directory for generated `.md` files |
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## npm Library Usage
|
|
222
|
+
|
|
223
|
+
Use `github-mobile-reader` as a plain library in any Node.js project — CI scripts, custom bots, local tooling, etc.
|
|
224
|
+
|
|
225
|
+
### Installation
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# npm
|
|
229
|
+
npm install github-mobile-reader
|
|
230
|
+
|
|
231
|
+
# pnpm
|
|
232
|
+
pnpm add github-mobile-reader
|
|
233
|
+
|
|
234
|
+
# yarn
|
|
235
|
+
yarn add github-mobile-reader
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### CommonJS
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
const { generateReaderMarkdown } = require('github-mobile-reader')
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### ESM / TypeScript
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import { generateReaderMarkdown, parseDiffToLogicalFlow } from 'github-mobile-reader'
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Basic Example
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
import { generateReaderMarkdown } from 'github-mobile-reader'
|
|
254
|
+
import { execSync } from 'child_process'
|
|
255
|
+
import { writeFileSync } from 'fs'
|
|
256
|
+
|
|
257
|
+
// Get the diff for the last commit
|
|
258
|
+
const diff = execSync('git diff HEAD~1 HEAD', { encoding: 'utf8' })
|
|
259
|
+
|
|
260
|
+
// Generate Reader Markdown with metadata
|
|
261
|
+
const markdown = generateReaderMarkdown(diff, {
|
|
262
|
+
pr: '42',
|
|
263
|
+
commit: 'a1b2c3d',
|
|
264
|
+
file: 'src/api/users.ts',
|
|
265
|
+
repo: 'my-org/my-repo',
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
// Write to a file or post to Slack / Discord / GitHub
|
|
269
|
+
writeFileSync('reader.md', markdown, 'utf8')
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Low-level API Example
|
|
273
|
+
|
|
274
|
+
If you only need the parsed tree (e.g. to build your own renderer):
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
import { parseDiffToLogicalFlow, renderFlowTree } from 'github-mobile-reader'
|
|
278
|
+
|
|
279
|
+
const { root, rawCode, removedCode } = parseDiffToLogicalFlow(diff)
|
|
280
|
+
|
|
281
|
+
// root → FlowNode[] (the logical tree)
|
|
282
|
+
// rawCode → string (added lines, joined)
|
|
283
|
+
// removedCode → string (removed lines, joined)
|
|
284
|
+
|
|
285
|
+
const treeLines = renderFlowTree(root)
|
|
286
|
+
console.log(treeLines.join('\n'))
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Output Format
|
|
292
|
+
|
|
293
|
+
A generated Reader Markdown document has four sections:
|
|
294
|
+
|
|
295
|
+
```markdown
|
|
296
|
+
# 📖 GitHub Reader View
|
|
297
|
+
|
|
298
|
+
> Generated by **github-mobile-reader**
|
|
299
|
+
> Repository: my-org/my-repo
|
|
300
|
+
> Pull Request: #42
|
|
301
|
+
> Commit: `a1b2c3d`
|
|
302
|
+
> File: `src/api/users.ts`
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## 🧠 Logical Flow
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
getData()
|
|
310
|
+
└─ filter(callback)
|
|
311
|
+
└─ map(item → value)
|
|
312
|
+
└─ reduce(callback)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## ✅ Added Code
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
const result = getData()
|
|
319
|
+
.filter(item => item.active)
|
|
320
|
+
.map(item => item.value)
|
|
321
|
+
.reduce((a, b) => a + b, 0)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## ❌ Removed Code
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
const result = getData().map(item => item.value)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
🛠 Auto-generated by github-mobile-reader. Do not edit manually.
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## API Reference
|
|
337
|
+
|
|
338
|
+
### `generateReaderMarkdown(diffText, meta?)`
|
|
339
|
+
|
|
340
|
+
The main entry point. Parses a raw git diff string and returns a complete Reader Markdown document.
|
|
341
|
+
|
|
342
|
+
| Parameter | Type | Description |
|
|
343
|
+
|-----------|------|-------------|
|
|
344
|
+
| `diffText` | `string` | Raw output of `git diff` |
|
|
345
|
+
| `meta.pr` | `string?` | Pull request number |
|
|
346
|
+
| `meta.commit` | `string?` | Commit SHA |
|
|
347
|
+
| `meta.file` | `string?` | File name shown in the header |
|
|
348
|
+
| `meta.repo` | `string?` | Repository in `owner/repo` format |
|
|
349
|
+
|
|
350
|
+
**Returns:** `string` — the complete Markdown document.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### `parseDiffToLogicalFlow(diffText)`
|
|
355
|
+
|
|
356
|
+
Parses a diff into a structured result without rendering.
|
|
357
|
+
|
|
358
|
+
**Returns:** `ParseResult`
|
|
359
|
+
|
|
360
|
+
```ts
|
|
361
|
+
interface ParseResult {
|
|
362
|
+
root: FlowNode[] // logical tree (added lines)
|
|
363
|
+
rawCode: string // added lines joined with \n
|
|
364
|
+
removedCode: string // removed lines joined with \n
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
### `renderFlowTree(nodes, indent?)`
|
|
371
|
+
|
|
372
|
+
Converts a `FlowNode[]` tree into an array of Markdown-safe text lines.
|
|
373
|
+
|
|
374
|
+
```ts
|
|
375
|
+
const lines = renderFlowTree(root)
|
|
376
|
+
// [ 'getData()', ' └─ filter(callback)', ' └─ map(item → value)' ]
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
### `FlowNode`
|
|
382
|
+
|
|
383
|
+
```ts
|
|
384
|
+
interface FlowNode {
|
|
385
|
+
type: 'root' | 'chain' | 'condition' | 'loop' | 'function' | 'call'
|
|
386
|
+
name: string
|
|
387
|
+
children: FlowNode[]
|
|
388
|
+
depth: number
|
|
389
|
+
priority: Priority
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
### `Priority` (enum)
|
|
396
|
+
|
|
397
|
+
| Value | Meaning |
|
|
398
|
+
|-------|---------|
|
|
399
|
+
| `CHAINING = 1` | Method chains (`.map()`, `.filter()`, …) — highest priority |
|
|
400
|
+
| `CONDITIONAL = 2` | `if` / `else` / `switch` blocks |
|
|
401
|
+
| `LOOP = 3` | `for` / `while` loops |
|
|
402
|
+
| `FUNCTION = 4` | Function declarations |
|
|
403
|
+
| `OTHER = 5` | Everything else |
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## How the Parser Works
|
|
408
|
+
|
|
409
|
+
The parser runs a deterministic pipeline — no AI, no external dependencies.
|
|
410
|
+
|
|
411
|
+
```
|
|
412
|
+
git diff text
|
|
413
|
+
│
|
|
414
|
+
▼
|
|
415
|
+
1. filterDiffLines() — split + and - lines, strip +++ / --- headers
|
|
416
|
+
│
|
|
417
|
+
▼
|
|
418
|
+
2. normalizeCode() — remove ; comments, trim whitespace
|
|
419
|
+
│
|
|
420
|
+
▼
|
|
421
|
+
3. getIndentDepth() — calculate nesting level (2 spaces = 1 level)
|
|
422
|
+
│
|
|
423
|
+
▼
|
|
424
|
+
4. parseToFlowTree() — match patterns in priority order:
|
|
425
|
+
│ P1 chaining (.map .filter .reduce …)
|
|
426
|
+
│ P2 conditional (if / else / switch)
|
|
427
|
+
│ P3 loop (for / while)
|
|
428
|
+
│ P4 function declaration
|
|
429
|
+
│
|
|
430
|
+
▼
|
|
431
|
+
5. renderFlowTree() — convert tree → indented text lines
|
|
432
|
+
│
|
|
433
|
+
▼
|
|
434
|
+
generateReaderMarkdown() — assemble the final Markdown document
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**Key design decisions:**
|
|
438
|
+
|
|
439
|
+
- **Conservative** — lines that cannot be classified are silently skipped rather than misrepresented.
|
|
440
|
+
- **Imports / exports / types / interfaces / console.log** are ignored; they do not contribute to understanding flow.
|
|
441
|
+
- **Callback arguments** are simplified: `.map(item => item.value)` becomes `map(item → value)` when the body is a single property access; otherwise it becomes `map(callback)`.
|
|
442
|
+
- **Depth** is tracked via indentation (2-space baseline) and used only as a fallback when chaining detection is ambiguous.
|
|
443
|
+
|
|
444
|
+
### Supported Languages (v0.1)
|
|
445
|
+
|
|
446
|
+
See the full breakdown in the [Language Support](#language-support) section.
|
|
447
|
+
In short: **JS / TS / React / Next.js are fully supported**; Java and C# are partial; C and others are planned via the Language Adapter system (v0.2).
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Contributing
|
|
452
|
+
|
|
453
|
+
Pull requests are welcome! Here's how to get started:
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
# Clone the repo
|
|
457
|
+
git clone https://github.com/3rdflr/github-mobile-reader.git
|
|
458
|
+
cd github-mobile-reader
|
|
459
|
+
|
|
460
|
+
# Install dependencies
|
|
461
|
+
npm install
|
|
462
|
+
|
|
463
|
+
# Build (library + action runner)
|
|
464
|
+
npm run build:all
|
|
465
|
+
|
|
466
|
+
# Watch mode during development
|
|
467
|
+
npm run dev
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Project Structure
|
|
471
|
+
|
|
472
|
+
```
|
|
473
|
+
github-mobile-reader/
|
|
474
|
+
├── src/
|
|
475
|
+
│ ├── parser.ts ← core diff → logical flow parser
|
|
476
|
+
│ ├── index.ts ← public npm API surface
|
|
477
|
+
│ └── action.ts ← GitHub Action entry point
|
|
478
|
+
├── dist/ ← compiled output (auto-generated, do not edit)
|
|
479
|
+
├── .github/
|
|
480
|
+
│ └── workflows/
|
|
481
|
+
│ └── mobile-reader.yml ← example workflow for consumers
|
|
482
|
+
├── action.yml ← GitHub Action definition
|
|
483
|
+
├── package.json
|
|
484
|
+
└── tsconfig.json
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### Adding Support for a New Language
|
|
488
|
+
|
|
489
|
+
The parser currently relies on JS/TS syntax heuristics (dot-chaining, `const`/`let`/`var`, `function`, `if`/`for`/`while`). To add a new language:
|
|
490
|
+
|
|
491
|
+
1. Add detection helpers in `src/parser.ts` (follow the existing `isChaining`, `isConditional` pattern)
|
|
492
|
+
2. Update `filterDiffLines` to handle the new file extension
|
|
493
|
+
3. Open a PR with a test diff as an example
|
|
494
|
+
|
|
495
|
+
---
|
|
496
|
+
|
|
497
|
+
## License
|
|
498
|
+
|
|
499
|
+
MIT © [3rdflr](https://github.com/3rdflr)
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
> **"The era of per-device number crunching is over.
|
|
504
|
+
> One logic. Every screen."**
|
package/action.yml
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: 'GitHub Mobile Reader'
|
|
2
|
+
description: 'Generate mobile-friendly Markdown summaries of PR diffs and post them as PR comments.'
|
|
3
|
+
author: 'your-org'
|
|
4
|
+
|
|
5
|
+
branding:
|
|
6
|
+
icon: 'book-open'
|
|
7
|
+
color: 'blue'
|
|
8
|
+
|
|
9
|
+
inputs:
|
|
10
|
+
github_token:
|
|
11
|
+
description: 'GitHub token with write access to issues/pull-requests (use ${{ secrets.GITHUB_TOKEN }})'
|
|
12
|
+
required: true
|
|
13
|
+
base_branch:
|
|
14
|
+
description: 'Base branch to diff against (default: main)'
|
|
15
|
+
required: false
|
|
16
|
+
default: 'main'
|
|
17
|
+
output_dir:
|
|
18
|
+
description: 'Directory where the generated .md file will be saved inside the repo'
|
|
19
|
+
required: false
|
|
20
|
+
default: 'docs/reader'
|
|
21
|
+
|
|
22
|
+
runs:
|
|
23
|
+
using: 'node20'
|
|
24
|
+
main: 'dist/action.js'
|