Changes
7 changed files (+204/-7)
-
-
@@ -147,6 +147,7 @@ "precompress","disable-markdown", "disable-jsoncanvas", "markdown-frontmatter", "markdown-downlevel-headings", "shortest-path-when-possible", ], alias: {
-
@@ -279,6 +280,12 @@ if (yamlFrontmatter) {log.debug("markdown.yamlFrontmatter = true"); } const downlevelHeadings = flags["markdown-downlevel-headings"] || configFile.markdown?.downlevelHeadings; if (downlevelHeadings) { log.debug("markdown.downlevelHeadings = true"); } const jsonCanvasDisabled = flags["disable-jsoncanvas"] || configFile.jsonCanvas?.enabled === false; if (jsonCanvasDisabled) {
-
@@ -287,9 +294,10 @@ }const parsers: readonly ContentParser[] = [ jsonCanvasDisabled ? null : new JSONCanvasParser(), markdownDisabled ? null : new ObsidianMarkdownParser({ frontmatter: yamlFrontmatter }), markdownDisabled ? null : new ObsidianMarkdownParser({ frontmatter: yamlFrontmatter, downlevel: downlevelHeadings, }), ].filter((p): p is NonNullable<typeof p> => !!p); if (parsers.length === 0) {
-
@@ -630,6 +638,12 @@--markdown-frontmatter Parse YAML frontmatter in Markdown files. Corresponding config key is ${p("markdown.yamlFrontmatter")} (${ t("boolean") }). --markdown-downlevel-headings Increase Markdown headings level by 1 (e.g. "# Foo" -> "## Foo"). Corresponding config key is ${p("markdown.downlevelHeadings")} (${ t("boolean") }).
-
-
-
@@ -171,6 +171,15 @@ - CLI: `--markdown-frontmatter` flagEnable parsing of YAML frontmatter in Markdown documents. ### `markdown.downlevelHeadings` - Type: `boolean` - CLI: `--markdown-downlevel-headings` flag Transform Markdown headings by down-levelling (incrementing level) by 1. Use this option if you prefer to write level 1 headings in your document: Macana inserts `<h1>` with document title so headings conflict with that without the `markdown.downlevelHeadings` option. ## JSONCanvas options ### `jsonCanvas.enabled`
-
-
-
@@ -18,7 +18,7 @@- [x] Option for OpenGraph attributes - [x] Custom fonts per language - [x] User provided global CSS - [ ] Headings down levelling option (render `# Foo` as `<h2>Foo</h2>`) - [x] Headings down levelling option (render `# Foo` as `<h2>Foo</h2>`) - [x] 404 page ## v0.1.2
-
-
-
@@ -60,6 +60,8 @@ markdown?: {enabled?: boolean; yamlFrontmatter?: boolean; downlevelHeadings?: boolean; }; jsonCanvas?: {
-
@@ -122,6 +124,7 @@ }),markdown: parser.object({ enabled: parser.boolean, yamlFrontmatter: parser.boolean, downlevelHeadings: parser.boolean, }), jsonCanvas: parser.object({ enabled: parser.boolean,
-
-
-
@@ -18,6 +18,7 @@ } from "../../lib/mdast_util_ofm/mod.ts";import { macanaMarkAssets } from "./obsidian_markdown/mdast_util_macana_mark_assets.ts"; import { macanaMarkDocumentToken } from "./obsidian_markdown/mdast_util_macana_mark_document_token.ts"; import { autoHeadingIdFromMarkdown } from "../../lib/mdast_util_auto_heading_id/mod.ts"; import { downlevelHeadings } from "../../lib/mdast_util_downlevel_headings/mod.ts"; import { logger } from "../logger.ts";
-
@@ -87,6 +88,12 @@ * Whether to enable reading of YAML frontmatter.* @default false */ frontmatter?: boolean; /** * Whether to down-level headings by 1. * @default false */ downlevel?: boolean; } /**
-
@@ -209,11 +216,16 @@ { fileReader, getDocumentToken, getAssetToken }: Pick<ParseParameters, "getAssetToken" | "getDocumentToken" | "fileReader" >, { downlevel }: Pick<ObsidianMarkdownParserOptions, "downlevel">, ): Promise<ObsidianMarkdownDocument> { const mdast = await parseMarkdown(markdown, { getDocumentToken, getAssetToken, }); if (downlevel) { downlevelHeadings(mdast); } return { kind: "obsidian_markdown",
-
@@ -241,9 +253,14 @@ */export class ObsidianMarkdownParser implements ContentParser<ObsidianMarkdownDocument> { #frontmatter: boolean; #downlevel: boolean; constructor({ frontmatter = false }: ObsidianMarkdownParserOptions = {}) { constructor( { frontmatter = false, downlevel = false }: ObsidianMarkdownParserOptions = {}, ) { this.#frontmatter = frontmatter; this.#downlevel = downlevel; } async parse(
-
@@ -253,12 +270,16 @@ ): Promise<ContentParseResult<ObsidianMarkdownDocument>> {const bytes = await fileReader.read(); if (!this.#frontmatter) { return ok(bytes, { getDocumentToken, getAssetToken, fileReader }); return ok(bytes, { getDocumentToken, getAssetToken, fileReader }, { downlevel: this.#downlevel, }); } const decoded = new TextDecoder().decode(bytes); if (!testFrontmatter(decoded)) { return ok(bytes, { getDocumentToken, getAssetToken, fileReader }); return ok(bytes, { getDocumentToken, getAssetToken, fileReader }, { downlevel: this.#downlevel, }); } const frontmatter = yamlFrontmatter.extract(decoded);
-
@@ -291,6 +312,8 @@ documentContent: await ok(frontmatter.body, {getDocumentToken, getAssetToken, fileReader, }, { downlevel: this.#downlevel, }), }; }
-
-
-
@@ -0,0 +1,94 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 import { assertObjectMatch, assertThrows, } from "../../deps/deno.land/std/assert/mod.ts"; import { fromMarkdown } from "../../deps/esm.sh/mdast-util-from-markdown/mod.ts"; import { toHast } from "../../deps/esm.sh/mdast-util-to-hast/mod.ts"; import { downlevelHeadingsFromMarkdown } from "./mod.ts"; Deno.test("Should down-level headings", () => { const hast = toHast(fromMarkdown( ` # Foo ## Bar ### Baz `.trim(), { mdastExtensions: [downlevelHeadingsFromMarkdown()], }, )); assertObjectMatch(hast, { type: "root", children: [ { type: "element", tagName: "h2", }, {}, { type: "element", tagName: "h3", }, {}, { type: "element", tagName: "h4", }, ], }); }); Deno.test("Should down-level headings by given magnitude", () => { const hast = toHast(fromMarkdown( ` # Foo ## Bar ### Baz `.trim(), { mdastExtensions: [downlevelHeadingsFromMarkdown({ magnitude: 3 })], }, )); assertObjectMatch(hast, { type: "root", children: [ { type: "element", tagName: "h4", }, {}, { type: "element", tagName: "h5", }, {}, { type: "element", tagName: "h6", }, ], }); }); Deno.test("Should throw an error if modified level exceeds 6", () => { assertThrows(() => { fromMarkdown( ` # Foo ## Bar ### Baz `.trim(), { mdastExtensions: [downlevelHeadingsFromMarkdown({ magnitude: 4 })], }, ); }); });
-
-
-
@@ -0,0 +1,54 @@// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com> // // SPDX-License-Identifier: Apache-2.0 import type * as Mdast from "../../deps/esm.sh/mdast/types.ts"; import type { Extension } from "../../deps/esm.sh/mdast-util-from-markdown/mod.ts"; import { SKIP, visit } from "../../deps/esm.sh/unist-util-visit/mod.ts"; export class HeadingLevelExceedsLimitError extends Error { constructor(level: number, magnitude: number) { super( `Attempt to down-level h${level} by ${magnitude},` + ` but resulting level (${level + magnitude}) exceeds limit (6)`, ); } } export interface DownlevelHeadingsOptions { magnitude?: 1 | 2 | 3 | 4 | 5; } /** * Down-level headings by given amount (`magnitude`). * e.g. `# Foo` -> `## Foo` * * This functions throws `HeadingLevelExceedsLimitError` when the final * heading level exceeds 6 (`<h6>`). */ export function downlevelHeadings( nodes: Mdast.Nodes, { magnitude = 1 }: DownlevelHeadingsOptions = {}, ): void { visit(nodes, (node) => node.type === "heading", (node) => { if (node.type !== "heading") { return SKIP; } if (node.depth + magnitude > 6) { throw new HeadingLevelExceedsLimitError(node.depth, magnitude); } node.depth = (node.depth + magnitude) as 1 | 2 | 3 | 4 | 5 | 6; }); } export function downlevelHeadingsFromMarkdown( options: DownlevelHeadingsOptions = {}, ): Extension { return { transforms: [(nodes) => { downlevelHeadings(nodes, options); }], }; }
-