github-mobile-reader 0.1.2 → 0.1.4

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/dist/action.js CHANGED
@@ -32,7 +32,9 @@ function isJSXFile(filename) {
32
32
  return /\.(jsx|tsx)$/.test(filename);
33
33
  }
34
34
  function hasJSXContent(lines) {
35
- return lines.some((l) => /<[A-Z][A-Za-z]*[\s/>]/.test(l) || /return\s*\(/.test(l));
35
+ return lines.some(
36
+ (l) => /<[A-Z][A-Za-z]*[\s/>]/.test(l) || /return\s*\(/.test(l)
37
+ );
36
38
  }
37
39
  function isClassNameOnlyLine(line) {
38
40
  return /^className=/.test(line.trim());
@@ -40,7 +42,9 @@ function isClassNameOnlyLine(line) {
40
42
  function extractClassName(line) {
41
43
  const staticMatch = line.match(/className="([^"]*)"/);
42
44
  if (staticMatch) return staticMatch[1];
43
- const ternaryMatch = line.match(/className=\{[^?]+\?\s*"([^"]*)"\s*:\s*"([^"]*)"\}/);
45
+ const ternaryMatch = line.match(
46
+ /className=\{[^?]+\?\s*"([^"]*)"\s*:\s*"([^"]*)"\}/
47
+ );
44
48
  if (ternaryMatch) return `${ternaryMatch[1]} ${ternaryMatch[2]}`;
45
49
  const templateMatch = line.match(/className=\{`([^`]*)`\}/);
46
50
  if (templateMatch) {
@@ -62,18 +66,21 @@ function parseClassNameChanges(addedLines, removedLines) {
62
66
  const cls = extractClassName(line);
63
67
  const comp = extractComponentFromLine(line);
64
68
  if (!cls) continue;
65
- if (!componentMap.has(comp)) componentMap.set(comp, { added: /* @__PURE__ */ new Set(), removed: /* @__PURE__ */ new Set() });
69
+ if (!componentMap.has(comp))
70
+ componentMap.set(comp, { added: /* @__PURE__ */ new Set(), removed: /* @__PURE__ */ new Set() });
66
71
  cls.split(/\s+/).filter(Boolean).forEach((c) => componentMap.get(comp).added.add(c));
67
72
  }
68
73
  for (const line of removedLines.filter((l) => /className=/.test(l))) {
69
74
  const cls = extractClassName(line);
70
75
  const comp = extractComponentFromLine(line);
71
76
  if (!cls) continue;
72
- if (!componentMap.has(comp)) componentMap.set(comp, { added: /* @__PURE__ */ new Set(), removed: /* @__PURE__ */ new Set() });
77
+ if (!componentMap.has(comp))
78
+ componentMap.set(comp, { added: /* @__PURE__ */ new Set(), removed: /* @__PURE__ */ new Set() });
73
79
  cls.split(/\s+/).filter(Boolean).forEach((c) => componentMap.get(comp).removed.add(c));
74
80
  }
75
81
  const changes = [];
76
82
  for (const [comp, { added, removed }] of componentMap) {
83
+ if (comp === "unknown") continue;
77
84
  const pureAdded = [...added].filter((c) => !removed.has(c));
78
85
  const pureRemoved = [...removed].filter((c) => !added.has(c));
79
86
  if (pureAdded.length === 0 && pureRemoved.length === 0) continue;
@@ -86,7 +93,8 @@ function renderStyleChanges(changes) {
86
93
  for (const change of changes) {
87
94
  lines.push(`**${change.component}**`);
88
95
  if (change.added.length > 0) lines.push(` + ${change.added.join(" ")}`);
89
- if (change.removed.length > 0) lines.push(` - ${change.removed.join(" ")}`);
96
+ if (change.removed.length > 0)
97
+ lines.push(` - ${change.removed.join(" ")}`);
90
98
  }
91
99
  return lines;
92
100
  }
@@ -155,192 +163,76 @@ function parseJSXToFlowTree(lines) {
155
163
  }
156
164
  function filterDiffLines(diffText) {
157
165
  const lines = diffText.split("\n");
158
- const added = lines.filter((l) => l.startsWith("+") && !l.startsWith("+++") && l.trim() !== "+").map((l) => l.substring(1));
159
- const removed = lines.filter((l) => l.startsWith("-") && !l.startsWith("---") && l.trim() !== "-").map((l) => l.substring(1));
166
+ const added = lines.filter(
167
+ (l) => l.startsWith("+") && !l.startsWith("+++") && l.trim() !== "+"
168
+ ).map((l) => l.substring(1));
169
+ const removed = lines.filter(
170
+ (l) => l.startsWith("-") && !l.startsWith("---") && l.trim() !== "-"
171
+ ).map((l) => l.substring(1));
160
172
  return { added, removed };
161
173
  }
162
- function normalizeCode(lines) {
163
- return lines.map((line) => {
164
- let normalized = line;
165
- normalized = normalized.replace(/\/\/.*$/, "");
166
- normalized = normalized.replace(/\/\*.*?\*\//, "");
167
- normalized = normalized.trim();
168
- normalized = normalized.replace(/;$/, "");
169
- return normalized;
170
- }).filter((line) => line.length > 0);
171
- }
172
174
  function getIndentDepth(line) {
173
175
  const match = line.match(/^(\s*)/);
174
176
  if (!match) return 0;
175
177
  return Math.floor(match[1].length / 2);
176
178
  }
177
- function isChaining(line, prevLine) {
178
- if (!prevLine) return false;
179
- if (!line.trim().startsWith(".")) return false;
180
- if (!prevLine.match(/[)\}]$/)) return false;
181
- return true;
182
- }
183
- function extractChainMethod(line) {
184
- const match = line.match(/\.(\w+)\(/);
185
- if (match) return `${match[1]}()`;
186
- return line.trim();
187
- }
188
- function simplifyCallback(methodCall) {
189
- const arrowMatch = methodCall.match(/(\w+)\((\w+)\s*=>\s*(\w+)\.(\w+)\)/);
190
- if (arrowMatch) {
191
- const [, method, param, , prop] = arrowMatch;
192
- return `${method}(${param} \u2192 ${prop})`;
193
- }
194
- const callbackMatch = methodCall.match(/(\w+)\([^)]+\)/);
195
- if (callbackMatch) return `${callbackMatch[1]}(callback)`;
196
- return methodCall;
197
- }
198
- function isConditional(line) {
199
- return /^(if|else|switch)\s*[\(\{]/.test(line.trim());
200
- }
201
- function isLoop(line) {
202
- return /^(for|while)\s*\(/.test(line.trim());
203
- }
204
- function isFunctionDeclaration(line) {
205
- const t = line.trim();
206
- return (
207
- // function foo() / async function foo()
208
- /^(async\s+)?function\s+\w+/.test(t) || // const foo = () => / const foo = async () => / const foo = async (x: T) =>
209
- /^(const|let|var)\s+\w+\s*=\s*(async\s*)?\(/.test(t) || // const foo = function / const foo = async function
210
- /^(const|let|var)\s+\w+\s*=\s*(async\s+)?function/.test(t)
211
- );
212
- }
213
- function shouldIgnore(line) {
214
- const ignorePatterns = [
215
- /^import\s+/,
216
- /^export\s+/,
217
- /^type\s+/,
218
- /^interface\s+/,
219
- /^console\./,
220
- /^return$/,
221
- /^throw\s+/
222
- ];
223
- return ignorePatterns.some((p) => p.test(line.trim()));
224
- }
225
- function extractRoot(line) {
226
- const assignMatch = line.match(/(?:const|let|var)\s+(\w+)\s*=\s*(\w+)/);
227
- if (assignMatch) return assignMatch[2];
228
- const callMatch = line.match(/^(\w+)\(/);
229
- if (callMatch) return `${callMatch[1]}()`;
230
- const methodMatch = line.match(/^(\w+)\./);
231
- if (methodMatch) return methodMatch[1];
232
- return null;
233
- }
234
- function parseToFlowTree(lines) {
235
- const roots = [];
236
- let currentChain = null;
237
- let prevLine = null;
238
- let baseDepth = -1;
239
- for (let i = 0; i < lines.length; i++) {
240
- const line = lines[i];
241
- if (shouldIgnore(line)) {
242
- prevLine = line;
243
- continue;
244
- }
245
- const depth = getIndentDepth(lines[i]);
246
- if (baseDepth === -1) baseDepth = depth;
247
- const relativeDepth = depth - baseDepth;
248
- if (isChaining(line, prevLine)) {
249
- const method = extractChainMethod(line);
250
- const simplified = simplifyCallback(method);
251
- if (currentChain) {
252
- const chainNode = {
253
- type: "chain",
254
- name: simplified,
255
- children: [],
256
- depth: relativeDepth,
257
- priority: 1 /* CHAINING */
258
- };
259
- let parent = currentChain;
260
- while (parent.children.length > 0 && parent.children[parent.children.length - 1].depth >= relativeDepth) {
261
- const last = parent.children[parent.children.length - 1];
262
- if (last.children.length > 0) parent = last;
263
- else break;
264
- }
265
- parent.children.push(chainNode);
179
+ function extractChangedSymbols(addedLines, removedLines) {
180
+ const FUNC_RE = /^(?:export\s+)?(?:async\s+)?function\s+([a-z]\w+)|^(?:export\s+)?(?:const|let|var)\s+([a-z]\w+)\s*=\s*(?:async\s+)?\(?|^(?:export\s+)?(?:const|let|var)\s+([a-z]\w+)\s*=\s*[a-z]\w+\s*[<(]/;
181
+ const COMPONENT_RE = /^(?:export\s+)?(?:default\s+)?(?:function|const)\s+([A-Z][a-z][A-Za-z0-9]*)/;
182
+ const extract = (lines) => {
183
+ const names = /* @__PURE__ */ new Set();
184
+ for (const line of lines) {
185
+ const cm = line.match(COMPONENT_RE) || line.match(FUNC_RE);
186
+ if (cm) {
187
+ const name = cm[1] || cm[2] || cm[3];
188
+ if (name) names.add(name);
266
189
  }
267
- prevLine = line;
268
- continue;
269
- }
270
- if (isFunctionDeclaration(line)) {
271
- const funcMatch = line.match(/(?:function|const|let|var)\s+(\w+)/);
272
- roots.push({
273
- type: "function",
274
- name: funcMatch ? `${funcMatch[1]}()` : "function()",
275
- children: [],
276
- depth: relativeDepth,
277
- priority: 4 /* FUNCTION */
278
- });
279
- currentChain = null;
280
- prevLine = line;
281
- continue;
282
190
  }
283
- const root = extractRoot(line);
284
- if (root) {
285
- currentChain = {
286
- type: "root",
287
- name: root,
288
- children: [],
289
- depth: relativeDepth,
290
- priority: 1 /* CHAINING */
291
- };
292
- roots.push(currentChain);
293
- } else if (isConditional(line)) {
294
- const condMatch = line.match(/(if|else|switch)\s*\(([^)]+)\)/);
295
- const condName = condMatch ? `${condMatch[1]} (${condMatch[2]})` : line.trim();
296
- roots.push({
297
- type: "condition",
298
- name: condName,
299
- children: [],
300
- depth: relativeDepth,
301
- priority: 2 /* CONDITIONAL */
302
- });
303
- currentChain = null;
304
- } else if (isLoop(line)) {
305
- roots.push({
306
- type: "loop",
307
- name: "loop",
308
- children: [],
309
- depth: relativeDepth,
310
- priority: 3 /* LOOP */
311
- });
312
- currentChain = null;
191
+ return names;
192
+ };
193
+ const addedNames = extract(addedLines);
194
+ const removedNames = extract(removedLines);
195
+ const results = [];
196
+ const seen = /* @__PURE__ */ new Set();
197
+ for (const name of addedNames) {
198
+ seen.add(name);
199
+ results.push({
200
+ name,
201
+ status: removedNames.has(name) ? "modified" : "added"
202
+ });
203
+ }
204
+ for (const name of removedNames) {
205
+ if (!seen.has(name)) {
206
+ results.push({ name, status: "removed" });
313
207
  }
314
- prevLine = line;
315
208
  }
316
- return roots;
209
+ return results;
317
210
  }
318
- function renderFlowTree(nodes, indent = 0) {
211
+ function renderJSXTreeCompact(nodes, maxDepth = 3) {
319
212
  const lines = [];
320
- const prefix = indent === 0 ? "" : " ".repeat((indent - 1) * 4) + " \u2514\u2500 ";
321
- for (const node of nodes) {
322
- lines.push(prefix + node.name);
323
- if (node.children.length > 0) {
324
- lines.push(...renderFlowTree(node.children, indent + 1));
213
+ function walk(node, depth) {
214
+ if (depth > maxDepth) return;
215
+ const indent = " ".repeat(depth);
216
+ const hasChildren = node.children.length > 0;
217
+ lines.push(`${indent}${node.name}${hasChildren ? "" : ""}`);
218
+ for (const child of node.children) {
219
+ walk(child, depth + 1);
325
220
  }
326
221
  }
327
- return lines;
222
+ for (const root of nodes) {
223
+ walk(root, 0);
224
+ }
225
+ return lines.join("\n");
328
226
  }
329
227
  function generateReaderMarkdown(diffText, meta = {}) {
330
228
  const { added, removed } = filterDiffLines(diffText);
331
229
  const isJSX = Boolean(
332
230
  meta.file && isJSXFile(meta.file) || hasJSXContent(added)
333
231
  );
334
- const addedForFlow = isJSX ? added.filter((l) => !isClassNameOnlyLine(l)) : added;
335
- const normalizedAdded = normalizeCode(addedForFlow);
336
- const flowTree = parseToFlowTree(normalizedAdded);
337
- const rawCode = addedForFlow.join("\n");
338
- const removedForCode = isJSX ? removed.filter((l) => !isClassNameOnlyLine(l)) : removed;
339
- const removedCode = removedForCode.join("\n");
232
+ const changedSymbols = extractChangedSymbols(added, removed);
340
233
  const classNameChanges = isJSX ? parseClassNameChanges(added, removed) : [];
341
234
  const jsxTree = isJSX ? parseJSXToFlowTree(added) : [];
342
235
  const sections = [];
343
- const lang = isJSX ? "tsx" : "typescript";
344
236
  sections.push("# \u{1F4D6} GitHub Reader View\n");
345
237
  sections.push("> Generated by **github-mobile-reader**");
346
238
  if (meta.repo) sections.push(`> Repository: ${meta.repo}`);
@@ -348,37 +240,29 @@ function generateReaderMarkdown(diffText, meta = {}) {
348
240
  if (meta.commit) sections.push(`> Commit: \`${meta.commit}\``);
349
241
  if (meta.file) sections.push(`> File: \`${meta.file}\``);
350
242
  sections.push("\n");
351
- if (flowTree.length > 0) {
352
- sections.push("## \u{1F9E0} Logical Flow\n");
353
- sections.push("```");
354
- sections.push(...renderFlowTree(flowTree));
355
- sections.push("```\n");
243
+ if (changedSymbols.length > 0) {
244
+ sections.push("### \uBCC0\uACBD\uB41C \uD568\uC218 / \uCEF4\uD3EC\uB10C\uD2B8\n");
245
+ const STATUS_ICON = { added: "\u2705", removed: "\u274C", modified: "\u270F\uFE0F" };
246
+ for (const { name, status } of changedSymbols) {
247
+ sections.push(`- ${STATUS_ICON[status]} \`${name}()\` \u2014 ${status}`);
248
+ }
249
+ sections.push("");
356
250
  }
357
251
  if (isJSX && jsxTree.length > 0) {
358
- sections.push("## \u{1F3A8} JSX Structure\n");
252
+ sections.push("### \u{1F3A8} JSX Structure\n");
359
253
  sections.push("```");
360
- sections.push(...renderFlowTree(jsxTree));
254
+ sections.push(renderJSXTreeCompact(jsxTree));
361
255
  sections.push("```\n");
362
256
  }
363
257
  if (isJSX && classNameChanges.length > 0) {
364
- sections.push("## \u{1F485} Style Changes\n");
258
+ sections.push("### \u{1F485} Style Changes\n");
365
259
  sections.push(...renderStyleChanges(classNameChanges));
366
260
  sections.push("");
367
261
  }
368
- if (rawCode.trim()) {
369
- sections.push("## \u2705 Added Code\n");
370
- sections.push(`\`\`\`${lang}`);
371
- sections.push(rawCode);
372
- sections.push("```\n");
373
- }
374
- if (removedCode.trim()) {
375
- sections.push("## \u274C Removed Code\n");
376
- sections.push(`\`\`\`${lang}`);
377
- sections.push(removedCode);
378
- sections.push("```\n");
379
- }
380
262
  sections.push("---");
381
- sections.push("\u{1F6E0} Auto-generated by [github-mobile-reader](https://github.com/your-org/github-mobile-reader). Do not edit manually.");
263
+ sections.push(
264
+ "\u{1F6E0} Auto-generated by [github-mobile-reader](https://github.com/3rdflr/github-mobile-reader). Do not edit manually."
265
+ );
382
266
  return sections.join("\n");
383
267
  }
384
268