diff options
Diffstat (limited to 'packages/astro-rss/src/util.ts')
-rw-r--r-- | packages/astro-rss/src/util.ts | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/packages/astro-rss/src/util.ts b/packages/astro-rss/src/util.ts new file mode 100644 index 000000000..43de370dd --- /dev/null +++ b/packages/astro-rss/src/util.ts @@ -0,0 +1,53 @@ +import type { z } from 'astro/zod'; +import type { RSSOptions } from './index.js'; + +/** Normalize URL to its canonical form */ +export function createCanonicalURL( + url: string, + trailingSlash?: RSSOptions['trailingSlash'], + base?: string, +): string { + let pathname = url.replace(/\/index.html$/, ''); // index.html is not canonical + if (!getUrlExtension(url)) { + // add trailing slash if there’s no extension or `trailingSlash` is true + pathname = pathname.replace(/\/*$/, '/'); + } + + pathname = pathname.replace(/\/+/g, '/'); // remove duplicate slashes (URL() won’t) + + const canonicalUrl = new URL(pathname, base).href; + if (trailingSlash === false) { + // remove the trailing slash + return canonicalUrl.replace(/\/*$/, ''); + } + return canonicalUrl; +} + +/** Check if a URL is already valid */ +export function isValidURL(url: string): boolean { + try { + new URL(url); + return true; + } catch {} + return false; +} + +function getUrlExtension(url: string) { + const lastDot = url.lastIndexOf('.'); + const lastSlash = url.lastIndexOf('/'); + return lastDot > lastSlash ? url.slice(lastDot + 1) : ''; +} + +const flattenErrorPath = (errorPath: (string | number)[]) => errorPath.join('.'); + +export const errorMap: z.ZodErrorMap = (error, ctx) => { + if (error.code === 'invalid_type') { + const badKeyPath = JSON.stringify(flattenErrorPath(error.path)); + if (error.received === 'undefined') { + return { message: `${badKeyPath} is required.` }; + } else { + return { message: `${badKeyPath} should be ${error.expected}, not ${error.received}.` }; + } + } + return { message: ctx.defaultError }; +}; |