md-to-svelte
Version:
Convert markdown file to svelte.
136 lines (135 loc) • 6.46 kB
JavaScript
import fs from "fs";
import path from "path";
import { globby } from 'globby';
import { marked } from 'marked';
import heading from "./handlers/heading.js";
import paragraph from "./handlers/paragraph.js";
import space from "./handlers/space.js";
import code from "./handlers/code.js";
import list from "./handlers/list.js";
import html from "./handlers/html.js";
/** Create page tags */
function createPage(page, options) {
const domainUrl = options.domainUrl.endsWith("/") ? options.domainUrl.slice(0, -1) : options.domainUrl;
let pageCode = "";
// add css
if (page.jsCode)
pageCode += `<script lang="ts">\n${page.jsCode}\n</script>\n`;
// add page code
pageCode += `\n<svelte:head>
<!-- Primary Meta Tags -->
<title>${page.metaData.title} | ${options.appName}</title>
<meta name="title" content="${page.metaData.title} | ${options.appName}" />
<meta name="description" content="${page.metaData.description}" />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="article" />
<meta property="og:url" content="${domainUrl + page.metaData.href}" />
<meta property="og:title" content="${page.metaData.title} | ${options.appName}" />
<meta property="og:description" content="${page.metaData.description}" />
<meta property="og:image" content="${page.metaData.image ? page.metaData.image : options.defaultImage}" />
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content="${domainUrl + page.metaData.href}" />
<meta property="twitter:title" content="${page.metaData.title} | ${options.appName}" />
<meta property="twitter:description" content="${page.metaData.description}" />
<meta property="twitter:image" content="${page.metaData.image ? page.metaData.image : options.defaultImage}" />
</svelte:head>\n` + page.code;
// add custom style
if (page.css)
pageCode += `<style>\n${page.css}</style>`;
// return page code
return pageCode;
}
/** Convert markdown file to svelte
* @param outPutDir - Directory to save converted markdown */
export default async function mdToSvelte(outPutDir, options) {
/** Result to be returned */
const result = {};
const markdowns = await globby(`${process.cwd()}/pages/`, { expandDirectories: { files: ['*.md'] } });
// delete all generated directories in docs folder
if (options.devMode) {
const oldMarkdowns = await globby(`${outPutDir.endsWith("/") ? outPutDir.slice(0, -1) : outPutDir}/**`, { onlyDirectories: true });
for (const markdownPath of oldMarkdowns) {
fs.rmSync(markdownPath, { recursive: true, force: true });
}
}
// loop all markdown files
for (const markdownPath of markdowns) {
const page = { jsCode: "", code: "", css: "", metaData: {}, headers: [] };
/** Clean md path after removing [..] */
const cleanMarkdownPath = markdownPath.replace(/\[\d+\]/g, '').replace(`${process.cwd()}/pages/`, "");
/** Slug for markdown path */
const slug = `${cleanMarkdownPath.replace("index.md", "").replace(".md", "")}`;
const markdownContent = fs.readFileSync(markdownPath).toString();
// get file tokens
const markdownTokens = marked.lexer(markdownContent);
for (const token of markdownTokens) {
// heading
if (token.type === "heading")
heading(token, page);
// paragraph
else if (token.type === "paragraph")
paragraph(token, page);
// space
else if (token.type === "space")
space(page);
// code
else if (token.type === "code")
await code(token, page);
// list
else if (token.type === "list")
list(token, page);
// any other html tag
else
html(token, page);
}
// Skip page creation md does not contain meta data
if (Object.keys(page.metaData).length < 3)
continue;
//@ts-ignore create page
outPutDir = outPutDir.endsWith("/") ? outPutDir.slice(0, -1) : outPutDir; // remove / from outPutDir if exists
const sveltePagePath = `${outPutDir}/${slug}/+page.svelte`.replace("//", "/");
// .replace(/\/\([^)]*\)/g, "") remove folder link (app)
const publicHref = `${outPutDir}/${slug}`.replace("//", "/").replace('src/routes', "").replace(/\/\([^)]*\)/g, "");
// add href to meta data
page.metaData.href = publicHref;
// create
fs.mkdirSync(path.dirname(sveltePagePath), { recursive: true });
fs.writeFileSync(sveltePagePath, createPage(page, options));
// console.log(`<<<<<<<<<<<<<< O >>>>>>>>>>>>>\n`)
// console.log(`${cleanMarkdownPath}\n${slug}\n${sveltePagePath}\n${publicHref}`)
// console.log(page.metaData)
// if layout does not exists in result create it to avoid error when adding links
const pageLayout = page.metaData.layout;
if (!result[pageLayout])
result[pageLayout] = [];
// add page link
result[pageLayout].push(Object.assign(Object.assign({}, page.metaData), { title: page.metaData.title,
// remove last / if exists
href: page.metaData.href.endsWith("/") ? page.metaData.href.slice(0, -1) : page.metaData.href,
// href: slug==="" ? `/` : slug,
description: page.metaData.description, new: page.metaData.new ? true : false, headers: page.headers }));
}
// return data
return result;
}
/** Convert markdown file to svelte
* @param outPutDir - Directory to save converted markdown */
export async function viteMdToSvelte(outPutDir, options) {
return {
name: 'md-to-svelte',
handleHotUpdate(data) {
const run = (data.file.endsWith(".md") && data.server.config.mode === "development");
if (run)
mdToSvelte(outPutDir, options);
},
};
}
// await mdToSvelte("src/routes/blog/",{
// appName:"TestApp",domainUrl:"https://developedbyant.com",
// defaultImage:"https://developedbyant.com/images/backdrop.png"
// })
// console.log(await mdToSvelte("src/routes/(app)/blog/",{
// appName:"TestApp",domainUrl:"https://developedbyant.com",
// defaultImage:"https://developedbyant.com/images/backdrop.png"
// }))