2023-03-10 10:19:57 -05:00
|
|
|
|
import type { z } from 'astro/zod';
|
|
|
|
|
import type { RSSOptions } from './index';
|
2023-01-19 11:24:55 -05:00
|
|
|
|
|
2022-05-03 17:26:13 -05:00
|
|
|
|
/** Normalize URL to its canonical form */
|
2023-03-09 02:57:03 -05:00
|
|
|
|
export function createCanonicalURL(
|
|
|
|
|
url: string,
|
|
|
|
|
trailingSlash?: RSSOptions['trailingSlash'],
|
|
|
|
|
base?: string
|
|
|
|
|
): URL {
|
2022-05-03 17:26:13 -05:00
|
|
|
|
let pathname = url.replace(/\/index.html$/, ''); // index.html is not canonical
|
2023-03-09 02:57:03 -05:00
|
|
|
|
if (trailingSlash === false) {
|
|
|
|
|
// remove the trailing slash
|
|
|
|
|
pathname = pathname.replace(/(\/+)?$/, '');
|
|
|
|
|
} else if (!getUrlExtension(url)) {
|
|
|
|
|
// add trailing slash if there’s no extension or `trailingSlash` is true
|
|
|
|
|
pathname = pathname.replace(/(\/+)?$/, '/');
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-03 17:26:13 -05:00
|
|
|
|
pathname = pathname.replace(/\/+/g, '/'); // remove duplicate slashes (URL() won’t)
|
|
|
|
|
return new URL(pathname, base);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Check if a URL is already valid */
|
|
|
|
|
export function isValidURL(url: string): boolean {
|
|
|
|
|
try {
|
|
|
|
|
new URL(url);
|
|
|
|
|
return true;
|
|
|
|
|
} catch (e) {}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-09-28 10:13:33 -05:00
|
|
|
|
|
|
|
|
|
function getUrlExtension(url: string) {
|
|
|
|
|
const lastDot = url.lastIndexOf('.');
|
|
|
|
|
const lastSlash = url.lastIndexOf('/');
|
|
|
|
|
return lastDot > lastSlash ? url.slice(lastDot + 1) : '';
|
|
|
|
|
}
|
2023-01-19 11:24:55 -05:00
|
|
|
|
|
|
|
|
|
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 };
|
|
|
|
|
};
|