@analogjs/content 3.0.0-alpha.95 → 3.0.0-alpha.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/fesm2022/analogjs-content-md4x.mjs +1 -2
  2. package/fesm2022/analogjs-content-md4x.mjs.map +1 -1
  3. package/fesm2022/analogjs-content-resources.mjs +1 -2
  4. package/fesm2022/analogjs-content-resources.mjs.map +1 -1
  5. package/fesm2022/analogjs-content.mjs +3 -122
  6. package/fesm2022/analogjs-content.mjs.map +1 -1
  7. package/fesm2022/content-list-loader.mjs +125 -2
  8. package/fesm2022/content-list-loader.mjs.map +1 -1
  9. package/package.json +3 -21
  10. package/plugin/migrations.json +1 -71
  11. package/types/src/index.d.ts +0 -3
  12. package/fesm2022/analogjs-content-prism-highlighter.mjs +0 -99
  13. package/fesm2022/analogjs-content-prism-highlighter.mjs.map +0 -1
  14. package/fesm2022/analogjs-content-shiki-highlighter.mjs +0 -12
  15. package/fesm2022/analogjs-content-shiki-highlighter.mjs.map +0 -1
  16. package/fesm2022/content-renderer.mjs +0 -128
  17. package/fesm2022/content-renderer.mjs.map +0 -1
  18. package/fesm2022/marked-content-highlighter.mjs +0 -40
  19. package/fesm2022/marked-content-highlighter.mjs.map +0 -1
  20. package/plugin/src/migrations/update-markdown-version/compat.d.ts +0 -6
  21. package/plugin/src/migrations/update-markdown-version/compat.d.ts.map +0 -1
  22. package/plugin/src/migrations/update-markdown-version/compat.js +0 -9
  23. package/plugin/src/migrations/update-markdown-version/compat.js.map +0 -1
  24. package/plugin/src/migrations/update-markdown-version/update-markdown-version.d.ts +0 -6
  25. package/plugin/src/migrations/update-markdown-version/update-markdown-version.d.ts.map +0 -1
  26. package/plugin/src/migrations/update-markdown-version/update-markdown-version.js +0 -21
  27. package/plugin/src/migrations/update-markdown-version/update-markdown-version.js.map +0 -1
  28. package/prism-highlighter/package.json +0 -4
  29. package/shiki-highlighter/package.json +0 -4
  30. package/types/prism-highlighter/src/index.d.ts +0 -8
  31. package/types/prism-highlighter/src/lib/prism/angular.d.ts +0 -1
  32. package/types/prism-highlighter/src/lib/prism-highlighter.d.ts +0 -8
  33. package/types/shiki-highlighter/src/index.d.ts +0 -7
  34. package/types/src/lib/markdown-content-renderer.service.d.ts +0 -10
  35. package/types/src/lib/marked-content-highlighter.d.ts +0 -17
  36. package/types/src/lib/marked-setup.service.d.ts +0 -10
  37. package/types/src/lib/utils/escape-html.d.ts +0 -7
@@ -1 +1 @@
1
- {"version":3,"file":"content-list-loader.mjs","names":[],"sources":["../../src/lib/content-locale.ts","../../src/lib/get-content-files.ts","../../src/lib/content-files-list-token.ts","../../src/lib/content-files-token.ts","../../src/lib/render-task.service.ts","../../src/lib/inject-content-files.ts","../../src/lib/content-file-loader.ts","../../src/lib/content-list-loader.ts"],"sourcesContent":["import { InjectionToken, inject, Provider } from '@angular/core';\n\nimport { ContentFile } from './content-file';\n\n/**\n * Token for the active content locale.\n * Provided via `withLocale()` in `provideContent()`.\n *\n * When set, `injectContentFiles()` filters to content matching this locale,\n * and `injectContent()` resolves locale-prefixed content paths first.\n */\nexport const CONTENT_LOCALE: InjectionToken<string> =\n new InjectionToken<string>('@analogjs/content Locale');\n\n/**\n * Injects the content locale, returning null if not configured.\n */\nexport function injectContentLocale(): string | null {\n return inject(CONTENT_LOCALE, { optional: true });\n}\n\nexport interface ContentLocaleOptions {\n /**\n * Function that returns the active locale.\n * Runs in injection context so `inject()` can be used to read\n * from other tokens (e.g., a LOCALE token from a router package).\n *\n * ```typescript\n * withLocale({ loadLocale: injectLocale })\n * withLocale({ loadLocale: () => navigator.language.split('-')[0] })\n * ```\n */\n loadLocale: () => string | null;\n}\n\n/**\n * Content feature that sets the active locale for content resolution.\n *\n * When provided, content APIs become locale-aware:\n * - `injectContentFiles()` filters to files in the locale subdirectory\n * or with a matching `locale` frontmatter attribute.\n * - `injectContent()` tries locale-prefixed paths first\n * (e.g., `content/fr/blog/post.md` before `content/blog/post.md`).\n *\n * Usage:\n * ```typescript\n * // With loader — runs in injection context\n * provideContent(\n * withMarkdownRenderer(),\n * withLocale({ loadLocale: injectLocale }),\n * )\n *\n * // Static locale\n * provideContent(\n * withMarkdownRenderer(),\n * withLocale('fr'),\n * )\n * ```\n */\nexport function withLocale(locale: string | ContentLocaleOptions): Provider {\n if (typeof locale === 'string') {\n return { provide: CONTENT_LOCALE, useValue: locale };\n }\n\n return { provide: CONTENT_LOCALE, useFactory: locale.loadLocale };\n}\n\n/**\n * Filters content files by locale using map-based key lookup.\n *\n * Matching rules:\n * 1. Frontmatter `locale` attribute matches the active locale.\n * 2. File is in the active locale subdirectory (e.g., `/content/fr/blog/post`).\n * 3. File has no locale marker and no localized variant exists — included as universal content.\n *\n * Files in a different locale's subdirectory are always excluded.\n */\nexport function filterByLocale<T extends Record<string, any>>(\n files: ContentFile<T>[],\n locale: string,\n): ContentFile<T>[] {\n const localePrefix = `/content/${locale}/`;\n\n // Collect all locale prefixes present in the file set\n const allLocalePrefixes = new Set<string>();\n for (const file of files) {\n const match = file.filename.match(/\\/content\\/([a-z]{2}(?:-[a-zA-Z]+)?)\\//);\n if (match) {\n allLocalePrefixes.add(`/content/${match[1]}/`);\n }\n }\n\n // Build set of base paths that have a localized variant for the active locale\n const localizedBasePaths = new Set<string>();\n for (const file of files) {\n if (file.filename.includes(localePrefix)) {\n localizedBasePaths.add(file.filename.replace(localePrefix, '/content/'));\n }\n }\n\n return files.filter((file) => {\n // Frontmatter locale attribute takes priority\n if (file.attributes['locale']) {\n return file.attributes['locale'] === locale;\n }\n // File is in the active locale subdirectory — include\n if (file.filename.includes(localePrefix)) {\n return true;\n }\n // File is in a different locale's subdirectory — exclude\n for (const prefix of allLocalePrefixes) {\n if (prefix !== localePrefix && file.filename.includes(prefix)) {\n return false;\n }\n }\n // Universal content — include only if no localized variant exists\n return !localizedBasePaths.has(file.filename);\n });\n}\n\n/**\n * Prepends locale-prefixed candidates before the standard candidates\n * for content file map key lookup.\n */\nexport function withLocaleCandidates(\n candidates: string[],\n locale: string | null | undefined,\n): string[] {\n if (!locale) {\n return candidates;\n }\n const localeCandidates = candidates.map((c) =>\n c.replace('/src/content/', `/src/content/${locale}/`),\n );\n return [...localeCandidates, ...candidates];\n}\n","/**\n * These bindings are rewritten at build time:\n * - `ANALOG_CONTENT_FILE_LIST` by `@analogjs/platform`'s content plugin,\n * which substitutes the empty-object initializer with the frontmatter\n * map for discovered content files.\n * - `ANALOG_CONTENT_ROUTE_FILES` by `@analogjs/platform`'s router plugin,\n * which substitutes the empty-object initializer with the lazy-import\n * map for discovered content files. The router plugin already rewrites\n * a same-named binding exported from `@analogjs/router/content`; it\n * matches this module for free because its filter keys off `_ROUTE_FILES`.\n *\n * They are declared as `export const` at module scope so the bundler treats\n * them as public module bindings and cannot constant-fold them away during\n * library build. Previously these lived as local consts inside each getter,\n * and Rolldown collapsed `const X = {}; return X;` into `return {};`, which\n * erased the rewrite target the platform plugins rely on.\n */\n\nexport const ANALOG_CONTENT_FILE_LIST = {};\nexport const ANALOG_CONTENT_ROUTE_FILES = {};\n\n/**\n * Returns the list of content files by filename with ?analog-content-list=true.\n * We use the query param to transform the return into an array of\n * just front matter attributes.\n */\nexport const getContentFilesList = () =>\n ANALOG_CONTENT_FILE_LIST as Record<string, Record<string, any>>;\n\n/**\n * Returns the lazy loaded content files for lookups.\n */\nexport const getContentFiles = () =>\n ANALOG_CONTENT_ROUTE_FILES as Record<string, () => Promise<string>>;\n","import { InjectionToken } from '@angular/core';\nimport { ContentFile } from './content-file';\nimport { getContentFilesList } from './get-content-files';\n\nfunction getSlug(filename: string) {\n // Extract the last path segment without its extension.\n // Handles names with dots like [[...slug]].md by stripping only the final extension.\n const lastSegment = (filename.split(/[/\\\\]/).pop() || '').trim();\n const base = lastSegment.replace(/\\.[^./\\\\]+$/, ''); // strip only the final extension\n // Treat index.md as index route => empty slug\n return base === 'index' ? '' : base;\n}\n\nexport const CONTENT_FILES_LIST_TOKEN: InjectionToken<ContentFile[]> =\n new InjectionToken<ContentFile[]>('@analogjs/content Content Files List', {\n providedIn: 'root',\n factory() {\n const contentFiles = getContentFilesList();\n\n return Object.keys(contentFiles).map((filename) => {\n const attributes = contentFiles[filename];\n const slug = attributes['slug'];\n\n return {\n filename,\n attributes,\n slug: slug ? encodeURI(slug) : encodeURI(getSlug(filename)),\n };\n });\n },\n });\n","import { InjectionToken, Signal, inject, signal } from '@angular/core';\n\nimport { getContentFiles } from './get-content-files';\nimport { CONTENT_FILES_LIST_TOKEN } from './content-files-list-token';\n\nexport const CONTENT_FILES_TOKEN: InjectionToken<\n Record<string, () => Promise<string>>\n> = new InjectionToken<Record<string, () => Promise<string>>>(\n '@analogjs/content Content Files',\n {\n providedIn: 'root',\n factory() {\n const contentFiles = getContentFiles();\n const allFiles = { ...contentFiles };\n const contentFilesList = inject(CONTENT_FILES_LIST_TOKEN);\n\n const lookup: Record<string, string> = {};\n contentFilesList.forEach((item) => {\n const contentFilename = item.filename.replace(\n /(.*?)\\/content/,\n '/src/content',\n );\n const fileParts = contentFilename.split('/');\n const filePath = fileParts.slice(0, fileParts.length - 1).join('/');\n const fileNameParts = fileParts[fileParts.length - 1].split('.');\n const ext = fileNameParts[fileNameParts.length - 1];\n let slug = (item.slug ?? '') as string;\n // Default empty slug to 'index'\n if (slug === '') {\n slug = 'index';\n }\n // Slugs with path separators are scoped to the file's top-level\n // subdirectory (e.g. `/src/content/docs`) rather than absolute root,\n // so nested files keep resolving through `subdirectory` lookups.\n // Files directly under `/src/content` keep the original root-relative\n // behavior since they have no subdirectory of their own.\n const subdirRoot =\n fileParts.length > 4\n ? fileParts.slice(0, 4).join('/')\n : '/src/content';\n const newBase = slug.includes('/')\n ? `${subdirRoot}/${slug}`\n : `${filePath}/${slug}`;\n lookup[contentFilename] = `${newBase}.${ext}`.replace(/\\/{2,}/g, '/');\n });\n\n const objectUsingSlugAttribute: Record<string, () => Promise<string>> =\n {};\n Object.entries(allFiles).forEach((entry) => {\n const filename = entry[0];\n const value = entry[1];\n const strippedFilename = filename.replace(\n /^\\/(.*?)\\/content/,\n '/src/content',\n );\n\n const newFilename = lookup[strippedFilename];\n if (newFilename !== undefined) {\n const objectFilename = newFilename.replace(\n /^\\/(.*?)\\/content/,\n '/src/content',\n );\n objectUsingSlugAttribute[objectFilename] =\n value as () => Promise<string>;\n }\n });\n\n return objectUsingSlugAttribute;\n },\n },\n);\n\nexport const CONTENT_FILES_MAP_TOKEN: InjectionToken<\n Signal<Record<string, () => Promise<string>>>\n> = new InjectionToken<Signal<Record<string, () => Promise<string>>>>(\n '@analogjs/content Content Files',\n {\n providedIn: 'root',\n factory() {\n return signal(inject(CONTENT_FILES_TOKEN));\n },\n },\n);\n","import { Injectable, inject } from '@angular/core';\nimport { ɵPendingTasksInternal as ɵPendingTasks } from '@angular/core';\n\n@Injectable()\nexport class RenderTaskService {\n #pendingTasks = inject(ɵPendingTasks);\n\n addRenderTask(): number {\n return this.#pendingTasks.add();\n }\n\n clearRenderTask(clear: number | (() => void)): void {\n if (typeof clear === 'function') {\n clear();\n } else if (typeof (this.#pendingTasks as any).remove === 'function') {\n (this.#pendingTasks as any).remove(clear);\n }\n }\n}\n","import { inject } from '@angular/core';\n\nimport { ContentFile } from './content-file';\nimport { CONTENT_FILES_LIST_TOKEN } from './content-files-list-token';\nimport { CONTENT_FILES_TOKEN } from './content-files-token';\nimport { CONTENT_LOCALE, filterByLocale } from './content-locale';\nimport { RenderTaskService } from './render-task.service';\n\nexport function injectContentFiles<Attributes extends Record<string, any>>(\n filterFn?: InjectContentFilesFilterFunction<Attributes>,\n): ContentFile<Attributes>[] {\n const renderTaskService = inject(RenderTaskService);\n const task = renderTaskService.addRenderTask();\n const allContentFiles = inject(\n CONTENT_FILES_LIST_TOKEN,\n ) as ContentFile<Attributes>[];\n const locale = inject(CONTENT_LOCALE, { optional: true });\n renderTaskService.clearRenderTask(task);\n\n let results = allContentFiles;\n\n if (locale) {\n results = filterByLocale(results, locale);\n }\n\n if (filterFn) {\n results = results.filter(filterFn);\n }\n\n return results;\n}\n\nexport type InjectContentFilesFilterFunction<T extends Record<string, any>> = (\n value: ContentFile<T>,\n index: number,\n array: ContentFile<T>[],\n) => boolean;\n\nexport function injectContentFilesMap(): Record<string, () => Promise<string>> {\n return inject(CONTENT_FILES_TOKEN);\n}\n","import { InjectionToken, Provider } from '@angular/core';\nimport { inject } from '@angular/core';\n\nimport { injectContentFilesMap } from './inject-content-files';\n\ntype ContentFileLoaderFunction = () => Promise<\n Record<string, () => Promise<string>>\n>;\n\nexport const CONTENT_FILE_LOADER: InjectionToken<ContentFileLoaderFunction> =\n new InjectionToken<ContentFileLoaderFunction>(\n '@analogjs/content/resource File Loader',\n );\n\nexport function injectContentFileLoader() {\n return inject(CONTENT_FILE_LOADER) as ContentFileLoaderFunction;\n}\n\nexport function withContentFileLoader(): Provider {\n return {\n provide: CONTENT_FILE_LOADER,\n useFactory() {\n return async () => injectContentFilesMap();\n },\n };\n}\n","import { InjectionToken, Provider } from '@angular/core';\nimport { inject } from '@angular/core';\n\nimport { ContentFile } from './content-file';\nimport { injectContentFiles } from './inject-content-files';\n\ntype ContentListLoaderFunction<Attributes extends Record<string, any>> =\n () => Promise<ContentFile<Attributes>[]>;\n\nexport const CONTENT_LIST_LOADER: InjectionToken<\n ContentListLoaderFunction<any>\n> = new InjectionToken<ContentListLoaderFunction<any>>(\n '@analogjs/content/resource List Loader',\n);\n\nexport function injectContentListLoader<\n Attributes extends Record<string, any>,\n>() {\n return inject(CONTENT_LIST_LOADER) as ContentListLoaderFunction<Attributes>;\n}\n\nexport function withContentListLoader(): Provider {\n return {\n provide: CONTENT_LIST_LOADER,\n useFactory() {\n return async () => injectContentFiles();\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"content-list-loader.mjs","names":[],"sources":["../../src/lib/content-renderer.ts","../../src/lib/content-locale.ts","../../src/lib/get-content-files.ts","../../src/lib/content-files-list-token.ts","../../src/lib/content-files-token.ts","../../src/lib/render-task.service.ts","../../src/lib/inject-content-files.ts","../../src/lib/content-file-loader.ts","../../src/lib/content-list-loader.ts"],"sourcesContent":["/// <reference types=\"vite/client\" />\n\nimport { Injectable, TransferState, inject, makeStateKey } from '@angular/core';\n\nexport type TableOfContentItem = {\n id: string;\n level: number; // starts at 1\n text: string;\n};\n\nexport type RenderedContent = {\n content: string;\n toc: TableOfContentItem[];\n};\n\n@Injectable()\nexport abstract class ContentRenderer {\n async render(content: string): Promise<RenderedContent> {\n return { content, toc: [] };\n }\n\n // Backward-compatible API for consumers that read headings directly.\n getContentHeadings(_content: string): TableOfContentItem[] {\n return [];\n }\n\n // eslint-disable-next-line\n enhance(): void {}\n}\n\nexport class NoopContentRenderer implements ContentRenderer {\n private readonly transferState = inject(TransferState);\n private contentId = 0;\n\n /**\n * Generates a hash from the content string\n * to be used with the transfer state\n */\n private generateHash(str: string) {\n let hash = 0;\n for (let i = 0, len = str.length; i < len; i++) {\n const chr = str.charCodeAt(i);\n hash = (hash << 5) - hash + chr;\n hash |= 0; // Convert to 32bit integer\n }\n return hash;\n }\n\n async render(content: string): Promise<RenderedContent> {\n this.contentId = this.generateHash(content);\n const toc = this.getContentHeadings(content);\n const key = makeStateKey<TableOfContentItem[]>(\n `content-headings-${this.contentId}`,\n );\n\n if (import.meta.env.SSR === true) {\n this.transferState.set(key, toc);\n return { content, toc };\n }\n\n return {\n content,\n toc: this.transferState.get(key, toc),\n };\n }\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n enhance(): void {}\n\n getContentHeadings(content: string): TableOfContentItem[] {\n return this.extractHeadings(content);\n }\n\n private extractHeadings(content: string): TableOfContentItem[] {\n const markdownHeadings = this.extractHeadingsFromMarkdown(content);\n if (markdownHeadings.length > 0) {\n return markdownHeadings;\n }\n\n const htmlHeadings = this.extractHeadingsFromHtml(content);\n return htmlHeadings;\n }\n\n private extractHeadingsFromMarkdown(content: string): TableOfContentItem[] {\n const lines = content.split('\\n');\n const toc: TableOfContentItem[] = [];\n const slugCounts = new Map<string, number>();\n\n for (const line of lines) {\n const match = /^(#{1,6})\\s+(.+?)\\s*$/.exec(line);\n if (!match) {\n continue;\n }\n\n const level = match[1].length;\n const text = match[2].trim();\n if (!text) {\n continue;\n }\n\n const baseSlug = text\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .trim()\n .replace(/\\s+/g, '-');\n const count = slugCounts.get(baseSlug) ?? 0;\n slugCounts.set(baseSlug, count + 1);\n const id = count === 0 ? baseSlug : `${baseSlug}-${count}`;\n\n toc.push({ id, level, text });\n }\n\n return toc;\n }\n\n private extractHeadingsFromHtml(content: string): TableOfContentItem[] {\n const toc: TableOfContentItem[] = [];\n const slugCounts = new Map<string, number>();\n const headingRegex = /<h([1-6])([^>]*)>([\\s\\S]*?)<\\/h\\1>/gi;\n\n for (const match of content.matchAll(headingRegex)) {\n const level = Number(match[1]);\n const attrs = match[2] ?? '';\n const rawInner = match[3] ?? '';\n const text = rawInner.replace(/<[^>]+>/g, '').trim();\n if (!text) {\n continue;\n }\n\n const idMatch =\n /\\sid=(['\"])(.*?)\\1/i.exec(attrs) ?? /\\sid=([^\\s>]+)/i.exec(attrs);\n let id = idMatch?.[2] ?? idMatch?.[1] ?? '';\n if (!id) {\n id = this.makeSlug(text, slugCounts);\n }\n\n toc.push({ id, level, text });\n }\n\n return toc;\n }\n\n private makeSlug(text: string, slugCounts: Map<string, number>): string {\n const baseSlug = text\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .trim()\n .replace(/\\s+/g, '-');\n const count = slugCounts.get(baseSlug) ?? 0;\n slugCounts.set(baseSlug, count + 1);\n return count === 0 ? baseSlug : `${baseSlug}-${count}`;\n }\n}\n","import { InjectionToken, inject, Provider } from '@angular/core';\n\nimport { ContentFile } from './content-file';\n\n/**\n * Token for the active content locale.\n * Provided via `withLocale()` in `provideContent()`.\n *\n * When set, `injectContentFiles()` filters to content matching this locale,\n * and `injectContent()` resolves locale-prefixed content paths first.\n */\nexport const CONTENT_LOCALE: InjectionToken<string> =\n new InjectionToken<string>('@analogjs/content Locale');\n\n/**\n * Injects the content locale, returning null if not configured.\n */\nexport function injectContentLocale(): string | null {\n return inject(CONTENT_LOCALE, { optional: true });\n}\n\nexport interface ContentLocaleOptions {\n /**\n * Function that returns the active locale.\n * Runs in injection context so `inject()` can be used to read\n * from other tokens (e.g., a LOCALE token from a router package).\n *\n * ```typescript\n * withLocale({ loadLocale: injectLocale })\n * withLocale({ loadLocale: () => navigator.language.split('-')[0] })\n * ```\n */\n loadLocale: () => string | null;\n}\n\n/**\n * Content feature that sets the active locale for content resolution.\n *\n * When provided, content APIs become locale-aware:\n * - `injectContentFiles()` filters to files in the locale subdirectory\n * or with a matching `locale` frontmatter attribute.\n * - `injectContent()` tries locale-prefixed paths first\n * (e.g., `content/fr/blog/post.md` before `content/blog/post.md`).\n *\n * Usage:\n * ```typescript\n * // With loader — runs in injection context\n * provideContent(\n * withMarkdownRenderer(),\n * withLocale({ loadLocale: injectLocale }),\n * )\n *\n * // Static locale\n * provideContent(\n * withMarkdownRenderer(),\n * withLocale('fr'),\n * )\n * ```\n */\nexport function withLocale(locale: string | ContentLocaleOptions): Provider {\n if (typeof locale === 'string') {\n return { provide: CONTENT_LOCALE, useValue: locale };\n }\n\n return { provide: CONTENT_LOCALE, useFactory: locale.loadLocale };\n}\n\n/**\n * Filters content files by locale using map-based key lookup.\n *\n * Matching rules:\n * 1. Frontmatter `locale` attribute matches the active locale.\n * 2. File is in the active locale subdirectory (e.g., `/content/fr/blog/post`).\n * 3. File has no locale marker and no localized variant exists — included as universal content.\n *\n * Files in a different locale's subdirectory are always excluded.\n */\nexport function filterByLocale<T extends Record<string, any>>(\n files: ContentFile<T>[],\n locale: string,\n): ContentFile<T>[] {\n const localePrefix = `/content/${locale}/`;\n\n // Collect all locale prefixes present in the file set\n const allLocalePrefixes = new Set<string>();\n for (const file of files) {\n const match = file.filename.match(/\\/content\\/([a-z]{2}(?:-[a-zA-Z]+)?)\\//);\n if (match) {\n allLocalePrefixes.add(`/content/${match[1]}/`);\n }\n }\n\n // Build set of base paths that have a localized variant for the active locale\n const localizedBasePaths = new Set<string>();\n for (const file of files) {\n if (file.filename.includes(localePrefix)) {\n localizedBasePaths.add(file.filename.replace(localePrefix, '/content/'));\n }\n }\n\n return files.filter((file) => {\n // Frontmatter locale attribute takes priority\n if (file.attributes['locale']) {\n return file.attributes['locale'] === locale;\n }\n // File is in the active locale subdirectory — include\n if (file.filename.includes(localePrefix)) {\n return true;\n }\n // File is in a different locale's subdirectory — exclude\n for (const prefix of allLocalePrefixes) {\n if (prefix !== localePrefix && file.filename.includes(prefix)) {\n return false;\n }\n }\n // Universal content — include only if no localized variant exists\n return !localizedBasePaths.has(file.filename);\n });\n}\n\n/**\n * Prepends locale-prefixed candidates before the standard candidates\n * for content file map key lookup.\n */\nexport function withLocaleCandidates(\n candidates: string[],\n locale: string | null | undefined,\n): string[] {\n if (!locale) {\n return candidates;\n }\n const localeCandidates = candidates.map((c) =>\n c.replace('/src/content/', `/src/content/${locale}/`),\n );\n return [...localeCandidates, ...candidates];\n}\n","/**\n * These bindings are rewritten at build time:\n * - `ANALOG_CONTENT_FILE_LIST` by `@analogjs/platform`'s content plugin,\n * which substitutes the empty-object initializer with the frontmatter\n * map for discovered content files.\n * - `ANALOG_CONTENT_ROUTE_FILES` by `@analogjs/platform`'s router plugin,\n * which substitutes the empty-object initializer with the lazy-import\n * map for discovered content files. The router plugin already rewrites\n * a same-named binding exported from `@analogjs/router/content`; it\n * matches this module for free because its filter keys off `_ROUTE_FILES`.\n *\n * They are declared as `export const` at module scope so the bundler treats\n * them as public module bindings and cannot constant-fold them away during\n * library build. Previously these lived as local consts inside each getter,\n * and Rolldown collapsed `const X = {}; return X;` into `return {};`, which\n * erased the rewrite target the platform plugins rely on.\n */\n\nexport const ANALOG_CONTENT_FILE_LIST = {};\nexport const ANALOG_CONTENT_ROUTE_FILES = {};\n\n/**\n * Returns the list of content files by filename with ?analog-content-list=true.\n * We use the query param to transform the return into an array of\n * just front matter attributes.\n */\nexport const getContentFilesList = () =>\n ANALOG_CONTENT_FILE_LIST as Record<string, Record<string, any>>;\n\n/**\n * Returns the lazy loaded content files for lookups.\n */\nexport const getContentFiles = () =>\n ANALOG_CONTENT_ROUTE_FILES as Record<string, () => Promise<string>>;\n","import { InjectionToken } from '@angular/core';\nimport { ContentFile } from './content-file';\nimport { getContentFilesList } from './get-content-files';\n\nfunction getSlug(filename: string) {\n // Extract the last path segment without its extension.\n // Handles names with dots like [[...slug]].md by stripping only the final extension.\n const lastSegment = (filename.split(/[/\\\\]/).pop() || '').trim();\n const base = lastSegment.replace(/\\.[^./\\\\]+$/, ''); // strip only the final extension\n // Treat index.md as index route => empty slug\n return base === 'index' ? '' : base;\n}\n\nexport const CONTENT_FILES_LIST_TOKEN: InjectionToken<ContentFile[]> =\n new InjectionToken<ContentFile[]>('@analogjs/content Content Files List', {\n providedIn: 'root',\n factory() {\n const contentFiles = getContentFilesList();\n\n return Object.keys(contentFiles).map((filename) => {\n const attributes = contentFiles[filename];\n const slug = attributes['slug'];\n\n return {\n filename,\n attributes,\n slug: slug ? encodeURI(slug) : encodeURI(getSlug(filename)),\n };\n });\n },\n });\n","import { InjectionToken, Signal, inject, signal } from '@angular/core';\n\nimport { getContentFiles } from './get-content-files';\nimport { CONTENT_FILES_LIST_TOKEN } from './content-files-list-token';\n\nexport const CONTENT_FILES_TOKEN: InjectionToken<\n Record<string, () => Promise<string>>\n> = new InjectionToken<Record<string, () => Promise<string>>>(\n '@analogjs/content Content Files',\n {\n providedIn: 'root',\n factory() {\n const contentFiles = getContentFiles();\n const allFiles = { ...contentFiles };\n const contentFilesList = inject(CONTENT_FILES_LIST_TOKEN);\n\n const lookup: Record<string, string> = {};\n contentFilesList.forEach((item) => {\n const contentFilename = item.filename.replace(\n /(.*?)\\/content/,\n '/src/content',\n );\n const fileParts = contentFilename.split('/');\n const filePath = fileParts.slice(0, fileParts.length - 1).join('/');\n const fileNameParts = fileParts[fileParts.length - 1].split('.');\n const ext = fileNameParts[fileNameParts.length - 1];\n let slug = (item.slug ?? '') as string;\n // Default empty slug to 'index'\n if (slug === '') {\n slug = 'index';\n }\n // Slugs with path separators are scoped to the file's top-level\n // subdirectory (e.g. `/src/content/docs`) rather than absolute root,\n // so nested files keep resolving through `subdirectory` lookups.\n // Files directly under `/src/content` keep the original root-relative\n // behavior since they have no subdirectory of their own.\n const subdirRoot =\n fileParts.length > 4\n ? fileParts.slice(0, 4).join('/')\n : '/src/content';\n const newBase = slug.includes('/')\n ? `${subdirRoot}/${slug}`\n : `${filePath}/${slug}`;\n lookup[contentFilename] = `${newBase}.${ext}`.replace(/\\/{2,}/g, '/');\n });\n\n const objectUsingSlugAttribute: Record<string, () => Promise<string>> =\n {};\n Object.entries(allFiles).forEach((entry) => {\n const filename = entry[0];\n const value = entry[1];\n const strippedFilename = filename.replace(\n /^\\/(.*?)\\/content/,\n '/src/content',\n );\n\n const newFilename = lookup[strippedFilename];\n if (newFilename !== undefined) {\n const objectFilename = newFilename.replace(\n /^\\/(.*?)\\/content/,\n '/src/content',\n );\n objectUsingSlugAttribute[objectFilename] =\n value as () => Promise<string>;\n }\n });\n\n return objectUsingSlugAttribute;\n },\n },\n);\n\nexport const CONTENT_FILES_MAP_TOKEN: InjectionToken<\n Signal<Record<string, () => Promise<string>>>\n> = new InjectionToken<Signal<Record<string, () => Promise<string>>>>(\n '@analogjs/content Content Files',\n {\n providedIn: 'root',\n factory() {\n return signal(inject(CONTENT_FILES_TOKEN));\n },\n },\n);\n","import { Injectable, inject } from '@angular/core';\nimport { ɵPendingTasksInternal as ɵPendingTasks } from '@angular/core';\n\n@Injectable()\nexport class RenderTaskService {\n #pendingTasks = inject(ɵPendingTasks);\n\n addRenderTask(): number {\n return this.#pendingTasks.add();\n }\n\n clearRenderTask(clear: number | (() => void)): void {\n if (typeof clear === 'function') {\n clear();\n } else if (typeof (this.#pendingTasks as any).remove === 'function') {\n (this.#pendingTasks as any).remove(clear);\n }\n }\n}\n","import { inject } from '@angular/core';\n\nimport { ContentFile } from './content-file';\nimport { CONTENT_FILES_LIST_TOKEN } from './content-files-list-token';\nimport { CONTENT_FILES_TOKEN } from './content-files-token';\nimport { CONTENT_LOCALE, filterByLocale } from './content-locale';\nimport { RenderTaskService } from './render-task.service';\n\nexport function injectContentFiles<Attributes extends Record<string, any>>(\n filterFn?: InjectContentFilesFilterFunction<Attributes>,\n): ContentFile<Attributes>[] {\n const renderTaskService = inject(RenderTaskService);\n const task = renderTaskService.addRenderTask();\n const allContentFiles = inject(\n CONTENT_FILES_LIST_TOKEN,\n ) as ContentFile<Attributes>[];\n const locale = inject(CONTENT_LOCALE, { optional: true });\n renderTaskService.clearRenderTask(task);\n\n let results = allContentFiles;\n\n if (locale) {\n results = filterByLocale(results, locale);\n }\n\n if (filterFn) {\n results = results.filter(filterFn);\n }\n\n return results;\n}\n\nexport type InjectContentFilesFilterFunction<T extends Record<string, any>> = (\n value: ContentFile<T>,\n index: number,\n array: ContentFile<T>[],\n) => boolean;\n\nexport function injectContentFilesMap(): Record<string, () => Promise<string>> {\n return inject(CONTENT_FILES_TOKEN);\n}\n","import { InjectionToken, Provider } from '@angular/core';\nimport { inject } from '@angular/core';\n\nimport { injectContentFilesMap } from './inject-content-files';\n\ntype ContentFileLoaderFunction = () => Promise<\n Record<string, () => Promise<string>>\n>;\n\nexport const CONTENT_FILE_LOADER: InjectionToken<ContentFileLoaderFunction> =\n new InjectionToken<ContentFileLoaderFunction>(\n '@analogjs/content/resource File Loader',\n );\n\nexport function injectContentFileLoader() {\n return inject(CONTENT_FILE_LOADER) as ContentFileLoaderFunction;\n}\n\nexport function withContentFileLoader(): Provider {\n return {\n provide: CONTENT_FILE_LOADER,\n useFactory() {\n return async () => injectContentFilesMap();\n },\n };\n}\n","import { InjectionToken, Provider } from '@angular/core';\nimport { inject } from '@angular/core';\n\nimport { ContentFile } from './content-file';\nimport { injectContentFiles } from './inject-content-files';\n\ntype ContentListLoaderFunction<Attributes extends Record<string, any>> =\n () => Promise<ContentFile<Attributes>[]>;\n\nexport const CONTENT_LIST_LOADER: InjectionToken<\n ContentListLoaderFunction<any>\n> = new InjectionToken<ContentListLoaderFunction<any>>(\n '@analogjs/content/resource List Loader',\n);\n\nexport function injectContentListLoader<\n Attributes extends Record<string, any>,\n>() {\n return inject(CONTENT_LIST_LOADER) as ContentListLoaderFunction<Attributes>;\n}\n\nexport function withContentListLoader(): Provider {\n return {\n provide: CONTENT_LIST_LOADER,\n useFactory() {\n return async () => injectContentFiles();\n },\n };\n}\n"],"mappings":";;;AAgBA,IAAsB,kBAAtB,MAAsB,gBAAe;CACnC,MAAM,OAAO,SAAe;AAC1B,SAAO;GAAE;GAAS,KAAK,EAAE;GAAE;;CAI7B,mBAAmB,UAAgB;AACjC,SAAO,EAAE;;CAIX,UAAO;;;;;;SAXa;GAAe,MAAA,EAAA;GAAA,QAAA,GAAA,gBAAA;GAAA,CAAA;;;;;;;SAAf;GAAe,CAAA;;;;;;;OAAf;CAAe,YAAA,CAAA,EAAA,MADpC,YAAA,CAAA;;AAeD,IAAa,sBAAb,MAAgC;CAAhC,cAAA;AACmB,OAAA,gBAAgB,OAAO,cAAc;AAC9C,OAAA,YAAY;;;;;;CAMZ,aAAa,KAAW;EAC9B,IAAI,OAAO;AACX,OAAK,IAAI,IAAI,GAAG,MAAM,IAAI,QAAQ,IAAI,KAAK,KAAK;GAC9C,MAAM,MAAM,IAAI,WAAW,EAAE;AAC7B,WAAQ,QAAQ,KAAK,OAAO;AAC5B,WAAQ;;AAEV,SAAO;;CAGT,MAAM,OAAO,SAAe;AAC1B,OAAK,YAAY,KAAK,aAAa,QAAQ;EAC3C,MAAM,MAAM,KAAK,mBAAmB,QAAQ;EAC5C,MAAM,MAAM,aACV,oBAAoB,KAAK,YAC1B;AAOD,SAAO;GACL;GACA,KAAK,KAAK,cAAc,IAAI,KAAK,IAAI;GACtC;;CAGH,UAAO;CAEP,mBAAmB,SAAe;AAChC,SAAO,KAAK,gBAAgB,QAAQ;;CAG9B,gBAAgB,SAAe;EACrC,MAAM,mBAAmB,KAAK,4BAA4B,QAAQ;AAClE,MAAI,iBAAiB,SAAS,EAC5B,QAAO;AAIT,SADqB,KAAK,wBAAwB,QAAQ;;CAIpD,4BAA4B,SAAe;EACjD,MAAM,QAAQ,QAAQ,MAAM,KAAK;EACjC,MAAM,MAA4B,EAAE;EACpC,MAAM,6BAAa,IAAI,KAAqB;AAE5C,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,QAAQ,wBAAwB,KAAK,KAAK;AAChD,OAAI,CAAC,MACH;GAGF,MAAM,QAAQ,MAAM,GAAG;GACvB,MAAM,OAAO,MAAM,GAAG,MAAM;AAC5B,OAAI,CAAC,KACH;GAGF,MAAM,WAAW,KACd,aAAa,CACb,QAAQ,aAAa,GAAG,CACxB,MAAM,CACN,QAAQ,QAAQ,IAAI;GACvB,MAAM,QAAQ,WAAW,IAAI,SAAS,IAAI;AAC1C,cAAW,IAAI,UAAU,QAAQ,EAAE;GACnC,MAAM,KAAK,UAAU,IAAI,WAAW,GAAG,SAAQ,GAAI;AAEnD,OAAI,KAAK;IAAE;IAAI;IAAO;IAAM,CAAC;;AAG/B,SAAO;;CAGD,wBAAwB,SAAe;EAC7C,MAAM,MAA4B,EAAE;EACpC,MAAM,6BAAa,IAAI,KAAqB;AAG5C,OAAK,MAAM,SAAS,QAAQ,SAFP,uCAE6B,EAAE;GAClD,MAAM,QAAQ,OAAO,MAAM,GAAG;GAC9B,MAAM,QAAQ,MAAM,MAAM;GAE1B,MAAM,QADW,MAAM,MAAM,IACP,QAAQ,YAAY,GAAG,CAAC,MAAM;AACpD,OAAI,CAAC,KACH;GAGF,MAAM,UACJ,sBAAsB,KAAK,MAAM,IAAI,kBAAkB,KAAK,MAAM;GACpE,IAAI,KAAK,UAAU,MAAM,UAAU,MAAM;AACzC,OAAI,CAAC,GACH,MAAK,KAAK,SAAS,MAAM,WAAW;AAGtC,OAAI,KAAK;IAAE;IAAI;IAAO;IAAM,CAAC;;AAG/B,SAAO;;CAGD,SAAS,MAAc,YAA+B;EAC5D,MAAM,WAAW,KACd,aAAa,CACb,QAAQ,aAAa,GAAG,CACxB,MAAM,CACN,QAAQ,QAAQ,IAAI;EACvB,MAAM,QAAQ,WAAW,IAAI,SAAS,IAAI;AAC1C,aAAW,IAAI,UAAU,QAAQ,EAAE;AACnC,SAAO,UAAU,IAAI,WAAW,GAAG,SAAQ,GAAI;;;;;;;;;;;;AC1InD,IAAa,iBACX,IAAI,eAAuB,2BAA2B;;;;AAKxD,SAAgB,sBAAmB;AACjC,QAAO,OAAO,gBAAgB,EAAE,UAAU,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCnD,SAAgB,WAAW,QAAqC;AAC9D,KAAI,OAAO,WAAW,SACpB,QAAO;EAAE,SAAS;EAAgB,UAAU;EAAQ;AAGtD,QAAO;EAAE,SAAS;EAAgB,YAAY,OAAO;EAAY;;;;;;;;;;;;AAanE,SAAgB,eACd,OACA,QAAc;CAEd,MAAM,eAAe,YAAY,OAAM;CAGvC,MAAM,oCAAoB,IAAI,KAAa;AAC3C,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,QAAQ,KAAK,SAAS,MAAM,yCAAyC;AAC3E,MAAI,MACF,mBAAkB,IAAI,YAAY,MAAM,GAAE,GAAI;;CAKlD,MAAM,qCAAqB,IAAI,KAAa;AAC5C,MAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,SAAS,SAAS,aAAa,CACtC,oBAAmB,IAAI,KAAK,SAAS,QAAQ,cAAc,YAAY,CAAC;AAI5E,QAAO,MAAM,QAAQ,SAAQ;AAE3B,MAAI,KAAK,WAAW,UAClB,QAAO,KAAK,WAAW,cAAc;AAGvC,MAAI,KAAK,SAAS,SAAS,aAAa,CACtC,QAAO;AAGT,OAAK,MAAM,UAAU,kBACnB,KAAI,WAAW,gBAAgB,KAAK,SAAS,SAAS,OAAO,CAC3D,QAAO;AAIX,SAAO,CAAC,mBAAmB,IAAI,KAAK,SAAS;GAC7C;;;;;;AAOJ,SAAgB,qBACd,YACA,QAAiC;AAEjC,KAAI,CAAC,OACH,QAAO;AAKT,QAAO,CAAC,GAHiB,WAAW,KAAK,MACvC,EAAE,QAAQ,iBAAiB,gBAAgB,OAAM,GAAI,CACtD,EAC4B,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;ACpH7C,IAAa,2BAA2B,EAAE;AAC1C,IAAa,6BAA6B,EAAE;;;;;;AAO5C,IAAa,4BACX;;;;AAKF,IAAa,wBACX;;;AC7BF,SAAS,QAAQ,UAAgB;CAI/B,MAAM,QADe,SAAS,MAAM,QAAQ,CAAC,KAAK,IAAI,IAAI,MAAM,CACvC,QAAQ,eAAe,GAAG;AAEnD,QAAO,SAAS,UAAU,KAAK;;AAGjC,IAAa,2BACX,IAAI,eAA8B,wCAAwC;CACxE,YAAY;CACZ,UAAO;EACL,MAAM,eAAe,qBAAqB;AAE1C,SAAO,OAAO,KAAK,aAAa,CAAC,KAAK,aAAY;GAChD,MAAM,aAAa,aAAa;GAChC,MAAM,OAAO,WAAW;AAExB,UAAO;IACL;IACA;IACA,MAAM,OAAO,UAAU,KAAK,GAAG,UAAU,QAAQ,SAAS,CAAC;IAC5D;IACD;;CAEL,CAAC;;;ACzBJ,IAAa,sBAET,IAAI,eACN,mCACA;CACE,YAAY;CACZ,UAAO;EAEL,MAAM,WAAW,EAAE,GADE,iBAAiB,EACF;EACpC,MAAM,mBAAmB,OAAO,yBAAyB;EAEzD,MAAM,SAAiC,EAAE;AACzC,mBAAiB,SAAS,SAAQ;GAChC,MAAM,kBAAkB,KAAK,SAAS,QACpC,kBACA,eACD;GACD,MAAM,YAAY,gBAAgB,MAAM,IAAI;GAC5C,MAAM,WAAW,UAAU,MAAM,GAAG,UAAU,SAAS,EAAE,CAAC,KAAK,IAAI;GACnE,MAAM,gBAAgB,UAAU,UAAU,SAAS,GAAG,MAAM,IAAI;GAChE,MAAM,MAAM,cAAc,cAAc,SAAS;GACjD,IAAI,OAAQ,KAAK,QAAQ;AAEzB,OAAI,SAAS,GACX,QAAO;GAOT,MAAM,aACJ,UAAU,SAAS,IACf,UAAU,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,GAC/B;AAIN,UAAO,mBAAmB,GAHV,KAAK,SAAS,IAAI,GAC9B,GAAG,WAAU,GAAI,SACjB,GAAG,SAAQ,GAAI,OACiB,GAAI,MAAM,QAAQ,WAAW,IAAI;IACrE;EAEF,MAAM,2BACJ,EAAE;AACJ,SAAO,QAAQ,SAAS,CAAC,SAAS,UAAS;GACzC,MAAM,WAAW,MAAM;GACvB,MAAM,QAAQ,MAAM;GAMpB,MAAM,cAAc,OALK,SAAS,QAChC,qBACA,eACD;AAGD,OAAI,gBAAgB,KAAA,GAAW;IAC7B,MAAM,iBAAiB,YAAY,QACjC,qBACA,eACD;AACD,6BAAyB,kBACvB;;IAEJ;AAEF,SAAO;;CAEV,CACF;AAIG,IAAI,eACN,mCACA;CACE,YAAY;CACZ,UAAO;AACL,SAAO,OAAO,OAAO,oBAAoB,CAAC;;CAE7C,CACF;;;AC9ED,IAAa,oBAAb,MAAa,kBAAiB;CAC5B,gBAAgB,OAAO,sBAAc;CAErC,gBAAa;AACX,SAAO,MAAA,aAAmB,KAAK;;CAGjC,gBAAgB,OAA4B;AAC1C,MAAI,OAAO,UAAU,WACnB,QAAO;WACE,OAAQ,MAAA,aAA2B,WAAW,WACtD,OAAA,aAA2B,OAAO,MAAM;;;;;;;SAXlC;GAAiB,MAAA,EAAA;GAAA,QAAA,GAAA,gBAAA;GAAA,CAAA;;;;;;;SAAjB;GAAiB,CAAA;;;;;;;OAAjB;CAAiB,YAAA,CAAA,EAAA,MAD7B,YAAA,CAAA;;;;ACKD,SAAgB,mBACd,UAAuD;CAEvD,MAAM,oBAAoB,OAAO,kBAAkB;CACnD,MAAM,OAAO,kBAAkB,eAAe;CAC9C,MAAM,kBAAkB,OACtB,yBAC4B;CAC9B,MAAM,SAAS,OAAO,gBAAgB,EAAE,UAAU,MAAM,CAAC;AACzD,mBAAkB,gBAAgB,KAAK;CAEvC,IAAI,UAAU;AAEd,KAAI,OACF,WAAU,eAAe,SAAS,OAAO;AAG3C,KAAI,SACF,WAAU,QAAQ,OAAO,SAAS;AAGpC,QAAO;;AAST,SAAgB,wBAAqB;AACnC,QAAO,OAAO,oBAAoB;;;;AC9BpC,IAAa,sBACX,IAAI,eACF,yCACD;AAEH,SAAgB,0BAAuB;AACrC,QAAO,OAAO,oBAAiD;;AAGjE,SAAgB,wBAAqB;AACnC,QAAO;EACL,SAAS;EACT,aAAU;AACR,UAAO,YAAY,uBAAuB;;EAE7C;;;;ACfH,IAAa,sBAET,IAAI,eACN,yCACD;AAED,SAAgB,0BAAuB;AAGrC,QAAO,OAAO,oBAA6D;;AAG7E,SAAgB,wBAAqB;AACnC,QAAO;EACL,SAAS;EACT,aAAU;AACR,UAAO,YAAY,oBAAoB;;EAE1C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@analogjs/content",
3
- "version": "3.0.0-alpha.95",
3
+ "version": "3.0.0-alpha.96",
4
4
  "description": "Content Rendering for Analog",
5
5
  "type": "module",
6
6
  "author": "Brandon Roberts <robertsbt@gmail.com>",
@@ -29,13 +29,8 @@
29
29
  "@angular/router": "^20.0.0 || ^21.0.0 || ^22.0.0",
30
30
  "@nx/devkit": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0 || ^23.0.0 || ^23",
31
31
  "front-matter": "^4.0.2",
32
- "marked": "^18.0.0",
33
- "marked-gfm-heading-id": "^4.1.3",
34
- "marked-highlight": "^2.2.3",
35
- "marked-mangle": "^1.1.12",
36
32
  "rxjs": "^6.5.0 || ^7.5.0",
37
33
  "@standard-schema/spec": "^1.1.0",
38
- "prismjs": "^1.30.0",
39
34
  "satori": "^0.10.14",
40
35
  "satori-html": "^0.3.2",
41
36
  "sharp": "^0.34.5",
@@ -59,9 +54,6 @@
59
54
  },
60
55
  "sharp": {
61
56
  "optional": true
62
- },
63
- "prismjs": {
64
- "optional": true
65
57
  }
66
58
  },
67
59
  "exports": {
@@ -88,28 +80,18 @@
88
80
  "import": "./fesm2022/analogjs-content-og.mjs",
89
81
  "default": "./fesm2022/analogjs-content-og.mjs"
90
82
  },
91
- "./prism-highlighter": {
92
- "types": "./types/prism-highlighter/src/index.d.ts",
93
- "import": "./fesm2022/analogjs-content-prism-highlighter.mjs",
94
- "default": "./fesm2022/analogjs-content-prism-highlighter.mjs"
95
- },
96
83
  "./resources": {
97
84
  "types": "./types/resources/src/index.d.ts",
98
85
  "import": "./fesm2022/analogjs-content-resources.mjs",
99
86
  "default": "./fesm2022/analogjs-content-resources.mjs"
100
- },
101
- "./shiki-highlighter": {
102
- "types": "./types/shiki-highlighter/src/index.d.ts",
103
- "import": "./fesm2022/analogjs-content-shiki-highlighter.mjs",
104
- "default": "./fesm2022/analogjs-content-shiki-highlighter.mjs"
105
87
  }
106
88
  },
107
89
  "dependencies": {
108
90
  "tslib": "^2.3.0"
109
91
  },
110
92
  "devDependencies": {
111
- "@analogjs/vite-plugin-angular": "3.0.0-alpha.95",
112
- "@analogjs/vitest-angular": "3.0.0-alpha.95"
93
+ "@analogjs/vite-plugin-angular": "3.0.0-alpha.96",
94
+ "@analogjs/vitest-angular": "3.0.0-alpha.96"
113
95
  },
114
96
  "ng-update": {
115
97
  "packageGroup": [
@@ -1,75 +1,5 @@
1
1
  {
2
2
  "generators": {},
3
3
  "schematics": {},
4
- "packageJsonUpdates": {
5
- "0.2.0-beta.23": {
6
- "version": "0.2.0-beta.19",
7
- "description": "Adds the new peer dependencies for marked to work properly with version 5.0.0",
8
- "requires": {
9
- "marked": ">=5.0.0"
10
- },
11
- "packages": {
12
- "marked-gfm-heading-id": {
13
- "version": "^3.0.4",
14
- "alwaysAddToPackageJson": true
15
- },
16
- "marked-highlight": {
17
- "version": "^2.0.1",
18
- "alwaysAddToPackageJson": true
19
- }
20
- }
21
- },
22
- "0.2.0-beta.26": {
23
- "version": "0.2.0-beta.25",
24
- "description": "Adds the new peer dependencies for mermaid",
25
- "packages": {
26
- "mermaid": {
27
- "version": "^10.2.4",
28
- "alwaysAddToPackageJson": true
29
- }
30
- }
31
- },
32
- "0.2.8": {
33
- "version": "0.2.7",
34
- "description": "Updates marked-gfm-heading-id to support TOCs generation",
35
- "packages": {
36
- "marked-gfm-heading-id": {
37
- "version": "^3.1.0",
38
- "alwaysAddToPackageJson": true
39
- }
40
- }
41
- },
42
- "1.5.0-beta.1": {
43
- "version": "1.4.0",
44
- "description": "Adds marked-mangle dependency for deprecated marked feature",
45
- "packages": {
46
- "marked-mangle": {
47
- "version": "^1.1.7",
48
- "alwaysAddToPackageJson": true
49
- }
50
- }
51
- },
52
- "1.15.0-beta.3": {
53
- "version": "1.14.1",
54
- "description": "Adds marked dependency to support markdown rendering",
55
- "packages": {
56
- "marked": {
57
- "version": "^18.0.0",
58
- "alwaysAddToPackageJson": true
59
- },
60
- "marked-mangle": {
61
- "version": "^1.1.10",
62
- "alwaysAddToPackageJson": true
63
- },
64
- "marked-highlight": {
65
- "version": "^2.2.1",
66
- "alwaysAddToPackageJson": true
67
- },
68
- "marked-gfm-heading-id": {
69
- "version": "^4.1.1",
70
- "alwaysAddToPackageJson": true
71
- }
72
- }
73
- }
74
- }
4
+ "packageJsonUpdates": {}
75
5
  }
@@ -5,13 +5,10 @@ export { ContentRenderer, NoopContentRenderer } from './lib/content-renderer';
5
5
  export type { RenderedContent, TableOfContentItem, } from './lib/content-renderer';
6
6
  export { injectContentFiles } from './lib/inject-content-files';
7
7
  export type { InjectContentFilesFilterFunction } from './lib/inject-content-files';
8
- export { MarkdownContentRendererService } from './lib/markdown-content-renderer.service';
9
8
  export { provideContent, withMarkdownRenderer, MERMAID_IMPORT_TOKEN, } from './lib/provide-content';
10
9
  export { default as MarkdownRouteComponent } from './lib/markdown-route.component';
11
10
  export { default as MarkdownComponent } from './lib/markdown.component';
12
11
  export { parseRawContentFile, parseRawContentFileAsync, FrontmatterValidationError, } from './lib/parse-raw-content-file';
13
- export { MarkedSetupService } from './lib/marked-setup.service';
14
- export { MarkedContentHighlighter, withHighlighter, } from './lib/marked-content-highlighter';
15
12
  export { injectContentFilesMap } from './lib/inject-content-files';
16
13
  export { injectContentListLoader, withContentListLoader, CONTENT_LIST_LOADER, } from './lib/content-list-loader';
17
14
  export { injectContentFileLoader, withContentFileLoader, CONTENT_FILE_LOADER, } from './lib/content-file-loader';
@@ -1,99 +0,0 @@
1
- import { n as NoopContentRenderer, t as ContentRenderer } from "./content-renderer.mjs";
2
- import { t as MarkedContentHighlighter } from "./marked-content-highlighter.mjs";
3
- import * as i0 from "@angular/core";
4
- import { Injectable } from "@angular/core";
5
- import { markedHighlight } from "marked-highlight";
6
- import Prism$1 from "prismjs";
7
- import "prismjs/plugins/toolbar/prism-toolbar";
8
- import "prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard";
9
- //#region packages/content/prism-highlighter/src/lib/prism-highlighter.ts
10
- var PrismHighlighter = class PrismHighlighter extends MarkedContentHighlighter {
11
- augmentCodeBlock(code, lang) {
12
- const classes = lang.startsWith("diff") && Prism.languages["diff"] ? `language-${lang} diff-highlight` : `language-${lang.replace("diff-", "")}`;
13
- return `<pre class="${classes}"><code class="${classes}">${code}</code></pre>`;
14
- }
15
- getHighlightExtension() {
16
- return markedHighlight({
17
- async: true,
18
- highlight: (code, lang) => {
19
- let diff = lang?.startsWith("diff-");
20
- lang = diff ? lang.replace("diff-", "") : lang || "typescript";
21
- if (diff && !Prism.languages["diff"]) {
22
- diff = false;
23
- console.warn(`Notice:
24
- ---------------------------------------------------------------------------------------
25
- The \`diff\` language and plugin are not available in the provided setup.
26
- To enable it, add the following imports your \`app.config.ts\`:
27
- import 'prismjs/components/prism-diff';
28
- import 'prismjs/plugins/diff-highlight/prism-diff-highlight';
29
- ---------------------------------------------------------------------------------------
30
- `);
31
- }
32
- if (!Prism.languages[lang]) {
33
- if (lang !== "mermaid") console.warn(`Notice:
34
- ---------------------------------------------------------------------------------------
35
- The requested language '${lang}' is not available in the provided setup.
36
- To enable it, add the following import your \`app.config.ts\`:
37
- import 'prismjs/components/prism-${lang}';
38
- ---------------------------------------------------------------------------------------
39
- `);
40
- return code;
41
- }
42
- return Prism.highlight(code, diff ? Prism.languages["diff"] : Prism.languages[lang], lang);
43
- }
44
- });
45
- }
46
- static {
47
- this.ɵfac = i0.ɵɵngDeclareFactory({
48
- minVersion: "12.0.0",
49
- version: "22.2.0",
50
- ngImport: i0,
51
- type: PrismHighlighter,
52
- deps: null,
53
- target: i0.ɵɵFactoryTarget.Injectable
54
- });
55
- }
56
- static {
57
- this.ɵprov = i0.ɵɵngDeclareInjectable({
58
- minVersion: "12.0.0",
59
- version: "22.2.0",
60
- ngImport: i0,
61
- type: PrismHighlighter
62
- });
63
- }
64
- };
65
- i0.ɵɵngDeclareClassMetadata({
66
- minVersion: "12.0.0",
67
- version: "22.2.0",
68
- ngImport: i0,
69
- type: PrismHighlighter,
70
- decorators: [{ type: Injectable }]
71
- });
72
- //#endregion
73
- //#region packages/content/prism-highlighter/src/lib/prism/angular.ts
74
- (function() {
75
- if (typeof Prism$1 === "undefined") return;
76
- Prism$1.languages["angular"] = Prism$1.languages.extend("markup", {
77
- keyword: /(?:@if|@for|@switch|@defer|@loading|@error|@placeholder|prefetch)\b/,
78
- operator: /\b(?:on|when)\b/,
79
- number: {
80
- pattern: /\b(minimum|after)\s+\d+(?:s|ms|)/gi,
81
- lookbehind: true
82
- },
83
- builtin: { pattern: /\b(?:viewport|timer|minimum|after|hover|idle|immediate|interaction)/ },
84
- function: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/
85
- });
86
- Prism$1.languages["ng"] = Prism$1.languages["angular"];
87
- })();
88
- //#endregion
89
- //#region packages/content/prism-highlighter/src/index.ts
90
- function withPrismHighlighter() {
91
- return [{
92
- provide: ContentRenderer,
93
- useClass: NoopContentRenderer
94
- }];
95
- }
96
- //#endregion
97
- export { PrismHighlighter, withPrismHighlighter };
98
-
99
- //# sourceMappingURL=analogjs-content-prism-highlighter.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"analogjs-content-prism-highlighter.mjs","names":[],"sources":["../../prism-highlighter/src/lib/prism-highlighter.ts","../../prism-highlighter/src/lib/prism/angular.ts","../../prism-highlighter/src/index.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { markedHighlight } from 'marked-highlight';\n\nimport { MarkedContentHighlighter } from '../../../src/lib/marked-content-highlighter';\n\ndeclare const Prism: typeof import('prismjs');\n\ntype HighlightExtension = ReturnType<\n MarkedContentHighlighter['getHighlightExtension']\n>;\n\n@Injectable()\nexport class PrismHighlighter extends MarkedContentHighlighter {\n override augmentCodeBlock(code: string, lang: string): string {\n const classes =\n lang.startsWith('diff') && Prism.languages['diff']\n ? `language-${lang} diff-highlight`\n : `language-${lang.replace('diff-', '')}`;\n return `<pre class=\"${classes}\"><code class=\"${classes}\">${code}</code></pre>`;\n }\n\n override getHighlightExtension(): import('marked').MarkedExtension {\n return markedHighlight({\n async: true,\n highlight: (code: string, lang: string) => {\n let diff = lang?.startsWith('diff-');\n lang = diff ? lang.replace('diff-', '') : lang || 'typescript';\n\n if (diff && !Prism.languages['diff']) {\n diff = false;\n console.warn(`Notice:\n ---------------------------------------------------------------------------------------\n The \\`diff\\` language and plugin are not available in the provided setup.\n To enable it, add the following imports your \\`app.config.ts\\`:\n import 'prismjs/components/prism-diff';\n import 'prismjs/plugins/diff-highlight/prism-diff-highlight';\n ---------------------------------------------------------------------------------------\n `);\n }\n\n if (!Prism.languages[lang]) {\n if (lang !== 'mermaid') {\n console.warn(`Notice:\n ---------------------------------------------------------------------------------------\n The requested language '${lang}' is not available in the provided setup.\n To enable it, add the following import your \\`app.config.ts\\`:\n import 'prismjs/components/prism-${lang}';\n ---------------------------------------------------------------------------------------\n `);\n }\n return code;\n }\n return Prism.highlight(\n code,\n diff ? Prism.languages['diff'] : Prism.languages[lang],\n lang,\n );\n },\n }) as HighlightExtension;\n }\n}\n","import Prism from 'prismjs';\n\n(function () {\n if (typeof Prism === 'undefined') {\n return;\n }\n\n Prism.languages['angular'] = Prism.languages.extend('markup', {\n keyword:\n /(?:@if|@for|@switch|@defer|@loading|@error|@placeholder|prefetch)\\b/,\n operator: /\\b(?:on|when)\\b/,\n number: {\n pattern: /\\b(minimum|after)\\s+\\d+(?:s|ms|)/gi,\n lookbehind: true,\n },\n builtin: {\n pattern:\n /\\b(?:viewport|timer|minimum|after|hover|idle|immediate|interaction)/,\n },\n function:\n /#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*(?:\\.\\s*(?:apply|bind|call)\\s*)?\\()/,\n });\n\n Prism.languages['ng'] = Prism.languages['angular'];\n})();\n","import { Provider } from '@angular/core';\nimport { PrismHighlighter } from './lib/prism-highlighter';\n\nimport {\n ContentRenderer,\n NoopContentRenderer,\n} from '../../src/lib/content-renderer';\nimport 'prismjs';\nimport 'prismjs/plugins/toolbar/prism-toolbar';\nimport 'prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard';\nimport './lib/prism/angular';\n\nexport { PrismHighlighter };\n\nexport function withPrismHighlighter(): Provider[] {\n return [{ provide: ContentRenderer, useClass: NoopContentRenderer }];\n}\n"],"mappings":";;;;;;;;;AAYA,IAAa,mBAAb,MAAa,yBAAyB,yBAAwB;CACnD,iBAAiB,MAAc,MAAY;EAClD,MAAM,UACJ,KAAK,WAAW,OAAO,IAAI,MAAM,UAAU,UACvC,YAAY,KAAI,mBAChB,YAAY,KAAK,QAAQ,SAAS,GAAG;AAC3C,SAAO,eAAe,QAAO,iBAAkB,QAAO,IAAK,KAAI;;CAGxD,wBAAqB;AAC5B,SAAO,gBAAgB;GACrB,OAAO;GACP,YAAY,MAAc,SAAgB;IACxC,IAAI,OAAO,MAAM,WAAW,QAAQ;AACpC,WAAO,OAAO,KAAK,QAAQ,SAAS,GAAG,GAAG,QAAQ;AAElD,QAAI,QAAQ,CAAC,MAAM,UAAU,SAAS;AACpC,YAAO;AACP,aAAQ,KAAK;;;;;;;cAOT;;AAGN,QAAI,CAAC,MAAM,UAAU,OAAO;AAC1B,SAAI,SAAS,UACX,SAAQ,KAAK;;8BAEK,KAAI;;yCAEO,KAAI;;gBAE7B;AAEN,YAAO;;AAET,WAAO,MAAM,UACX,MACA,OAAO,MAAM,UAAU,UAAU,MAAM,UAAU,OACjD,KACD;;GAEJ,CAAuB;;;;;;;SA9Cf;GAAgB,MAAA;GAAA,QAAA,GAAA,gBAAA;GAAA,CAAA;;;;;;;SAAhB;GAAgB,CAAA;;;;;;;OAAhB;CAAgB,YAAA,CAAA,EAAA,MAD5B,YAAA,CAAA;;;;CCTA,WAAA;AACC,KAAI,OAAO,YAAU,YACnB;AAGF,SAAM,UAAU,aAAa,QAAM,UAAU,OAAO,UAAU;EAC5D,SACE;EACF,UAAU;EACV,QAAQ;GACN,SAAS;GACT,YAAY;GACb;EACD,SAAS,EACP,SACE,uEACH;EACD,UACE;EACH,CAAC;AAEF,SAAM,UAAU,QAAQ,QAAM,UAAU;IACtC;;;ACVJ,SAAgB,uBAAoB;AAClC,QAAO,CAAC;EAAE,SAAS;EAAiB,UAAU;EAAqB,CAAC"}
@@ -1,12 +0,0 @@
1
- import { n as NoopContentRenderer, t as ContentRenderer } from "./content-renderer.mjs";
2
- //#region packages/content/shiki-highlighter/src/index.ts
3
- function withShikiHighlighter(_opts = {}) {
4
- return [{
5
- provide: ContentRenderer,
6
- useClass: NoopContentRenderer
7
- }];
8
- }
9
- //#endregion
10
- export { withShikiHighlighter };
11
-
12
- //# sourceMappingURL=analogjs-content-shiki-highlighter.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"analogjs-content-shiki-highlighter.mjs","names":[],"sources":["../../shiki-highlighter/src/index.ts"],"sourcesContent":["import { Provider } from '@angular/core';\nimport type {\n BundledLanguage,\n BundledTheme,\n CodeOptionsMeta,\n CodeOptionsMultipleThemes,\n CodeOptionsSingleTheme,\n CodeToHastOptionsCommon,\n} from 'shiki';\n\nimport {\n ContentRenderer,\n NoopContentRenderer,\n} from '../../src/lib/content-renderer';\n\nexport type ShikiHighlightOptions = Partial<\n Omit<CodeToHastOptionsCommon<BundledLanguage>, 'lang'>\n> &\n CodeOptionsMeta &\n Partial<CodeOptionsSingleTheme<BundledTheme>> &\n Partial<CodeOptionsMultipleThemes<BundledTheme>>;\n\nexport type WithShikiHighlighterOptions = ShikiHighlightOptions & {\n container?: string;\n};\n\nexport function withShikiHighlighter(\n _opts: WithShikiHighlighterOptions = {},\n): Provider[] {\n return [\n {\n provide: ContentRenderer,\n useClass: NoopContentRenderer,\n },\n ];\n}\n"],"mappings":";;AA0BA,SAAgB,qBACd,QAAqC,EAAE,EAAA;AAEvC,QAAO,CACL;EACE,SAAS;EACT,UAAU;EACX,CACF"}
@@ -1,128 +0,0 @@
1
- import * as i0 from "@angular/core";
2
- import { Injectable, TransferState, inject, makeStateKey } from "@angular/core";
3
- //#region packages/content/src/lib/content-renderer.ts
4
- var ContentRenderer = class ContentRenderer {
5
- async render(content) {
6
- return {
7
- content,
8
- toc: []
9
- };
10
- }
11
- getContentHeadings(_content) {
12
- return [];
13
- }
14
- enhance() {}
15
- static {
16
- this.ɵfac = i0.ɵɵngDeclareFactory({
17
- minVersion: "12.0.0",
18
- version: "22.2.0",
19
- ngImport: i0,
20
- type: ContentRenderer,
21
- deps: [],
22
- target: i0.ɵɵFactoryTarget.Injectable
23
- });
24
- }
25
- static {
26
- this.ɵprov = i0.ɵɵngDeclareInjectable({
27
- minVersion: "12.0.0",
28
- version: "22.2.0",
29
- ngImport: i0,
30
- type: ContentRenderer
31
- });
32
- }
33
- };
34
- i0.ɵɵngDeclareClassMetadata({
35
- minVersion: "12.0.0",
36
- version: "22.2.0",
37
- ngImport: i0,
38
- type: ContentRenderer,
39
- decorators: [{ type: Injectable }]
40
- });
41
- var NoopContentRenderer = class {
42
- constructor() {
43
- this.transferState = inject(TransferState);
44
- this.contentId = 0;
45
- }
46
- /**
47
- * Generates a hash from the content string
48
- * to be used with the transfer state
49
- */
50
- generateHash(str) {
51
- let hash = 0;
52
- for (let i = 0, len = str.length; i < len; i++) {
53
- const chr = str.charCodeAt(i);
54
- hash = (hash << 5) - hash + chr;
55
- hash |= 0;
56
- }
57
- return hash;
58
- }
59
- async render(content) {
60
- this.contentId = this.generateHash(content);
61
- const toc = this.getContentHeadings(content);
62
- const key = makeStateKey(`content-headings-${this.contentId}`);
63
- return {
64
- content,
65
- toc: this.transferState.get(key, toc)
66
- };
67
- }
68
- enhance() {}
69
- getContentHeadings(content) {
70
- return this.extractHeadings(content);
71
- }
72
- extractHeadings(content) {
73
- const markdownHeadings = this.extractHeadingsFromMarkdown(content);
74
- if (markdownHeadings.length > 0) return markdownHeadings;
75
- return this.extractHeadingsFromHtml(content);
76
- }
77
- extractHeadingsFromMarkdown(content) {
78
- const lines = content.split("\n");
79
- const toc = [];
80
- const slugCounts = /* @__PURE__ */ new Map();
81
- for (const line of lines) {
82
- const match = /^(#{1,6})\s+(.+?)\s*$/.exec(line);
83
- if (!match) continue;
84
- const level = match[1].length;
85
- const text = match[2].trim();
86
- if (!text) continue;
87
- const baseSlug = text.toLowerCase().replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-");
88
- const count = slugCounts.get(baseSlug) ?? 0;
89
- slugCounts.set(baseSlug, count + 1);
90
- const id = count === 0 ? baseSlug : `${baseSlug}-${count}`;
91
- toc.push({
92
- id,
93
- level,
94
- text
95
- });
96
- }
97
- return toc;
98
- }
99
- extractHeadingsFromHtml(content) {
100
- const toc = [];
101
- const slugCounts = /* @__PURE__ */ new Map();
102
- for (const match of content.matchAll(/<h([1-6])([^>]*)>([\s\S]*?)<\/h\1>/gi)) {
103
- const level = Number(match[1]);
104
- const attrs = match[2] ?? "";
105
- const text = (match[3] ?? "").replace(/<[^>]+>/g, "").trim();
106
- if (!text) continue;
107
- const idMatch = /\sid=(['"])(.*?)\1/i.exec(attrs) ?? /\sid=([^\s>]+)/i.exec(attrs);
108
- let id = idMatch?.[2] ?? idMatch?.[1] ?? "";
109
- if (!id) id = this.makeSlug(text, slugCounts);
110
- toc.push({
111
- id,
112
- level,
113
- text
114
- });
115
- }
116
- return toc;
117
- }
118
- makeSlug(text, slugCounts) {
119
- const baseSlug = text.toLowerCase().replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-");
120
- const count = slugCounts.get(baseSlug) ?? 0;
121
- slugCounts.set(baseSlug, count + 1);
122
- return count === 0 ? baseSlug : `${baseSlug}-${count}`;
123
- }
124
- };
125
- //#endregion
126
- export { NoopContentRenderer as n, ContentRenderer as t };
127
-
128
- //# sourceMappingURL=content-renderer.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"content-renderer.mjs","names":[],"sources":["../../src/lib/content-renderer.ts"],"sourcesContent":["/// <reference types=\"vite/client\" />\n\nimport { Injectable, TransferState, inject, makeStateKey } from '@angular/core';\n\nexport type TableOfContentItem = {\n id: string;\n level: number; // starts at 1\n text: string;\n};\n\nexport type RenderedContent = {\n content: string;\n toc: TableOfContentItem[];\n};\n\n@Injectable()\nexport abstract class ContentRenderer {\n async render(content: string): Promise<RenderedContent> {\n return { content, toc: [] };\n }\n\n // Backward-compatible API for consumers that read headings directly.\n getContentHeadings(_content: string): TableOfContentItem[] {\n return [];\n }\n\n // eslint-disable-next-line\n enhance(): void {}\n}\n\nexport class NoopContentRenderer implements ContentRenderer {\n private readonly transferState = inject(TransferState);\n private contentId = 0;\n\n /**\n * Generates a hash from the content string\n * to be used with the transfer state\n */\n private generateHash(str: string) {\n let hash = 0;\n for (let i = 0, len = str.length; i < len; i++) {\n const chr = str.charCodeAt(i);\n hash = (hash << 5) - hash + chr;\n hash |= 0; // Convert to 32bit integer\n }\n return hash;\n }\n\n async render(content: string): Promise<RenderedContent> {\n this.contentId = this.generateHash(content);\n const toc = this.getContentHeadings(content);\n const key = makeStateKey<TableOfContentItem[]>(\n `content-headings-${this.contentId}`,\n );\n\n if (import.meta.env.SSR === true) {\n this.transferState.set(key, toc);\n return { content, toc };\n }\n\n return {\n content,\n toc: this.transferState.get(key, toc),\n };\n }\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n enhance(): void {}\n\n getContentHeadings(content: string): TableOfContentItem[] {\n return this.extractHeadings(content);\n }\n\n private extractHeadings(content: string): TableOfContentItem[] {\n const markdownHeadings = this.extractHeadingsFromMarkdown(content);\n if (markdownHeadings.length > 0) {\n return markdownHeadings;\n }\n\n const htmlHeadings = this.extractHeadingsFromHtml(content);\n return htmlHeadings;\n }\n\n private extractHeadingsFromMarkdown(content: string): TableOfContentItem[] {\n const lines = content.split('\\n');\n const toc: TableOfContentItem[] = [];\n const slugCounts = new Map<string, number>();\n\n for (const line of lines) {\n const match = /^(#{1,6})\\s+(.+?)\\s*$/.exec(line);\n if (!match) {\n continue;\n }\n\n const level = match[1].length;\n const text = match[2].trim();\n if (!text) {\n continue;\n }\n\n const baseSlug = text\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .trim()\n .replace(/\\s+/g, '-');\n const count = slugCounts.get(baseSlug) ?? 0;\n slugCounts.set(baseSlug, count + 1);\n const id = count === 0 ? baseSlug : `${baseSlug}-${count}`;\n\n toc.push({ id, level, text });\n }\n\n return toc;\n }\n\n private extractHeadingsFromHtml(content: string): TableOfContentItem[] {\n const toc: TableOfContentItem[] = [];\n const slugCounts = new Map<string, number>();\n const headingRegex = /<h([1-6])([^>]*)>([\\s\\S]*?)<\\/h\\1>/gi;\n\n for (const match of content.matchAll(headingRegex)) {\n const level = Number(match[1]);\n const attrs = match[2] ?? '';\n const rawInner = match[3] ?? '';\n const text = rawInner.replace(/<[^>]+>/g, '').trim();\n if (!text) {\n continue;\n }\n\n const idMatch =\n /\\sid=(['\"])(.*?)\\1/i.exec(attrs) ?? /\\sid=([^\\s>]+)/i.exec(attrs);\n let id = idMatch?.[2] ?? idMatch?.[1] ?? '';\n if (!id) {\n id = this.makeSlug(text, slugCounts);\n }\n\n toc.push({ id, level, text });\n }\n\n return toc;\n }\n\n private makeSlug(text: string, slugCounts: Map<string, number>): string {\n const baseSlug = text\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .trim()\n .replace(/\\s+/g, '-');\n const count = slugCounts.get(baseSlug) ?? 0;\n slugCounts.set(baseSlug, count + 1);\n return count === 0 ? baseSlug : `${baseSlug}-${count}`;\n }\n}\n"],"mappings":"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"}
@@ -1,40 +0,0 @@
1
- import * as i0 from "@angular/core";
2
- import { Injectable } from "@angular/core";
3
- //#region packages/content/src/lib/marked-content-highlighter.ts
4
- var MarkedContentHighlighter = class MarkedContentHighlighter {
5
- static {
6
- this.ɵfac = i0.ɵɵngDeclareFactory({
7
- minVersion: "12.0.0",
8
- version: "22.2.0",
9
- ngImport: i0,
10
- type: MarkedContentHighlighter,
11
- deps: [],
12
- target: i0.ɵɵFactoryTarget.Injectable
13
- });
14
- }
15
- static {
16
- this.ɵprov = i0.ɵɵngDeclareInjectable({
17
- minVersion: "12.0.0",
18
- version: "22.2.0",
19
- ngImport: i0,
20
- type: MarkedContentHighlighter
21
- });
22
- }
23
- };
24
- i0.ɵɵngDeclareClassMetadata({
25
- minVersion: "12.0.0",
26
- version: "22.2.0",
27
- ngImport: i0,
28
- type: MarkedContentHighlighter,
29
- decorators: [{ type: Injectable }]
30
- });
31
- function withHighlighter(provider) {
32
- return {
33
- provide: MarkedContentHighlighter,
34
- ...provider
35
- };
36
- }
37
- //#endregion
38
- export { withHighlighter as n, MarkedContentHighlighter as t };
39
-
40
- //# sourceMappingURL=marked-content-highlighter.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"marked-content-highlighter.mjs","names":[],"sources":["../../src/lib/marked-content-highlighter.ts"],"sourcesContent":["import {\n AbstractType,\n Injectable,\n Provider,\n ProviderToken,\n Type,\n} from '@angular/core';\n\n@Injectable()\nexport abstract class MarkedContentHighlighter {\n augmentCodeBlock?(code: string, lang: string): string;\n abstract getHighlightExtension(): import('marked').MarkedExtension;\n}\n\nexport function withHighlighter(\n provider: (\n | { useValue: MarkedContentHighlighter }\n | {\n useClass:\n | Type<MarkedContentHighlighter>\n | AbstractType<MarkedContentHighlighter>;\n }\n | { useFactory: (...deps: any[]) => MarkedContentHighlighter }\n ) & { deps?: ProviderToken<any>[] },\n): Provider {\n return { provide: MarkedContentHighlighter, ...provider } as Provider;\n}\n"],"mappings":";;;AASA,IAAsB,2BAAtB,MAAsB,yBAAwB;;;;;;SAAxB;GAAwB,MAAA,EAAA;GAAA,QAAA,GAAA,gBAAA;GAAA,CAAA;;;;;;;SAAxB;GAAwB,CAAA;;;;;;;OAAxB;CAAwB,YAAA,CAAA,EAAA,MAD7C,YAAA,CAAA;;AAMD,SAAgB,gBACd,UAQmC;AAEnC,QAAO;EAAE,SAAS;EAA0B,GAAG;EAAsB"}
@@ -1,6 +0,0 @@
1
- import { convertNxGenerator } from "@nx/devkit";
2
-
3
- //#region src/migrations/update-markdown-version/compat.d.ts
4
- declare const _default: ReturnType<typeof convertNxGenerator>;
5
- export = _default;
6
- //# sourceMappingURL=compat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"compat.d.ts","names":[],"sources":["../../../../../../content-plugin/src/migrations/update-markdown-version/compat.ts"],"mappings":";;;cAGM,QAAA,EAAU,UAAA,QAAkB,kBAAA;AAAA"}
@@ -1,9 +0,0 @@
1
- const require_src_migrations_update_markdown_version_update_markdown_version = require('./update-markdown-version.js');
2
- let _nx_devkit = require("@nx/devkit");
3
-
4
- //#region src/migrations/update-markdown-version/compat.ts
5
- const _default = (0, _nx_devkit.convertNxGenerator)(require_src_migrations_update_markdown_version_update_markdown_version);
6
-
7
- //#endregion
8
- module.exports = _default;
9
- //# sourceMappingURL=compat.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"compat.js","names":["updateMarkdownVersion"],"sources":["../../../../../../content-plugin/src/migrations/update-markdown-version/compat.ts"],"sourcesContent":["import { convertNxGenerator } from '@nx/devkit';\nimport updateMarkdownVersion from './update-markdown-version';\n\nconst _default: ReturnType<typeof convertNxGenerator> = convertNxGenerator(\n updateMarkdownVersion,\n);\nexport default _default;\n"],"mappings":";;;;AAGA,MAAM,8CACJA,uEACD"}
@@ -1,6 +0,0 @@
1
- import { Tree } from "@nx/devkit";
2
-
3
- //#region src/migrations/update-markdown-version/update-markdown-version.d.ts
4
- declare function update(host: Tree): Promise<(() => void) | undefined>;
5
- export = update;
6
- //# sourceMappingURL=update-markdown-version.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"update-markdown-version.d.ts","names":[],"sources":["../../../../../../content-plugin/src/migrations/update-markdown-version/update-markdown-version.ts"],"mappings":";;;iBAO8B,MAAA,CAC5B,IAAA,EAAM,IAAA,GACL,OAAA;AAAA"}
@@ -1,21 +0,0 @@
1
- let _nx_devkit = require("@nx/devkit");
2
-
3
- //#region src/migrations/update-markdown-version/update-markdown-version.ts
4
- async function update(host) {
5
- let dependencyAdded = false;
6
- if (host.exists("/angular.json")) {
7
- (0, _nx_devkit.addDependenciesToPackageJson)(host, {
8
- marked: "^18.0.0",
9
- "marked-mangle": "^1.1.10",
10
- "marked-highlight": "^2.2.1",
11
- "marked-gfm-heading-id": "^4.1.1"
12
- }, {});
13
- dependencyAdded = true;
14
- }
15
- await (0, _nx_devkit.formatFiles)(host);
16
- if (dependencyAdded) return () => (0, _nx_devkit.installPackagesTask)(host);
17
- }
18
-
19
- //#endregion
20
- module.exports = update;
21
- //# sourceMappingURL=update-markdown-version.js.map