1
0
mirror of https://github.com/kremalicious/astro-redirect-from.git synced 2024-11-22 09:57:03 +01:00
This commit is contained in:
Matthias Kretschmann 2023-09-23 14:17:33 +01:00
parent 659c0a0fc9
commit 93e72936e4
Signed by: m
GPG Key ID: 606EEEF3C479A91F
7 changed files with 94 additions and 59 deletions

13
package-lock.json generated
View File

@ -9,8 +9,8 @@
"version": "0.1.0", "version": "0.1.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"astro": "^3.1.2", "astro": ">= 3",
"fast-glob": "^3.3.1", "globby": "^13.2.2",
"gray-matter": "^4.0.3" "gray-matter": "^4.0.3"
}, },
"devDependencies": { "devDependencies": {
@ -25,6 +25,10 @@
"typescript": "^5.2.2", "typescript": "^5.2.2",
"vite": "^4.4.9" "vite": "^4.4.9"
}, },
"engines": {
"node": ">=18.14.1",
"npm": ">=6.14.0"
},
"peerDependencies": { "peerDependencies": {
"astro": ">= 3" "astro": ">= 3"
} }
@ -3101,7 +3105,6 @@
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
"dev": true,
"dependencies": { "dependencies": {
"path-type": "^4.0.0" "path-type": "^4.0.0"
}, },
@ -4123,7 +4126,6 @@
"version": "13.2.2", "version": "13.2.2",
"resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz",
"integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==",
"dev": true,
"dependencies": { "dependencies": {
"dir-glob": "^3.0.1", "dir-glob": "^3.0.1",
"fast-glob": "^3.3.0", "fast-glob": "^3.3.0",
@ -4571,7 +4573,6 @@
"version": "5.2.4", "version": "5.2.4",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
"dev": true,
"engines": { "engines": {
"node": ">= 4" "node": ">= 4"
} }
@ -7523,7 +7524,6 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true,
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@ -9024,7 +9024,6 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
"integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
"dev": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },

View File

@ -18,6 +18,12 @@
"release": "release-it --non-interactive", "release": "release-it --non-interactive",
"prepublishOnly": "npm run build" "prepublishOnly": "npm run build"
}, },
"exports": {
".": "./dist/index.js"
},
"files": [
"dist"
],
"devDependencies": { "devDependencies": {
"@types/node": "^20.6.3", "@types/node": "^20.6.3",
"@typescript-eslint/eslint-plugin": "^6.7.2", "@typescript-eslint/eslint-plugin": "^6.7.2",
@ -32,7 +38,7 @@
}, },
"dependencies": { "dependencies": {
"astro": ">= 3", "astro": ">= 3",
"fast-glob": "^3.3.1", "globby": "^13.2.2",
"gray-matter": "^4.0.3" "gray-matter": "^4.0.3"
}, },
"peerDependencies": { "peerDependencies": {

32
src/getRedirects.ts Normal file
View File

@ -0,0 +1,32 @@
import path from 'node:path'
import type { Redirects } from './types'
import { getMarkdownFrontmatter } from './utils'
export async function getRedirects(
files: string[],
srcDir: string,
getSlug: (filePath: string) => string
) {
const redirects: Redirects = {}
for (const file of files) {
const frontmatter = await getMarkdownFrontmatter(path.join(srcDir, file))
const redirectFrom: string[] = frontmatter?.redirect_from
if (
!frontmatter ||
!redirectFrom ||
(import.meta.env.PROD && frontmatter.draft === true)
)
continue
let postSlug = frontmatter.slug
if (!postSlug) postSlug = getSlug(file)
if (!postSlug) continue
for (const slug of redirectFrom) {
redirects[slug] = postSlug
}
}
return redirects
}

View File

@ -1,73 +1,43 @@
import fs from 'node:fs/promises'
import path from 'node:path' import path from 'node:path'
import fg from 'fast-glob' import type { AstroIntegration } from 'astro'
import matter from 'gray-matter' import type { PluginOptions } from './types'
import type { AstroIntegration, AstroIntegrationLogger } from 'astro' import { getMarkdownFiles, getSlugFromFilePath, writeJson } from './utils'
import { getSlugFromFilePath, writeJson } from './utils' import { getRedirects } from './getRedirects'
type PluginOptions = {
contentDir?: string
getSlug?: (filePath: string) => string
}
export default function astroRedirectFrom({ export default function astroRedirectFrom({
contentDir = 'src/pages/', contentDir = 'src/pages/',
getSlug = getSlugFromFilePath getSlug = getSlugFromFilePath
}: PluginOptions = {}): AstroIntegration { }: PluginOptions): AstroIntegration {
const sourceDir = path.join(process.cwd(), contentDir) const contentDirPath = path.join(process.cwd(), contentDir)
return { return {
name: 'redirect-from', name: 'redirect-from',
hooks: { hooks: {
'astro:config:setup': async ({ 'astro:config:setup': async ({ config, updateConfig, logger }) => {
updateConfig,
logger
}: {
updateConfig: (newConfig: Record<string, any>) => void
logger: AstroIntegrationLogger
}) => {
const redirects: { [old: string]: string } = {}
try { try {
const markdownFiles = await fg.glob('./**/*.{md,mdx}', { const markdownFiles = await getMarkdownFiles(contentDirPath)
cwd: sourceDir
})
if (!markdownFiles?.length) { if (!markdownFiles?.length) {
logger.warn('No markdown files found') logger.warn('No markdown files found')
return return
} }
for (const markdownFile of markdownFiles) { const redirects = await getRedirects(
const fileContent = await fs.readFile( markdownFiles,
path.join(sourceDir, markdownFile), contentDirPath,
'utf-8' getSlug
) )
if (!redirects || !Object.keys(redirects).length) {
const { data: frontmatter } = matter(fileContent) logger.info('No redirects found in markdown files')
const postRedirectFrom: string[] = frontmatter?.redirect_from return
if (
!frontmatter ||
!postRedirectFrom ||
// filter out drafts in production
(import.meta.env.PROD && frontmatter.draft === true)
)
continue
let postSlug = frontmatter.slug
if (!postSlug) postSlug = getSlug(markdownFile)
if (!postSlug) continue
for (const slug of postRedirectFrom) {
redirects[slug] = postSlug
}
} }
updateConfig({ redirects }) updateConfig({ redirects })
await writeJson( const redirectFilePath = path.join(
path.join(process.cwd(), '.astro', 'redirect_from.json'), config.cacheDir.pathname, // Default is ./node_modules/.astro/
redirects 'redirect_from.json'
) )
await writeJson(redirectFilePath, redirects)
logger.info( logger.info(
`Added ${Object.keys(redirects).length} redirects to Astro config` `Added ${Object.keys(redirects).length} redirects to Astro config`

8
src/types.ts Normal file
View File

@ -0,0 +1,8 @@
export type GetSlug = (filePath: string) => string
export type PluginOptions = {
contentDir?: string
getSlug?: GetSlug
}
export type Redirects = { [old: string]: string }

View File

@ -1,5 +1,21 @@
import path from 'node:path' import path from 'node:path'
import { promises as fs, type PathLike } from 'node:fs' import { promises as fs, type PathLike } from 'node:fs'
import { globby } from 'globby'
import matter from 'gray-matter'
export async function getMarkdownFiles(sourceDir: string) {
const markdownFiles = await globby('./**/*.{md,mdx}', {
cwd: sourceDir,
gitignore: true
})
return markdownFiles
}
export async function getMarkdownFrontmatter(filePath: string) {
const fileContent = await fs.readFile(filePath, { encoding: 'utf-8' })
const { data: frontmatter } = matter(fileContent)
return frontmatter
}
export function getSlugFromFilePath(filePath: string) { export function getSlugFromFilePath(filePath: string) {
const parsedPath = path.parse(filePath) const parsedPath = path.parse(filePath)

View File

@ -4,6 +4,10 @@
"exclude": ["node_modules", "dist"], "exclude": ["node_modules", "dist"],
"compilerOptions": { "compilerOptions": {
"outDir": "./dist", "outDir": "./dist",
"types": ["vite/client"] "types": ["vite/client"],
"declaration": true,
// ovewrite astro/tsconfigs values
"noEmit": false,
"allowImportingTsExtensions": false
} }
} }