Skip to content

Commit 0206457

Browse files
refactor(migrate): use ts and create diff visualizer
1 parent 61c0477 commit 0206457

File tree

3 files changed

+386
-28
lines changed

3 files changed

+386
-28
lines changed
Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#!/usr/bin/env node
2-
31
import { Octokit } from "@octokit/rest";
42
import { JSDOM } from "jsdom";
53
import fs, { readFile } from "fs/promises";
@@ -25,14 +23,14 @@ if (!OPENROUTER_API_KEY) {
2523

2624
const octokit = new Octokit({ auth: GITHUB_TOKEN });
2725

28-
async function retry(fn, retries = 3, delay = 1000) {
29-
let lastError;
26+
async function retry<T>(fn: () => Promise<T>, retries = 3, delay = 1000): Promise<T> {
27+
let lastError: unknown;
3028
for (let attempt = 1; attempt <= retries; attempt++) {
3129
try {
3230
return await fn();
3331
} catch (error) {
3432
lastError = error;
35-
console.warn(`Attempt ${attempt} failed: ${error.message}`);
33+
console.warn(`Attempt ${attempt} failed: ${error instanceof Error ? error.message : String(error)}`);
3634
if (attempt < retries) {
3735
await new Promise((res) => setTimeout(res, delay));
3836
}
@@ -41,17 +39,17 @@ async function retry(fn, retries = 3, delay = 1000) {
4139
throw lastError;
4240
}
4341

44-
function extractLink(title) {
42+
function extractLink(title: string): string | null {
4543
const urlRegex = /https?:\/\/.*?cppreference\.com\/w\/[^\s]+/g;
4644
const match = title.match(urlRegex);
4745
return match ? match[0] : null;
4846
}
4947

50-
function hasPRReference(title) {
48+
function hasPRReference(title: string): boolean {
5149
return /\[#\d+\]/.test(title);
5250
}
5351

54-
async function fetchPageContent(url) {
52+
async function fetchPageContent(url: string): Promise<{ html: string; title: string; url: string }> {
5553
const response = await fetch(url);
5654
if (!response.ok) {
5755
throw new Error(`Failed to fetch ${url}: ${response.status}`);
@@ -70,7 +68,7 @@ async function fetchPageContent(url) {
7068
};
7169
}
7270

73-
async function convertToMDX(html, title, url) {
71+
async function convertToMDX(html: string, title: string, url: string): Promise<string> {
7472
const prompt = (await readFile(__dirname + "/PROMPT.md", "utf8")).replace(
7573
"{{LLM_DOCS}}",
7674
await readFile(
@@ -116,7 +114,7 @@ ${html}
116114
throw new Error(`OpenRouter API error: ${error}`);
117115
}
118116

119-
const data = await response.json();
117+
const data = await response.json() as { choices: Array<{ message: { content: string } }> };
120118
let content = data.choices[0].message.content.trim();
121119

122120
console.log("Raw content:", content);
@@ -151,13 +149,13 @@ ${html}
151149
];
152150

153151
const usedComponents = components.filter(
154-
(comp) => content.includes(`<${comp} `) || content.includes(`<${comp}>`),
152+
(comp: string) => content.includes(`<${comp} `) || content.includes(`<${comp}>`),
155153
);
156154

157155
// Remove all existing import statements
158156
content = content
159157
.split("\n")
160-
.filter((line) => !line.startsWith("import "))
158+
.filter((line: string) => !line.startsWith("import "))
161159
.join("\n");
162160

163161
// Sort used components alphabetically
@@ -169,7 +167,7 @@ ${html}
169167
}
170168

171169
// Verify content
172-
let normalElements = [
170+
const normalElements = [
173171
"<div",
174172
"<section",
175173
"<span",
@@ -179,10 +177,11 @@ ${html}
179177
"<tr",
180178
"<td",
181179
"<th",
182-
],
183-
normalElementsCount = 0;
180+
];
181+
let normalElementsCount = 0;
184182
for (const elem of normalElements) {
185-
normalElementsCount += (content.match(new RegExp(elem, "g")) || []).length;
183+
const matches = content.match(new RegExp(elem, "g"));
184+
normalElementsCount += matches ? matches.length : 0;
186185
}
187186

188187
console.log(`Normal HTML elements count: ${normalElementsCount}`);
@@ -195,7 +194,7 @@ ${html}
195194
}
196195

197196
// https://cppreference.com/w/cpp/comments => src/content/docs/cpp/comments.mdx
198-
function getRelativePath(url) {
197+
function getRelativePath(url: string): string {
199198
const match = url.match(/https?:\/\/.*?cppreference\.com\/w\/(.+)\.html$/);
200199
if (!match) {
201200
throw new Error(`无法从URL解析路径: ${url}`);
@@ -204,14 +203,14 @@ function getRelativePath(url) {
204203
return `src/content/docs/${relative}.mdx`;
205204
}
206205

207-
function getLocalPath(url) {
206+
function getLocalPath(url: string): string {
208207
return path.join(
209208
__dirname,
210209
"..", getRelativePath(url)
211210
);
212211
}
213212

214-
async function writeMDXFile(filePath, content, title) {
213+
async function writeMDXFile(filePath: string, content: string, title: string): Promise<void> {
215214
const dir = path.dirname(filePath);
216215
await fs.mkdir(dir, { recursive: true });
217216
const frontmatter = `---
@@ -222,9 +221,11 @@ description: Auto‑generated from cppreference
222221
console.log(`写入 ${filePath}`);
223222
}
224223

225-
async function createPullRequest(issue, filePath, url) {
224+
async function createPullRequest(issue: { number: number; title: string }, filePath: string, url: string): Promise<number> {
226225
const branchName = `migrate/${issue.number}-${Date.now().toString(36)}`;
227-
const prTitle = `feat: migrate ${url.split("/w/").pop().replace(".html", "")} from cppref [#${issue.number}]`;
226+
const page = url.split("/w/").pop();
227+
const pageName = page ? page.replace(".html", "") : "unknown";
228+
const prTitle = `feat: migrate ${pageName} from cppref [#${issue.number}]`;
228229
const commitMessage = prTitle;
229230
const prBody = `自动迁移自 ${url}
230231
@@ -244,7 +245,7 @@ async function createPullRequest(issue, filePath, url) {
244245
execSync(`git commit -m "${commitMessage}"`);
245246
execSync(`git push origin ${branchName}`);
246247
} catch (error) {
247-
console.error("Git操作失败:", error.message);
248+
console.error("Git操作失败:", error instanceof Error ? error.message : String(error));
248249
throw error;
249250
}
250251

@@ -261,7 +262,7 @@ async function createPullRequest(issue, filePath, url) {
261262
return pr.number;
262263
}
263264

264-
async function updateIssue(issue, prNumber, error = null) {
265+
async function updateIssue(issue: { number: number; title: string }, prNumber: number | null, error: unknown = null): Promise<void> {
265266
const newTitle = `[#${prNumber}] ${issue.title.replace(/\[#\d+\]\s*/, "")}`;
266267
await octokit.issues.update({
267268
owner: REPO_OWNER,
@@ -271,11 +272,12 @@ async function updateIssue(issue, prNumber, error = null) {
271272
});
272273

273274
if (error) {
275+
const message = error instanceof Error ? error.message : String(error);
274276
await octokit.issues.createComment({
275277
owner: REPO_OWNER,
276278
repo: REPO_NAME,
277279
issue_number: issue.number,
278-
body: `迁移失败: ${error.message}\n\n已关闭issue。`,
280+
body: `迁移失败: ${message}\n\n已关闭issue。`,
279281
});
280282
await octokit.issues.update({
281283
owner: REPO_OWNER,

0 commit comments

Comments
 (0)