- point it at a directory of markdown files
- it finds all links, identifies the ones that link to redirects
- it re-links those links to the eventual destination
Created
September 25, 2018 01:14
-
-
Save tmcw/1e2c4a16a27ebee36f8a0295aef7ff57 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
const Remark = require("remark"); | |
const frontmatter = require("remark-frontmatter"); | |
const select = require("unist-util-select"); | |
const fs = require("fs"); | |
const path = require("path"); | |
const MagicString = require("magic-string"); | |
const got = require("got"); | |
const { extname, basename } = require("path"); | |
const pAll = require("p-all"); | |
const REDIRECT = Symbol("REDIRECT"); | |
const OK = Symbol("OK"); | |
const NOT_FOUND = Symbol("NOT_FOUND"); | |
async function localizeFile(dirname) { | |
const files = fs.readdirSync(dirname).filter(f => path.extname(f) === ".md"); | |
await pAll( | |
files.map(filename => async () => { | |
filename = path.join(dirname, filename); | |
const remark = Remark().use(frontmatter, "yaml"); | |
const text = fs.readFileSync(filename, "utf8"); | |
const base = basename(filename, ".md"); | |
const ast = remark.parse(text); | |
const links = select(ast, "link"); | |
const s = new MagicString(text); | |
const linkStatuses = await pAll( | |
links.map(link => async () => { | |
try { | |
const resp = await got.head(link.url, { timeout: 1000 }); | |
if (resp.redirectUrls && resp.redirectUrls.length) { | |
return { | |
type: REDIRECT, | |
link: { | |
...link, | |
url: resp.redirectUrls[resp.redirectUrls.length - 1] | |
} | |
}; | |
} | |
return { type: OK }; | |
} catch { | |
return { type: NOT_FOUND }; | |
} | |
}), | |
{ concurrency: 10 } | |
); | |
let modified = false; | |
for (let { type, link } of linkStatuses) { | |
if (type === REDIRECT) { | |
s.overwrite( | |
link.position.start.offset, | |
link.position.end.offset, | |
Remark().stringify(link) | |
); | |
modified = true; | |
} | |
} | |
console.error(`${filename} | |
${linkStatuses.length} links | |
| ${linkStatuses.filter(l => l.type === OK).length} OK | |
| ${linkStatuses.filter(l => l.type === NOT_FOUND).length} NOT_FOUND | |
| ${linkStatuses.filter(l => l.type === REDIRECT).length} REDIRECT`); | |
if (modified) { | |
fs.writeFileSync(filename, s.toString()); | |
} | |
}), | |
{ concurrency: 10 } | |
); | |
} | |
localizeFile(process.argv[2]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "hypertext-doctor", | |
"version": "1.0.0", | |
"main": "index.js", | |
"license": "MIT", | |
"dependencies": { | |
"got": "^9.2.2", | |
"magic-string": "^0.25.1", | |
"p-all": "^1.0.0", | |
"remark": "^9.0.0", | |
"remark-frontmatter": "^1.3.0", | |
"unist-util-select": "^1.5.0" | |
}, | |
"devDependencies": { | |
"prettier": "^1.14.3" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment