transpile-md-to-json
Version:
Transpile multiple markdown files to a single JSON file.
155 lines • 5.86 kB
JavaScript
import { program } from "commander";
import chokidar from "chokidar";
import { dirname, resolve, sep } from "path";
import escapeStringRegexp from "escape-string-regexp";
import fsExtra from "fs-extra";
import readdirp from "readdirp";
import slugify from "@sindresorhus/slugify";
import { setProperty } from "dot-prop";
import camelcase from "camelcase";
import { createHash } from "crypto";
import { flatten } from "flat";
import { execa } from "execa";
import chalk from "chalk";
const { existsSync, readFile, stat, writeFile } = fsExtra;
program
.requiredOption("--src <source>", "path to content folder")
.option("--dest <destination>", "path to JSON file")
.option("--ignore <ignore...>", "paths to ignore")
.option("--slugify", "slugify folder and file names")
.option("--flatten", "flatten nested properties")
.option("--blogify", "enable slugify and flatten and parse metadata")
.option("--git", "include last Git commit date")
.option("--watch", "watch source for changes");
program.parse(process.argv);
const options = program.opts();
const src = resolve(process.cwd(), options.src);
const ignorePathRegExps = [];
if (options.ignore) {
for (const ignorePath of options.ignore) {
if (existsSync(resolve(src, ignorePath))) {
ignorePathRegExps.push(new RegExp(`^${escapeStringRegexp(ignorePath)}`));
}
}
}
const run = async function () {
const readdirpOptions = {
fileFilter: "*.md",
};
let data = {};
try {
if (options.dest) {
console.info("Transpiling…");
}
const blogifyData = {};
for await (const file of readdirp(src, readdirpOptions)) {
let ignoreMatch = false;
for (const ignorePathRegExp of ignorePathRegExps) {
if (file.path.match(ignorePathRegExp)) {
ignoreMatch = true;
break;
}
}
if (ignoreMatch === true) {
continue;
}
const parts = file.path.replace(/\.md$/, "").split(sep);
if (options.slugify || options.flatten || options.blogify) {
parts.forEach(function (part, index) {
parts[index] = slugify(part, { decamelize: false });
});
}
const dots = parts.join(sep).replace(new RegExp(sep, "g"), ".");
const content = await readFile(resolve(src, file.path), "utf8");
setProperty(data, dots, content);
if (options.blogify === true) {
const metadata = {};
const headerMatch = content.match(/<!--\n((.|\n)*?)\n-->/);
if (headerMatch) {
const lines = headerMatch[1].split("\n");
for (const line of lines) {
const lineMatch = line.match(/([^:]+): ?(.+)?/);
if (lineMatch) {
const key = camelcase(slugify(lineMatch[1], { decamelize: false }));
const value = lineMatch[2] ? lineMatch[2].trim() : "";
metadata[key] = value;
}
}
}
const fileStat = await stat(file.fullPath);
let git = {};
if (options.git === true) {
const fileDirname = dirname(file.fullPath);
const gitLog = await execa("git", [
"-C",
fileDirname,
"log",
"-1",
'--format="%ad"',
"--",
fileDirname,
]);
const gitLogStdout = gitLog.stdout;
if (gitLogStdout) {
git.lastCommitOn = new Date(gitLogStdout);
}
const gitRevList = await execa("git", [
"-C",
fileDirname,
"rev-list",
"--count",
"HEAD",
fileDirname,
]);
const gitRevListStdout = gitRevList.stdout;
if (gitRevListStdout) {
git.numberOfCommits = parseInt(gitRevListStdout);
}
}
blogifyData[dots] = {
id: createHash("md5").update(dots).digest("hex"),
path: file.path,
dirname: dirname(file.path),
basename: file.basename,
createdOn: fileStat.birthtime,
modifiedOn: fileStat.mtime,
git: git,
metadata: metadata,
content: content,
};
}
}
if (options.flatten === true || options.blogify === true) {
data = flatten(data);
}
if (options.blogify === true) {
for (const property in data) {
data[property] = blogifyData[property];
}
}
const json = JSON.stringify(data, null, 2);
if (options.dest) {
const dest = resolve(process.cwd(), options.dest);
await writeFile(dest, json);
console.info(chalk.green("Transpiled successfully!"));
}
else {
console.info(json);
}
}
catch (error) {
console.error(error);
process.exit(1);
}
};
run();
if (options.watch === true) {
chokidar
.watch(`${src}/**/*.md`, {
ignoreInitial: true,
})
.on("add", run)
.on("change", run)
.on("unlink", run);
}
//# sourceMappingURL=index.js.map