From bf91528f016772d97141eab28b3b7fd20f91f59c Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 23 Mar 2024 20:32:39 -0700 Subject: [PATCH] normalizeFrontMatter --- src/build.ts | 2 +- src/config.ts | 27 ++++--- src/frontMatter.ts | 54 +++++++++++++ src/markdown.ts | 81 +++---------------- src/preview.ts | 2 +- src/render.ts | 9 +-- src/resolvers.ts | 2 +- test/config-test.ts | 10 +-- test/frontMatter-test.ts | 88 +++++++++++++++++++++ test/input/yaml-frontmatter.md | 3 +- test/output/block-expression.md.json | 2 +- test/output/comment.md.json | 2 +- test/output/dollar-expression.md.json | 2 +- test/output/dot-graphviz.md.json | 2 +- test/output/double-quote-expression.md.json | 2 +- test/output/embedded-expression.md.json | 2 +- test/output/escaped-expression.md.json | 2 +- test/output/fenced-code-options.md.json | 2 +- test/output/fenced-code.md.json | 2 +- test/output/fetch-parent-dir.md.json | 2 +- test/output/heading-expression.md.json | 2 +- test/output/hello-world.md.json | 2 +- test/output/inline-expression.md.json | 2 +- test/output/linkify.md.json | 2 +- test/output/local-fetch.md.json | 2 +- test/output/malformed-block.md.json | 2 +- test/output/markdown-in-html.md.json | 2 +- test/output/mermaid.md.json | 2 +- test/output/script-expression.md.json | 2 +- test/output/single-quote-expression.md.json | 2 +- test/output/template-expression.md.json | 2 +- test/output/tex-block.md.json | 2 +- test/output/tex-expression.md.json | 2 +- test/output/wellformed-block.md.json | 2 +- test/output/yaml-frontmatter.md.json | 7 +- 35 files changed, 209 insertions(+), 124 deletions(-) create mode 100644 src/frontMatter.ts create mode 100644 test/frontMatter-test.ts diff --git a/src/build.ts b/src/build.ts index 602fd637e..de974f52f 100644 --- a/src/build.ts +++ b/src/build.ts @@ -73,7 +73,7 @@ export async function build( const start = performance.now(); const source = await readFile(sourcePath, "utf8"); const page = parseMarkdown(source, options); - if (page?.data?.draft) { + if (page.data.draft) { effects.logger.log(faint("(skipped)")); continue; } diff --git a/src/config.ts b/src/config.ts index 240a957a3..1803f7149 100644 --- a/src/config.ts +++ b/src/config.ts @@ -104,10 +104,10 @@ function readPages(root: string, md: MarkdownIt): Page[] { if (cachedPages?.key === key) return cachedPages.pages; const pages: Page[] = []; for (const {file, source} of files) { - const parsed = parseMarkdownMetadata(source, {path: file, md}); - if (parsed?.data?.draft) continue; + const {data, title} = parseMarkdownMetadata(source, {path: file, md}); + if (data.draft) continue; const name = basename(file, ".md"); - const page = {path: join("/", dirname(file), name), name: parsed.title ?? "Untitled"}; + const page = {path: join("/", dirname(file), name), name: title ?? "Untitled"}; if (name === "index") pages.unshift(page); else pages.push(page); } @@ -199,7 +199,7 @@ function normalizeBase(base: any): string { return base; } -function normalizeTheme(spec: any): string[] { +export function normalizeTheme(spec: any): string[] { return resolveTheme(typeof spec === "string" ? [spec] : spec === null ? [] : Array.from(spec, String)); } @@ -254,19 +254,24 @@ function normalizeToc(spec: any): TableOfContents { return {label, show}; } -export function mergeToc(spec: any, toc: TableOfContents): TableOfContents { - let {label = toc.label, show = toc.show} = typeof spec !== "object" ? {show: spec} : spec ?? {}; - label = String(label); - show = Boolean(show); +export function mergeToc(spec: Partial = {}, toc: TableOfContents): TableOfContents { + const {label = toc.label, show = toc.show} = spec; return {label, show}; } -export function mergeStyle(path: string, style: any, theme: any, defaultStyle: null | Style): null | Style { +export function mergeStyle( + path: string, + style: string | null | undefined, + theme: string[] | undefined, + defaultStyle: null | Style +): null | Style { return style === undefined && theme === undefined ? defaultStyle : style === null ? null // disable : style !== undefined - ? {path: resolvePath(path, String(style))} - : {theme: normalizeTheme(theme)}; + ? {path: resolvePath(path, style)} + : theme === undefined + ? defaultStyle + : {theme}; } diff --git a/src/frontMatter.ts b/src/frontMatter.ts new file mode 100644 index 000000000..b79ab7b30 --- /dev/null +++ b/src/frontMatter.ts @@ -0,0 +1,54 @@ +import {normalizeTheme} from "./config.js"; + +export interface FrontMatter { + title?: string | null; + toc?: {show?: boolean; label?: string}; + style?: string | null; + theme?: string[]; + index?: boolean; + keywords?: string[]; + draft?: boolean; + sidebar?: boolean; + sql?: {[key: string]: string}; +} + +export function normalizeFrontMatter(spec: any = {}): FrontMatter { + const frontMatter: FrontMatter = {}; + if (spec == null || typeof spec !== "object") return frontMatter; + const {title, sidebar, toc, index, keywords, draft, sql, style, theme} = spec; + if (title !== undefined) frontMatter.title = stringOrNull(title); + if (sidebar !== undefined) frontMatter.sidebar = Boolean(sidebar); + if (toc !== undefined) frontMatter.toc = normalizeToc(toc); + if (index !== undefined) frontMatter.index = Boolean(index); + if (keywords !== undefined) frontMatter.keywords = normalizeKeywords(keywords); + if (draft !== undefined) frontMatter.draft = Boolean(draft); + if (sql !== undefined) frontMatter.sql = normalizeSql(sql); + if (style !== undefined) frontMatter.style = stringOrNull(style); + if (theme !== undefined) frontMatter.theme = normalizeTheme(theme); + return frontMatter; +} + +function stringOrNull(spec: unknown): string | null { + return spec == null ? null : String(spec); +} + +function normalizeToc(spec: unknown): {show?: boolean; label?: string} { + if (spec == null) return {show: false}; + if (typeof spec !== "object") return {show: Boolean(spec)}; + const {show, label} = spec as {show: unknown; label: unknown}; + const toc: FrontMatter["toc"] = {}; + if (show !== undefined) toc.show = Boolean(show); + if (label !== undefined) toc.label = String(label); + return toc; +} + +function normalizeKeywords(spec: unknown): string[] { + return spec == null ? [] : typeof spec === "string" ? [spec] : Array.from(spec as any, String); +} + +function normalizeSql(spec: unknown): {[key: string]: string} { + if (spec == null || typeof spec !== "object") return {}; + const sql: {[key: string]: string} = {}; + for (const key in spec) sql[key] = String(spec[key]); + return sql; +} diff --git a/src/markdown.ts b/src/markdown.ts index a0d133fac..852f7932c 100644 --- a/src/markdown.ts +++ b/src/markdown.ts @@ -10,6 +10,8 @@ import type {RenderRule} from "markdown-it/lib/renderer.js"; import MarkdownItAnchor from "markdown-it-anchor"; import type {Config} from "./config.js"; import {mergeStyle} from "./config.js"; +import type {FrontMatter} from "./frontMatter.js"; +import {normalizeFrontMatter} from "./frontMatter.js"; import {rewriteHtmlPaths} from "./html.js"; import {parseInfo} from "./info.js"; import type {JavaScriptNode} from "./javascript/parse.js"; @@ -31,7 +33,7 @@ export interface MarkdownPage { header: string | null; body: string; footer: string | null; - data: {[key: string]: any} | null; + data: FrontMatter; style: string | null; code: MarkdownCode[]; } @@ -43,15 +45,6 @@ export interface ParseContext { path: string; } -interface FrontMatter { - title?: string; - toc?: boolean | {show?: boolean; label?: string}; - index?: boolean; - keywords?: string[]; - draft?: boolean; - sql?: {[key: string]: string}; -} - function uniqueCodeId(context: ParseContext, content: string): string { const hash = createHash("sha256").update(content).digest("hex").slice(0, 8); let id = hash; @@ -335,7 +328,8 @@ export function createMarkdownIt({ export function parseMarkdown(input: string, options: ParseOptions): MarkdownPage { const {md, path} = options; - const {content, data} = getContents(input); + const {content, data: frontMatter} = matter(input, {}); + const data = normalizeFrontMatter(frontMatter); const code: MarkdownCode[] = []; const context: ParseContext = {code, startLine: 0, currentLine: 0, path}; const tokens = md.parse(content, context); @@ -345,7 +339,7 @@ export function parseMarkdown(input: string, options: ParseOptions): MarkdownPag header: getHtml("header", data, options), body, footer: getHtml("footer", data, options), - data: isEmpty(data) ? null : data, + data, title: data.title ?? findTitle(tokens) ?? null, style: getStyle(data, options), code @@ -355,63 +349,14 @@ export function parseMarkdown(input: string, options: ParseOptions): MarkdownPag /** Like parseMarkdown, but optimized to return only metadata. */ export function parseMarkdownMetadata(input: string, options: ParseOptions): Pick { const {md, path} = options; - const {content, data} = matter(input, {}); + const {content, data: frontMatter} = matter(input, {}); + const data = normalizeFrontMatter(frontMatter); return { - data: isEmpty(data) ? null : data, + data, title: data.title ?? findTitle(md.parse(content, {code: [], startLine: 0, currentLine: 0, path})) ?? null }; } -function getContents(input: string): {content: string; data: FrontMatter & {[key: string]: any}} { - try { - const {data, content} = matter(input, {}); - if ("title" in data) data.title = normalizeString(data.title); - if ("toc" in data) data.toc = normalizeToc(data.toc); - if ("index" in data) data.index = normalizeBoolean(data.index, "index"); - if ("keywords" in data) data.keywords = normalizeStringArray(data.keywords); - if ("draft" in data) data.draft = normalizeBoolean(data.draft, "draft"); - if ("sql" in data) data.sql = normalizeSqlData(data.sql); - return {data, content}; - } catch (error) { - return { - data: {}, - content: '
Invalid front matter
' - }; - } -} - -function normalizeString(value: any): string { - return value == null ? "" : String(value); -} - -function normalizeToc(toc: any): FrontMatter["toc"] { - if (toc == null || typeof toc === "boolean") return toc; - if (typeof toc !== "object" || Array.isArray(toc)) console.warn(`Invalid toc format: ${toc}`); - if ("show" in toc) toc.show = normalizeBoolean(toc.show, "toc.show"); - if ("label" in toc) toc.label = normalizeString(toc.label); - return toc; -} - -function normalizeBoolean(value: any, name: string): boolean { - if (typeof value !== "boolean") - console.warn(`the ${name} option should be boolean, ${value} (${typeof value} found instead)`); - return Boolean(value); -} - -function normalizeStringArray(value: any): string[] { - return value == null ? [] : typeof value === "string" ? [value] : Array.from(value, String); -} - -function normalizeSqlData(sql: any): {[key: string]: string} { - if (!sql || typeof sql !== "object" || Array.isArray(sql)) return console.warn("Unsupported sql definition", sql), {}; - const tables = new Map(); - for (const [name, source] of Object.entries(sql)) { - if (typeof source !== "string") return console.warn("Unsupported sql table source definition", source), {}; - tables.set(name, source); - } - return Object.fromEntries(tables); -} - function getHtml( key: "head" | "header" | "footer", data: Record, @@ -426,7 +371,7 @@ function getHtml( : null; } -function getStyle(data: Record, {path, style = null}: ParseOptions): string | null { +function getStyle(data: FrontMatter, {path, style = null}: ParseOptions): string | null { try { style = mergeStyle(path, data.style, data.theme, style); } catch (error) { @@ -441,12 +386,6 @@ function getStyle(data: Record, {path, style = null}: ParseOptions) : `observablehq:theme-${style.theme.join(",")}.css`; } -// TODO Use gray-matter’s parts.isEmpty, but only when it’s accurate. -function isEmpty(object) { - for (const key in object) return false; - return true; -} - // TODO Make this smarter. function findTitle(tokens: ReturnType): string | undefined { for (const [i, token] of tokens.entries()) { diff --git a/src/preview.ts b/src/preview.ts index cd0b2748b..2d2c84af1 100644 --- a/src/preview.ts +++ b/src/preview.ts @@ -435,7 +435,7 @@ function getFiles({files, resolveFile}: Resolvers): Map { } function getTables({data}: MarkdownPage): Map { - return new Map(Object.entries(data?.sql ?? {})); + return new Map(Object.entries(data.sql ?? {})); } type CodePatch = {removed: string[]; added: string[]}; diff --git a/src/render.ts b/src/render.ts index 447c9947a..e38223b8f 100644 --- a/src/render.ts +++ b/src/render.ts @@ -27,9 +27,8 @@ export async function renderPage(page: MarkdownPage, options: RenderOptions & Re const {data} = page; const {base, path, title, preview} = options; const {loaders, resolvers = await getResolvers(page, options)} = options; - const sidebar = data?.sidebar !== undefined ? Boolean(data.sidebar) : options.sidebar; - const toc = mergeToc(data?.toc, options.toc); - const draft = Boolean(data?.draft); + const {draft = false, sidebar = options.sidebar} = data; + const toc = mergeToc(data.toc, options.toc); const {files, resolveFile, resolveImport} = resolvers; return String(html` ${path === "/404" ? html`\n` : ""} @@ -86,13 +85,13 @@ ${html.unsafe(rewriteHtml(page.body, resolvers))}${renderFooter(page.foot `); } -function registerTables(sql: Record, options: RenderOptions): string { +function registerTables(sql: Record, options: RenderOptions): string { return Object.entries(sql) .map(([name, source]) => registerTable(name, source, options)) .join("\n"); } -function registerTable(name: string, source: any, {path}: RenderOptions): string { +function registerTable(name: string, source: string, {path}: RenderOptions): string { return `registerTable(${JSON.stringify(name)}, ${ isAssetPath(source) ? `FileAttachment(${JSON.stringify(resolveRelativePath(path, source))})` diff --git a/src/resolvers.ts b/src/resolvers.ts index 88f5ba435..a34ebe945 100644 --- a/src/resolvers.ts +++ b/src/resolvers.ts @@ -112,7 +112,7 @@ export async function getResolvers( } // Add SQL sources. - if (page.data?.sql) { + if (page.data.sql) { for (const source of Object.values(page.data.sql)) { files.add(String(source)); } diff --git a/test/config-test.ts b/test/config-test.ts index efc768300..0668511f7 100644 --- a/test/config-test.ts +++ b/test/config-test.ts @@ -178,11 +178,9 @@ describe("mergeToc(spec, toc)", () => { const toc = config({pages: [], toc: true}, root).toc; assert.deepStrictEqual(mergeToc({show: false}, toc), {label: "Contents", show: false}); assert.deepStrictEqual(mergeToc({label: "On this page"}, toc), {label: "On this page", show: true}); - assert.deepStrictEqual(mergeToc(false, toc), {label: "Contents", show: false}); - assert.deepStrictEqual(mergeToc(true, toc), {label: "Contents", show: true}); - assert.deepStrictEqual(mergeToc(undefined, toc), {label: "Contents", show: true}); - assert.deepStrictEqual(mergeToc(null, toc), {label: "Contents", show: true}); - assert.deepStrictEqual(mergeToc(0, toc), {label: "Contents", show: false}); - assert.deepStrictEqual(mergeToc(1, toc), {label: "Contents", show: true}); + assert.deepStrictEqual(mergeToc({label: undefined}, toc), {label: "Contents", show: true}); + assert.deepStrictEqual(mergeToc({show: true}, toc), {label: "Contents", show: true}); + assert.deepStrictEqual(mergeToc({show: undefined}, toc), {label: "Contents", show: true}); + assert.deepStrictEqual(mergeToc({}, toc), {label: "Contents", show: true}); }); }); diff --git a/test/frontMatter-test.ts b/test/frontMatter-test.ts new file mode 100644 index 000000000..d51372441 --- /dev/null +++ b/test/frontMatter-test.ts @@ -0,0 +1,88 @@ +import assert from "node:assert"; +import {normalizeFrontMatter} from "../src/frontMatter.js"; + +describe("normalizeFrontMatter(spec)", () => { + it("returns the empty object for an undefined, null, empty spec", () => { + assert.deepStrictEqual(normalizeFrontMatter(), {}); + assert.deepStrictEqual(normalizeFrontMatter(undefined), {}); + assert.deepStrictEqual(normalizeFrontMatter(null), {}); + assert.deepStrictEqual(normalizeFrontMatter(false), {}); + assert.deepStrictEqual(normalizeFrontMatter(true), {}); + assert.deepStrictEqual(normalizeFrontMatter({}), {}); + assert.deepStrictEqual(normalizeFrontMatter(42), {}); + }); + it("coerces the title to a string or null", () => { + assert.deepStrictEqual(normalizeFrontMatter({title: 42}), {title: "42"}); + assert.deepStrictEqual(normalizeFrontMatter({title: undefined}), {}); + assert.deepStrictEqual(normalizeFrontMatter({title: null}), {title: null}); + assert.deepStrictEqual(normalizeFrontMatter({title: ""}), {title: ""}); + assert.deepStrictEqual(normalizeFrontMatter({title: "foo"}), {title: "foo"}); + assert.deepStrictEqual(normalizeFrontMatter({title: {toString: () => "foo"}}), {title: "foo"}); + }); + it("coerces the toc to {show?, label?}", () => { + assert.deepStrictEqual(normalizeFrontMatter({toc: false}), {toc: {show: false}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: true}), {toc: {show: true}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: null}), {toc: {show: false}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: ""}), {toc: {show: false}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: 42}), {toc: {show: true}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: {}}), {toc: {}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: {show: 1}}), {toc: {show: true}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: {show: 0}}), {toc: {show: false}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: {show: null}}), {toc: {show: false}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: {show: undefined}}), {toc: {}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: {label: null}}), {toc: {label: "null"}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: {label: false}}), {toc: {label: "false"}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: {label: 42}}), {toc: {label: "42"}}); + assert.deepStrictEqual(normalizeFrontMatter({toc: {label: {toString: () => "foo"}}}), {toc: {label: "foo"}}); + }); + it("coerces index to a boolean", () => { + assert.deepStrictEqual(normalizeFrontMatter({index: undefined}), {}); + assert.deepStrictEqual(normalizeFrontMatter({index: null}), {index: false}); + assert.deepStrictEqual(normalizeFrontMatter({index: 0}), {index: false}); + assert.deepStrictEqual(normalizeFrontMatter({index: 1}), {index: true}); + assert.deepStrictEqual(normalizeFrontMatter({index: true}), {index: true}); + assert.deepStrictEqual(normalizeFrontMatter({index: false}), {index: false}); + }); + it("coerces sidebar to a boolean", () => { + assert.deepStrictEqual(normalizeFrontMatter({sidebar: undefined}), {}); + assert.deepStrictEqual(normalizeFrontMatter({sidebar: null}), {sidebar: false}); + assert.deepStrictEqual(normalizeFrontMatter({sidebar: 0}), {sidebar: false}); + assert.deepStrictEqual(normalizeFrontMatter({sidebar: 1}), {sidebar: true}); + assert.deepStrictEqual(normalizeFrontMatter({sidebar: true}), {sidebar: true}); + assert.deepStrictEqual(normalizeFrontMatter({sidebar: false}), {sidebar: false}); + }); + it("coerces draft to a boolean", () => { + assert.deepStrictEqual(normalizeFrontMatter({draft: undefined}), {}); + assert.deepStrictEqual(normalizeFrontMatter({draft: null}), {draft: false}); + assert.deepStrictEqual(normalizeFrontMatter({draft: 0}), {draft: false}); + assert.deepStrictEqual(normalizeFrontMatter({draft: 1}), {draft: true}); + assert.deepStrictEqual(normalizeFrontMatter({draft: true}), {draft: true}); + assert.deepStrictEqual(normalizeFrontMatter({draft: false}), {draft: false}); + }); + it("coerces keywords to an array of strings", () => { + assert.deepStrictEqual(normalizeFrontMatter({keywords: undefined}), {}); + assert.deepStrictEqual(normalizeFrontMatter({keywords: null}), {keywords: []}); + assert.deepStrictEqual(normalizeFrontMatter({keywords: []}), {keywords: []}); + assert.deepStrictEqual(normalizeFrontMatter({keywords: [1, 2]}), {keywords: ["1", "2"]}); + assert.deepStrictEqual(normalizeFrontMatter({keywords: "test"}), {keywords: ["test"]}); + assert.deepStrictEqual(normalizeFrontMatter({keywords: ""}), {keywords: [""]}); + assert.deepStrictEqual(normalizeFrontMatter({keywords: "foo, bar"}), {keywords: ["foo, bar"]}); + assert.deepStrictEqual(normalizeFrontMatter({keywords: [1, "foo"]}), {keywords: ["1", "foo"]}); + assert.deepStrictEqual(normalizeFrontMatter({keywords: new Set([1, "foo"])}), {keywords: ["1", "foo"]}); + }); + it("coerces sql to a Record", () => { + assert.deepStrictEqual(normalizeFrontMatter({sql: undefined}), {}); + assert.deepStrictEqual(normalizeFrontMatter({sql: null}), {sql: {}}); + assert.deepStrictEqual(normalizeFrontMatter({sql: 0}), {sql: {}}); + assert.deepStrictEqual(normalizeFrontMatter({sql: 1}), {sql: {}}); + assert.deepStrictEqual(normalizeFrontMatter({sql: false}), {sql: {}}); + assert.deepStrictEqual(normalizeFrontMatter({sql: {foo: 1}}), {sql: {foo: "1"}}); + assert.deepStrictEqual(normalizeFrontMatter({sql: {foo: null}}), {sql: {foo: "null"}}); + assert.deepStrictEqual(normalizeFrontMatter({sql: {foo: "bar"}}), {sql: {foo: "bar"}}); + assert.deepStrictEqual(normalizeFrontMatter({sql: {foo: []}}), {sql: {foo: ""}}); + assert.deepStrictEqual(normalizeFrontMatter({sql: {foo: {toString: () => "bar"}}}), {sql: {foo: "bar"}}); + }); + it("ignores unknown properties", () => { + assert.deepStrictEqual(normalizeFrontMatter({foo: 42}), {}); + }); +}); diff --git a/test/input/yaml-frontmatter.md b/test/input/yaml-frontmatter.md index 8d4dfdf06..fd1a0b071 100644 --- a/test/input/yaml-frontmatter.md +++ b/test/input/yaml-frontmatter.md @@ -1,6 +1,7 @@ --- title: YAML -style: +style: custom.css +keywords: - one - two --- diff --git a/test/output/block-expression.md.json b/test/output/block-expression.md.json index 35921f8e8..0734646fb 100644 --- a/test/output/block-expression.md.json +++ b/test/output/block-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [ diff --git a/test/output/comment.md.json b/test/output/comment.md.json index 4b3e423b4..7cf6ce0b3 100644 --- a/test/output/comment.md.json +++ b/test/output/comment.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [] diff --git a/test/output/dollar-expression.md.json b/test/output/dollar-expression.md.json index 35921f8e8..0734646fb 100644 --- a/test/output/dollar-expression.md.json +++ b/test/output/dollar-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [ diff --git a/test/output/dot-graphviz.md.json b/test/output/dot-graphviz.md.json index 9b38b3978..b2c2a7dba 100644 --- a/test/output/dot-graphviz.md.json +++ b/test/output/dot-graphviz.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [ diff --git a/test/output/double-quote-expression.md.json b/test/output/double-quote-expression.md.json index c8fade0fd..e1a95a2a3 100644 --- a/test/output/double-quote-expression.md.json +++ b/test/output/double-quote-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [ diff --git a/test/output/embedded-expression.md.json b/test/output/embedded-expression.md.json index 6a97f084d..66b79d2fc 100644 --- a/test/output/embedded-expression.md.json +++ b/test/output/embedded-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Embedded expression", "style": null, "code": [ diff --git a/test/output/escaped-expression.md.json b/test/output/escaped-expression.md.json index 4b3e423b4..7cf6ce0b3 100644 --- a/test/output/escaped-expression.md.json +++ b/test/output/escaped-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [] diff --git a/test/output/fenced-code-options.md.json b/test/output/fenced-code-options.md.json index b8453d301..b8a908216 100644 --- a/test/output/fenced-code-options.md.json +++ b/test/output/fenced-code-options.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Fenced code options", "style": null, "code": [ diff --git a/test/output/fenced-code.md.json b/test/output/fenced-code.md.json index e970b9059..6ac043d03 100644 --- a/test/output/fenced-code.md.json +++ b/test/output/fenced-code.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Fenced code", "style": null, "code": [ diff --git a/test/output/fetch-parent-dir.md.json b/test/output/fetch-parent-dir.md.json index 14ab5c81d..ed3d7424b 100644 --- a/test/output/fetch-parent-dir.md.json +++ b/test/output/fetch-parent-dir.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Parent dir", "style": null, "code": [ diff --git a/test/output/heading-expression.md.json b/test/output/heading-expression.md.json index 35921f8e8..0734646fb 100644 --- a/test/output/heading-expression.md.json +++ b/test/output/heading-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [ diff --git a/test/output/hello-world.md.json b/test/output/hello-world.md.json index b5adf736b..2026591f2 100644 --- a/test/output/hello-world.md.json +++ b/test/output/hello-world.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Hello, world!", "style": null, "code": [] diff --git a/test/output/inline-expression.md.json b/test/output/inline-expression.md.json index 35921f8e8..0734646fb 100644 --- a/test/output/inline-expression.md.json +++ b/test/output/inline-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [ diff --git a/test/output/linkify.md.json b/test/output/linkify.md.json index 6e10bc956..98770d6cb 100644 --- a/test/output/linkify.md.json +++ b/test/output/linkify.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Linkify", "style": null, "code": [] diff --git a/test/output/local-fetch.md.json b/test/output/local-fetch.md.json index f660331a8..14217c8d7 100644 --- a/test/output/local-fetch.md.json +++ b/test/output/local-fetch.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Local fetch", "style": null, "code": [ diff --git a/test/output/malformed-block.md.json b/test/output/malformed-block.md.json index 0fc87bd06..1f1097a0a 100644 --- a/test/output/malformed-block.md.json +++ b/test/output/malformed-block.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Malformed block", "style": null, "code": [] diff --git a/test/output/markdown-in-html.md.json b/test/output/markdown-in-html.md.json index a40cd797a..7bc9c0071 100644 --- a/test/output/markdown-in-html.md.json +++ b/test/output/markdown-in-html.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Markdown in HTML", "style": null, "code": [] diff --git a/test/output/mermaid.md.json b/test/output/mermaid.md.json index 7f8ad764e..b01e6649c 100644 --- a/test/output/mermaid.md.json +++ b/test/output/mermaid.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [ diff --git a/test/output/script-expression.md.json b/test/output/script-expression.md.json index 7fbe6bc32..a1f33a334 100644 --- a/test/output/script-expression.md.json +++ b/test/output/script-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Script expression", "style": null, "code": [] diff --git a/test/output/single-quote-expression.md.json b/test/output/single-quote-expression.md.json index 570b9e859..3296daaae 100644 --- a/test/output/single-quote-expression.md.json +++ b/test/output/single-quote-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [ diff --git a/test/output/template-expression.md.json b/test/output/template-expression.md.json index b86f8d298..fffdd181b 100644 --- a/test/output/template-expression.md.json +++ b/test/output/template-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [ diff --git a/test/output/tex-block.md.json b/test/output/tex-block.md.json index 6f235847c..c46459a02 100644 --- a/test/output/tex-block.md.json +++ b/test/output/tex-block.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": null, "style": null, "code": [ diff --git a/test/output/tex-expression.md.json b/test/output/tex-expression.md.json index 10f100b16..d4c07ef28 100644 --- a/test/output/tex-expression.md.json +++ b/test/output/tex-expression.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Hello, ", "style": null, "code": [ diff --git a/test/output/wellformed-block.md.json b/test/output/wellformed-block.md.json index 9ca9b7c4c..71437db8e 100644 --- a/test/output/wellformed-block.md.json +++ b/test/output/wellformed-block.md.json @@ -1,5 +1,5 @@ { - "data": null, + "data": {}, "title": "Well-formed block", "style": null, "code": [] diff --git a/test/output/yaml-frontmatter.md.json b/test/output/yaml-frontmatter.md.json index 8f1ff4f3e..c4e1d1987 100644 --- a/test/output/yaml-frontmatter.md.json +++ b/test/output/yaml-frontmatter.md.json @@ -1,12 +1,13 @@ { "data": { "title": "YAML", - "style": [ + "keywords": [ "one", "two" - ] + ], + "style": "custom.css" }, "title": "YAML", - "style": "./one,two", + "style": "./custom.css", "code": [] } \ No newline at end of file