refactor: replace duplicate parseSlug
This commit is contained in:
parent
45404cfd8b
commit
7f77913b9f
3 changed files with 57 additions and 32 deletions
|
@ -12,16 +12,15 @@ import { CONTENT_TYPES_FILE, VIRTUAL_MODULE_ID } from './consts.js';
|
||||||
import {
|
import {
|
||||||
getContentPaths,
|
getContentPaths,
|
||||||
getEntryInfo,
|
getEntryInfo,
|
||||||
getEntrySlug,
|
|
||||||
getEntryType,
|
getEntryType,
|
||||||
loadContentConfig,
|
loadContentConfig,
|
||||||
NoCollectionError,
|
NoCollectionError,
|
||||||
parseFrontmatter,
|
|
||||||
type ContentConfig,
|
type ContentConfig,
|
||||||
type ContentObservable,
|
type ContentObservable,
|
||||||
type ContentPaths,
|
type ContentPaths,
|
||||||
type EntryInfo,
|
type EntryInfo,
|
||||||
getContentEntryConfigByExtMap,
|
getContentEntryConfigByExtMap,
|
||||||
|
getEntrySlug,
|
||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
|
|
||||||
type ChokidarEvent = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir';
|
type ChokidarEvent = 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir';
|
||||||
|
@ -187,14 +186,23 @@ export async function createContentTypesGenerator({
|
||||||
return { shouldGenerateTypes: false };
|
return { shouldGenerateTypes: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id, collection } = entryInfo;
|
const { id, collection, slug: generatedSlug } = entryInfo;
|
||||||
|
const contentEntryType = contentEntryConfigByExt.get(path.extname(event.entry.pathname));
|
||||||
|
if (!contentEntryType) return { shouldGenerateTypes: false };
|
||||||
|
|
||||||
const collectionKey = JSON.stringify(collection);
|
const collectionKey = JSON.stringify(collection);
|
||||||
const entryKey = JSON.stringify(id);
|
const entryKey = JSON.stringify(id);
|
||||||
|
|
||||||
switch (event.name) {
|
switch (event.name) {
|
||||||
case 'add':
|
case 'add':
|
||||||
const addedSlug = await parseSlug({ fs, event, entryInfo });
|
const addedSlug = await getEntrySlug({
|
||||||
|
generatedSlug,
|
||||||
|
id,
|
||||||
|
collection,
|
||||||
|
fileUrl: event.entry,
|
||||||
|
contentEntryType,
|
||||||
|
fs,
|
||||||
|
});
|
||||||
if (!(collectionKey in contentTypes)) {
|
if (!(collectionKey in contentTypes)) {
|
||||||
addCollection(contentTypes, collectionKey);
|
addCollection(contentTypes, collectionKey);
|
||||||
}
|
}
|
||||||
|
@ -210,7 +218,14 @@ export async function createContentTypesGenerator({
|
||||||
case 'change':
|
case 'change':
|
||||||
// User may modify `slug` in their frontmatter.
|
// User may modify `slug` in their frontmatter.
|
||||||
// Only regen types if this change is detected.
|
// Only regen types if this change is detected.
|
||||||
const changedSlug = await parseSlug({ fs, event, entryInfo });
|
const changedSlug = await getEntrySlug({
|
||||||
|
generatedSlug,
|
||||||
|
id,
|
||||||
|
collection,
|
||||||
|
fileUrl: event.entry,
|
||||||
|
contentEntryType,
|
||||||
|
fs,
|
||||||
|
});
|
||||||
if (contentTypes[collectionKey]?.[entryKey]?.slug !== changedSlug) {
|
if (contentTypes[collectionKey]?.[entryKey]?.slug !== changedSlug) {
|
||||||
setEntry(contentTypes, collectionKey, entryKey, changedSlug);
|
setEntry(contentTypes, collectionKey, entryKey, changedSlug);
|
||||||
return { shouldGenerateTypes: true };
|
return { shouldGenerateTypes: true };
|
||||||
|
@ -309,25 +324,6 @@ function removeCollection(contentMap: ContentTypes, collectionKey: string) {
|
||||||
delete contentMap[collectionKey];
|
delete contentMap[collectionKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function parseSlug({
|
|
||||||
fs,
|
|
||||||
event,
|
|
||||||
entryInfo: { id, collection, slug: generatedSlug },
|
|
||||||
}: {
|
|
||||||
fs: typeof fsMod;
|
|
||||||
event: ContentEvent;
|
|
||||||
entryInfo: EntryInfo;
|
|
||||||
}) {
|
|
||||||
// `slug` may be present in entry frontmatter.
|
|
||||||
// This should be respected by the generated `slug` type!
|
|
||||||
// Parse frontmatter and retrieve `slug` value for this.
|
|
||||||
// Note: will raise any YAML exceptions and `slug` parse errors (i.e. `slug` is a boolean)
|
|
||||||
// on dev server startup or production build init.
|
|
||||||
const rawContents = await fs.promises.readFile(event.entry, 'utf-8');
|
|
||||||
const { data: frontmatter } = parseFrontmatter(rawContents, fileURLToPath(event.entry));
|
|
||||||
return getEntrySlug({ id, collection, generatedSlug, frontmatterSlug: frontmatter.slug });
|
|
||||||
}
|
|
||||||
|
|
||||||
function setEntry(
|
function setEntry(
|
||||||
contentTypes: ContentTypes,
|
contentTypes: ContentTypes,
|
||||||
collectionKey: string,
|
collectionKey: string,
|
||||||
|
|
|
@ -52,7 +52,7 @@ export const msg = {
|
||||||
`${collection} does not have a config. We suggest adding one for type safety!`,
|
`${collection} does not have a config. We suggest adding one for type safety!`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getEntrySlug({
|
export function parseEntrySlug({
|
||||||
id,
|
id,
|
||||||
collection,
|
collection,
|
||||||
generatedSlug,
|
generatedSlug,
|
||||||
|
@ -422,16 +422,19 @@ export async function getStringifiedLookupMap({
|
||||||
contentGlob.map(async (filePath) => {
|
contentGlob.map(async (filePath) => {
|
||||||
const info = getEntryInfo({ contentDir, entry: filePath });
|
const info = getEntryInfo({ contentDir, entry: filePath });
|
||||||
if (info instanceof NoCollectionError) return;
|
if (info instanceof NoCollectionError) return;
|
||||||
const contentEntryConfig = contentEntryConfigByExt.get(extname(filePath));
|
const contentEntryType = contentEntryConfigByExt.get(extname(filePath));
|
||||||
if (!contentEntryConfig) return;
|
if (!contentEntryType) return;
|
||||||
|
|
||||||
const { id, collection, slug: generatedSlug } = info;
|
const { id, collection, slug: generatedSlug } = info;
|
||||||
filePathByLookupId[collection] ??= {};
|
filePathByLookupId[collection] ??= {};
|
||||||
const { slug: frontmatterSlug } = await contentEntryConfig.getEntryInfo({
|
const slug = await getEntrySlug({
|
||||||
|
id,
|
||||||
|
collection,
|
||||||
|
generatedSlug,
|
||||||
|
fs,
|
||||||
fileUrl: pathToFileURL(filePath),
|
fileUrl: pathToFileURL(filePath),
|
||||||
contents: await fs.promises.readFile(filePath, 'utf-8'),
|
contentEntryType,
|
||||||
});
|
});
|
||||||
const slug = getEntrySlug({ id, collection, generatedSlug, frontmatterSlug });
|
|
||||||
filePathByLookupId[collection][slug] = rootRelativePath(root, filePath);
|
filePathByLookupId[collection][slug] = rootRelativePath(root, filePath);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -439,6 +442,32 @@ export async function getStringifiedLookupMap({
|
||||||
return JSON.stringify(filePathByLookupId);
|
return JSON.stringify(filePathByLookupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for slug in content entry frontmatter and validate the type,
|
||||||
|
* falling back to the `generatedSlug` if none is found.
|
||||||
|
*/
|
||||||
|
export async function getEntrySlug({
|
||||||
|
id,
|
||||||
|
collection,
|
||||||
|
generatedSlug,
|
||||||
|
contentEntryType,
|
||||||
|
fileUrl,
|
||||||
|
fs,
|
||||||
|
}: {
|
||||||
|
fs: typeof fsMod;
|
||||||
|
id: string;
|
||||||
|
collection: string;
|
||||||
|
generatedSlug: string;
|
||||||
|
fileUrl: URL;
|
||||||
|
contentEntryType: Pick<ContentEntryType, 'getEntryInfo'>;
|
||||||
|
}) {
|
||||||
|
const { slug: frontmatterSlug } = await contentEntryType.getEntryInfo({
|
||||||
|
fileUrl,
|
||||||
|
contents: await fs.promises.readFile(fileUrl, 'utf-8'),
|
||||||
|
});
|
||||||
|
return parseEntrySlug({ generatedSlug, frontmatterSlug, id, collection });
|
||||||
|
}
|
||||||
|
|
||||||
export function getExtGlob(exts: string[]) {
|
export function getExtGlob(exts: string[]) {
|
||||||
return exts.length === 1
|
return exts.length === 1
|
||||||
? // Wrapping {...} breaks when there is only one extension
|
? // Wrapping {...} breaks when there is only one extension
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
getContentPaths,
|
getContentPaths,
|
||||||
getEntryData,
|
getEntryData,
|
||||||
getEntryInfo,
|
getEntryInfo,
|
||||||
getEntrySlug,
|
parseEntrySlug,
|
||||||
getEntryType,
|
getEntryType,
|
||||||
globalContentConfigObserver,
|
globalContentConfigObserver,
|
||||||
NoCollectionError,
|
NoCollectionError,
|
||||||
|
@ -221,7 +221,7 @@ export function astroContentImportPlugin({
|
||||||
const _internal = { filePath: fileId, rawData: rawData };
|
const _internal = { filePath: fileId, rawData: rawData };
|
||||||
// TODO: move slug calculation to the start of the build
|
// TODO: move slug calculation to the start of the build
|
||||||
// to generate a performant lookup map for `getEntryBySlug`
|
// to generate a performant lookup map for `getEntryBySlug`
|
||||||
const slug = getEntrySlug({
|
const slug = parseEntrySlug({
|
||||||
id,
|
id,
|
||||||
collection,
|
collection,
|
||||||
generatedSlug,
|
generatedSlug,
|
||||||
|
|
Loading…
Reference in a new issue