Skip to content

Commit f536a7c

Browse files
committed
fix website @milestone mentions
1 parent cd4c704 commit f536a7c

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
const pat = process.env.GITHUB_PAT;
2+
3+
const headers = { Authorization: `token ${pat}` };
4+
5+
import fetch from 'node-fetch';
6+
7+
const repo = `infinite-table/infinite-react`;
8+
9+
interface GithubIssue {
10+
title: string;
11+
state: 'open' | 'closed';
12+
labels: { name: string }[];
13+
html_url: string;
14+
type?: string;
15+
}
16+
17+
const order = ['open', 'closed'];
18+
const sortOpenFirst = (issue1: GithubIssue, issue2: GithubIssue) => {
19+
const state1 = issue1.state;
20+
const state2 = issue2.state;
21+
22+
if (state1 === state2) {
23+
return 0;
24+
}
25+
return order.indexOf(state1) - order.indexOf(state2);
26+
};
27+
28+
async function fetchAllMilestoneIssues(
29+
milestone: string | number,
30+
status = 'all',
31+
currentPage = 0,
32+
) {
33+
const url = `https://api.github.com/repos/${repo}/issues?milestone=${milestone}&state=${status}&per_page=100`;
34+
35+
const issues: GithubIssue[] = (
36+
await fetch(url, { headers })
37+
).json() as unknown as GithubIssue[];
38+
39+
if (issues.length) {
40+
issues.push(
41+
...(await fetchAllMilestoneIssues(milestone, status, currentPage + 1)),
42+
);
43+
}
44+
45+
return issues;
46+
}
47+
48+
async function getMilestone(milestone: string | number, status = 'all') {
49+
const url = `https://api.github.com/repos/${repo}/issues?milestone=${milestone}&state=${status}`;
50+
51+
const issues = await fetchAllMilestoneIssues(milestone, status);
52+
53+
if (!Array.isArray(issues)) {
54+
console.warn(`Loading of issues for milestone ${milestone} has failed!`);
55+
}
56+
57+
return {
58+
milestone: await (
59+
await fetch(
60+
`https://api.github.com/repos/${repo}/milestones/${milestone}`,
61+
{
62+
headers,
63+
},
64+
)
65+
).json(),
66+
issues: !Array.isArray(issues)
67+
? []
68+
: issues
69+
.map((issue) => {
70+
const typeLabel = issue.labels.find((label) =>
71+
label.name.startsWith('Type'),
72+
);
73+
const result: GithubIssue = {
74+
title: issue.title,
75+
state: issue.state,
76+
labels: issue.labels,
77+
html_url: issue.html_url,
78+
type: typeLabel
79+
? typeLabel.name.slice('Type:'.length).trim()
80+
: issue.labels[0]
81+
? issue.labels[0].name
82+
: '',
83+
};
84+
return result;
85+
})
86+
.sort(sortOpenFirst),
87+
};
88+
}
89+
90+
import { visit } from 'unist-util-visit';
91+
92+
const remarkMilestonePlugin = function () {
93+
const unified = this as any;
94+
const tasks: [number, any, number | null, any][] = [];
95+
96+
return async function transformer(tree: any, file: any) {
97+
visit(tree, 'paragraph', (node, index, parent) => {
98+
if (
99+
node.children &&
100+
node.children[0] &&
101+
node.children[0].type === 'text'
102+
) {
103+
const value = node.children[0].value;
104+
105+
if (!value.startsWith('@milestone')) return;
106+
107+
const parameters = value
108+
.split(/\s+(?=\w+=)/)
109+
.slice(1)
110+
.map((token: string) => token.split('='))
111+
.reduce((acc: Record<string, string>, [k, v]: [string, string]) => {
112+
acc[k] = v.slice(1, -1);
113+
return acc;
114+
}, {});
115+
116+
const id = Number(parameters.id);
117+
118+
tasks.push([id, node, index, parent]);
119+
}
120+
});
121+
122+
await Promise.all(
123+
tasks.map(async ([id, node, index, parent]) => {
124+
const { issues, milestone } = await getMilestone(id);
125+
126+
const content = [
127+
`<table>`,
128+
'<thead>',
129+
'<tr>',
130+
'<th>Type</th>',
131+
'<th width="100%" align="left">Description</th>',
132+
'</tr>',
133+
'</thead>',
134+
// '--- | ---',
135+
...issues.map(
136+
(issue) =>
137+
`<tr><td>${issue.type}</td><td>${
138+
issue.state === 'closed' ? '✅ ' : '🔲 '
139+
}<a href="${
140+
issue.html_url
141+
}" className="ml-2" target="_blank" rel="noopener">${
142+
issue.title
143+
}</a></td></tr>`,
144+
),
145+
'</table>',
146+
].join('');
147+
const children = unified.parse(content).children;
148+
parent.children.splice(index, 1, ...children);
149+
}),
150+
);
151+
};
152+
};
153+
154+
export default remarkMilestonePlugin;

www/src/components/renderMarkdownPage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { siteContent } from '@www/content';
88
import snippetTransformer from '@www/utils/markdownSnippetTransformer';
99
import markdownLinkChecker from '@www/utils/markdownLinkChecker';
1010
import markdownPropLinkChecker from '@www/utils/markdownPropLinkChecker';
11+
import remarkMilestonePlugin from '@www/components/remarkMilestone';
1112
import type { JSX } from 'react';
1213

1314
export async function renderMarkdownPage(options: {
@@ -58,6 +59,7 @@ export async function renderMarkdownPage(options: {
5859
markdownLinkChecker({
5960
fileInfo,
6061
}),
62+
remarkMilestonePlugin,
6163
markdownPropLinkChecker({
6264
fileInfo,
6365
env,

0 commit comments

Comments
 (0)