-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add Markdown Link Converter Script #8650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 26_1
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| let fs = require('fs'); | ||
| let path = require('path'); | ||
|
|
||
| const specifiedPath = process.argv[2]; | ||
| const linkRegex = /<a\b(?=[^>]*\btarget=["']_blank["'])[^>]*\bhref=["']([^"']*)["'][^>]*>([\s\S]*?)<\/a>/gi; | ||
|
|
||
| function isInsideTableCell(content, offset) { | ||
| const before = content.slice(0, offset).toLowerCase(); | ||
|
Comment on lines
+1
to
+8
|
||
| const after = content.slice(offset).toLowerCase(); | ||
|
|
||
| return before.lastIndexOf('<td') > before.lastIndexOf('</td>') && after.includes('</td>'); | ||
| } | ||
|
|
||
| function escapeForRegex(value) { | ||
| return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); | ||
| } | ||
|
|
||
| function isInsideCodeSnippet(content, offset) { | ||
| const lineStart = content.lastIndexOf('\n', offset - 1) + 1; | ||
| const lineEndIndex = content.indexOf('\n', offset); | ||
| const lineEnd = lineEndIndex === -1 ? content.length : lineEndIndex; | ||
| const line = content.slice(lineStart, lineEnd); | ||
| const indentMatch = line.match(/^[\t ]+(?=<a\b)/i); | ||
|
|
||
| if (!indentMatch) { | ||
| return false; | ||
| } | ||
|
|
||
| const indent = indentMatch[0]; | ||
| const commentRegex = new RegExp(`^${escapeForRegex(indent)}(?:<!--\s*tab:\s*index\.html\s*-->|<!--\s*HTML\s*-->)\s*$`, 'i'); | ||
Check failureCode scanning / CodeQL Useless regular-expression character escape High
The escape sequence '\s' is equivalent to just 's', so the sequence is not a character class when it is used in a
regular expression Error loading related location Loading Check failureCode scanning / CodeQL Useless regular-expression character escape High
The escape sequence '\s' is equivalent to just 's', so the sequence is not a character class when it is used in a
regular expression Error loading related location Loading Check failureCode scanning / CodeQL Useless regular-expression character escape High
The escape sequence '.' is equivalent to just '.', so the sequence may still represent a meta-character when it is used in a
regular expression Error loading related location Loading Check failureCode scanning / CodeQL Useless regular-expression character escape High
The escape sequence '\s' is equivalent to just 's', so the sequence is not a character class when it is used in a
regular expression Error loading related location Loading Check failureCode scanning / CodeQL Useless regular-expression character escape High
The escape sequence '\s' is equivalent to just 's', so the sequence is not a character class when it is used in a
regular expression Error loading related location Loading Check failureCode scanning / CodeQL Useless regular-expression character escape High
The escape sequence '\s' is equivalent to just 's', so the sequence is not a character class when it is used in a
regular expression Error loading related location Loading Check failureCode scanning / CodeQL Useless regular-expression character escape High
The escape sequence '\s' is equivalent to just 's', so the sequence is not a character class when it is used in a
regular expression Error loading related location Loading |
||
|
|
||
| const linesAbove = content.slice(0, lineStart).split(/\r?\n/); | ||
|
|
||
| for (let i = linesAbove.length - 1; i >= 0; i -= 1) { | ||
| const currentLine = linesAbove[i]; | ||
|
|
||
| if (!currentLine.trim()) { | ||
| continue; | ||
| } | ||
|
|
||
| if (commentRegex.test(currentLine)) { | ||
| return true; | ||
| } | ||
|
|
||
| if (!currentLine.startsWith(indent)) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| function getFilePaths(targetPath) { | ||
| const stats = fs.statSync(targetPath); | ||
|
|
||
| if (stats.isFile()) { | ||
| return [targetPath]; | ||
| } | ||
|
|
||
| if (!stats.isDirectory()) { | ||
| return []; | ||
| } | ||
|
|
||
| return fs.readdirSync(targetPath, { withFileTypes: true }).flatMap((entry) => { | ||
| const entryPath = path.join(targetPath, entry.name); | ||
|
|
||
| if (entry.isDirectory()) { | ||
| return getFilePaths(entryPath); | ||
| } | ||
|
|
||
| return entry.isFile() ? [entryPath] : []; | ||
| }); | ||
|
Comment on lines
+52
to
+71
|
||
| } | ||
|
|
||
| function convertFile(filePath) { | ||
| const content = fs.readFileSync(filePath, 'utf-8'); | ||
| const updatedContent = content.replace(linkRegex, (match, href, innerHtml, offset) => { | ||
| if (isInsideTableCell(content, offset) || isInsideCodeSnippet(content, offset)) { | ||
| return match; | ||
| } | ||
|
|
||
| return `[${innerHtml}](${href})`; | ||
| }); | ||
|
Comment on lines
+74
to
+82
|
||
|
|
||
| if (updatedContent !== content) { | ||
| fs.writeFileSync(filePath, updatedContent, 'utf-8'); | ||
| return true; | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| if (!specifiedPath) { | ||
| console.error('Specify a file or directory path.'); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| try { | ||
| const filePaths = getFilePaths(specifiedPath); | ||
| let updatedFilesCount = 0; | ||
|
|
||
| filePaths.forEach((filePath) => { | ||
| if (convertFile(filePath)) { | ||
| updatedFilesCount += 1; | ||
| } | ||
| }); | ||
|
|
||
| console.log(`Processed ${filePaths.length} file(s). Updated ${updatedFilesCount} file(s).`); | ||
| } catch (error) { | ||
| console.error(error.message || error); | ||
| process.exit(1); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new npm script runs a
.jsfile viats-node. By default,ts-nodedoes not execute plain JavaScript unless it is configured withallowJs, so this script can fail in a clean environment. Either run it withnodeor rename the file to.tsand keepts-nodeconsistent with the othertools/*.tsscripts.