diff --git a/src/getRedirects.ts b/src/getRedirects.ts index 9c8ba5b..d62f6e7 100644 --- a/src/getRedirects.ts +++ b/src/getRedirects.ts @@ -3,19 +3,43 @@ import type { Redirects } from '.' import { createRedirect } from './createRedirect.js' import { getMarkdownFrontmatter } from './utils.js' +function isValidDomainRelativePath(path: string): boolean { + return !path.includes('://') && !path.includes(' ') && !path.includes('\n') +} + export async function getRedirects( files: string[], srcDir: string, getSlug: (filePath: string) => string, - command: 'dev' | 'build' | 'preview' + command: 'dev' | 'build' | 'preview', + logger: { warn: (msg: string) => void } ) { let redirects: Redirects = {} for (const file of files) { const frontmatter = await getMarkdownFrontmatter(path.join(srcDir, file)) - const redirectFrom: string[] = frontmatter?.redirect_from + let redirectFrom: string[] = [] + + if (frontmatter?.redirect_from){ + if (typeof frontmatter?.redirect_from === 'string') { + redirectFrom = [frontmatter.redirect_from] + } else if (Array.isArray(frontmatter?.redirect_from)) { + redirectFrom = frontmatter.redirect_from + } else { + logger.warn(`Unexpected type ${typeof frontmatter?.redirect_from} for redirect_from in file: ${file}`) + } + } + + redirectFrom = redirectFrom.filter(redirect => { + if (isValidDomainRelativePath(redirect)) { + return true + } + logger.warn(`Invalid redirect path: ${redirect} in file: ${file}`) + return false + }) + const isExcluded = command === 'build' && frontmatter?.draft === true - if (!frontmatter || !redirectFrom || isExcluded) continue + if (!frontmatter || !redirectFrom.length || isExcluded) continue const postSlug = frontmatter.slug || getSlug(file) if (!postSlug) continue diff --git a/src/index.ts b/src/index.ts index f0bc05b..eaad926 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import path from 'node:path' +import fs from 'node:fs' import type { AstroIntegration } from 'astro' import { getRedirects } from './getRedirects.js' import { getMarkdownFiles, getSlugFromFilePath, writeJson } from './utils.js' @@ -36,7 +37,8 @@ export async function initPlugin( markdownFiles, _contentDirPath, _getSlug, - command + command, + logger ) if (!redirects || !Object.keys(redirects).length) { logger.warn('No redirects found in markdown files') @@ -45,6 +47,9 @@ export async function initPlugin( updateConfig({ redirects }) + if (!fs.existsSync(config.cacheDir.pathname)) { + fs.mkdirSync(config.cacheDir.pathname, { recursive: true }) + } const redirectFilePath = path.join( config.cacheDir.pathname, // Default is ./node_modules/.astro/ 'redirect_from.json' diff --git a/test/__fixtures__/markdown/posts/hello-once.md b/test/__fixtures__/markdown/posts/hello-once.md new file mode 100644 index 0000000..20370da --- /dev/null +++ b/test/__fixtures__/markdown/posts/hello-once.md @@ -0,0 +1,3 @@ +--- +redirect_from: /hello-once +--- diff --git a/test/redirects.test.ts b/test/redirects.test.ts index 2093853..c2e51f5 100644 --- a/test/redirects.test.ts +++ b/test/redirects.test.ts @@ -3,6 +3,8 @@ import { createRedirect } from '../src/createRedirect' import { getRedirects } from '../src/getRedirects' import { getMarkdownFiles, getSlugFromFilePath } from '../src/utils' + + describe('getRedirects', async () => { // handling this more as an integration test const srcDir = './test/__fixtures__/markdown' @@ -13,13 +15,15 @@ describe('getRedirects', async () => { files, srcDir, getSlugFromFilePath, - 'build' + 'build', + console ) expect(result).toBeInstanceOf(Object) expect(result).toStrictEqual({ '/hello-astro-old': '/hello-astroooooo', '/hello-astro-old-234837': '/hello-astroooooo', '/hello-world-old': '/posts/hello-world', + "/hello-once": "/posts/hello-once", '/hello-world-old-234837': '/posts/hello-world', '/hello-markdown-old': '/hello-markdown', '/hello-markdown-old-234837': '/hello-markdown' diff --git a/test/utils.test.ts b/test/utils.test.ts index b433bb9..337cb0c 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -12,7 +12,7 @@ describe('getMarkdownFiles', () => { it('should return an array of markdown files from the given directory', async () => { const files = await getMarkdownFiles('./test/__fixtures__/markdown') expect(files).toBeInstanceOf(Array) - expect(files).toHaveLength(4) + expect(files).toHaveLength(5) }) })