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/index.mjs CHANGED
@@ -11,7 +11,9 @@ function isJSXFile(filename) {
11
11
  return /\.(jsx|tsx)$/.test(filename);
12
12
  }
13
13
  function hasJSXContent(lines) {
14
- return lines.some((l) => /<[A-Z][A-Za-z]*[\s/>]/.test(l) || /return\s*\(/.test(l));
14
+ return lines.some(
15
+ (l) => /<[A-Z][A-Za-z]*[\s/>]/.test(l) || /return\s*\(/.test(l)
16
+ );
15
17
  }
16
18
  function isClassNameOnlyLine(line) {
17
19
  return /^className=/.test(line.trim());
@@ -19,7 +21,9 @@ function isClassNameOnlyLine(line) {
19
21
  function extractClassName(line) {
20
22
  const staticMatch = line.match(/className="([^"]*)"/);
21
23
  if (staticMatch) return staticMatch[1];
22
- const ternaryMatch = line.match(/className=\{[^?]+\?\s*"([^"]*)"\s*:\s*"([^"]*)"\}/);
24
+ const ternaryMatch = line.match(
25
+ /className=\{[^?]+\?\s*"([^"]*)"\s*:\s*"([^"]*)"\}/
26
+ );
23
27
  if (ternaryMatch) return `${ternaryMatch[1]} ${ternaryMatch[2]}`;
24
28
  const templateMatch = line.match(/className=\{`([^`]*)`\}/);
25
29
  if (templateMatch) {
@@ -41,18 +45,21 @@ function parseClassNameChanges(addedLines, removedLines) {
41
45
  const cls = extractClassName(line);
42
46
  const comp = extractComponentFromLine(line);
43
47
  if (!cls) continue;
44
- if (!componentMap.has(comp)) componentMap.set(comp, { added: /* @__PURE__ */ new Set(), removed: /* @__PURE__ */ new Set() });
48
+ if (!componentMap.has(comp))
49
+ componentMap.set(comp, { added: /* @__PURE__ */ new Set(), removed: /* @__PURE__ */ new Set() });
45
50
  cls.split(/\s+/).filter(Boolean).forEach((c) => componentMap.get(comp).added.add(c));
46
51
  }
47
52
  for (const line of removedLines.filter((l) => /className=/.test(l))) {
48
53
  const cls = extractClassName(line);
49
54
  const comp = extractComponentFromLine(line);
50
55
  if (!cls) continue;
51
- if (!componentMap.has(comp)) componentMap.set(comp, { added: /* @__PURE__ */ new Set(), removed: /* @__PURE__ */ new Set() });
56
+ if (!componentMap.has(comp))
57
+ componentMap.set(comp, { added: /* @__PURE__ */ new Set(), removed: /* @__PURE__ */ new Set() });
52
58
  cls.split(/\s+/).filter(Boolean).forEach((c) => componentMap.get(comp).removed.add(c));
53
59
  }
54
60
  const changes = [];
55
61
  for (const [comp, { added, removed }] of componentMap) {
62
+ if (comp === "unknown") continue;
56
63
  const pureAdded = [...added].filter((c) => !removed.has(c));
57
64
  const pureRemoved = [...removed].filter((c) => !added.has(c));
58
65
  if (pureAdded.length === 0 && pureRemoved.length === 0) continue;
@@ -65,7 +72,8 @@ function renderStyleChanges(changes) {
65
72
  for (const change of changes) {
66
73
  lines.push(`**${change.component}**`);
67
74
  if (change.added.length > 0) lines.push(` + ${change.added.join(" ")}`);
68
- if (change.removed.length > 0) lines.push(` - ${change.removed.join(" ")}`);
75
+ if (change.removed.length > 0)
76
+ lines.push(` - ${change.removed.join(" ")}`);
69
77
  }
70
78
  return lines;
71
79
  }
@@ -134,8 +142,12 @@ function parseJSXToFlowTree(lines) {
134
142
  }
135
143
  function filterDiffLines(diffText) {
136
144
  const lines = diffText.split("\n");
137
- const added = lines.filter((l) => l.startsWith("+") && !l.startsWith("+++") && l.trim() !== "+").map((l) => l.substring(1));
138
- const removed = lines.filter((l) => l.startsWith("-") && !l.startsWith("---") && l.trim() !== "-").map((l) => l.substring(1));
145
+ const added = lines.filter(
146
+ (l) => l.startsWith("+") && !l.startsWith("+++") && l.trim() !== "+"
147
+ ).map((l) => l.substring(1));
148
+ const removed = lines.filter(
149
+ (l) => l.startsWith("-") && !l.startsWith("---") && l.trim() !== "-"
150
+ ).map((l) => l.substring(1));
139
151
  return { added, removed };
140
152
  }
141
153
  function normalizeCode(lines) {
@@ -315,21 +327,63 @@ function parseDiffToLogicalFlow(diffText) {
315
327
  removedCode: removed.join("\n")
316
328
  };
317
329
  }
330
+ function extractChangedSymbols(addedLines, removedLines) {
331
+ 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*[<(]/;
332
+ const COMPONENT_RE = /^(?:export\s+)?(?:default\s+)?(?:function|const)\s+([A-Z][a-z][A-Za-z0-9]*)/;
333
+ const extract = (lines) => {
334
+ const names = /* @__PURE__ */ new Set();
335
+ for (const line of lines) {
336
+ const cm = line.match(COMPONENT_RE) || line.match(FUNC_RE);
337
+ if (cm) {
338
+ const name = cm[1] || cm[2] || cm[3];
339
+ if (name) names.add(name);
340
+ }
341
+ }
342
+ return names;
343
+ };
344
+ const addedNames = extract(addedLines);
345
+ const removedNames = extract(removedLines);
346
+ const results = [];
347
+ const seen = /* @__PURE__ */ new Set();
348
+ for (const name of addedNames) {
349
+ seen.add(name);
350
+ results.push({
351
+ name,
352
+ status: removedNames.has(name) ? "modified" : "added"
353
+ });
354
+ }
355
+ for (const name of removedNames) {
356
+ if (!seen.has(name)) {
357
+ results.push({ name, status: "removed" });
358
+ }
359
+ }
360
+ return results;
361
+ }
362
+ function renderJSXTreeCompact(nodes, maxDepth = 3) {
363
+ const lines = [];
364
+ function walk(node, depth) {
365
+ if (depth > maxDepth) return;
366
+ const indent = " ".repeat(depth);
367
+ const hasChildren = node.children.length > 0;
368
+ lines.push(`${indent}${node.name}${hasChildren ? "" : ""}`);
369
+ for (const child of node.children) {
370
+ walk(child, depth + 1);
371
+ }
372
+ }
373
+ for (const root of nodes) {
374
+ walk(root, 0);
375
+ }
376
+ return lines.join("\n");
377
+ }
318
378
  function generateReaderMarkdown(diffText, meta = {}) {
319
379
  const { added, removed } = filterDiffLines(diffText);
320
380
  const isJSX = Boolean(
321
381
  meta.file && isJSXFile(meta.file) || hasJSXContent(added)
322
382
  );
323
- const addedForFlow = isJSX ? added.filter((l) => !isClassNameOnlyLine(l)) : added;
324
- const normalizedAdded = normalizeCode(addedForFlow);
325
- const flowTree = parseToFlowTree(normalizedAdded);
326
- const rawCode = addedForFlow.join("\n");
327
- const removedForCode = isJSX ? removed.filter((l) => !isClassNameOnlyLine(l)) : removed;
328
- const removedCode = removedForCode.join("\n");
383
+ const changedSymbols = extractChangedSymbols(added, removed);
329
384
  const classNameChanges = isJSX ? parseClassNameChanges(added, removed) : [];
330
385
  const jsxTree = isJSX ? parseJSXToFlowTree(added) : [];
331
386
  const sections = [];
332
- const lang = isJSX ? "tsx" : "typescript";
333
387
  sections.push("# \u{1F4D6} GitHub Reader View\n");
334
388
  sections.push("> Generated by **github-mobile-reader**");
335
389
  if (meta.repo) sections.push(`> Repository: ${meta.repo}`);
@@ -337,41 +391,34 @@ function generateReaderMarkdown(diffText, meta = {}) {
337
391
  if (meta.commit) sections.push(`> Commit: \`${meta.commit}\``);
338
392
  if (meta.file) sections.push(`> File: \`${meta.file}\``);
339
393
  sections.push("\n");
340
- if (flowTree.length > 0) {
341
- sections.push("## \u{1F9E0} Logical Flow\n");
342
- sections.push("```");
343
- sections.push(...renderFlowTree(flowTree));
344
- sections.push("```\n");
394
+ if (changedSymbols.length > 0) {
395
+ sections.push("### \uBCC0\uACBD\uB41C \uD568\uC218 / \uCEF4\uD3EC\uB10C\uD2B8\n");
396
+ const STATUS_ICON = { added: "\u2705", removed: "\u274C", modified: "\u270F\uFE0F" };
397
+ for (const { name, status } of changedSymbols) {
398
+ sections.push(`- ${STATUS_ICON[status]} \`${name}()\` \u2014 ${status}`);
399
+ }
400
+ sections.push("");
345
401
  }
346
402
  if (isJSX && jsxTree.length > 0) {
347
- sections.push("## \u{1F3A8} JSX Structure\n");
403
+ sections.push("### \u{1F3A8} JSX Structure\n");
348
404
  sections.push("```");
349
- sections.push(...renderFlowTree(jsxTree));
405
+ sections.push(renderJSXTreeCompact(jsxTree));
350
406
  sections.push("```\n");
351
407
  }
352
408
  if (isJSX && classNameChanges.length > 0) {
353
- sections.push("## \u{1F485} Style Changes\n");
409
+ sections.push("### \u{1F485} Style Changes\n");
354
410
  sections.push(...renderStyleChanges(classNameChanges));
355
411
  sections.push("");
356
412
  }
357
- if (rawCode.trim()) {
358
- sections.push("## \u2705 Added Code\n");
359
- sections.push(`\`\`\`${lang}`);
360
- sections.push(rawCode);
361
- sections.push("```\n");
362
- }
363
- if (removedCode.trim()) {
364
- sections.push("## \u274C Removed Code\n");
365
- sections.push(`\`\`\`${lang}`);
366
- sections.push(removedCode);
367
- sections.push("```\n");
368
- }
369
413
  sections.push("---");
370
- sections.push("\u{1F6E0} Auto-generated by [github-mobile-reader](https://github.com/your-org/github-mobile-reader). Do not edit manually.");
414
+ sections.push(
415
+ "\u{1F6E0} Auto-generated by [github-mobile-reader](https://github.com/3rdflr/github-mobile-reader). Do not edit manually."
416
+ );
371
417
  return sections.join("\n");
372
418
  }
373
419
  export {
374
420
  Priority,
421
+ extractChangedSymbols,
375
422
  extractClassName,
376
423
  extractJSXComponentName,
377
424
  filterDiffLines,
@@ -386,5 +433,6 @@ export {
386
433
  parseJSXToFlowTree,
387
434
  parseToFlowTree,
388
435
  renderFlowTree,
436
+ renderJSXTreeCompact,
389
437
  renderStyleChanges
390
438
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-mobile-reader",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Transform git diffs into mobile-friendly Markdown — no more horizontal scrolling when reviewing code on your phone.",
5
5
  "keywords": [
6
6
  "github",