Skip to content

Instantly share code, notes, and snippets.

@RomanHotsiy
Last active December 4, 2023 03:50
Show Gist options
  • Save RomanHotsiy/8401c72b25ce5c3f1e8261598bb12908 to your computer and use it in GitHub Desktop.
Save RomanHotsiy/8401c72b25ce5c3f1e8261598bb12908 to your computer and use it in GitHub Desktop.

Convert markdown indented code blocks to fenced code blocks

This script runs on a folder and converts all the indented code blocks in markdown files to fenced code blocks.

The script tries to preserve the original markdown formatting.

Usage

npm install
node index.js ../../my-project/content/

Use bundle

I bundled the script into a zero-dep single js-exectuable

You can download it and run:

node convert.js ../../my-project/content
// run `node index.js` in the terminal
import { remark } from 'remark';
import { readFileSync, writeFileSync } from 'fs';
import remarkFrontmatter from 'remark-frontmatter';
import { visit } from 'unist-util-visit';
import * as glob from 'glob';
import stripIndent from 'strip-indent';
import indentString from 'indent-string';
function convertIndentedToFenced(filePath) {
const doc = readFileSync(filePath, 'utf-8');
const outputDoc = doc.split('');
console.log;
let changeOffset = 0;
let hasCode = false;
const file = remark()
.use(remarkFrontmatter)
.use(function detector() {
return (tree) => {
visit(tree, 'code', (node) => {
if (node.lang) return;
hasCode = true;
// fix identation by removing extra indent
const value = stripIndent(node.value);
const from = node.position.start.offset;
const to = node.position.end.offset;
const indentLevel = Math.round(node.position.start.column / 4) * 4;
const newBlock =
' '.repeat(
Math.max(0, indentLevel - node.position.start.column + 1)
) +
'```\n' +
indentString(value + '\n```', indentLevel);
outputDoc.splice(
from + changeOffset,
to - from,
...newBlock.split('')
);
changeOffset = changeOffset + newBlock.length - (to - from);
});
};
})
.processSync(doc);
if (hasCode) {
console.log(`Updating ${filePath} in-place`);
writeFileSync(filePath, outputDoc.join(''), 'utf-8');
} else {
console.log(`Skip ${filePath} as it doesn't contain code blocks`);
}
}
const dir = process.argv[2];
if (!dir) {
console.log('Error: provide directory as argument');
process.exit(10);
}
const mdFiles = glob.sync(dir + '/**/*.md', { nodir: true });
for (const f of mdFiles) {
convertIndentedToFenced(f);
}
{
"name": "convert-indented-to-fenced-md",
"type": "module",
"version": "0.0.0",
"dependencies": {
"glob": "^10.3.10",
"indent-string": "^5.0.0",
"remark": "^15.0.1",
"remark-frontmatter": "^5.0.0",
"strip-indent": "^4.0.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment