UNPKG

@analogjs/content

Version:

Content Rendering for Analog

152 lines (147 loc) 5.66 kB
import { resource, inject, computed } from '@angular/core'; import { injectContentListLoader, injectContentLocale, filterByLocale, parseRawContentFile, injectContentFileLoader, ContentRenderer } from '@analogjs/content'; import { ActivatedRoute } from '@angular/router'; import { toSignal } from '@angular/core/rxjs-interop'; import { from } from 'rxjs'; import { map } from 'rxjs/operators'; function contentFilesResource(filterFn) { const contentListLoader = injectContentListLoader(); const locale = injectContentLocale(); const contentList = contentListLoader().then((items) => { let results = locale ? filterByLocale(items, locale) : items; if (filterFn) { results = results.filter(filterFn); } return results; }); return resource({ loader: () => contentList, }); } async function getContentFile(contentFiles, slug, fallback, locale) { // Normalize file keys so both "/src/content/..." and "/<project>/src/content/..." resolve. // This mirrors normalization used elsewhere in the content pipeline. const normalizedFiles = {}; const stemToKey = {}; for (const [key, resolver] of Object.entries(contentFiles)) { const normalizedKey = key // replace any prefix up to the content directory with /src/content // use a non-greedy match so nested paths containing "/content" are preserved .replace(/^(?:.*?)\/content(?=\/)/, '/src/content') // normalize duplicate slashes .replace(/\/{2,}/g, '/'); normalizedFiles[normalizedKey] = resolver; // Index by bare filename stem so slug-only lookups work const stem = normalizedKey .split('/') .pop() ?.replace(/\.[^.]+$/, ''); if (stem && !stemToKey[stem]) { stemToKey[stem] = normalizedKey; } } // Try direct file first, then directory index variants, then bare slug via stem const base = `/src/content/${slug}`.replace(/\/{2,}/g, '/'); const candidates = [ `${base}.md`, `${base}.agx`, `${base}/index.md`, `${base}/index.agx`, ]; // Try locale-prefixed paths first, then fall back to unprefixed, then bare slug via stem const localeCandidates = locale ? candidates.map((c) => c.replace('/src/content/', `/src/content/${locale}/`)) : []; const allCandidates = [...localeCandidates, ...candidates]; const matchKey = allCandidates.find((k) => k in normalizedFiles) ?? stemToKey[slug]; const contentFile = matchKey ? normalizedFiles[matchKey] : undefined; if (!contentFile) { return { filename: base, attributes: {}, slug: '', content: fallback, }; } const resolvedBase = matchKey.replace(/\.(md|agx)$/, ''); return contentFile().then((contentFile) => { if (typeof contentFile === 'string') { const { content, attributes } = parseRawContentFile(contentFile); return { filename: resolvedBase, slug, attributes, content, }; } return { filename: resolvedBase, slug, attributes: contentFile.metadata, content: contentFile.default, }; }); } /** * Resource for requesting an individual content file * * @param params * @param fallback * @returns */ function contentFileResource(params, fallback = 'No Content Found') { const loaderPromise = injectContentFileLoader(); const contentRenderer = inject(ContentRenderer); const locale = injectContentLocale(); const contentFilesMap = toSignal(from(loaderPromise())); const input = params || toSignal(inject(ActivatedRoute).paramMap.pipe(map((params) => params.get('slug'))), { requireSync: true }); return resource({ params: computed(() => ({ input: input(), files: contentFilesMap() })), loader: async ({ params }) => { const { input: param, files } = params; if (typeof param === 'string') { if (param) { const file = await getContentFile(files, param, fallback, locale); if (typeof file.content === 'string') { const rendered = (await contentRenderer.render(file.content)); return { ...file, toc: rendered.toc ?? [], }; } return { ...file, toc: [], }; } return { filename: '', slug: '', attributes: {}, content: fallback, toc: [], }; } else { const file = await getContentFile(files, param.customFilename, fallback, locale); if (typeof file.content === 'string') { const rendered = (await contentRenderer.render(file.content)); return { ...file, toc: rendered.toc ?? [], }; } return { ...file, toc: [], }; } }, }); } /** * Generated bundle index. Do not edit. */ export { contentFileResource, contentFilesResource }; //# sourceMappingURL=analogjs-content-resources.mjs.map