From f405cd27add05ee97aa6bc025ce874f35b5a4c3d Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 9 Nov 2024 08:59:00 -0800 Subject: [PATCH 1/5] async parseMarkdown --- src/loader.ts | 2 +- src/markdown.ts | 2 +- test/markdown-test.ts | 2 +- test/resolvers-test.ts | 30 +++++++++++++++--------------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/loader.ts b/src/loader.ts index 324f1a8e1..2a9c1cef0 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -81,7 +81,7 @@ export class LoaderResolver { const loader = this.findPage(path); if (!loader) throw enoent(path); const input = await readFile(join(this.root, await loader.load(options, effects)), "utf8"); - return parseMarkdown(input, {source: loader.path, params: loader.params, ...options}); + return await parseMarkdown(input, {source: loader.path, params: loader.params, ...options}); } /** diff --git a/src/markdown.ts b/src/markdown.ts index cb43b5726..85c25b1e7 100644 --- a/src/markdown.ts +++ b/src/markdown.ts @@ -243,7 +243,7 @@ export function createMarkdownIt({ return markdownIt === undefined ? md : markdownIt(md); } -export function parseMarkdown(input: string, options: ParseOptions): MarkdownPage { +export async function parseMarkdown(input: string, options: ParseOptions): Promise { const {md, path, source = path, params} = options; const {content, data} = readFrontMatter(input); const code: MarkdownCode[] = []; diff --git a/test/markdown-test.ts b/test/markdown-test.ts index eeecb222a..5e37b9222 100644 --- a/test/markdown-test.ts +++ b/test/markdown-test.ts @@ -23,7 +23,7 @@ describe("parseMarkdown(input)", () => { (only ? it.only : skip ? it.skip : it)(`test/input/${name}`, async () => { const source = await readFile(path, "utf8"); - const snapshot = parseMarkdown(source, {path: name, md}); + const snapshot = await parseMarkdown(source, {path: name, md}); let allequal = true; for (const ext of ["html", "json"]) { const actual = ext === "json" ? jsonMeta(snapshot) : snapshot.body; diff --git a/test/resolvers-test.ts b/test/resolvers-test.ts index 090d34d21..a60c807d7 100644 --- a/test/resolvers-test.ts +++ b/test/resolvers-test.ts @@ -14,74 +14,74 @@ describe("getResolvers(page, {root, path})", () => { const builtins = ["observablehq:runtime", "observablehq:stdlib", "observablehq:client"]; it("resolves directly-attached files", async () => { const options = getOptions({root: "test/input", path: "attached.md"}); - const page = parseMarkdown("${FileAttachment('foo.csv')}", options); + const page = await parseMarkdown("${FileAttachment('foo.csv')}", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.files, new Set(["./foo.csv"])); }); it("ignores files that are outside of the source root", async () => { const options = getOptions({root: "test/input", path: "attached.md"}); - const page = parseMarkdown("${FileAttachment('../foo.csv')}", options); + const page = await parseMarkdown("${FileAttachment('../foo.csv')}", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.files, new Set([])); }); it("detects file methods", async () => { const options = getOptions({root: "test/input", path: "attached.md"}); - const page = parseMarkdown("${FileAttachment('foo.csv').csv}", options); + const page = await parseMarkdown("${FileAttachment('foo.csv').csv}", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.staticImports, new Set(["npm:d3-dsv", ...builtins])); }); it("detects local static imports", async () => { const options = getOptions({root: "test/input/imports", path: "attached.md"}); - const page = parseMarkdown("```js\nimport './bar.js';\n```", options); + const page = await parseMarkdown("```js\nimport './bar.js';\n```", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.staticImports, new Set(["./bar.js", ...builtins])); assert.deepStrictEqual(resolvers.localImports, new Set(["./bar.js"])); }); it("detects local transitive static imports", async () => { const options = getOptions({root: "test/input/imports", path: "attached.md"}); - const page = parseMarkdown("```js\nimport './other/foo.js';\n```", options); + const page = await parseMarkdown("```js\nimport './other/foo.js';\n```", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.staticImports, new Set(["./other/foo.js", "./bar.js", ...builtins])); assert.deepStrictEqual(resolvers.localImports, new Set(["./other/foo.js", "./bar.js"])); }); it("detects local transitive static imports (2)", async () => { const options = getOptions({root: "test/input/imports", path: "attached.md"}); - const page = parseMarkdown("```js\nimport './transitive-static-import.js';\n```", options); + const page = await parseMarkdown("```js\nimport './transitive-static-import.js';\n```", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.staticImports, new Set(["./transitive-static-import.js", "./other/foo.js", "./bar.js", ...builtins])); // prettier-ignore assert.deepStrictEqual(resolvers.localImports, new Set(["./transitive-static-import.js", "./other/foo.js", "./bar.js"])); // prettier-ignore }); it("detects local transitive dynamic imports", async () => { const options = getOptions({root: "test/input/imports", path: "attached.md"}); - const page = parseMarkdown("```js\nimport './dynamic-import.js';\n```", options); + const page = await parseMarkdown("```js\nimport './dynamic-import.js';\n```", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.staticImports, new Set(["./dynamic-import.js", ...builtins])); assert.deepStrictEqual(resolvers.localImports, new Set(["./dynamic-import.js", "./bar.js"])); }); it("detects local transitive dynamic imports (2)", async () => { const options = getOptions({root: "test/input/imports", path: "attached.md"}); - const page = parseMarkdown("```js\nimport('./dynamic-import.js');\n```", options); + const page = await parseMarkdown("```js\nimport('./dynamic-import.js');\n```", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.staticImports, new Set(builtins)); assert.deepStrictEqual(resolvers.localImports, new Set(["./dynamic-import.js", "./bar.js"])); }); it("detects local transitive dynamic imports (3)", async () => { const options = getOptions({root: "test/input/imports", path: "attached.md"}); - const page = parseMarkdown("```js\nimport('./transitive-dynamic-import.js');\n```", options); + const page = await parseMarkdown("```js\nimport('./transitive-dynamic-import.js');\n```", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.staticImports, new Set(builtins)); assert.deepStrictEqual(resolvers.localImports, new Set(["./transitive-dynamic-import.js", "./other/foo.js", "./bar.js"])); // prettier-ignore }); it("detects local transitive dynamic imports (4)", async () => { const options = getOptions({root: "test/input/imports", path: "attached.md"}); - const page = parseMarkdown("```js\nimport('./transitive-static-import.js');\n```", options); + const page = await parseMarkdown("```js\nimport('./transitive-static-import.js');\n```", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.staticImports, new Set(builtins)); assert.deepStrictEqual(resolvers.localImports, new Set(["./transitive-static-import.js", "./other/foo.js", "./bar.js"])); // prettier-ignore }); it("detects local dynamic imports", async () => { const options = getOptions({root: "test/input", path: "attached.md"}); - const page = parseMarkdown("${import('./foo.js')}", options); + const page = await parseMarkdown("${import('./foo.js')}", options); const resolvers = await getResolvers(page, options); assert.deepStrictEqual(resolvers.staticImports, new Set(builtins)); assert.deepStrictEqual(resolvers.localImports, new Set(["./foo.js"])); @@ -89,9 +89,9 @@ describe("getResolvers(page, {root, path})", () => { }); describe("resolveLink(href) with {preserveExtension: true}", () => { - const options = getOptions({root: "test/input", path: "sub/index.html", preserveExtension: true}); - const page = parseMarkdown("", options); async function getResolveLink() { + const options = getOptions({root: "test/input", path: "sub/index.html", preserveExtension: true}); + const page = await parseMarkdown("", options); const resolvers = await getResolvers(page, options); return resolvers.resolveLink; } @@ -164,9 +164,9 @@ describe("resolveLink(href) with {preserveExtension: true}", () => { }); describe("resolveLink(href) with {preserveExtension: false}", () => { - const options = getOptions({root: "test/input", path: "sub/index.html", preserveExtension: false}); - const page = parseMarkdown("", options); async function getResolveLink() { + const options = getOptions({root: "test/input", path: "sub/index.html", preserveExtension: false}); + const page = await parseMarkdown("", options); const resolvers = await getResolvers(page, options); return resolvers.resolveLink; } From 5fcb96d7bf5e8f165bbdc7585bb2afdad1456224 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Sat, 9 Nov 2024 09:35:24 -0800 Subject: [PATCH 2/5] page fragment loaders --- docs/index.md | 8 +++++ src/loader.ts | 2 +- src/markdown.ts | 84 ++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 86 insertions(+), 8 deletions(-) diff --git a/docs/index.md b/docs/index.md index 83cc6a13f..a59dff688 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,6 +2,14 @@ index: false --- +```js server +console.log(`The current version of Node is: ${process.env.npm_package_version}.`); +``` + +```sh server +uname -a +``` +