refactor: better typings (#3634)

This commit is contained in:
Oleksii Tymoshenko 2022-06-20 22:29:53 +03:00 committed by GitHub
parent d9f6dcf6ea
commit facfc4682f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 67 deletions

View file

@ -141,7 +141,7 @@ export default {
### entryLimit
Non-negative `Number` of entries per sitemap file. Default value is 45000. A sitemap index and multiple sitemaps are created if you have more entries. See explanation on [Google](https://developers.google.com/search/docs/advanced/sitemaps/large-sitemaps).
Non-negative `Number` of entries per sitemap file. Default value is 45000. A sitemap index and multiple sitemaps are created if you have more entries. See explanation about large sitemaps on [Google](https://developers.google.com/search/docs/advanced/sitemaps/large-sitemaps).
__astro.config.mjs__
@ -166,7 +166,7 @@ export default {
`lastmod` - The date of page last modification.
`changefreq` and `priority` are ignored by Google.
The `changefreq` and `priority` are ignored by Google.
See detailed explanation of sitemap specific options on [sitemap.org](https://www.sitemaps.org/protocol.html).
@ -194,12 +194,12 @@ export default {
Async or sync function called for each sitemap entry just before writing to a disk.
It receives as parameter `SitemapItem` object which consists of `url` (required, absolute page URL) and optional `changefreq`, `lastmod`, `priority` and `links` properties.
It receives as parameter a `SitemapItem` object which consists of `url` (required, absolute page URL) and optional `changefreq`, `lastmod` (ISO formatted date, `String` type), `priority` and `links` properties.
Optional `links` property contains a `LinkItem` list of alternate pages including a parent page.
`LinkItem` type has two required fields: `url` (the fully-qualified URL for the version of this page for the specified language) and `hreflang` (a supported language code targeted by this version of the page).
Optional `links` property contains the `LinkItem` list of alternate pages including a parent page.
The `LinkItem` type has two required fields: `url` (the fully-qualified URL for the version of this page for the specified language) and `lang` (a supported language code targeted by this version of the page).
`serialize` function should return `SitemapItem`, touched or not.
The `serialize` function should return `SitemapItem`, touched or not.
The example below shows the ability to add the sitemap specific properties individually.

View file

@ -1,9 +0,0 @@
export const changefreqValues = [
'always',
'hourly',
'daily',
'weekly',
'monthly',
'yearly',
'never',
] as const;

View file

@ -1,19 +1,16 @@
import { SitemapItemLoose } from 'sitemap';
import type { SitemapOptions } from './index';
import type { SitemapOptions, SitemapItem } from './index';
import { parseUrl } from './utils/parse-url';
const STATUS_CODE_PAGE_REGEXP = /\/[0-9]{3}\/?$/;
/** Construct sitemap.xml given a set of URLs */
export function generateSitemap(pages: string[], finalSiteUrl: string, opts: SitemapOptions) {
const { changefreq, priority: prioritySrc, lastmod: lastmodSrc, i18n } = opts || {};
const { changefreq, priority, lastmod: lastmodSrc, i18n } = opts!;
// TODO: find way to respect <link rel="canonical"> URLs here
const urls = [...pages].filter((url) => !STATUS_CODE_PAGE_REGEXP.test(url));
urls.sort((a, b) => a.localeCompare(b, 'en', { numeric: true })); // sort alphabetically so sitemap is same each time
const lastmod = lastmodSrc?.toISOString();
const priority = typeof prioritySrc === 'number' ? prioritySrc : undefined;
const { locales, defaultLocale } = i18n || {};
const localeCodes = Object.keys(locales || {});
@ -27,7 +24,7 @@ export function generateSitemap(pages: string[], finalSiteUrl: string, opts: Sit
return result?.locale;
};
const urlData = urls.map((url) => {
const urlData: SitemapItem[] = urls.map((url) => {
let links;
if (defaultLocale && locales) {
const currentPath = getPath(url);
@ -47,8 +44,8 @@ export function generateSitemap(pages: string[], finalSiteUrl: string, opts: Sit
links,
lastmod,
priority,
changefreq, // : changefreq as EnumChangefreq,
} as SitemapItemLoose;
changefreq,
};
});
return urlData;

View file

@ -1,14 +1,13 @@
import type { AstroConfig, AstroIntegration } from 'astro';
import { LinkItem as LinkItemBase, simpleSitemapAndIndex, SitemapItemLoose } from 'sitemap';
import { LinkItem as LinkItemBase, simpleSitemapAndIndex, SitemapItemLoose, EnumChangefreq } from 'sitemap';
import { fileURLToPath } from 'url';
import { ZodError } from 'zod';
import { changefreqValues } from './constants';
import { generateSitemap } from './generate-sitemap';
import { Logger } from './utils/logger';
import { validateOptions } from './validate-options';
export type ChangeFreq = typeof changefreqValues[number];
export type ChangeFreq = EnumChangefreq;
export type SitemapItem = Pick<
SitemapItemLoose,
'url' | 'lastmod' | 'changefreq' | 'priority' | 'links'
@ -34,7 +33,7 @@ export type SitemapOptions =
priority?: number;
// called for each sitemap item just before to save them on disk, sync or async
serialize?(item: SitemapItemLoose): SitemapItemLoose;
serialize?(item: SitemapItem): SitemapItem | Promise<SitemapItem>;
}
| undefined;
@ -103,7 +102,7 @@ const createPlugin = (options?: SitemapOptions): AstroIntegration => {
if (serialize) {
try {
const serializedUrls: SitemapItemLoose[] = [];
const serializedUrls: SitemapItem[] = [];
for (const item of urlData) {
const serialized = await Promise.resolve(serialize(item));
serializedUrls.push(serialized);

View file

@ -1,47 +1,39 @@
import { z } from 'zod';
import { EnumChangefreq as ChangeFreq } from 'sitemap';
import { SITEMAP_CONFIG_DEFAULTS } from './config-defaults';
import { changefreqValues } from './constants';
const localeKeySchema = () => z.string().min(1);
const isFunction = (fn: any) => fn instanceof Function;
const fnSchema = () =>
z
.any()
.refine((val) => !val || isFunction(val), { message: 'Not a function' })
.optional();
const localeKeySchema = z.string().min(1);
export const SitemapOptionsSchema = z
.object({
filter: fnSchema(),
customPages: z.string().url().array().optional(),
canonicalURL: z.string().url().optional(),
.object({
filter: z.function().args(z.string()).returns(z.boolean()).optional(),
customPages: z.string().url().array().optional(),
canonicalURL: z.string().url().optional(),
i18n: z
.object({
defaultLocale: localeKeySchema(),
locales: z.record(
localeKeySchema(),
z
.string()
.min(2)
.regex(/^[a-zA-Z\-]+$/gm, {
message: 'Only English alphabet symbols and hyphen allowed',
})
),
})
.refine((val) => !val || val.locales[val.defaultLocale], {
message: '`defaultLocale` must exists in `locales` keys',
})
.optional(),
i18n: z
.object({
defaultLocale: localeKeySchema,
locales: z.record(
localeKeySchema,
z
.string()
.min(2)
.regex(/^[a-zA-Z\-]+$/gm, {
message: 'Only English alphabet symbols and hyphen allowed',
}),
),
})
.refine((val) => !val || val.locales[val.defaultLocale], {
message: '`defaultLocale` must exist in `locales` keys',
})
.optional(),
entryLimit: z.number().nonnegative().default(SITEMAP_CONFIG_DEFAULTS.entryLimit),
serialize: fnSchema(),
entryLimit: z.number().nonnegative().optional().default(SITEMAP_CONFIG_DEFAULTS.entryLimit),
serialize: z.function().args(z.any()).returns(z.any()).optional(),
changefreq: z.enum(changefreqValues).optional(),
lastmod: z.date().optional(),
priority: z.number().min(0).max(1).optional(),
})
.strict()
.default(SITEMAP_CONFIG_DEFAULTS);
changefreq: z.nativeEnum(ChangeFreq).optional(),
lastmod: z.date().optional(),
priority: z.number().min(0).max(1).optional(),
})
.strict()
.default(SITEMAP_CONFIG_DEFAULTS);