1- #!/usr/bin/env node
2-
31import { Octokit } from "@octokit/rest" ;
42import { JSDOM } from "jsdom" ;
53import fs , { readFile } from "fs/promises" ;
@@ -25,14 +23,14 @@ if (!OPENROUTER_API_KEY) {
2523
2624const 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 = / h t t p s ? : \/ \/ .* ?c p p r e f e r e n c e \. c o m \/ 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 ( / h t t p s ? : \/ \/ .* ?c p p r e f e r e n c e \. c o m \/ w \/ ( .+ ) \. h t m l $ / ) ;
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