From b8766cc0f2fe92bb2ef9ecae20a4e930c47ef437 Mon Sep 17 00:00:00 2001 From: ryu <114303361+ryuapp@users.noreply.github.com> Date: Sun, 1 Dec 2024 16:04:00 +0900 Subject: [PATCH] feat: experimental front matter support (#7) * feat: experimental front matter support * docs: about front matter * chore: rename keyword * fix: change to load stylesheet --- .gitignore | 2 +- README.md | 12 ++++++++++++ deno.json | 5 ++++- deno.lock | 30 +++++++++++++++++++++++++++++- src/testdata/bluecode.md | 8 ++++++++ src/utils/server.ts | 31 ++++++++++++++++++++++++------- 6 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 src/testdata/bluecode.md diff --git a/.gitignore b/.gitignore index da700bb..f08278d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -README.pdf \ No newline at end of file +*.pdf \ No newline at end of file diff --git a/README.md b/README.md index f852322..97f53c7 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,18 @@ Options: --css Set CSS file used for rendering. ``` +## Front matter (Experimental) + +We can specify CSS file used in the front matter of markdown. + +```md +--- +stylesheet: ./github.css +--- + +# Hello World +``` + ## Related - [md-to-pdf](https://github.com/simonhaenisch/md-to-pdf) - Markdown to PDF CLI diff --git a/deno.json b/deno.json index 9f1d571..cb557ea 100644 --- a/deno.json +++ b/deno.json @@ -10,7 +10,7 @@ "dev": "deno run --allow-read --allow-write --allow-env --allow-net=0.0.0.0,127.0.0.1 --allow-run ./src/cli.ts -- README.md", "dev:all": "deno run --allow-read --allow-write --allow-env --allow-net=0.0.0.0,127.0.0.1 --allow-run ./src/cli.ts -w --css=src/testdata/bluecode.css -- README.md", "dev:help": "deno run --allow-read --allow-write --allow-env --allow-net=0.0.0.0,127.0.0.1 --allow-run ./src/cli.ts --help", - "dev:css": "deno run --allow-read --allow-write --allow-env --allow-net=0.0.0.0,127.0.0.1 --allow-run ./src/cli.ts --css=src/testdata/bluecode.css -- README.md", + "dev:css": "deno run --allow-read --allow-write --allow-env --allow-net=0.0.0.0,127.0.0.1 --allow-run ./src/cli.ts -- ./src/testdata/bluecode.md", "dev:invalidcss": "deno run --allow-read --allow-write --allow-env --allow-net=0.0.0.0,127.0.0.1 --allow-run ./src/cli.ts --css=src/testdata/redcode.css -- README.md", "dev:watch": "deno run --allow-read --allow-write --allow-env --allow-net=0.0.0.0,127.0.0.1 --allow-run ./src/cli.ts --watch -- README.md" }, @@ -19,6 +19,9 @@ "@std/assert": "jsr:@std/assert@^1.0.2", "@std/cli": "jsr:@std/cli@1.0.7", "@std/fmt": "jsr:@std/fmt@^1", + "@std/front-matter": "jsr:@std/front-matter@^1.0.5", + "@std/path": "jsr:@std/path@^1.0.8", + "@std/yaml": "jsr:@std/yaml@^1.0.5", "md4w": "npm:md4w@^0.2.6" }, "exclude": [".gitattributes", ".github", "src/testdata", "**/*/*_test.ts"] diff --git a/deno.lock b/deno.lock index 5881b2e..5c83eea 100644 --- a/deno.lock +++ b/deno.lock @@ -6,12 +6,18 @@ "jsr:@std/assert@^1.0.2": "1.0.8", "jsr:@std/async@1": "1.0.9", "jsr:@std/cli@1.0.7": "1.0.7", + "jsr:@std/collections@^1.0.5": "1.0.9", "jsr:@std/fmt@1": "1.0.3", "jsr:@std/fmt@1.0.3": "1.0.3", + "jsr:@std/front-matter@^1.0.5": "1.0.5", "jsr:@std/fs@1": "1.0.6", "jsr:@std/internal@^1.0.5": "1.0.5", "jsr:@std/io@0.225.0": "0.225.0", + "jsr:@std/path@*": "1.0.8", "jsr:@std/path@1": "1.0.8", + "jsr:@std/path@^1.0.8": "1.0.8", + "jsr:@std/toml@^1.0.1": "1.0.1", + "jsr:@std/yaml@^1.0.5": "1.0.5", "jsr:@zip-js/zip-js@^2.7.52": "2.7.53", "npm:md4w@~0.2.6": "0.2.6" }, @@ -22,7 +28,7 @@ "jsr:@deno-library/progress", "jsr:@std/async", "jsr:@std/fs", - "jsr:@std/path", + "jsr:@std/path@1", "jsr:@zip-js/zip-js" ] }, @@ -45,9 +51,19 @@ "@std/cli@1.0.7": { "integrity": "98359df9df586a69015ba570305183b0cb9e7d53c05ea2016ef9a3e77e82c7cd" }, + "@std/collections@1.0.9": { + "integrity": "4f58104ead08a04a2199374247f07befe50ba01d9cca8cbb23ab9a0419921e71" + }, "@std/fmt@1.0.3": { "integrity": "97765c16aa32245ff4e2204ecf7d8562496a3cb8592340a80e7e554e0bb9149f" }, + "@std/front-matter@1.0.5": { + "integrity": "abddc64030a33eb5bc524b8c73e7c417cea09177aaeb4abf75a56b540c4b6e60", + "dependencies": [ + "jsr:@std/toml", + "jsr:@std/yaml" + ] + }, "@std/fs@1.0.6": { "integrity": "42b56e1e41b75583a21d5a37f6a6a27de9f510bcd36c0c85791d685ca0b85fa2" }, @@ -60,6 +76,15 @@ "@std/path@1.0.8": { "integrity": "548fa456bb6a04d3c1a1e7477986b6cffbce95102d0bb447c67c4ee70e0364be" }, + "@std/toml@1.0.1": { + "integrity": "b55b407159930f338d384b1f8fd317c8e8a35e27ebb8946155f49e3a158d16c4", + "dependencies": [ + "jsr:@std/collections" + ] + }, + "@std/yaml@1.0.5": { + "integrity": "71ba3d334305ee2149391931508b2c293a8490f94a337eef3a09cade1a2a2742" + }, "@zip-js/zip-js@2.7.53": { "integrity": "acea5bd8e01feb3fe4c242cfbde7d33dd5e006549a4eb1d15283bc0c778ed672" } @@ -75,6 +100,9 @@ "jsr:@std/assert@^1.0.2", "jsr:@std/cli@1.0.7", "jsr:@std/fmt@1", + "jsr:@std/front-matter@^1.0.5", + "jsr:@std/path@^1.0.8", + "jsr:@std/yaml@^1.0.5", "npm:md4w@~0.2.6" ] } diff --git a/src/testdata/bluecode.md b/src/testdata/bluecode.md new file mode 100644 index 0000000..4f970da --- /dev/null +++ b/src/testdata/bluecode.md @@ -0,0 +1,8 @@ +--- +stylesheet: bluecode.css +--- + +# Blue Code +```js +console.log("Hello, World!"); +``` \ No newline at end of file diff --git a/src/utils/server.ts b/src/utils/server.ts index 7b3ad14..689e0ae 100644 --- a/src/utils/server.ts +++ b/src/utils/server.ts @@ -1,6 +1,9 @@ import { init as initMd4w, mdToHtml } from "md4w"; import type { MdToPdfOptions } from "../types.ts"; import { getFilename } from "./filename.ts"; +import { extract } from "@std/front-matter/yaml"; +import { parse } from "@std/yaml/parse"; +import { join } from "@std/path"; export const DEFAULT_PORT = 33433; @@ -20,18 +23,32 @@ export function launchHttpServer( if (url.pathname === "/") { const decoder = new TextDecoder("utf-8"); - const css = options?.css - ? decoder.decode(await Deno.readFile(options?.css)) - : ""; - const content = mdToHtml( - decoder.decode(await Deno.readFile(path)), - ); + const fileContent = decoder.decode(await Deno.readFile(path)); + + let markdown = ""; + let stylesheet = ""; + // Front matter + try { + const file = extract(fileContent); + const frontMatter = parse(file.frontMatter) as { + stylesheet?: string; + }; + markdown = file.body; + if (frontMatter && frontMatter.stylesheet) { + stylesheet = join(path, "..", frontMatter.stylesheet); + } + } catch (_e) { + markdown = fileContent; + } + stylesheet = options?.css ? options?.css : stylesheet; + + const content = mdToHtml(markdown); const title = getFilename(path.split("/").at(-1) || "") || "Untitled"; return new Response( `