From 582f17675d353991de25b999e41f8bf5b29f6156 Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 04:44:21 -0700 Subject: [PATCH 01/14] test: add tests for #14 --- .../test-custom-slug-in-dot-dir.md | 5 +++ src/fixtures/test-custom-slug.md | 5 +++ src/index.test.mjs | 32 +++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 src/fixtures/dir-test-custom-slug.md/test-custom-slug-in-dot-dir.md create mode 100644 src/fixtures/test-custom-slug.md diff --git a/src/fixtures/dir-test-custom-slug.md/test-custom-slug-in-dot-dir.md b/src/fixtures/dir-test-custom-slug.md/test-custom-slug-in-dot-dir.md new file mode 100644 index 0000000..5228ff6 --- /dev/null +++ b/src/fixtures/dir-test-custom-slug.md/test-custom-slug-in-dot-dir.md @@ -0,0 +1,5 @@ +--- +slug: dir-test-custom-slug/test.custom.slug.in.dot.dir +--- + +Test \ No newline at end of file diff --git a/src/fixtures/test-custom-slug.md b/src/fixtures/test-custom-slug.md new file mode 100644 index 0000000..b8124cb --- /dev/null +++ b/src/fixtures/test-custom-slug.md @@ -0,0 +1,5 @@ +--- +slug: test.custom.slug +--- + +Test Custom Slug \ No newline at end of file diff --git a/src/index.test.mjs b/src/index.test.mjs index 9ebd22f..72f2d57 100644 --- a/src/index.test.mjs +++ b/src/index.test.mjs @@ -125,4 +125,36 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { assert.equal(actual, expected); }, ); + + await t.test( + "should transform with correct path when destination has custom slug", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }, + ); + + await t.test( + "should transform with correct path when destination in subpath has custom slug", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }, + ); }); From d1a8cf638b315c7bfc327e91c0068d4b8406d39e Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 04:47:43 -0700 Subject: [PATCH 02/14] test: add test for #15 --- src/fixtures.md/test-1.md | 3 +++ src/index.test.mjs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/fixtures.md/test-1.md diff --git a/src/fixtures.md/test-1.md b/src/fixtures.md/test-1.md new file mode 100644 index 0000000..157023e --- /dev/null +++ b/src/fixtures.md/test-1.md @@ -0,0 +1,3 @@ +## Test + +Test [link](./other-markdown.md) diff --git a/src/index.test.mjs b/src/index.test.mjs index 72f2d57..d77a526 100644 --- a/src/index.test.mjs +++ b/src/index.test.mjs @@ -154,6 +154,22 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { const expected = 'foo'; + assert.equal(actual, expected); + }, + ); + + await t.test( + "should not transform content collection path segment", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .process(input); + + const expected = + 'foo'; + assert.equal(actual, expected); }, ); From fc75e8d470bbd5739326d1d6715ded43eb9a1009 Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 09:31:43 -0700 Subject: [PATCH 03/14] test: fix & add tests for #16 --- src/fixtures/dir-test-custom-slug-2/index.md | 5 +++ src/fixtures/dir-test-custom-slug/index.md | 5 +++ src/fixtures/dir-test/index.md | 1 + src/index.test.mjs | 43 +++++++++++++++++++- 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/fixtures/dir-test-custom-slug-2/index.md create mode 100644 src/fixtures/dir-test-custom-slug/index.md create mode 100644 src/fixtures/dir-test/index.md diff --git a/src/fixtures/dir-test-custom-slug-2/index.md b/src/fixtures/dir-test-custom-slug-2/index.md new file mode 100644 index 0000000..959610d --- /dev/null +++ b/src/fixtures/dir-test-custom-slug-2/index.md @@ -0,0 +1,5 @@ +--- +slug: myindex +--- + +# Test \ No newline at end of file diff --git a/src/fixtures/dir-test-custom-slug/index.md b/src/fixtures/dir-test-custom-slug/index.md new file mode 100644 index 0000000..065dafc --- /dev/null +++ b/src/fixtures/dir-test-custom-slug/index.md @@ -0,0 +1,5 @@ +--- +slug: '' +--- + +Test \ No newline at end of file diff --git a/src/fixtures/dir-test/index.md b/src/fixtures/dir-test/index.md new file mode 100644 index 0000000..c409365 --- /dev/null +++ b/src/fixtures/dir-test/index.md @@ -0,0 +1 @@ +## Test \ No newline at end of file diff --git a/src/index.test.mjs b/src/index.test.mjs index d77a526..ef50320 100644 --- a/src/index.test.mjs +++ b/src/index.test.mjs @@ -36,7 +36,7 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { assert.equal(actual, expected); }); - await t.test("should transform index.md paths", async () => { + await t.test("should transform and contain index for root collection index.md paths", async () => { const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) @@ -44,7 +44,46 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { .process(input); const expected = - 'foo'; + 'foo'; + + assert.equal(actual, expected); + }); + + await t.test("should transform root collection index.md paths with empty string custom slug", async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }); + + await t.test("should transform root collection index.md paths with non-empty string custom slug", async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }); + + await t.test("should transform non-root collection index.md paths", async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .process(input); + + const expected = + 'foo'; assert.equal(actual, expected); }); From 1285ed210bb222cb2292b55faa210fa9840d6fad Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 09:41:16 -0700 Subject: [PATCH 04/14] chore: maintain single fixtures directory --- .../dir-test-with-extension.md}/test-1.md | 0 src/index.test.mjs | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/{fixtures.md => fixtures/dir-test-with-extension.md}/test-1.md (100%) diff --git a/src/fixtures.md/test-1.md b/src/fixtures/dir-test-with-extension.md/test-1.md similarity index 100% rename from src/fixtures.md/test-1.md rename to src/fixtures/dir-test-with-extension.md/test-1.md diff --git a/src/index.test.mjs b/src/index.test.mjs index ef50320..1281ee1 100644 --- a/src/index.test.mjs +++ b/src/index.test.mjs @@ -200,14 +200,14 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { await t.test( "should not transform content collection path segment", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, From 553eef19af6b1f0ec191f195f45beee4c957a984 Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 09:53:52 -0700 Subject: [PATCH 05/14] test: additional tests for #14 --- src/fixtures/test-custom-slug-ext.md | 5 +++++ src/fixtures/test-custom-slug.md | 2 +- src/index.test.mjs | 18 +++++++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/fixtures/test-custom-slug-ext.md diff --git a/src/fixtures/test-custom-slug-ext.md b/src/fixtures/test-custom-slug-ext.md new file mode 100644 index 0000000..2deaede --- /dev/null +++ b/src/fixtures/test-custom-slug-ext.md @@ -0,0 +1,5 @@ +--- +slug: test.custom.slug.md +--- + +Test Custom Slug MD \ No newline at end of file diff --git a/src/fixtures/test-custom-slug.md b/src/fixtures/test-custom-slug.md index b8124cb..e07d229 100644 --- a/src/fixtures/test-custom-slug.md +++ b/src/fixtures/test-custom-slug.md @@ -1,5 +1,5 @@ --- -slug: test.custom.slug +slug: test.custom.slug-custom --- Test Custom Slug \ No newline at end of file diff --git a/src/index.test.mjs b/src/index.test.mjs index 1281ee1..30743e0 100644 --- a/src/index.test.mjs +++ b/src/index.test.mjs @@ -175,7 +175,23 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { .process(input); const expected = - 'foo'; + 'foo'; + + assert.equal(actual, expected); + }, + ); + + await t.test( + "should transform with correct path when destination has custom slug with file extension", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .process(input); + + const expected = + 'foo'; assert.equal(actual, expected); }, From 0cd55e2170cc2944eb936da102e9979c81b63790 Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 10:08:00 -0700 Subject: [PATCH 06/14] test: fix broken test for #14 --- src/index.test.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.test.mjs b/src/index.test.mjs index 30743e0..28a1632 100644 --- a/src/index.test.mjs +++ b/src/index.test.mjs @@ -200,14 +200,14 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { await t.test( "should transform with correct path when destination in subpath has custom slug", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, From 0e6b89362ec1cd11abb2421b11381e7102ad0cc1 Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 11:21:02 -0700 Subject: [PATCH 07/14] test: add fixture file for test for #14 --- .../dir-test-custom-slug.md/test-custom-slug-in-dot-dir.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fixtures/dir-test-custom-slug.md/test-custom-slug-in-dot-dir.md b/src/fixtures/dir-test-custom-slug.md/test-custom-slug-in-dot-dir.md index 5228ff6..b046ede 100644 --- a/src/fixtures/dir-test-custom-slug.md/test-custom-slug-in-dot-dir.md +++ b/src/fixtures/dir-test-custom-slug.md/test-custom-slug-in-dot-dir.md @@ -1,5 +1,5 @@ --- -slug: dir-test-custom-slug/test.custom.slug.in.dot.dir +slug: dir-test-custom-slug.md/test.custom.slug.in.dot.dir --- Test \ No newline at end of file From 36b48fb6867b2e4c72c63f1f8d49ebf50725af2f Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 11:32:09 -0700 Subject: [PATCH 08/14] fix: resolves #14, #15 & #16 --- package.json | 3 +- src/index.mjs | 67 +++++++++++++---------------- src/utils.d.ts | 2 + src/utils.mjs | 33 ++++++++------- src/utils.test.mjs | 102 +++++++++++++++++++++++++++++++++++++++++---- yarn.lock | 8 ++++ 6 files changed, 150 insertions(+), 65 deletions(-) diff --git a/package.json b/package.json index ac01a80..5c6d349 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "debug": "^4.3.4", "github-slugger": "^2.0.0", "gray-matter": "^4.0.3", - "unist-util-visit": "^4.1.2" + "unist-util-visit": "^4.1.2", + "zod": "^3.22.4" }, "peerDependencies": { "astro": ">=2.x <5" diff --git a/src/index.mjs b/src/index.mjs index 4b95f49..8a7f9be 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -8,6 +8,8 @@ import { isValidRelativeLink, splitPathFromQueryAndFragment, normaliseAstroOutputPath, + generateSlug, + resolveSlug, } from "./utils.mjs"; // This package makes a lot of assumptions based on it being used with Astro @@ -49,34 +51,22 @@ function astroRehypeRelativeMarkdownLinks(options = {}) { // read gray matter from relative file const relativeFileContent = fs.readFileSync(relativeFile); const { data: frontmatter } = matter(relativeFileContent); - const relativeFileCustomSlug = frontmatter.slug; - const relativeFileHasCustomSlug = Boolean(relativeFileCustomSlug); - - let webPathFinal; - const webPath = relativeFile.split( - options.contentPath || defaultContentPath, - )[1]; - - if (relativeFileHasCustomSlug) { - webPathFinal = - path.posix.sep + - [ - webPath.split(path.sep)[1], // this should be the content collection - relativeFileCustomSlug, - ].join(path.posix.sep); - } else { - webPathFinal = replaceExt(webPath, ""); - } - - webPathFinal = webPathFinal.split(path.sep); - - // Remove index from the end of the path to satsify instances where we'll be generating - // index.html files for directories - if (webPathFinal[webPathFinal.length - 1] === "index") { - webPathFinal.pop(); - } - - webPathFinal = webPathFinal.join(path.posix.sep); + const frontmatterSlug = frontmatter.slug; + const contentDir = options.contentPath || defaultContentPath; + + const relativeToContentPath = path.relative(contentDir, relativeFile); + const collectionName = path.dirname(relativeToContentPath).split(path.posix.sep)[0]; + const relativeToCollectionPath = path.relative(collectionName, relativeToContentPath); + const withoutFileExt = replaceExt(relativeToCollectionPath, "") + const pathSegments = withoutFileExt.split(path.posix.sep); + const generatedSlug = generateSlug(pathSegments); + const resolvedSlug = resolveSlug(generatedSlug, frontmatterSlug); + + let webPathFinal = path.posix.sep + + [ + collectionName, + resolvedSlug, + ].join(path.posix.sep); if (queryStringAndFragment) { webPathFinal += queryStringAndFragment; @@ -86,17 +76,16 @@ function astroRehypeRelativeMarkdownLinks(options = {}) { // Debugging debug("--------------------------------"); - debug("md/mdx AST Current File : %s", currentFile); - debug("md/mdx AST Current File Dir : %s", currentFileDirectory); - debug("md/mdx AST href full : %s", nodeHref); - debug("md/mdx AST href path : %s", url); - debug("md/mdx AST href qs and/or hash : %s", queryStringAndFragment); - debug("File relative to current md/mdx: %s", relativeFile); - debug("File relative has custom slug : %s", relativeFileHasCustomSlug); - if (relativeFileHasCustomSlug) { - debug("File relative custom slug : %s", relativeFileCustomSlug); - } - debug("Final URL path : %s", webPathFinal); + debug("md/mdx AST Current File : %s", currentFile); + debug("md/mdx AST Current File Dir : %s", currentFileDirectory); + debug("md/mdx AST href full : %s", nodeHref); + debug("md/mdx AST href path : %s", url); + debug("md/mdx AST href qs and/or hash : %s", queryStringAndFragment); + debug("File relative to current md/mdx : %s", relativeFile); + debug("File relative custom slug : %s", frontmatterSlug); + debug("File relative generated slug : %s", generatedSlug); + debug("File relative resolved slug : %s", resolvedSlug); + debug("Final URL path : %s", webPathFinal); node.properties.href = webPathFinal; }); diff --git a/src/utils.d.ts b/src/utils.d.ts index 8d733dd..3f0bb74 100644 --- a/src/utils.d.ts +++ b/src/utils.d.ts @@ -4,3 +4,5 @@ export type SplitPathFromQueryAndFragmentFn = ( export type ReplaceExtFn = (path: string, ext: string) => string; export type IsCurrentDirectoryFn = (path: string) => boolean; export type IsValidRelativeLinkFn = (link: string) => boolean; +export type GenerateSlug = (pathSegments: string[]) => string; +export type ResolveSlug = (generatedSlug: string, frontmatterSlug?: unknown) => string; diff --git a/src/utils.mjs b/src/utils.mjs index 89980cc..e428dc1 100644 --- a/src/utils.mjs +++ b/src/utils.mjs @@ -1,5 +1,6 @@ import path from "path"; import { slug as githubSlug } from "github-slugger"; +import { z } from 'zod'; const pathSeparator = path.sep; const validMarkdownExtensions = [".md", ".mdx"]; @@ -82,26 +83,26 @@ export const normaliseAstroOutputPath = (initialPath, options = {}) => { return; } - const [pathWithoutQueryAndFragment, queryStringAndFragment] = - splitPathFromQueryAndFragment(initialPath); - - const pathSegments = pathWithoutQueryAndFragment.split(pathSeparator); - - let normalisedPath = pathSegments - .map((segment) => githubSlug(segment)) - .join("/"); - - if (queryStringAndFragment) { - normalisedPath += queryStringAndFragment; - } - if (!options.basePath) { - return normalisedPath; + return initialPath; } if (options.basePath.startsWith("/")) { - return path.join(options.basePath, normalisedPath); + return path.join(options.basePath, initialPath); } - return "/" + path.join(options.basePath, normalisedPath); + return "/" + path.join(options.basePath, initialPath); }; + +/** @type {import('./utils').GenerateSlug} */ +export const generateSlug = (pathSegments) => { + return pathSegments + .map((segment) => githubSlug(segment)) + .join("/") + .replace(/\/index$/, ''); +} + +/** @type {import('./utils').ResolveSlug} */ +export const resolveSlug = (generatedSlug, frontmatterSlug) => { + return z.string().default(generatedSlug).parse(frontmatterSlug); +} \ No newline at end of file diff --git a/src/utils.test.mjs b/src/utils.test.mjs index 680ef3b..c42e937 100644 --- a/src/utils.test.mjs +++ b/src/utils.test.mjs @@ -6,6 +6,8 @@ import { normaliseAstroOutputPath, replaceExt, splitPathFromQueryAndFragment, + generateSlug, + resolveSlug } from "./utils.mjs"; describe("replaceExt", () => { @@ -104,22 +106,104 @@ describe("splitPathFromQueryAndFragment", () => { }); }); -describe("normaliseAstroOutputPath", () => { +describe("generateSlug", () => { test("removes uppercase characters", () => { - const actual = normaliseAstroOutputPath("/Foo-TESTING-test"); + const actual = generateSlug(["/Foo-TESTING-test"]); - assert.equal(actual, "/foo-testing-test"); + assert.equal(actual, "foo-testing-test"); }); test("replaces spaces with dashes", () => { - const actual = normaliseAstroOutputPath("/foo testing test"); + const actual = generateSlug(["/foo testing test"]); + + assert.equal(actual, "foo-testing-test"); + }); + + test("removes periods", () => { + const actual = generateSlug(["/foo.testing.test"]); + + assert.equal(actual, "footestingtest"); + }); + + test("removes uppercase across multiple segments", () => { + const actual = generateSlug(["/FOO", "/foo-TESTING-test"]); + + assert.equal(actual, "foo/foo-testing-test"); + }); + + test("removes spaces across multiple segments with no leading slashes", () => { + const actual = generateSlug(["FOO", "foo TESTING test"]); - assert.equal(actual, "/foo-testing-test"); + assert.equal(actual, "foo/foo-testing-test"); }); + test("should strip index when subdirectory", () => { + const actual = generateSlug(["foo", "index"]); + + assert.equal(actual, "foo"); + }); + + test("should strip mixed-case index when subdirectory", () => { + const actual = generateSlug(["foo", "iNdEX"]); + + assert.equal(actual, "foo"); + }); + + test("should not strip index root", () => { + const actual = generateSlug(["index"]); + + assert.equal(actual, "index"); + }); + + test("should not strip mixed case index root", () => { + const actual = generateSlug(["iNdEX"]); + + assert.equal(actual, "index"); + }); +}); + +describe("resolveSlug", () => { + test("uses generated slug when frontmatter undefined", () => { + const actual = resolveSlug("foo/bar"); + + assert.equal(actual, "foo/bar"); + }); + + test("uses frontmatter when frontmatter empty string", () => { + const actual = resolveSlug("foo/bar", ""); + + assert.equal(actual, ""); + }); + + test("uses frontmatter when frontmatter is index", () => { + const actual = resolveSlug("foo/bar", "index"); + + assert.equal(actual, "index"); + }); + + test("uses frontmatter when frontmatter has extension", () => { + const actual = resolveSlug("foo/bar", "foo.md"); + + assert.equal(actual, "foo.md"); + }); + + test("throws exception when no valid slug", () => { + assert.throws(() => resolveSlug()); + }); + + test("throws exception when frontmatter is null", () => { + assert.throws(() => resolveSlug("foo/bar", null )); + }); + + test("throws exception when frontmatter is number", () => { + assert.throws(() => resolveSlug("foo/bar", 5 )); + }); +}); + +describe("normaliseAstroOutputPath", () => { describe("prefix base to path", () => { test("base with no slashes", () => { - const actual = normaliseAstroOutputPath("/foo testing test", { + const actual = normaliseAstroOutputPath("/foo-testing-test", { basePath: "base", }); @@ -127,7 +211,7 @@ describe("normaliseAstroOutputPath", () => { }); test("base with slash at start", () => { - const actual = normaliseAstroOutputPath("/foo testing test", { + const actual = normaliseAstroOutputPath("/foo-testing-test", { basePath: "/base", }); @@ -135,7 +219,7 @@ describe("normaliseAstroOutputPath", () => { }); test("base with slash at end", () => { - const actual = normaliseAstroOutputPath("/foo testing test", { + const actual = normaliseAstroOutputPath("/foo-testing-test", { basePath: "base/", }); @@ -143,7 +227,7 @@ describe("normaliseAstroOutputPath", () => { }); test("base with slash at start and end", () => { - const actual = normaliseAstroOutputPath("/foo testing test", { + const actual = normaliseAstroOutputPath("/foo-testing-test", { basePath: "/base/", }); diff --git a/yarn.lock b/yarn.lock index 27247dd..bb6200f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -122,6 +122,7 @@ __metadata: prettier: "npm:^4.0.0-alpha.8" rehype: "npm:^13.0.1" unist-util-visit: "npm:^4.1.2" + zod: "npm:^3.22.4" peerDependencies: astro: ">=2.x <5" languageName: unknown @@ -1170,6 +1171,13 @@ __metadata: languageName: node linkType: hard +"zod@npm:^3.22.4": + version: 3.22.4 + resolution: "zod@npm:3.22.4" + checksum: 10c0/7578ab283dac0eee66a0ad0fc4a7f28c43e6745aadb3a529f59a4b851aa10872b3890398b3160f257f4b6817b4ce643debdda4fb21a2c040adda7862cab0a587 + languageName: node + linkType: hard + "zwitch@npm:^2.0.0, zwitch@npm:^2.0.4": version: 2.0.4 resolution: "zwitch@npm:2.0.4" From 15bf744a32d3868e8ca7f8012f8eb3bf89dddb30 Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 21:31:58 -0700 Subject: [PATCH 09/14] test: add tests for #18 --- src/index.test.mjs | 112 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/src/index.test.mjs b/src/index.test.mjs index 28a1632..fb0d43f 100644 --- a/src/index.test.mjs +++ b/src/index.test.mjs @@ -228,4 +228,116 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { assert.equal(actual, expected); }, ); + + await t.test( + "should transform and contain index for root index.md when content path same as collection path", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }, + ); + + await t.test( + "should transform root index.md with empty string custom slug when content path same as collection path", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures/dir-test-custom-slug" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }, + ); + + await t.test( + "should transform root path when content path same as collection path", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }, + ); + + await t.test( + "should transform root path custom slug when content path same as collection path", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }, + ); + + await t.test( + "should transform subdir index.md when content path same as collection path", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }, + ); + + await t.test( + "should transform subdir path when content path same as collection path", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }, + ); + + await t.test( + "should transform subdir path custom slug when content path same as collection path", + async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .process(input); + + const expected = + 'foo'; + + assert.equal(actual, expected); + }, + ); }); From 29f745dc3aba04c0c23c45638344127a95e14c7d Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 21:33:09 -0700 Subject: [PATCH 10/14] test: add fixture for test for #18 --- src/fixtures/dir-test/dir-test-child.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/fixtures/dir-test/dir-test-child.md diff --git a/src/fixtures/dir-test/dir-test-child.md b/src/fixtures/dir-test/dir-test-child.md new file mode 100644 index 0000000..21e60f8 --- /dev/null +++ b/src/fixtures/dir-test/dir-test-child.md @@ -0,0 +1 @@ +# Test \ No newline at end of file From 20951518bbd5ba738a1c38a5bfaec68bffe69b94 Mon Sep 17 00:00:00 2001 From: techfg Date: Sun, 7 Apr 2024 21:35:24 -0700 Subject: [PATCH 11/14] fix: resolves #18 --- src/index.d.ts | 24 ++++++++++++++++++++++++ src/index.mjs | 11 +++++++---- src/index.test.mjs | 14 +++++++------- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/index.d.ts b/src/index.d.ts index 7597a1b..436bf95 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,4 +1,28 @@ +type CollectionPathMode = 'subdirectory' | `root` + export interface Options { contentPath?: string; // where you store your content relative to the root directory + /** + * @docs + * @name collectionPathMode + * @type {CollectionPathMode} + * @default `'subdirectory'` + * @description + * + * Where you store your collections: + * - `'subdirectory'` - Subdirectories under `contentPath` (ex: "src/content/docs/index.md" where docs is the content collection subdirectory of the contentPath src/content) + * - `'root'` - Directly inside `contentPath` (ex. src/content/index.md where src/content is the contentPath) + * + * Use the `root` configuration option when you are treating a single content collection as if it where located in the site root. In most scenarios, you should set this + * value to `subdirectory` or not set this value and the default of `subdirectory` will be used. + * + * ```js + * { + * // Example: Use `subdirectory` mode + * collectionPathMode: `subdirectory` + * } + * ``` + */ + collectionPathMode?: CollectionPathMode; basePath?: string; // https://docs.astro.build/en/reference/configuration-reference/#base } diff --git a/src/index.mjs b/src/index.mjs index 8a7f9be..4642107 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -19,6 +19,9 @@ const debug = debugFn("astro-rehype-relative-markdown-links"); // This is very specific to Astro const defaultContentPath = ["src", "content"].join(path.sep); +/** @type {import("./index").CollectionPathMode} */ +const defaultCollectionPathMode = 'subdirectory'; + /** @param {import('./index').Options} options */ function astroRehypeRelativeMarkdownLinks(options = {}) { return (tree, file) => { @@ -53,18 +56,18 @@ function astroRehypeRelativeMarkdownLinks(options = {}) { const { data: frontmatter } = matter(relativeFileContent); const frontmatterSlug = frontmatter.slug; const contentDir = options.contentPath || defaultContentPath; - + const collectionPathMode = options.collectionPathMode || defaultCollectionPathMode; const relativeToContentPath = path.relative(contentDir, relativeFile); - const collectionName = path.dirname(relativeToContentPath).split(path.posix.sep)[0]; + const collectionName = collectionPathMode === 'root' ? "" : path.dirname(relativeToContentPath).split(path.posix.sep)[0]; const relativeToCollectionPath = path.relative(collectionName, relativeToContentPath); const withoutFileExt = replaceExt(relativeToCollectionPath, "") const pathSegments = withoutFileExt.split(path.posix.sep); const generatedSlug = generateSlug(pathSegments); const resolvedSlug = resolveSlug(generatedSlug, frontmatterSlug); - let webPathFinal = path.posix.sep + + let webPathFinal = [ - collectionName, + !collectionName ? '' : (path.posix.sep + collectionName), resolvedSlug, ].join(path.posix.sep); diff --git a/src/index.test.mjs b/src/index.test.mjs index fb0d43f..bb2e311 100644 --- a/src/index.test.mjs +++ b/src/index.test.mjs @@ -235,7 +235,7 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = @@ -251,7 +251,7 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures/dir-test-custom-slug" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures/dir-test-custom-slug", collectionPathMode: 'root' }) .process(input); const expected = @@ -267,7 +267,7 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = @@ -283,7 +283,7 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = @@ -299,7 +299,7 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = @@ -315,7 +315,7 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = @@ -331,7 +331,7 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = From 6936190267ee3747248605ef06ca9eebc471e7b7 Mon Sep 17 00:00:00 2001 From: techfg Date: Tue, 9 Apr 2024 03:35:05 -0700 Subject: [PATCH 12/14] chore: improve jsdoc & debug statements --- src/index.d.ts | 44 ++++++++++++++++++++++---------------------- src/index.mjs | 1 + 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/index.d.ts b/src/index.d.ts index 436bf95..3971485 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,28 +1,28 @@ -type CollectionPathMode = 'subdirectory' | `root` +export type CollectionPathMode = 'subdirectory' | `root` export interface Options { contentPath?: string; // where you store your content relative to the root directory - /** - * @docs - * @name collectionPathMode - * @type {CollectionPathMode} - * @default `'subdirectory'` - * @description - * - * Where you store your collections: - * - `'subdirectory'` - Subdirectories under `contentPath` (ex: "src/content/docs/index.md" where docs is the content collection subdirectory of the contentPath src/content) - * - `'root'` - Directly inside `contentPath` (ex. src/content/index.md where src/content is the contentPath) - * - * Use the `root` configuration option when you are treating a single content collection as if it where located in the site root. In most scenarios, you should set this - * value to `subdirectory` or not set this value and the default of `subdirectory` will be used. - * - * ```js - * { - * // Example: Use `subdirectory` mode - * collectionPathMode: `subdirectory` - * } - * ``` - */ + /** + * @name collectionPathMode + * @type {CollectionPathMode} + * @default `'subdirectory'` + * @description + * + * Where you store your collections: + * - `'subdirectory'` - Subdirectories under `contentPath` (ex: `src/content/docs/index.md` where `docs` is the content collection subdirectory of the contentPath `src/content`) + * - `'root'` - Directly inside `contentPath` (ex: `src/content/docs/index.md` where `src/content/docs` is the `contentPath`) + * + * Use the `root` configuration option when you are explicitly setting the {@link contentPath} property to something other than `src/content` and you want the directory you specify + * for {@link contentPath} to be treated a single content collection as if it where located in the site root. In most scenarios, you should set this value to `subdirectory` or not + * set this value and the default of `subdirectory` will be used. + * @example + * ```js + * { + * // Use `subdirectory` mode + * collectionPathMode: `subdirectory` + * } + * ``` + */ collectionPathMode?: CollectionPathMode; basePath?: string; // https://docs.astro.build/en/reference/configuration-reference/#base } diff --git a/src/index.mjs b/src/index.mjs index 4642107..0a2860d 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -79,6 +79,7 @@ function astroRehypeRelativeMarkdownLinks(options = {}) { // Debugging debug("--------------------------------"); + debug("CollectionPathMode : %s", collectionPathMode); debug("md/mdx AST Current File : %s", currentFile); debug("md/mdx AST Current File Dir : %s", currentFileDirectory); debug("md/mdx AST href full : %s", nodeHref); From 60d8e3444841f177d87628fb28a77906b6a80b6c Mon Sep 17 00:00:00 2001 From: techfg Date: Thu, 11 Apr 2024 02:52:08 -0700 Subject: [PATCH 13/14] chore: dedupe bad merge --- src/index.test.mjs | 230 ++++++++++++++++----------------------------- 1 file changed, 83 insertions(+), 147 deletions(-) diff --git a/src/index.test.mjs b/src/index.test.mjs index 49450fc..73ec561 100644 --- a/src/index.test.mjs +++ b/src/index.test.mjs @@ -36,7 +36,7 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { assert.equal(actual, expected); }); - await t.test("should transform and contain index for root collection and contain index for root collection index.md file paths that exist", async () => { + await t.test("should transform and contain index for root collection index.md file paths that exist", async () => { const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) @@ -235,280 +235,216 @@ test("astroRehypeRelativeMarkdownLinks", async (t) => { }, ); - await t.test( - "should transform and contain index for root index.md when content path same as collection path", - async () => { - const input = 'foo'; - const { value: actual } = await rehype() - .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) - .process(input); + await t.test("should not replace absolute path if file exists", async () => { + const absolutePath = path.resolve("./fixtures/test.md"); + const input = `foo`; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .process(input); - const expected = - 'foo'; + const expected = `foo`; - assert.equal(actual, expected); - }, - ); + assert.equal(actual, expected); + }); await t.test( - "should transform root index.md with empty string custom slug when content path same as collection path", + "should not replace absolute path if file does not exist", async () => { - const input = 'foo'; + const absolutePath = `${path.dirname(path.resolve("./fixtures/test.md"))}/does-not-exist.md`; + const input = `foo`; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures/dir-test-custom-slug", collectionPathMode: 'root' }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) .process(input); - const expected = - 'foo'; + const expected = `foo`; assert.equal(actual, expected); }, - ); + ); await t.test( - "should transform root path when content path same as collection path", + "should not transform index.md file paths if file does not exist", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, ); - - await t.test( - "should transform root path custom slug when content path same as collection path", - async () => { - const input = 'foo'; - const { value: actual } = await rehype() - .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) - .process(input); - const expected = - 'foo'; + await t.test("should not replace path if .md directory exists", async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .process(input); - assert.equal(actual, expected); - }, - ); + const expected = + 'foo'; - await t.test( - "should transform subdir index.md when content path same as collection path", - async () => { - const input = 'foo'; - const { value: actual } = await rehype() - .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) - .process(input); + assert.equal(actual, expected); + }); - const expected = - 'foo'; + await t.test("should not replace path if .mdx directory exists", async () => { + const input = 'foo'; + const { value: actual } = await rehype() + .use(testSetupRehype) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .process(input); - assert.equal(actual, expected); - }, - ); + const expected = + 'foo'; + + assert.equal(actual, expected); + }); await t.test( - "should transform subdir path when content path same as collection path", + "should not replace path if .md directory does not exist", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, ); await t.test( - "should transform subdir path custom slug when content path same as collection path", + "should not replace path if .mdx directory does not exist", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, - ); + ); await t.test( - "should transform with correct path when destination has custom slug", + "should transform and contain index for root index.md when content path same as collection path", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, ); await t.test( - "should transform with correct path when destination has custom slug with file extension", + "should transform root index.md with empty string custom slug when content path same as collection path", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures/dir-test-custom-slug", collectionPathMode: 'root' }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, - ); - + ); + await t.test( - "should transform with correct path when destination in subpath has custom slug", + "should transform root path when content path same as collection path", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, ); - + await t.test( - "should not transform content collection path segment", + "should transform root path custom slug when content path same as collection path", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = - 'foo'; - - assert.equal(actual, expected); - }, - ); - - await t.test("should not replace absolute path if file exists", async () => { - const absolutePath = path.resolve("./fixtures/test.md"); - const input = `foo`; - const { value: actual } = await rehype() - .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) - .process(input); - - const expected = `foo`; - - assert.equal(actual, expected); - }); - - await t.test( - "should not replace absolute path if file does not exist", - async () => { - const absolutePath = `${path.dirname(path.resolve("./fixtures/test.md"))}/does-not-exist.md`; - const input = `foo`; - const { value: actual } = await rehype() - .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) - .process(input); - - const expected = `foo`; + 'foo'; assert.equal(actual, expected); }, - ); + ); await t.test( - "should not transform index.md file paths if file does not exist", + "should transform subdir index.md when content path same as collection path", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, ); - await t.test("should not replace path if .md directory exists", async () => { - const input = 'foo'; - const { value: actual } = await rehype() - .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) - .process(input); - - const expected = - 'foo'; - - assert.equal(actual, expected); - }); - - await t.test("should not replace path if .mdx directory exists", async () => { - const input = 'foo'; - const { value: actual } = await rehype() - .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) - .process(input); - - const expected = - 'foo'; - - assert.equal(actual, expected); - }); - await t.test( - "should not replace path if .md directory does not exist", + "should transform subdir path when content path same as collection path", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, ); await t.test( - "should not replace path if .mdx directory does not exist", + "should transform subdir path custom slug when content path same as collection path", async () => { - const input = 'foo'; + const input = 'foo'; const { value: actual } = await rehype() .use(testSetupRehype) - .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src" }) + .use(astroRehypeRelativeMarkdownLinks, { contentPath: "src/fixtures", collectionPathMode: 'root' }) .process(input); const expected = - 'foo'; + 'foo'; assert.equal(actual, expected); }, From e4b1924ceefbc71a15dea6fad6c5edaa3bf4e622 Mon Sep 17 00:00:00 2001 From: Alex Vernacchia Date: Thu, 11 Apr 2024 11:37:31 +0100 Subject: [PATCH 14/14] chore: nitpick ternary check update ternary check to be explicit about check, instead of just falsy check --- src/index.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.mjs b/src/index.mjs index bf34eb8..b09f89a 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -113,7 +113,7 @@ function astroRehypeRelativeMarkdownLinks(options = {}) { // page (see details above) let webPathFinal = [ - !collectionName ? '' : (path.posix.sep + collectionName), + collectionName === '' ? '' : (path.posix.sep + collectionName), resolvedSlug, ].join(path.posix.sep);