Skip to content

Commit 99bf927

Browse files
committed
Add issue to markdown script
1 parent d36d5e6 commit 99bf927

File tree

2 files changed

+236
-0
lines changed

2 files changed

+236
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# GitHub Issue to Markdown Converter
2+
3+
A standalone TypeScript script that converts GitHub issue JSON files (with comments) into readable Markdown format.
4+
5+
## Features
6+
7+
- Converts GitHub issue JSON to clean Markdown
8+
- Includes issue metadata (author, date, comment count)
9+
- Formats all comments with author and date information
10+
- Highlights author associations (MEMBER, CONTRIBUTOR, etc.)
11+
- Uses only built-in Node.js modules (no dependencies)
12+
- Can be run with Bun, Node.js, or ts-node
13+
14+
## Usage
15+
16+
### With Bun (recommended)
17+
18+
```bash
19+
bun run packages/toolkit/scripts/github-issue-to-markdown.ts <input-json-file> [output-md-file]
20+
```
21+
22+
### With ts-node
23+
24+
```bash
25+
npx ts-node packages/toolkit/scripts/github-issue-to-markdown.ts <input-json-file> [output-md-file]
26+
```
27+
28+
### With Node.js (after compilation)
29+
30+
```bash
31+
tsc packages/toolkit/scripts/github-issue-to-markdown.ts
32+
node packages/toolkit/scripts/github-issue-to-markdown.js <input-json-file> [output-md-file]
33+
```
34+
35+
## Arguments
36+
37+
- `<input-json-file>` (required): Path to the GitHub issue JSON file
38+
- `[output-md-file]` (optional): Path for the output Markdown file. If not specified, uses the input filename with `.md` extension
39+
40+
## Examples
41+
42+
### Basic usage (auto-generate output filename)
43+
44+
```bash
45+
bun run packages/toolkit/scripts/github-issue-to-markdown.ts docs/dev-plans/issue-3692-comments.json
46+
# Creates: docs/dev-plans/issue-3692-comments.md
47+
```
48+
49+
### Specify output filename
50+
51+
```bash
52+
bun run packages/toolkit/scripts/github-issue-to-markdown.ts docs/dev-plans/issue-3692-comments.json docs/dev-plans/rtk-query-feedback.md
53+
```
54+
55+
## Input Format
56+
57+
The script expects a JSON file with the following structure:
58+
59+
```json
60+
{
61+
"number": 3692,
62+
"title": "Issue title",
63+
"user": {
64+
"login": "username",
65+
"id": 12345
66+
},
67+
"created_at": "2023-09-01T17:41:01Z",
68+
"updated_at": "2023-09-01T17:41:01Z",
69+
"body": "Issue description...",
70+
"author_association": "MEMBER",
71+
"comments": 106,
72+
"comments_data": [
73+
{
74+
"id": 1703237481,
75+
"user": {
76+
"login": "commenter",
77+
"id": 67890
78+
},
79+
"created_at": "2023-09-01T19:35:29Z",
80+
"updated_at": "2023-09-01T19:35:29Z",
81+
"body": "Comment text...",
82+
"author_association": "NONE"
83+
}
84+
]
85+
}
86+
```
87+
88+
## Output Format
89+
90+
The script generates a Markdown file with:
91+
92+
1. Issue header with number and title
93+
2. Issue metadata (author, date, comment count)
94+
3. Issue description
95+
4. All comments with:
96+
- Horizontal rule separator
97+
- Comment author and date
98+
- Author association badge (if not NONE)
99+
- Comment body text
100+
101+
## Notes
102+
103+
- Dates are formatted as YYYY-MM-DD
104+
- The script preserves all Markdown formatting in issue/comment bodies
105+
- Author associations like MEMBER, CONTRIBUTOR are displayed as emphasized text
106+
- Comments are separated by horizontal rules (`---`) for readability
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Converts a GitHub issue JSON file (with comments) to a readable Markdown format.
4+
*
5+
* Usage:
6+
* bun run github-issue-to-markdown.ts <input-json-file> [output-md-file]
7+
*
8+
* If output file is not specified, it will use the input filename with .md extension
9+
*/
10+
11+
import { readFileSync, writeFileSync } from 'fs'
12+
import { resolve, dirname, basename, extname } from 'path'
13+
14+
interface GitHubUser {
15+
login: string
16+
id: number
17+
}
18+
19+
interface GitHubComment {
20+
id: number
21+
user: GitHubUser
22+
created_at: string
23+
updated_at: string
24+
body: string
25+
author_association: string
26+
}
27+
28+
interface GitHubIssue {
29+
number: number
30+
title: string
31+
user: GitHubUser
32+
created_at: string
33+
updated_at: string
34+
body: string
35+
author_association: string
36+
comments: number
37+
comments_data?: GitHubComment[]
38+
}
39+
40+
function formatDate(dateString: string): string {
41+
const date = new Date(dateString)
42+
return date.toISOString().split('T')[0]
43+
}
44+
45+
function convertIssueToMarkdown(issue: GitHubIssue): string {
46+
let markdown = ''
47+
48+
// Issue header
49+
markdown += `# Issue #${issue.number}: ${issue.title}\n\n`
50+
51+
// Issue metadata
52+
markdown += `**Author:** ${issue.user.login}\n`
53+
markdown += `**Date:** ${formatDate(issue.created_at)}\n`
54+
markdown += `**Comments:** ${issue.comments}\n\n`
55+
56+
// Issue body
57+
markdown += `## Issue Description\n\n`
58+
markdown += `${issue.body}\n\n`
59+
60+
// Comments section
61+
if (issue.comments_data && issue.comments_data.length > 0) {
62+
markdown += `## Comments (${issue.comments_data.length})\n\n`
63+
64+
for (const comment of issue.comments_data) {
65+
markdown += `---\n\n`
66+
markdown += `### Comment by ${comment.user.login} on ${formatDate(comment.created_at)}\n\n`
67+
68+
if (comment.author_association && comment.author_association !== 'NONE') {
69+
markdown += `_${comment.author_association}_\n\n`
70+
}
71+
72+
markdown += `${comment.body}\n\n`
73+
}
74+
}
75+
76+
return markdown
77+
}
78+
79+
function main() {
80+
const args = process.argv.slice(2)
81+
82+
if (args.length === 0) {
83+
console.error('Error: No input file specified')
84+
console.error(
85+
'Usage: bun run github-issue-to-markdown.ts <input-json-file> [output-md-file]',
86+
)
87+
process.exit(1)
88+
}
89+
90+
const inputFile = resolve(args[0])
91+
let outputFile: string
92+
93+
if (args.length > 1) {
94+
outputFile = resolve(args[1])
95+
} else {
96+
// Generate output filename from input filename
97+
const dir = dirname(inputFile)
98+
const base = basename(inputFile, extname(inputFile))
99+
outputFile = resolve(dir, `${base}.md`)
100+
}
101+
102+
try {
103+
// Read and parse JSON file
104+
console.log(`Reading ${inputFile}...`)
105+
const jsonContent = readFileSync(inputFile, 'utf-8')
106+
const issue: GitHubIssue = JSON.parse(jsonContent)
107+
108+
// Convert to Markdown
109+
console.log('Converting to Markdown...')
110+
const markdown = convertIssueToMarkdown(issue)
111+
112+
// Write output file
113+
console.log(`Writing to ${outputFile}...`)
114+
writeFileSync(outputFile, markdown, 'utf-8')
115+
116+
console.log('✓ Conversion complete!')
117+
console.log(` Input: ${inputFile}`)
118+
console.log(` Output: ${outputFile}`)
119+
console.log(` Comments: ${issue.comments_data?.length || 0}`)
120+
} catch (error) {
121+
if (error instanceof Error) {
122+
console.error(`Error: ${error.message}`)
123+
} else {
124+
console.error('An unknown error occurred')
125+
}
126+
process.exit(1)
127+
}
128+
}
129+
130+
main()

0 commit comments

Comments
 (0)