github-mobile-reader 0.1.0 β 0.1.1
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.ko.md +517 -0
- package/README.md +81 -76
- package/dist/action.js +21 -12
- package/dist/index.js +21 -12
- package/dist/index.mjs +21 -12
- package/package.json +1 -1
package/README.ko.md
ADDED
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
# π github-mobile-reader
|
|
2
|
+
|
|
3
|
+
> `github-mobile-reader`λ git diffλ₯Ό κΉλνκ² μΈλ‘ μ€ν¬λ‘€λ‘ μ½μ μ μλ Markdown λ¬Έμλ‘ λ³νν©λλ€ β λ μ΄μ μ’μ° νμΉμ€μ΄λ κ°λ‘ μ€μμ΄νλ νμ μμ΅λλ€.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/github-mobile-reader)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
|
|
9
|
+
> μμ΄ λ¬Έμλ [README.md](./README.md)μμ νμΈνμΈμ.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## λ¬Έμ μν©
|
|
14
|
+
|
|
15
|
+
GitHubμ λͺ¨λ°μΌ μΉ λ·°λ μ½λλ₯Ό κ³ μ λλΉμ λͺ¨λ
Έμ€νμ΄μ€ λΈλ‘μΌλ‘ λ λλ§ν©λλ€. κΈ΄ μ€μ κ°λ‘ μ€ν¬λ‘€μ μꡬνκ³ , κΉκ² μ€μ²©λ λ‘μ§μ νλμ νμ
μ΄ λΆκ°λ₯νλ©°, μΆν΄κ·Ό μ§νμ² μμ PR 리뷰λ₯Ό νλ 건 μ¬μ€μ λΆκ°λ₯μ κ°κΉμ΅λλ€.
|
|
16
|
+
|
|
17
|
+
## ν΄κ²°μ±
|
|
18
|
+
|
|
19
|
+
`github-mobile-reader`λ git diffλ₯Ό νμ±ν΄μ **Logical Flow** β λ¨μν μ΄λ€ λ¬Έμκ° λ°λμλμ§κ° μλλΌ *μ½λκ° λ¬΄μμ νλμ§*λ₯Ό 보μ¬μ£Όλ κ°κ²°ν νΈλ¦¬ β λ₯Ό μμ±ν©λλ€. κ²°κ³Όλ¬Όμ μ΄λ€ νλ©΄ λλΉμμλ μμμ μλλ‘ μ½νλ Markdown λ¬Έμμ
λλ€.
|
|
20
|
+
|
|
21
|
+
**Before** (κΈ°μ‘΄ diff, λͺ¨λ°μΌ μΉ):
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
β μ€μμ΄ν β μ€μμ΄ν β μ€μμ΄ν β
|
|
25
|
+
+ const result = data.map(item => item.value).filter(v => v > 10).reduce((a,b) => a+b, 0)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**After** (Reader Markdown):
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
data
|
|
32
|
+
ββ map(item β value)
|
|
33
|
+
ββ filter(callback)
|
|
34
|
+
ββ reduce(callback)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## μ£Όμ κΈ°λ₯
|
|
40
|
+
|
|
41
|
+
- **μμ‘΄μ± μ λ‘ μ½μ΄** β νμλ Node.js β₯ 18μ΄ μλ μ΄λμλ λμν©λλ€
|
|
42
|
+
- **μ΄μ€ μΆλ ₯ ν¬λ§·** β CJS (`require`)μ ESM (`import`) λͺ¨λ μ§μ, TypeScript νμ
ν¬ν¨
|
|
43
|
+
- **GitHub Action** β λ ν¬μ YAML νμΌ νλλ§ μΆκ°νλ©΄ PRλ§λ€ Reader λ¬Έμκ° μλ μμ±λ©λλ€
|
|
44
|
+
- **μλ°©ν₯ diff μΆμ ** β μΆκ°λ μ½λμ μμ λ μ½λλ₯Ό κ°κ° λ³λ μΉμ
μΌλ‘ νμ
|
|
45
|
+
- **보μμ μ€κ³** β ν¨ν΄μ΄ μ λ§€ν λλ μλͺ»λ μ 보λ₯Ό 보μ¬μ£Όλ λμ λ 보μ¬μ€λλ€
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## λͺ©μ°¨
|
|
50
|
+
|
|
51
|
+
1. [λΉ λ₯Έ μμ](#λΉ λ₯Έ-μμ)
|
|
52
|
+
2. [μΈμ΄ μ§μ](#μΈμ΄-μ§μ)
|
|
53
|
+
3. [GitHub Action (κΆμ₯)](#github-action-κΆμ₯)
|
|
54
|
+
4. [npm λΌμ΄λΈλ¬λ¦¬ μ¬μ©λ²](#npm-λΌμ΄λΈλ¬λ¦¬-μ¬μ©λ²)
|
|
55
|
+
5. [μΆλ ₯ νμ](#μΆλ ₯-νμ)
|
|
56
|
+
6. [API λ νΌλ°μ€](#api-λ νΌλ°μ€)
|
|
57
|
+
7. [νμ λμ μ리](#νμ-λμ-μ리)
|
|
58
|
+
8. [κΈ°μ¬νκΈ°](#κΈ°μ¬νκΈ°)
|
|
59
|
+
9. [λΌμ΄μ μ€](#λΌμ΄μ μ€)
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## λΉ λ₯Έ μμ
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install github-mobile-reader
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { generateReaderMarkdown } from "github-mobile-reader";
|
|
71
|
+
import { execSync } from "child_process";
|
|
72
|
+
|
|
73
|
+
const diff = execSync("git diff HEAD~1", { encoding: "utf8" });
|
|
74
|
+
const markdown = generateReaderMarkdown(diff, { file: "src/utils.ts" });
|
|
75
|
+
|
|
76
|
+
console.log(markdown);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## μΈμ΄ μ§μ
|
|
82
|
+
|
|
83
|
+
νμλ μ κ·μ κΈ°λ° ν¨ν΄ λ§€μΉμΌλ‘ λμνλ―λ‘ κΈ°μ μ μΌλ‘λ μ΄λ€ μΈμ΄μ diffλ μ
λ ₯λ°μ μ μμ΅λλ€. λ€λ§ κ°μ§ ν¨ν΄μ΄ JavaScript/TypeScript λ¬Έλ²μ λ§μΆ° μ€κ³λμ΄ μμ΄ **Logical Flow μΆλ ₯ νμ§μ΄ μΈμ΄λ§λ€ λ€λ¦
λλ€**.
|
|
84
|
+
|
|
85
|
+
### νμ¬ μ§μ νν© (v0.1)
|
|
86
|
+
|
|
87
|
+
| μΈμ΄ | νμ₯μ | νμ§ | λΉκ³ |
|
|
88
|
+
| ----------------------- | ------------------------- | :------------: | --------------------------------------------------------------------------- |
|
|
89
|
+
| **JavaScript** | `.js` `.mjs` `.cjs` | β
μμ | νμμ κΈ°μ€ μΈμ΄ |
|
|
90
|
+
| **TypeScript** | `.ts` | β
μμ | JS μμ μ§ν© β λͺ¨λ ν¨ν΄ μ μ© |
|
|
91
|
+
| **React JSX** | `.jsx` | β
μμ | JSμ λμΌν λ¬Έλ² |
|
|
92
|
+
| **React TSX** | `.tsx` | β
μμ | TSμ λμΌν λ¬Έλ² |
|
|
93
|
+
| **Next.js** | `.js` `.ts` `.jsx` `.tsx` | β
μμ | JS/TS μμμ λμνλ νλ μμν¬ |
|
|
94
|
+
| **Java** | `.java` | β οΈ λΆλΆ (~55%) | `if/for/while`κ³Ό 체μ΄λμ λμ; ν¨μ μ μΈ κ°μ§ μ€ν¨ (`const/let/var` μμ) |
|
|
95
|
+
| **C#** | `.cs` | β οΈ λΆλΆ (~35%) | LINQ 체μ΄λ(`.Where().Select()`)μ λμ; `using`/`namespace`/`class` λ―Έκ°μ§ |
|
|
96
|
+
| **C** | `.c` `.h` | β μ΅μ (~15%) | λ§€μΉ ν€μλ μμ; ν¬μΈν° λ¬Έλ²(`->`, `*`) λ―Έμ§μ |
|
|
97
|
+
| **Python, Go, Rust λ±** | β | π μμ | μλ λ‘λλ§΅ μ°Έκ³ |
|
|
98
|
+
|
|
99
|
+
> **μ°Έκ³ :** Java, C#, C νμΌμ κΈ°λ³Έμ μΌλ‘ GitHub Actionμμ μ²λ¦¬λμ§ μμ΅λλ€.
|
|
100
|
+
> Actionμ `.js .jsx .ts .tsx .mjs .cjs` νμΌλ§ μ€μΊν©λλ€ ([`src/action.ts` 66λ²μ§Έ μ€](src/action.ts)).
|
|
101
|
+
> λ€λ₯Έ μΈμ΄λ₯Ό μ²λ¦¬νλ €λ©΄ 컀μ€ν
μ΄λν°κ° νμν©λλ€ ([κΈ°μ¬νκΈ°](#κΈ°μ¬νκΈ°) μ°Έκ³ ).
|
|
102
|
+
|
|
103
|
+
### JS/TS/React/Next.jsκ° μμ μ§μλλ μ΄μ
|
|
104
|
+
|
|
105
|
+
λ€ κ°μ§ λͺ¨λ λμΌν κΈ°λ° λ¬Έλ²μ 곡μ ν©λλ€. νμκ° μΈμνλ κ²:
|
|
106
|
+
|
|
107
|
+
- **λ©μλ 체μ΄λ** β `)`λ `}`λ‘ λλλ μ€ λ€μμ `.`μΌλ‘ μμνλ μ€
|
|
108
|
+
```ts
|
|
109
|
+
data
|
|
110
|
+
.filter((item) => item.active) // P1 체μ΄λμΌλ‘ κ°μ§
|
|
111
|
+
.map((item) => item.value); // P1 체μ΄λμΌλ‘ κ°μ§
|
|
112
|
+
```
|
|
113
|
+
- **ν¨μ μ μΈ** β `const`, `let`, `var`, `function`, `async`
|
|
114
|
+
- **쑰건문** β `if / else / switch`
|
|
115
|
+
- **λ°λ³΅λ¬Έ** β `for / while`
|
|
116
|
+
- **λ
Έμ΄μ¦ νν°λ§** β `import`, `export`, `type`, `interface`, `console.log`λ μλμΌλ‘ μ κ±°
|
|
117
|
+
|
|
118
|
+
### C / C# / Javaκ° μ νμ μΈ μ΄μ
|
|
119
|
+
|
|
120
|
+
μ΄ μΈμ΄λ€μ μ ν¨ν΄μ λν΄ λ€λ₯Έ νκΈ° λ°©μμ μ¬μ©ν©λλ€:
|
|
121
|
+
|
|
122
|
+
| κ°λ
| JS/TS (β
κ°μ§λ¨) | Java / C# / C (β λ―Έκ°μ§) |
|
|
123
|
+
| ------------- | ---------------------- | -------------------------------- |
|
|
124
|
+
| λ³μ μ μΈ | `const x = β¦` | `int x = β¦` / `String x = β¦` |
|
|
125
|
+
| νμ΄ν μ½λ°± | `x => x.value` | μΈμ΄λ§λ€ λλ€ λ¬Έλ² λ€λ¦ |
|
|
126
|
+
| λ
Έμ΄μ¦ import | `import` / `export` | `using` / `#include` / `package` |
|
|
127
|
+
| λΉλκΈ° ν¨μ | `async function foo()` | `async Task<T> Foo()` |
|
|
128
|
+
|
|
129
|
+
### λ‘λλ§΅ β Language Adapter μμ€ν
(v0.2)
|
|
130
|
+
|
|
131
|
+
μΆκ° μΈμ΄ μ§μμ μν΄ **Language Adapter** μν€ν
μ²κ° κ³νλμ΄ μμ΅λλ€:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
src/languages/
|
|
135
|
+
βββ base.adapter.ts β κ³΅ν΅ μΈν°νμ΄μ€
|
|
136
|
+
βββ js-ts.adapter.ts β νμ¬ λ‘μ§ (parser.tsμμ λΆλ¦¬)
|
|
137
|
+
βββ java.adapter.ts β public/private/void μ μΈ, Stream 체μ΄λ
|
|
138
|
+
βββ csharp.adapter.ts β using/namespace, LINQ 체μ΄λ
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
κ° μ΄λν°κ° μ 곡νλ κ²:
|
|
142
|
+
|
|
143
|
+
- μ§μ νμΌ νμ₯μ λͺ©λ‘
|
|
144
|
+
- ν¨μ μ μΈ κ°μ§ ν¨ν΄
|
|
145
|
+
- 무μν ν€μλ λͺ©λ‘ (λ
Έμ΄μ¦)
|
|
146
|
+
- 체μ΄λ νκΈ° λ°©μ (μ (`.`) vs. νμ΄ν(`->`))
|
|
147
|
+
|
|
148
|
+
μΈμ΄ μ΄λν°λ₯Ό κΈ°μ¬νκ³ μΆλ€λ©΄ [κΈ°μ¬νκΈ°](#κΈ°μ¬νκΈ°)λ₯Ό νμΈνμΈμ.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## GitHub Action (κΆμ₯)
|
|
153
|
+
|
|
154
|
+
μ΄ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ κ°μ₯ μ¬μ΄ λ°©λ²μ
λλ€. λ§€ PRλ§λ€ μλμΌλ‘:
|
|
155
|
+
|
|
156
|
+
1. λ³κ²½λ `.js` / `.ts` νμΌμ diffλ₯Ό νμ±
|
|
157
|
+
2. `docs/reader/pr-<λ²νΈ>.md` νμΌμ λ ν¬μ μ μ₯
|
|
158
|
+
3. PRμ μμ½ μ½λ©νΈλ₯Ό μλμΌλ‘ λ¬μμ€λλ€
|
|
159
|
+
|
|
160
|
+
### Step 1 β μν¬νλ‘μ° νμΌ μΆκ°
|
|
161
|
+
|
|
162
|
+
λ ν¬μ `.github/workflows/mobile-reader.yml`μ λ§λ€μ΄ μ£ΌμΈμ:
|
|
163
|
+
|
|
164
|
+
```yaml
|
|
165
|
+
name: π Mobile Reader
|
|
166
|
+
|
|
167
|
+
on:
|
|
168
|
+
pull_request:
|
|
169
|
+
types: [opened, synchronize, reopened]
|
|
170
|
+
|
|
171
|
+
permissions:
|
|
172
|
+
contents: write # .md νμΌ μ»€λ°
|
|
173
|
+
pull-requests: write # PR μ½λ©νΈ μμ±
|
|
174
|
+
|
|
175
|
+
jobs:
|
|
176
|
+
generate-reader:
|
|
177
|
+
name: Generate Mobile Reader View
|
|
178
|
+
runs-on: ubuntu-latest
|
|
179
|
+
|
|
180
|
+
steps:
|
|
181
|
+
- name: Checkout
|
|
182
|
+
uses: actions/checkout@v4
|
|
183
|
+
with:
|
|
184
|
+
fetch-depth: 0 # git diffμ μ 체 νμ€ν 리 νμ
|
|
185
|
+
|
|
186
|
+
- name: Generate Reader Markdown
|
|
187
|
+
uses: 3rdflr/github-mobile-reader@v1
|
|
188
|
+
with:
|
|
189
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
190
|
+
base_branch: ${{ github.base_ref }}
|
|
191
|
+
output_dir: docs/reader
|
|
192
|
+
env:
|
|
193
|
+
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
194
|
+
|
|
195
|
+
- name: Commit Reader Markdown
|
|
196
|
+
run: |
|
|
197
|
+
git config user.name "github-actions[bot]"
|
|
198
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
199
|
+
git add docs/reader/
|
|
200
|
+
if git diff --cached --quiet; then
|
|
201
|
+
echo "λ³κ²½μ¬ν μμ"
|
|
202
|
+
else
|
|
203
|
+
git commit -m "docs(reader): PR #${{ github.event.pull_request.number }} λͺ¨λ°μΌ 리λ μ
λ°μ΄νΈ [skip ci]"
|
|
204
|
+
git push
|
|
205
|
+
fi
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Step 2 β PR μ΄κΈ°
|
|
209
|
+
|
|
210
|
+
μ΄κ² μ λΆμ
λλ€. μ΄ν λͺ¨λ PRμ μλμΌλ‘:
|
|
211
|
+
|
|
212
|
+
- `docs/reader/pr-<λ²νΈ>.md` νμΌ μμ±
|
|
213
|
+
- μμ±λ νμΌ λ§ν¬κ° λ΄κΈ΄ PR μ½λ©νΈ μλ κ²μ
|
|
214
|
+
|
|
215
|
+
### Action μ
λ ₯κ°
|
|
216
|
+
|
|
217
|
+
| μ
λ ₯κ° | νμ | κΈ°λ³Έκ° | μ€λͺ
|
|
|
218
|
+
| -------------- | ---- | ------------- | ---------------------------------- |
|
|
219
|
+
| `github_token` | β
| β | `${{ secrets.GITHUB_TOKEN }}` μ¬μ© |
|
|
220
|
+
| `base_branch` | β | `main` | PRμ΄ λ¨Έμ§λλ λμ λΈλμΉ |
|
|
221
|
+
| `output_dir` | β | `docs/reader` | μμ±λ `.md` νμΌ μ μ₯ κ²½λ‘ |
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## npm λΌμ΄λΈλ¬λ¦¬ μ¬μ©λ²
|
|
226
|
+
|
|
227
|
+
CI μ€ν¬λ¦½νΈ, 컀μ€ν
λ΄, λ‘컬 λꡬ λ± λͺ¨λ Node.js νλ‘μ νΈμμ λΌμ΄λΈλ¬λ¦¬λ‘ μ¬μ©ν μ μμ΅λλ€.
|
|
228
|
+
|
|
229
|
+
### μ€μΉ
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# npm
|
|
233
|
+
npm install github-mobile-reader
|
|
234
|
+
|
|
235
|
+
# pnpm
|
|
236
|
+
pnpm add github-mobile-reader
|
|
237
|
+
|
|
238
|
+
# yarn
|
|
239
|
+
yarn add github-mobile-reader
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### CommonJS
|
|
243
|
+
|
|
244
|
+
```js
|
|
245
|
+
const { generateReaderMarkdown } = require("github-mobile-reader");
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### ESM / TypeScript
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
import {
|
|
252
|
+
generateReaderMarkdown,
|
|
253
|
+
parseDiffToLogicalFlow,
|
|
254
|
+
} from "github-mobile-reader";
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### κΈ°λ³Έ μ¬μ© μμ
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
import { generateReaderMarkdown } from "github-mobile-reader";
|
|
261
|
+
import { execSync } from "child_process";
|
|
262
|
+
import { writeFileSync } from "fs";
|
|
263
|
+
|
|
264
|
+
// λ§μ§λ§ 컀λ°μ diff κ°μ Έμ€κΈ°
|
|
265
|
+
const diff = execSync("git diff HEAD~1 HEAD", { encoding: "utf8" });
|
|
266
|
+
|
|
267
|
+
// λ©νλ°μ΄ν°μ ν¨κ» Reader Markdown μμ±
|
|
268
|
+
const markdown = generateReaderMarkdown(diff, {
|
|
269
|
+
pr: "42",
|
|
270
|
+
commit: "a1b2c3d",
|
|
271
|
+
file: "src/api/users.ts",
|
|
272
|
+
repo: "my-org/my-repo",
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// νμΌ μ μ₯ λλ Slack / Discord / GitHubμ κ²μ
|
|
276
|
+
writeFileSync("reader.md", markdown, "utf8");
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### μ μμ€ API μμ
|
|
280
|
+
|
|
281
|
+
νΈλ¦¬ κ΅¬μ‘°λ§ νμν κ²½μ° (μ: 컀μ€ν
λ λλ¬ μ μ):
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
import { parseDiffToLogicalFlow, renderFlowTree } from "github-mobile-reader";
|
|
285
|
+
|
|
286
|
+
const { root, rawCode, removedCode } = parseDiffToLogicalFlow(diff);
|
|
287
|
+
|
|
288
|
+
// root β FlowNode[] (λ
Όλ¦¬ νΈλ¦¬)
|
|
289
|
+
// rawCode β string (μΆκ°λ μ€, μ€λ°κΏμΌλ‘ μ°κ²°)
|
|
290
|
+
// removedCode β string (μμ λ μ€, μ€λ°κΏμΌλ‘ μ°κ²°)
|
|
291
|
+
|
|
292
|
+
const treeLines = renderFlowTree(root);
|
|
293
|
+
console.log(treeLines.join("\n"));
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## μΆλ ₯ νμ
|
|
299
|
+
|
|
300
|
+
μμ±λ Reader Markdown λ¬Έμλ λ€ κ°μ μΉμ
μΌλ‘ ꡬμ±λ©λλ€:
|
|
301
|
+
|
|
302
|
+
````markdown
|
|
303
|
+
# π GitHub Reader View
|
|
304
|
+
|
|
305
|
+
> Generated by **github-mobile-reader**
|
|
306
|
+
> Repository: my-org/my-repo
|
|
307
|
+
> Pull Request: #42
|
|
308
|
+
> Commit: `a1b2c3d`
|
|
309
|
+
> File: `src/api/users.ts`
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## π§ Logical Flow
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
getData()
|
|
317
|
+
ββ filter(callback)
|
|
318
|
+
ββ map(item β value)
|
|
319
|
+
ββ reduce(callback)
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## β
Added Code
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
const result = getData()
|
|
326
|
+
.filter((item) => item.active)
|
|
327
|
+
.map((item) => item.value)
|
|
328
|
+
.reduce((a, b) => a + b, 0);
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## β Removed Code
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
const result = getData().map((item) => item.value);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
π Auto-generated by github-mobile-reader. Do not edit manually.
|
|
340
|
+
````
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## API λ νΌλ°μ€
|
|
345
|
+
|
|
346
|
+
### `generateReaderMarkdown(diffText, meta?)`
|
|
347
|
+
|
|
348
|
+
λ©μΈ μ§μ
μ . μμ git diff λ¬Έμμ΄μ νμ±ν΄μ μμ±λ Reader Markdown λ¬Έμλ₯Ό λ°νν©λλ€.
|
|
349
|
+
|
|
350
|
+
| νλΌλ―Έν° | νμ
| μ€λͺ
|
|
|
351
|
+
| ------------- | --------- | ----------------------------- |
|
|
352
|
+
| `diffText` | `string` | `git diff`μ μμ μΆλ ₯ |
|
|
353
|
+
| `meta.pr` | `string?` | PR λ²νΈ |
|
|
354
|
+
| `meta.commit` | `string?` | μ»€λ° SHA |
|
|
355
|
+
| `meta.file` | `string?` | ν€λμ νμν νμΌλͺ
|
|
|
356
|
+
| `meta.repo` | `string?` | `owner/repo` νμμ λ ν¬ μ΄λ¦ |
|
|
357
|
+
|
|
358
|
+
**λ°νκ°:** `string` β μμ±λ Markdown λ¬Έμ
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
### `parseDiffToLogicalFlow(diffText)`
|
|
363
|
+
|
|
364
|
+
λ λλ§ μμ΄ diffλ₯Ό ꡬ쑰νλ κ²°κ³Όλ‘ νμ±ν©λλ€.
|
|
365
|
+
|
|
366
|
+
**λ°νκ°:** `ParseResult`
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
interface ParseResult {
|
|
370
|
+
root: FlowNode[]; // λ
Όλ¦¬ νΈλ¦¬ (μΆκ°λ μ€)
|
|
371
|
+
rawCode: string; // μΆκ°λ μ€ (\nμΌλ‘ μ°κ²°)
|
|
372
|
+
removedCode: string; // μμ λ μ€ (\nμΌλ‘ μ°κ²°)
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
### `renderFlowTree(nodes, indent?)`
|
|
379
|
+
|
|
380
|
+
`FlowNode[]` νΈλ¦¬λ₯Ό Markdown μμ ν ν
μ€νΈ μ€ λ°°μ΄λ‘ λ³νν©λλ€.
|
|
381
|
+
|
|
382
|
+
```ts
|
|
383
|
+
const lines = renderFlowTree(root);
|
|
384
|
+
// [ 'getData()', ' ββ filter(callback)', ' ββ map(item β value)' ]
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
### `FlowNode`
|
|
390
|
+
|
|
391
|
+
```ts
|
|
392
|
+
interface FlowNode {
|
|
393
|
+
type: "root" | "chain" | "condition" | "loop" | "function" | "call";
|
|
394
|
+
name: string;
|
|
395
|
+
children: FlowNode[];
|
|
396
|
+
depth: number;
|
|
397
|
+
priority: Priority;
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### `Priority` (μ΄κ±°ν)
|
|
404
|
+
|
|
405
|
+
| κ° | μλ―Έ |
|
|
406
|
+
| ----------------- | ----------------------------------------------- |
|
|
407
|
+
| `CHAINING = 1` | λ©μλ μ²΄μΈ (`.map()`, `.filter()`, β¦) β μ΅μ°μ |
|
|
408
|
+
| `CONDITIONAL = 2` | `if` / `else` / `switch` λΈλ‘ |
|
|
409
|
+
| `LOOP = 3` | `for` / `while` λ°λ³΅λ¬Έ |
|
|
410
|
+
| `FUNCTION = 4` | ν¨μ μ μΈ |
|
|
411
|
+
| `OTHER = 5` | κ·Έ μΈ |
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## νμ λμ μ리
|
|
416
|
+
|
|
417
|
+
νμλ κ²°μ λ‘ μ νμ΄νλΌμΈμΌλ‘ λμν©λλ€ β AI μμ, μΈλΆ μμ‘΄μ± μμ.
|
|
418
|
+
|
|
419
|
+
```
|
|
420
|
+
git diff ν
μ€νΈ
|
|
421
|
+
β
|
|
422
|
+
βΌ
|
|
423
|
+
1. filterDiffLines() β + / - μ€ λΆλ¦¬, +++ / --- ν€λ μ κ±°
|
|
424
|
+
β
|
|
425
|
+
βΌ
|
|
426
|
+
2. normalizeCode() β ; μ κ±°, μ£Όμ μ κ±°, 곡백 μ 리
|
|
427
|
+
β
|
|
428
|
+
βΌ
|
|
429
|
+
3. getIndentDepth() β μ€μ²© λ 벨 κ³μ° (2 spaces = 1 λ 벨)
|
|
430
|
+
β
|
|
431
|
+
βΌ
|
|
432
|
+
4. parseToFlowTree() β μ°μ μμ μμλ‘ ν¨ν΄ λ§€μΉ:
|
|
433
|
+
β P1 체μ΄λ (.map .filter .reduce β¦)
|
|
434
|
+
β P2 쑰건문 (if / else / switch)
|
|
435
|
+
β P3 λ°λ³΅λ¬Έ (for / while)
|
|
436
|
+
β P4 ν¨μ μ μΈ
|
|
437
|
+
β
|
|
438
|
+
βΌ
|
|
439
|
+
5. renderFlowTree() β νΈλ¦¬ β λ€μ¬μ°κΈ°λ ν
μ€νΈ μ€λ‘ λ³ν
|
|
440
|
+
β
|
|
441
|
+
βΌ
|
|
442
|
+
generateReaderMarkdown() β μ΅μ’
Markdown λ¬Έμ 쑰립
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**μ£Όμ μ€κ³ κ²°μ :**
|
|
446
|
+
|
|
447
|
+
- **보μμ ** β λΆλ₯λμ§ μλ μ€μ μλͺ»λ μ 보 λμ μ‘°μ©ν 건λλλλ€
|
|
448
|
+
- **import / export / type / interface / console.log**λ 무μλ©λλ€. νλ¦ μ΄ν΄μ κΈ°μ¬νμ§ μκΈ° λλ¬Έμ
λλ€
|
|
449
|
+
- **μ½λ°± μΈμ μΆμ½** β λ³Έλ¬Έμ΄ λ¨μΌ μμ± μ κ·ΌμΌ λ `.map(item => item.value)`λ₯Ό `map(item β value)`λ‘ μΆμ½ν©λλ€. κ·Έ μΈμλ `map(callback)`μΌλ‘ νμν©λλ€
|
|
450
|
+
- **ν¨μ μ μΈμ μ΅μ°μ 체ν¬** β `const foo = async β¦`κ° `extractRoot`μ μλͺ» λΆλ₯λμ§ μλλ‘, ν¨μ μ μΈ κ°μ§λ₯Ό λ£¨νΈ μΆμΆλ³΄λ€ λ¨Όμ μνν©λλ€
|
|
451
|
+
- **depth**λ λ€μ¬μ°κΈ° κΈ°λ° (2-space κΈ°μ€)μΌλ‘ μΆμ λλ©°, 체μ΄λ κ°μ§κ° μ λ§€ν λ 보쑰 μ 보λ‘λ§ μ¬μ©λ©λλ€
|
|
452
|
+
|
|
453
|
+
### μ§μ μΈμ΄ (v0.1)
|
|
454
|
+
|
|
455
|
+
[μΈμ΄ μ§μ](#μΈμ΄-μ§μ) μΉμ
μ μ 체 νλ₯Ό νμΈνμΈμ.
|
|
456
|
+
μμ½: **JS / TS / React / Next.js μμ μ§μ**, Javaμ C#μ λΆλΆ μ§μ, C λ±μ Language Adapter μμ€ν
(v0.2)μΌλ‘ κ³ν μ€.
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## κΈ°μ¬νκΈ°
|
|
461
|
+
|
|
462
|
+
PRμ μΈμ λ μ§ νμν©λλ€! μμ λ°©λ²:
|
|
463
|
+
|
|
464
|
+
```bash
|
|
465
|
+
# λ ν¬ ν΄λ‘
|
|
466
|
+
git clone https://github.com/3rdflr/github-mobile-reader.git
|
|
467
|
+
cd github-mobile-reader
|
|
468
|
+
|
|
469
|
+
# μμ‘΄μ± μ€μΉ
|
|
470
|
+
npm install
|
|
471
|
+
|
|
472
|
+
# λΉλ (λΌμ΄λΈλ¬λ¦¬ + Action runner)
|
|
473
|
+
npm run build:all
|
|
474
|
+
|
|
475
|
+
# κ°λ° μ€ watch λͺ¨λ
|
|
476
|
+
npm run dev
|
|
477
|
+
|
|
478
|
+
# ν
μ€νΈ μ€ν
|
|
479
|
+
npx ts-node src/test.ts
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### νλ‘μ νΈ κ΅¬μ‘°
|
|
483
|
+
|
|
484
|
+
```
|
|
485
|
+
github-mobile-reader/
|
|
486
|
+
βββ src/
|
|
487
|
+
β βββ parser.ts β ν΅μ¬ diff β logical flow νμ
|
|
488
|
+
β βββ index.ts β npm κ³΅κ° API
|
|
489
|
+
β βββ action.ts β GitHub Action μ§μ
μ
|
|
490
|
+
β βββ test.ts β μ€λͺ¨ν¬ ν
μ€νΈ (33κ°)
|
|
491
|
+
βββ dist/ β μ»΄νμΌ κ²°κ³Όλ¬Ό (μλ μμ±, μμ κΈμ§)
|
|
492
|
+
βββ .github/
|
|
493
|
+
β βββ workflows/
|
|
494
|
+
β βββ mobile-reader.yml β μ¬μ©μμ© μμ μν¬νλ‘μ°
|
|
495
|
+
βββ action.yml β GitHub Action μ μ
|
|
496
|
+
βββ README.md β μμ΄ λ¬Έμ
|
|
497
|
+
βββ README.ko.md β νκ΅μ΄ λ¬Έμ (νμ¬ νμΌ)
|
|
498
|
+
βββ package.json
|
|
499
|
+
βββ tsconfig.json
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### μ μΈμ΄ μ΄λν° μΆκ°νκΈ°
|
|
503
|
+
|
|
504
|
+
νμλ νμ¬ JS/TS λ¬Έλ² ν΄λ¦¬μ€ν±μ μμ‘΄ν©λλ€ (μ 체μ΄λ, `const`/`let`/`var`, `function`, `if`/`for`/`while`). μ μΈμ΄λ₯Ό μΆκ°νλ €λ©΄:
|
|
505
|
+
|
|
506
|
+
1. `src/parser.ts`μμ κ°μ§ ν¬νΌ μΆκ° (κΈ°μ‘΄ `isChaining`, `isConditional` ν¨ν΄ μ°Έκ³ )
|
|
507
|
+
2. `src/action.ts`μ `filterDiffLines`μμ μ νμΌ νμ₯μ νμ©
|
|
508
|
+
3. `src/test.ts`μ ν΄λΉ μΈμ΄μ diff μμλ₯Ό ν
μ€νΈ μΌμ΄μ€λ‘ μΆκ°
|
|
509
|
+
4. μμ diffλ₯Ό ν¬ν¨ν΄μ PR μ€ν
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## λΌμ΄μ μ€
|
|
514
|
+
|
|
515
|
+
MIT Β© [3rdflr](https://github.com/3rdflr)
|
|
516
|
+
|
|
517
|
+
---
|
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# π github-mobile-reader
|
|
2
2
|
|
|
3
|
-
> **Stop squinting at code on your phone.**
|
|
4
3
|
> `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
4
|
|
|
6
5
|
[](https://www.npmjs.com/package/github-mobile-reader)
|
|
@@ -15,15 +14,17 @@ GitHub's mobile web view renders code in a fixed-width monospace block. Long lin
|
|
|
15
14
|
|
|
16
15
|
## The Solution
|
|
17
16
|
|
|
18
|
-
`github-mobile-reader` parses a git diff and produces a **Logical Flow** β a compact tree that shows
|
|
17
|
+
`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
18
|
|
|
20
19
|
**Before** (raw diff, mobile web):
|
|
20
|
+
|
|
21
21
|
```
|
|
22
22
|
β swipe β swipe β swipe β
|
|
23
23
|
+ const result = data.map(item => item.value).filter(v => v > 10).reduce((a,b) => a+b, 0)
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
**After** (Reader Markdown):
|
|
27
|
+
|
|
27
28
|
```
|
|
28
29
|
data
|
|
29
30
|
ββ map(item β value)
|
|
@@ -38,7 +39,7 @@ data
|
|
|
38
39
|
- **Zero-dependency core** β the parser runs anywhere Node.js β₯ 18 is available
|
|
39
40
|
- **Dual output format** β CJS (`require`) and ESM (`import`) with full TypeScript types
|
|
40
41
|
- **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
|
|
42
|
+
- **Tracks both sides of a diff** β shows added _and_ removed code in separate sections
|
|
42
43
|
- **Conservative by design** β when a pattern is ambiguous, the library shows less rather than showing something wrong
|
|
43
44
|
|
|
44
45
|
---
|
|
@@ -63,17 +64,17 @@ The parser is built on regex-based pattern matching, so it can technically recei
|
|
|
63
64
|
|
|
64
65
|
### Current support (v0.1)
|
|
65
66
|
|
|
66
|
-
| Language
|
|
67
|
-
|
|
68
|
-
| **JavaScript**
|
|
69
|
-
| **TypeScript**
|
|
70
|
-
| **React JSX**
|
|
71
|
-
| **React TSX**
|
|
72
|
-
| **Next.js**
|
|
73
|
-
| **Java**
|
|
74
|
-
| **C#**
|
|
75
|
-
| **C**
|
|
76
|
-
| **Python, Go, Rust, etc.** | β
|
|
67
|
+
| Language | Extensions | Flow Quality | Notes |
|
|
68
|
+
| -------------------------- | ------------------------- | :---------------: | --------------------------------------------------------------------------------------- |
|
|
69
|
+
| **JavaScript** | `.js` `.mjs` `.cjs` | β
Full | Baseline target language |
|
|
70
|
+
| **TypeScript** | `.ts` | β
Full | JS superset β all patterns apply |
|
|
71
|
+
| **React JSX** | `.jsx` | β
Full | Same syntax as JS |
|
|
72
|
+
| **React TSX** | `.tsx` | β
Full | Same syntax as TS |
|
|
73
|
+
| **Next.js** | `.js` `.ts` `.jsx` `.tsx` | β
Full | Framework on top of JS/TS |
|
|
74
|
+
| **Java** | `.java` | β οΈ Partial (~55%) | `if/for/while` and dot-chaining work; function declarations missed (no `const/let/var`) |
|
|
75
|
+
| **C#** | `.cs` | β οΈ Partial (~35%) | LINQ chaining (`.Where().Select()`) works; `using`/`namespace`/`class` not detected |
|
|
76
|
+
| **C** | `.c` `.h` | β Minimal (~15%) | No matching keywords; pointer syntax (`->`, `*`) not understood |
|
|
77
|
+
| **Python, Go, Rust, etc.** | β | π Planned | See roadmap below |
|
|
77
78
|
|
|
78
79
|
> **Note:** Java, C#, and C files are not processed by the GitHub Action by default.
|
|
79
80
|
> The Action only scans `.js .jsx .ts .tsx .mjs .cjs` files ([`src/action.ts` line 66](src/action.ts)).
|
|
@@ -86,8 +87,8 @@ All four share the same underlying syntax. The parser recognises:
|
|
|
86
87
|
- **Method chaining** β line starting with `.` after a line ending with `)` or `}`
|
|
87
88
|
```ts
|
|
88
89
|
data
|
|
89
|
-
.filter(item => item.active)
|
|
90
|
-
.map(item => item.value)
|
|
90
|
+
.filter((item) => item.active) // detected as P1 chain
|
|
91
|
+
.map((item) => item.value); // detected as P1 chain
|
|
91
92
|
```
|
|
92
93
|
- **Function declarations** β `const`, `let`, `var`, `function`, `async`
|
|
93
94
|
- **Conditionals** β `if / else / switch`
|
|
@@ -98,12 +99,12 @@ All four share the same underlying syntax. The parser recognises:
|
|
|
98
99
|
|
|
99
100
|
These languages use different conventions for the patterns above:
|
|
100
101
|
|
|
101
|
-
| Concept
|
|
102
|
-
|
|
103
|
-
| Variable declaration | `const x = β¦`
|
|
104
|
-
| Arrow callbacks
|
|
105
|
-
| Noise imports
|
|
106
|
-
| Async functions
|
|
102
|
+
| Concept | JS/TS (β
detected) | Java / C# / C (β missed) |
|
|
103
|
+
| -------------------- | ---------------------- | -------------------------------- |
|
|
104
|
+
| Variable declaration | `const x = β¦` | `int x = β¦` / `String x = β¦` |
|
|
105
|
+
| Arrow callbacks | `x => x.value` | Lambdas differ per language |
|
|
106
|
+
| Noise imports | `import` / `export` | `using` / `#include` / `package` |
|
|
107
|
+
| Async functions | `async function foo()` | `async Task<T> Foo()` |
|
|
107
108
|
|
|
108
109
|
### Roadmap β Language Adapter system (v0.2)
|
|
109
110
|
|
|
@@ -118,6 +119,7 @@ src/languages/
|
|
|
118
119
|
```
|
|
119
120
|
|
|
120
121
|
Each adapter will declare:
|
|
122
|
+
|
|
121
123
|
- Supported file extensions
|
|
122
124
|
- Function-declaration detection pattern
|
|
123
125
|
- Keywords to ignore (noise list)
|
|
@@ -134,13 +136,13 @@ npm install github-mobile-reader
|
|
|
134
136
|
```
|
|
135
137
|
|
|
136
138
|
```ts
|
|
137
|
-
import { generateReaderMarkdown } from
|
|
138
|
-
import { execSync } from
|
|
139
|
+
import { generateReaderMarkdown } from "github-mobile-reader";
|
|
140
|
+
import { execSync } from "child_process";
|
|
139
141
|
|
|
140
|
-
const diff = execSync(
|
|
141
|
-
const markdown = generateReaderMarkdown(diff, { file:
|
|
142
|
+
const diff = execSync("git diff HEAD~1", { encoding: "utf8" });
|
|
143
|
+
const markdown = generateReaderMarkdown(diff, { file: "src/utils.ts" });
|
|
142
144
|
|
|
143
|
-
console.log(markdown)
|
|
145
|
+
console.log(markdown);
|
|
144
146
|
```
|
|
145
147
|
|
|
146
148
|
---
|
|
@@ -165,8 +167,8 @@ on:
|
|
|
165
167
|
types: [opened, synchronize, reopened]
|
|
166
168
|
|
|
167
169
|
permissions:
|
|
168
|
-
contents: write
|
|
169
|
-
pull-requests: write
|
|
170
|
+
contents: write # commit the generated .md file
|
|
171
|
+
pull-requests: write # post the PR comment
|
|
170
172
|
|
|
171
173
|
jobs:
|
|
172
174
|
generate-reader:
|
|
@@ -177,7 +179,7 @@ jobs:
|
|
|
177
179
|
- name: Checkout
|
|
178
180
|
uses: actions/checkout@v4
|
|
179
181
|
with:
|
|
180
|
-
fetch-depth: 0
|
|
182
|
+
fetch-depth: 0 # full history required for git diff
|
|
181
183
|
|
|
182
184
|
- name: Generate Reader Markdown
|
|
183
185
|
uses: 3rdflr/github-mobile-reader@v1
|
|
@@ -210,11 +212,11 @@ That's it. Every subsequent PR will automatically get:
|
|
|
210
212
|
|
|
211
213
|
### Action Inputs
|
|
212
214
|
|
|
213
|
-
| Input
|
|
214
|
-
|
|
215
|
-
| `github_token` | β
|
|
216
|
-
| `base_branch`
|
|
217
|
-
| `output_dir`
|
|
215
|
+
| Input | Required | Default | Description |
|
|
216
|
+
| -------------- | -------- | ------------- | ----------------------------------- |
|
|
217
|
+
| `github_token` | β
| β | Use `${{ secrets.GITHUB_TOKEN }}` |
|
|
218
|
+
| `base_branch` | β | `main` | The branch the PR is merging into |
|
|
219
|
+
| `output_dir` | β | `docs/reader` | Directory for generated `.md` files |
|
|
218
220
|
|
|
219
221
|
---
|
|
220
222
|
|
|
@@ -238,35 +240,38 @@ yarn add github-mobile-reader
|
|
|
238
240
|
### CommonJS
|
|
239
241
|
|
|
240
242
|
```js
|
|
241
|
-
const { generateReaderMarkdown } = require(
|
|
243
|
+
const { generateReaderMarkdown } = require("github-mobile-reader");
|
|
242
244
|
```
|
|
243
245
|
|
|
244
246
|
### ESM / TypeScript
|
|
245
247
|
|
|
246
248
|
```ts
|
|
247
|
-
import {
|
|
249
|
+
import {
|
|
250
|
+
generateReaderMarkdown,
|
|
251
|
+
parseDiffToLogicalFlow,
|
|
252
|
+
} from "github-mobile-reader";
|
|
248
253
|
```
|
|
249
254
|
|
|
250
255
|
### Basic Example
|
|
251
256
|
|
|
252
257
|
```ts
|
|
253
|
-
import { generateReaderMarkdown } from
|
|
254
|
-
import { execSync } from
|
|
255
|
-
import { writeFileSync } from
|
|
258
|
+
import { generateReaderMarkdown } from "github-mobile-reader";
|
|
259
|
+
import { execSync } from "child_process";
|
|
260
|
+
import { writeFileSync } from "fs";
|
|
256
261
|
|
|
257
262
|
// Get the diff for the last commit
|
|
258
|
-
const diff = execSync(
|
|
263
|
+
const diff = execSync("git diff HEAD~1 HEAD", { encoding: "utf8" });
|
|
259
264
|
|
|
260
265
|
// Generate Reader Markdown with metadata
|
|
261
266
|
const markdown = generateReaderMarkdown(diff, {
|
|
262
|
-
pr:
|
|
263
|
-
commit:
|
|
264
|
-
file:
|
|
265
|
-
repo:
|
|
266
|
-
})
|
|
267
|
+
pr: "42",
|
|
268
|
+
commit: "a1b2c3d",
|
|
269
|
+
file: "src/api/users.ts",
|
|
270
|
+
repo: "my-org/my-repo",
|
|
271
|
+
});
|
|
267
272
|
|
|
268
273
|
// Write to a file or post to Slack / Discord / GitHub
|
|
269
|
-
writeFileSync(
|
|
274
|
+
writeFileSync("reader.md", markdown, "utf8");
|
|
270
275
|
```
|
|
271
276
|
|
|
272
277
|
### Low-level API Example
|
|
@@ -274,16 +279,16 @@ writeFileSync('reader.md', markdown, 'utf8')
|
|
|
274
279
|
If you only need the parsed tree (e.g. to build your own renderer):
|
|
275
280
|
|
|
276
281
|
```ts
|
|
277
|
-
import { parseDiffToLogicalFlow, renderFlowTree } from
|
|
282
|
+
import { parseDiffToLogicalFlow, renderFlowTree } from "github-mobile-reader";
|
|
278
283
|
|
|
279
|
-
const { root, rawCode, removedCode } = parseDiffToLogicalFlow(diff)
|
|
284
|
+
const { root, rawCode, removedCode } = parseDiffToLogicalFlow(diff);
|
|
280
285
|
|
|
281
286
|
// root β FlowNode[] (the logical tree)
|
|
282
287
|
// rawCode β string (added lines, joined)
|
|
283
288
|
// removedCode β string (removed lines, joined)
|
|
284
289
|
|
|
285
|
-
const treeLines = renderFlowTree(root)
|
|
286
|
-
console.log(treeLines.join(
|
|
290
|
+
const treeLines = renderFlowTree(root);
|
|
291
|
+
console.log(treeLines.join("\n"));
|
|
287
292
|
```
|
|
288
293
|
|
|
289
294
|
---
|
|
@@ -304,13 +309,14 @@ A generated Reader Markdown document has four sections:
|
|
|
304
309
|
---
|
|
305
310
|
|
|
306
311
|
## π§ Logical Flow
|
|
307
|
-
|
|
308
312
|
```
|
|
313
|
+
|
|
309
314
|
getData()
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
315
|
+
ββ filter(callback)
|
|
316
|
+
ββ map(item β value)
|
|
317
|
+
ββ reduce(callback)
|
|
318
|
+
|
|
319
|
+
````
|
|
314
320
|
|
|
315
321
|
## β
Added Code
|
|
316
322
|
|
|
@@ -319,17 +325,19 @@ const result = getData()
|
|
|
319
325
|
.filter(item => item.active)
|
|
320
326
|
.map(item => item.value)
|
|
321
327
|
.reduce((a, b) => a + b, 0)
|
|
322
|
-
|
|
328
|
+
````
|
|
323
329
|
|
|
324
330
|
## β Removed Code
|
|
325
331
|
|
|
326
332
|
```typescript
|
|
327
|
-
const result = getData().map(item => item.value)
|
|
333
|
+
const result = getData().map((item) => item.value);
|
|
328
334
|
```
|
|
329
335
|
|
|
330
336
|
---
|
|
337
|
+
|
|
331
338
|
π Auto-generated by github-mobile-reader. Do not edit manually.
|
|
332
|
-
|
|
339
|
+
|
|
340
|
+
````
|
|
333
341
|
|
|
334
342
|
---
|
|
335
343
|
|
|
@@ -363,7 +371,7 @@ interface ParseResult {
|
|
|
363
371
|
rawCode: string // added lines joined with \n
|
|
364
372
|
removedCode: string // removed lines joined with \n
|
|
365
373
|
}
|
|
366
|
-
|
|
374
|
+
````
|
|
367
375
|
|
|
368
376
|
---
|
|
369
377
|
|
|
@@ -372,7 +380,7 @@ interface ParseResult {
|
|
|
372
380
|
Converts a `FlowNode[]` tree into an array of Markdown-safe text lines.
|
|
373
381
|
|
|
374
382
|
```ts
|
|
375
|
-
const lines = renderFlowTree(root)
|
|
383
|
+
const lines = renderFlowTree(root);
|
|
376
384
|
// [ 'getData()', ' ββ filter(callback)', ' ββ map(item β value)' ]
|
|
377
385
|
```
|
|
378
386
|
|
|
@@ -382,11 +390,11 @@ const lines = renderFlowTree(root)
|
|
|
382
390
|
|
|
383
391
|
```ts
|
|
384
392
|
interface FlowNode {
|
|
385
|
-
type:
|
|
386
|
-
name: string
|
|
387
|
-
children: FlowNode[]
|
|
388
|
-
depth: number
|
|
389
|
-
priority: Priority
|
|
393
|
+
type: "root" | "chain" | "condition" | "loop" | "function" | "call";
|
|
394
|
+
name: string;
|
|
395
|
+
children: FlowNode[];
|
|
396
|
+
depth: number;
|
|
397
|
+
priority: Priority;
|
|
390
398
|
}
|
|
391
399
|
```
|
|
392
400
|
|
|
@@ -394,13 +402,13 @@ interface FlowNode {
|
|
|
394
402
|
|
|
395
403
|
### `Priority` (enum)
|
|
396
404
|
|
|
397
|
-
| Value
|
|
398
|
-
|
|
399
|
-
| `CHAINING = 1`
|
|
400
|
-
| `CONDITIONAL = 2` | `if` / `else` / `switch` blocks
|
|
401
|
-
| `LOOP = 3`
|
|
402
|
-
| `FUNCTION = 4`
|
|
403
|
-
| `OTHER = 5`
|
|
405
|
+
| Value | Meaning |
|
|
406
|
+
| ----------------- | ----------------------------------------------------------- |
|
|
407
|
+
| `CHAINING = 1` | Method chains (`.map()`, `.filter()`, β¦) β highest priority |
|
|
408
|
+
| `CONDITIONAL = 2` | `if` / `else` / `switch` blocks |
|
|
409
|
+
| `LOOP = 3` | `for` / `while` loops |
|
|
410
|
+
| `FUNCTION = 4` | Function declarations |
|
|
411
|
+
| `OTHER = 5` | Everything else |
|
|
404
412
|
|
|
405
413
|
---
|
|
406
414
|
|
|
@@ -499,6 +507,3 @@ The parser currently relies on JS/TS syntax heuristics (dot-chaining, `const`/`l
|
|
|
499
507
|
MIT Β© [3rdflr](https://github.com/3rdflr)
|
|
500
508
|
|
|
501
509
|
---
|
|
502
|
-
|
|
503
|
-
> **"The era of per-device number crunching is over.
|
|
504
|
-
> One logic. Every screen."**
|
package/dist/action.js
CHANGED
|
@@ -37,10 +37,10 @@ function filterDiffLines(diffText) {
|
|
|
37
37
|
function normalizeCode(lines) {
|
|
38
38
|
return lines.map((line) => {
|
|
39
39
|
let normalized = line;
|
|
40
|
-
normalized = normalized.replace(/;$/, "");
|
|
41
40
|
normalized = normalized.replace(/\/\/.*$/, "");
|
|
42
41
|
normalized = normalized.replace(/\/\*.*?\*\//, "");
|
|
43
42
|
normalized = normalized.trim();
|
|
43
|
+
normalized = normalized.replace(/;$/, "");
|
|
44
44
|
return normalized;
|
|
45
45
|
}).filter((line) => line.length > 0);
|
|
46
46
|
}
|
|
@@ -77,7 +77,13 @@ function isLoop(line) {
|
|
|
77
77
|
return /^(for|while)\s*\(/.test(line.trim());
|
|
78
78
|
}
|
|
79
79
|
function isFunctionDeclaration(line) {
|
|
80
|
-
|
|
80
|
+
const t = line.trim();
|
|
81
|
+
return (
|
|
82
|
+
// function foo() / async function foo()
|
|
83
|
+
/^(async\s+)?function\s+\w+/.test(t) || // const foo = () => / const foo = async () => / const foo = async (x: T) =>
|
|
84
|
+
/^(const|let|var)\s+\w+\s*=\s*(async\s*)?\(/.test(t) || // const foo = function / const foo = async function
|
|
85
|
+
/^(const|let|var)\s+\w+\s*=\s*(async\s+)?function/.test(t)
|
|
86
|
+
);
|
|
81
87
|
}
|
|
82
88
|
function shouldIgnore(line) {
|
|
83
89
|
const ignorePatterns = [
|
|
@@ -136,6 +142,19 @@ function parseToFlowTree(lines) {
|
|
|
136
142
|
prevLine = line;
|
|
137
143
|
continue;
|
|
138
144
|
}
|
|
145
|
+
if (isFunctionDeclaration(line)) {
|
|
146
|
+
const funcMatch = line.match(/(?:function|const|let|var)\s+(\w+)/);
|
|
147
|
+
roots.push({
|
|
148
|
+
type: "function",
|
|
149
|
+
name: funcMatch ? `${funcMatch[1]}()` : "function()",
|
|
150
|
+
children: [],
|
|
151
|
+
depth: relativeDepth,
|
|
152
|
+
priority: 4 /* FUNCTION */
|
|
153
|
+
});
|
|
154
|
+
currentChain = null;
|
|
155
|
+
prevLine = line;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
139
158
|
const root = extractRoot(line);
|
|
140
159
|
if (root) {
|
|
141
160
|
currentChain = {
|
|
@@ -166,16 +185,6 @@ function parseToFlowTree(lines) {
|
|
|
166
185
|
priority: 3 /* LOOP */
|
|
167
186
|
});
|
|
168
187
|
currentChain = null;
|
|
169
|
-
} else if (isFunctionDeclaration(line)) {
|
|
170
|
-
const funcMatch = line.match(/(?:function|const|let|var)\s+(\w+)/);
|
|
171
|
-
roots.push({
|
|
172
|
-
type: "function",
|
|
173
|
-
name: funcMatch ? `${funcMatch[1]}()` : "function()",
|
|
174
|
-
children: [],
|
|
175
|
-
depth: relativeDepth,
|
|
176
|
-
priority: 4 /* FUNCTION */
|
|
177
|
-
});
|
|
178
|
-
currentChain = null;
|
|
179
188
|
}
|
|
180
189
|
prevLine = line;
|
|
181
190
|
}
|
package/dist/index.js
CHANGED
|
@@ -48,10 +48,10 @@ function filterDiffLines(diffText) {
|
|
|
48
48
|
function normalizeCode(lines) {
|
|
49
49
|
return lines.map((line) => {
|
|
50
50
|
let normalized = line;
|
|
51
|
-
normalized = normalized.replace(/;$/, "");
|
|
52
51
|
normalized = normalized.replace(/\/\/.*$/, "");
|
|
53
52
|
normalized = normalized.replace(/\/\*.*?\*\//, "");
|
|
54
53
|
normalized = normalized.trim();
|
|
54
|
+
normalized = normalized.replace(/;$/, "");
|
|
55
55
|
return normalized;
|
|
56
56
|
}).filter((line) => line.length > 0);
|
|
57
57
|
}
|
|
@@ -88,7 +88,13 @@ function isLoop(line) {
|
|
|
88
88
|
return /^(for|while)\s*\(/.test(line.trim());
|
|
89
89
|
}
|
|
90
90
|
function isFunctionDeclaration(line) {
|
|
91
|
-
|
|
91
|
+
const t = line.trim();
|
|
92
|
+
return (
|
|
93
|
+
// function foo() / async function foo()
|
|
94
|
+
/^(async\s+)?function\s+\w+/.test(t) || // const foo = () => / const foo = async () => / const foo = async (x: T) =>
|
|
95
|
+
/^(const|let|var)\s+\w+\s*=\s*(async\s*)?\(/.test(t) || // const foo = function / const foo = async function
|
|
96
|
+
/^(const|let|var)\s+\w+\s*=\s*(async\s+)?function/.test(t)
|
|
97
|
+
);
|
|
92
98
|
}
|
|
93
99
|
function shouldIgnore(line) {
|
|
94
100
|
const ignorePatterns = [
|
|
@@ -147,6 +153,19 @@ function parseToFlowTree(lines) {
|
|
|
147
153
|
prevLine = line;
|
|
148
154
|
continue;
|
|
149
155
|
}
|
|
156
|
+
if (isFunctionDeclaration(line)) {
|
|
157
|
+
const funcMatch = line.match(/(?:function|const|let|var)\s+(\w+)/);
|
|
158
|
+
roots.push({
|
|
159
|
+
type: "function",
|
|
160
|
+
name: funcMatch ? `${funcMatch[1]}()` : "function()",
|
|
161
|
+
children: [],
|
|
162
|
+
depth: relativeDepth,
|
|
163
|
+
priority: 4 /* FUNCTION */
|
|
164
|
+
});
|
|
165
|
+
currentChain = null;
|
|
166
|
+
prevLine = line;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
150
169
|
const root = extractRoot(line);
|
|
151
170
|
if (root) {
|
|
152
171
|
currentChain = {
|
|
@@ -177,16 +196,6 @@ function parseToFlowTree(lines) {
|
|
|
177
196
|
priority: 3 /* LOOP */
|
|
178
197
|
});
|
|
179
198
|
currentChain = null;
|
|
180
|
-
} else if (isFunctionDeclaration(line)) {
|
|
181
|
-
const funcMatch = line.match(/(?:function|const|let|var)\s+(\w+)/);
|
|
182
|
-
roots.push({
|
|
183
|
-
type: "function",
|
|
184
|
-
name: funcMatch ? `${funcMatch[1]}()` : "function()",
|
|
185
|
-
children: [],
|
|
186
|
-
depth: relativeDepth,
|
|
187
|
-
priority: 4 /* FUNCTION */
|
|
188
|
-
});
|
|
189
|
-
currentChain = null;
|
|
190
199
|
}
|
|
191
200
|
prevLine = line;
|
|
192
201
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -16,10 +16,10 @@ function filterDiffLines(diffText) {
|
|
|
16
16
|
function normalizeCode(lines) {
|
|
17
17
|
return lines.map((line) => {
|
|
18
18
|
let normalized = line;
|
|
19
|
-
normalized = normalized.replace(/;$/, "");
|
|
20
19
|
normalized = normalized.replace(/\/\/.*$/, "");
|
|
21
20
|
normalized = normalized.replace(/\/\*.*?\*\//, "");
|
|
22
21
|
normalized = normalized.trim();
|
|
22
|
+
normalized = normalized.replace(/;$/, "");
|
|
23
23
|
return normalized;
|
|
24
24
|
}).filter((line) => line.length > 0);
|
|
25
25
|
}
|
|
@@ -56,7 +56,13 @@ function isLoop(line) {
|
|
|
56
56
|
return /^(for|while)\s*\(/.test(line.trim());
|
|
57
57
|
}
|
|
58
58
|
function isFunctionDeclaration(line) {
|
|
59
|
-
|
|
59
|
+
const t = line.trim();
|
|
60
|
+
return (
|
|
61
|
+
// function foo() / async function foo()
|
|
62
|
+
/^(async\s+)?function\s+\w+/.test(t) || // const foo = () => / const foo = async () => / const foo = async (x: T) =>
|
|
63
|
+
/^(const|let|var)\s+\w+\s*=\s*(async\s*)?\(/.test(t) || // const foo = function / const foo = async function
|
|
64
|
+
/^(const|let|var)\s+\w+\s*=\s*(async\s+)?function/.test(t)
|
|
65
|
+
);
|
|
60
66
|
}
|
|
61
67
|
function shouldIgnore(line) {
|
|
62
68
|
const ignorePatterns = [
|
|
@@ -115,6 +121,19 @@ function parseToFlowTree(lines) {
|
|
|
115
121
|
prevLine = line;
|
|
116
122
|
continue;
|
|
117
123
|
}
|
|
124
|
+
if (isFunctionDeclaration(line)) {
|
|
125
|
+
const funcMatch = line.match(/(?:function|const|let|var)\s+(\w+)/);
|
|
126
|
+
roots.push({
|
|
127
|
+
type: "function",
|
|
128
|
+
name: funcMatch ? `${funcMatch[1]}()` : "function()",
|
|
129
|
+
children: [],
|
|
130
|
+
depth: relativeDepth,
|
|
131
|
+
priority: 4 /* FUNCTION */
|
|
132
|
+
});
|
|
133
|
+
currentChain = null;
|
|
134
|
+
prevLine = line;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
118
137
|
const root = extractRoot(line);
|
|
119
138
|
if (root) {
|
|
120
139
|
currentChain = {
|
|
@@ -145,16 +164,6 @@ function parseToFlowTree(lines) {
|
|
|
145
164
|
priority: 3 /* LOOP */
|
|
146
165
|
});
|
|
147
166
|
currentChain = null;
|
|
148
|
-
} else if (isFunctionDeclaration(line)) {
|
|
149
|
-
const funcMatch = line.match(/(?:function|const|let|var)\s+(\w+)/);
|
|
150
|
-
roots.push({
|
|
151
|
-
type: "function",
|
|
152
|
-
name: funcMatch ? `${funcMatch[1]}()` : "function()",
|
|
153
|
-
children: [],
|
|
154
|
-
depth: relativeDepth,
|
|
155
|
-
priority: 4 /* FUNCTION */
|
|
156
|
-
});
|
|
157
|
-
currentChain = null;
|
|
158
167
|
}
|
|
159
168
|
prevLine = line;
|
|
160
169
|
}
|
package/package.json
CHANGED