@analogjs/content 3.0.0-alpha.25 → 3.0.0-alpha.27

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.
@@ -46,7 +46,7 @@ var DevToolsContentRenderer = class DevToolsContentRenderer extends ContentRende
46
46
  static {
47
47
  this.ɵfac = i0.ɵɵngDeclareFactory({
48
48
  minVersion: "12.0.0",
49
- version: "21.2.6",
49
+ version: "21.2.8",
50
50
  ngImport: i0,
51
51
  type: DevToolsContentRenderer,
52
52
  deps: null,
@@ -56,7 +56,7 @@ var DevToolsContentRenderer = class DevToolsContentRenderer extends ContentRende
56
56
  static {
57
57
  this.ɵprov = i0.ɵɵngDeclareInjectable({
58
58
  minVersion: "12.0.0",
59
- version: "21.2.6",
59
+ version: "21.2.8",
60
60
  ngImport: i0,
61
61
  type: DevToolsContentRenderer
62
62
  });
@@ -64,7 +64,7 @@ var DevToolsContentRenderer = class DevToolsContentRenderer extends ContentRende
64
64
  };
65
65
  i0.ɵɵngDeclareClassMetadata({
66
66
  minVersion: "12.0.0",
67
- version: "21.2.6",
67
+ version: "21.2.8",
68
68
  ngImport: i0,
69
69
  type: DevToolsContentRenderer,
70
70
  decorators: [{ type: Injectable }]
@@ -69,7 +69,7 @@ var Md4xContentRendererService = class Md4xContentRendererService extends Conten
69
69
  static {
70
70
  this.ɵfac = i0.ɵɵngDeclareFactory({
71
71
  minVersion: "12.0.0",
72
- version: "21.2.6",
72
+ version: "21.2.8",
73
73
  ngImport: i0,
74
74
  type: Md4xContentRendererService,
75
75
  deps: null,
@@ -79,7 +79,7 @@ var Md4xContentRendererService = class Md4xContentRendererService extends Conten
79
79
  static {
80
80
  this.ɵprov = i0.ɵɵngDeclareInjectable({
81
81
  minVersion: "12.0.0",
82
- version: "21.2.6",
82
+ version: "21.2.8",
83
83
  ngImport: i0,
84
84
  type: Md4xContentRendererService
85
85
  });
@@ -87,7 +87,7 @@ var Md4xContentRendererService = class Md4xContentRendererService extends Conten
87
87
  };
88
88
  i0.ɵɵngDeclareClassMetadata({
89
89
  minVersion: "12.0.0",
90
- version: "21.2.6",
90
+ version: "21.2.8",
91
91
  ngImport: i0,
92
92
  type: Md4xContentRendererService,
93
93
  decorators: [{ type: Injectable }]
@@ -162,7 +162,7 @@ var Md4xWasmContentRendererService = class Md4xWasmContentRendererService extend
162
162
  static {
163
163
  this.ɵfac = i0.ɵɵngDeclareFactory({
164
164
  minVersion: "12.0.0",
165
- version: "21.2.6",
165
+ version: "21.2.8",
166
166
  ngImport: i0,
167
167
  type: Md4xWasmContentRendererService,
168
168
  deps: null,
@@ -172,7 +172,7 @@ var Md4xWasmContentRendererService = class Md4xWasmContentRendererService extend
172
172
  static {
173
173
  this.ɵprov = i0.ɵɵngDeclareInjectable({
174
174
  minVersion: "12.0.0",
175
- version: "21.2.6",
175
+ version: "21.2.8",
176
176
  ngImport: i0,
177
177
  type: Md4xWasmContentRendererService
178
178
  });
@@ -180,7 +180,7 @@ var Md4xWasmContentRendererService = class Md4xWasmContentRendererService extend
180
180
  };
181
181
  i0.ɵɵngDeclareClassMetadata({
182
182
  minVersion: "12.0.0",
183
- version: "21.2.6",
183
+ version: "21.2.8",
184
184
  ngImport: i0,
185
185
  type: Md4xWasmContentRendererService,
186
186
  decorators: [{ type: Injectable }]
@@ -117,7 +117,7 @@ var MdcRendererDirective = class MdcRendererDirective {
117
117
  static {
118
118
  this.ɵfac = i0.ɵɵngDeclareFactory({
119
119
  minVersion: "12.0.0",
120
- version: "21.2.6",
120
+ version: "21.2.8",
121
121
  ngImport: i0,
122
122
  type: MdcRendererDirective,
123
123
  deps: [],
@@ -127,7 +127,7 @@ var MdcRendererDirective = class MdcRendererDirective {
127
127
  static {
128
128
  this.ɵdir = i0.ɵɵngDeclareDirective({
129
129
  minVersion: "17.1.0",
130
- version: "21.2.6",
130
+ version: "21.2.8",
131
131
  type: MdcRendererDirective,
132
132
  isStandalone: true,
133
133
  selector: "[mdcAst]",
@@ -144,7 +144,7 @@ var MdcRendererDirective = class MdcRendererDirective {
144
144
  };
145
145
  i0.ɵɵngDeclareClassMetadata({
146
146
  minVersion: "12.0.0",
147
- version: "21.2.6",
147
+ version: "21.2.8",
148
148
  ngImport: i0,
149
149
  type: MdcRendererDirective,
150
150
  decorators: [{
@@ -1,6 +1,7 @@
1
+ import { n as NoopContentRenderer, t as ContentRenderer } from "./content-renderer.mjs";
2
+ import { t as MarkedContentHighlighter } from "./marked-content-highlighter.mjs";
1
3
  import * as i0 from "@angular/core";
2
4
  import { Injectable } from "@angular/core";
3
- import { ContentRenderer, MarkedContentHighlighter, NoopContentRenderer } from "@analogjs/content";
4
5
  import { markedHighlight } from "marked-highlight";
5
6
  import Prism$1 from "prismjs";
6
7
  import "prismjs/plugins/toolbar/prism-toolbar";
@@ -45,7 +46,7 @@ var PrismHighlighter = class PrismHighlighter extends MarkedContentHighlighter {
45
46
  static {
46
47
  this.ɵfac = i0.ɵɵngDeclareFactory({
47
48
  minVersion: "12.0.0",
48
- version: "21.2.6",
49
+ version: "21.2.8",
49
50
  ngImport: i0,
50
51
  type: PrismHighlighter,
51
52
  deps: null,
@@ -55,7 +56,7 @@ var PrismHighlighter = class PrismHighlighter extends MarkedContentHighlighter {
55
56
  static {
56
57
  this.ɵprov = i0.ɵɵngDeclareInjectable({
57
58
  minVersion: "12.0.0",
58
- version: "21.2.6",
59
+ version: "21.2.8",
59
60
  ngImport: i0,
60
61
  type: PrismHighlighter
61
62
  });
@@ -63,7 +64,7 @@ var PrismHighlighter = class PrismHighlighter extends MarkedContentHighlighter {
63
64
  };
64
65
  i0.ɵɵngDeclareClassMetadata({
65
66
  minVersion: "12.0.0",
66
- version: "21.2.6",
67
+ version: "21.2.8",
67
68
  ngImport: i0,
68
69
  type: PrismHighlighter,
69
70
  decorators: [{ type: Injectable }]
@@ -1 +1 @@
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 { MarkedContentHighlighter } from '@analogjs/content';\nimport { Injectable } from '@angular/core';\nimport { markedHighlight } from 'marked-highlight';\n\ndeclare const Prism: typeof import('prismjs');\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 });\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 { ContentRenderer, NoopContentRenderer } from '@analogjs/content';\nimport { Provider } from '@angular/core';\nimport { PrismHighlighter } from './lib/prism-highlighter';\n\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":";;;;;;;;AAOO,IAAA,mBAAA,MAAA,yBAAM,yBAAyB;CACpC,iBAA0B,MAAc,MAAsB;EACtD,MAAA,UACC,KAAA,WAAW,OAAW,IAAM,MAAA,UAAU,UAGtC,YAAe,KAAA,mBAAA,YAAA,KAAA,QAAA,SAAA,GAAA;AAGxB,SAAA,eAAmE,QAAA,iBAAA,QAAA,IAAA,KAAA;;CAE/D,wBAAO;AACP,SAAY,gBAA+B;GACrC,OAAO;GACJ,YAAY,MAAA,SAAQ;IAEf,IAAC,OAAM,MAAU,WAAS,QAAA;AAC7B,WAAA,OAAA,KAAA,QAAA,SAAA,GAAA,GAAA,QAAA;AACC,QAAK,QAAA,CAAA,MAAA,UAAA,SAAA;;;;;;;;;cAUV;;AAEO,QAAK,CAAA,MAAA,UAAA,OAAA;qCAEK,KAAK;;;;yCAInB,KAAA;;gBAEC;AAEI,YACX;;AAKJ,WAAA,MAAA,UAAA,MAAA,OAAA,MAAA,UAAA,UAAA,MAAA,UAAA,OAAA,KAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CCnDL,WAAY;AACX,KAAI,OAAO,YAAU,YACnB;AAGF,SAAM,UAAU,aAAa,QAAM,UAAU,OAAO,UAAU;EAC5D,SACE;EACF,UAAU;EACV,QAAQ;GACG,SAAA;GACT,YAAY;GACb;EACD,SACE,EAIA,SAAA,uEACF;EAEI,UAAU;EACd,CAAA;;;;;ACbJ,SAAgB,uBAAmC;AACjD,QAAQ,CAAA;EAAA,SAAA;EAAA,UAAA;EAAA,CAAA"}
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\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 });\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":";;;;;;;;;AAQO,IAAA,mBAAA,MAAA,yBAAM,yBAAyB;CACpC,iBAA0B,MAAc,MAAsB;EACtD,MAAA,UACC,KAAA,WAAW,OAAW,IAAM,MAAA,UAAU,UAGtC,YAAe,KAAA,mBAAA,YAAA,KAAA,QAAA,SAAA,GAAA;AAGxB,SAAA,eAAmE,QAAA,iBAAA,QAAA,IAAA,KAAA;;CAE/D,wBAAO;AACP,SAAY,gBAA+B;GACrC,OAAO;GACJ,YAAY,MAAA,SAAQ;IAEf,IAAC,OAAM,MAAU,WAAS,QAAA;AAC7B,WAAA,OAAA,KAAA,QAAA,SAAA,GAAA,GAAA,QAAA;AACC,QAAK,QAAA,CAAA,MAAA,UAAA,SAAA;;;;;;;;;cAUV;;AAEO,QAAK,CAAA,MAAA,UAAA,OAAA;qCAEK,KAAK;;;;yCAInB,KAAA;;gBAEC;AAEI,YACX;;AAKJ,WAAA,MAAA,UAAA,MAAA,OAAA,MAAA,UAAA,UAAA,MAAA,UAAA,OAAA,KAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CCpDL,WAAY;AACX,KAAI,OAAO,YAAU,YACnB;AAGF,SAAM,UAAU,aAAa,QAAM,UAAU,OAAO,UAAU;EAC5D,SACE;EACF,UAAU;EACV,QAAQ;GACG,SAAA;GACT,YAAY;GACb;EACD,SACE,EAIA,SAAA,uEACF;EAEI,UAAU;EACd,CAAA;;;;;ACVJ,SAAgB,uBAAmC;AACjD,QAAQ,CAAA;EAAA,SAAA;EAAA,UAAA;EAAA,CAAA"}
@@ -1,9 +1,11 @@
1
+ import { t as ContentRenderer } from "./content-renderer.mjs";
2
+ import { a as injectContentFileLoader, n as injectContentListLoader } from "./content-list-loader.mjs";
3
+ import { n as parseRawContentFile, r as parseRawContentFileAsync, t as FrontmatterValidationError } from "./parse-raw-content-file.mjs";
1
4
  import { computed, inject, resource } from "@angular/core";
2
5
  import { ActivatedRoute } from "@angular/router";
3
6
  import { from } from "rxjs";
4
7
  import { map } from "rxjs/operators";
5
8
  import { toSignal } from "@angular/core/rxjs-interop";
6
- import { ContentRenderer, FrontmatterValidationError, injectContentFileLoader, injectContentListLoader, parseRawContentFile, parseRawContentFileAsync } from "@analogjs/content";
7
9
  //#region packages/content/resources/src/content-files-resource.ts
8
10
  function contentFilesResource(filterFn) {
9
11
  const contentList = injectContentListLoader()().then((items) => filterFn ? items.filter(filterFn) : items);
@@ -1 +1 @@
1
- {"version":3,"file":"analogjs-content-resources.mjs","names":[],"sources":["../../resources/src/content-files-resource.ts","../../resources/src/content-file-resource.ts"],"sourcesContent":["import { resource, ResourceRef } from '@angular/core';\nimport {\n ContentFile,\n injectContentListLoader,\n InjectContentFilesFilterFunction,\n} from '@analogjs/content';\n\nexport function contentFilesResource<Attributes extends Record<string, any>>(\n filterFn?: InjectContentFilesFilterFunction<Attributes> | undefined,\n): ResourceRef<ContentFile<Attributes>[] | undefined> {\n const contentListLoader = injectContentListLoader<Attributes>();\n const contentList = contentListLoader().then((items) =>\n filterFn ? items.filter(filterFn) : items,\n );\n\n return resource({\n loader: () => contentList,\n });\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport {\n computed,\n inject,\n resource,\n Signal,\n type ResourceRef,\n} from '@angular/core';\nimport {\n ContentFile,\n ContentRenderer,\n FrontmatterValidationError,\n parseRawContentFile,\n parseRawContentFileAsync,\n injectContentFileLoader,\n} from '@analogjs/content';\nimport { ActivatedRoute } from '@angular/router';\n\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { from } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nexport interface ContentFileResourceResult<\n Attributes extends Record<string, any> = Record<string, any>,\n> extends ContentFile<Attributes | Record<string, never>> {\n toc: Array<{ id: string; level: number; text: string }>;\n}\n\ntype ContentFileParams =\n | Signal<string | { customFilename: string }>\n | Signal<string>\n | Signal<{ customFilename: string }>;\n\nasync function validateAttributes<TSchema extends StandardSchemaV1>(\n schema: TSchema,\n attributes: unknown,\n filename?: string,\n) {\n const result = await schema['~standard'].validate(attributes);\n if (result.issues) {\n throw new FrontmatterValidationError(result.issues, filename);\n }\n\n return result.value;\n}\n\nfunction getValidationFilename(filename: string): string {\n return filename.replace(/^\\/src\\/content\\//, '');\n}\n\nasync function getContentFile<\n Attributes extends Record<string, any> = Record<string, any>,\n>(\n contentFiles: Record<string, () => Promise<string>>,\n slug: string,\n fallback: string,\n schema?: StandardSchemaV1,\n): Promise<ContentFile<Attributes | Record<string, never>>> {\n // Normalize file keys so both \"/src/content/...\" and \"/<project>/src/content/...\" resolve.\n // This mirrors normalization used elsewhere in the content pipeline.\n const normalizedFiles: Record<string, () => Promise<string>> = {};\n const stemToKey: Record<string, string> = {};\n for (const [key, resolver] of Object.entries(contentFiles)) {\n const normalizedKey = key\n // replace any prefix up to the content directory with /src/content\n // use a non-greedy match so nested paths containing \"/content\" are preserved\n .replace(/^(?:.*?)\\/content(?=\\/)/, '/src/content')\n // normalize duplicate slashes\n .replace(/\\/{2,}/g, '/');\n normalizedFiles[normalizedKey] = resolver;\n // Index by bare filename stem so slug-only lookups work\n const stem = normalizedKey\n .split('/')\n .pop()\n ?.replace(/\\.[^.]+$/, '');\n if (stem && !stemToKey[stem]) {\n stemToKey[stem] = normalizedKey;\n }\n }\n\n // Try direct file first, then directory index variants, then bare slug via stem\n const base = `/src/content/${slug}`.replace(/\\/{2,}/g, '/');\n const candidates = [`${base}.md`, `${base}/index.md`];\n\n const matchKey =\n candidates.find((k) => k in normalizedFiles) ?? stemToKey[slug];\n const contentFile = matchKey ? normalizedFiles[matchKey] : undefined;\n\n if (!contentFile) {\n return {\n filename: base,\n attributes: {},\n slug: '',\n content: fallback,\n } as ContentFile<Attributes | Record<string, never>>;\n }\n\n const resolvedBase = matchKey!.replace(/\\.md$/, '');\n const validationFilename = getValidationFilename(matchKey!);\n\n return contentFile().then(\n async (contentFile: string | { default: any; metadata: any }) => {\n if (typeof contentFile === 'string') {\n const { content, attributes } = schema\n ? await parseRawContentFileAsync(\n contentFile,\n schema,\n validationFilename,\n )\n : parseRawContentFile<Attributes>(contentFile);\n\n return {\n filename: resolvedBase,\n slug,\n attributes,\n content,\n } as ContentFile<Attributes | Record<string, never>>;\n }\n\n const attributes = schema\n ? await validateAttributes(\n schema,\n contentFile.metadata,\n validationFilename,\n )\n : contentFile.metadata;\n\n return {\n filename: resolvedBase,\n slug,\n attributes,\n content: contentFile.default,\n } as ContentFile<Attributes | Record<string, never>>;\n },\n );\n}\n\n/**\n * Resource for requesting an individual content file.\n *\n * @example\n * ```typescript\n * // Without schema (existing behavior)\n * const post = contentFileResource<BlogAttributes>();\n *\n * // With schema validation\n * import * as v from 'valibot';\n * const BlogSchema = v.object({\n * title: v.string(),\n * date: v.pipe(v.string(), v.isoDate()),\n * });\n * const post = contentFileResource({ schema: BlogSchema });\n * ```\n */\nexport function contentFileResource<\n Attributes extends Record<string, any> = Record<string, any>,\n>(\n params?: ContentFileParams,\n fallback?: string,\n): ResourceRef<ContentFileResourceResult<Attributes> | undefined>;\n\nexport function contentFileResource<TSchema extends StandardSchemaV1>(options: {\n params?: ContentFileParams;\n fallback?: string;\n schema: TSchema;\n}): ResourceRef<\n | ContentFileResourceResult<\n StandardSchemaV1.InferOutput<TSchema> & Record<string, any>\n >\n | undefined\n>;\n\nexport function contentFileResource(\n paramsOrOptions?:\n | ContentFileParams\n | {\n params?: ContentFileParams;\n fallback?: string;\n schema?: StandardSchemaV1;\n },\n fallbackArg = 'No Content Found',\n) {\n // Detect options-object form vs legacy positional form\n const isOptionsObject =\n paramsOrOptions &&\n typeof paramsOrOptions === 'object' &&\n !('set' in paramsOrOptions) && // not a Signal\n ('schema' in paramsOrOptions ||\n 'params' in paramsOrOptions ||\n 'fallback' in paramsOrOptions);\n\n const params: ContentFileParams | undefined = isOptionsObject\n ? (paramsOrOptions as { params?: ContentFileParams }).params\n : (paramsOrOptions as ContentFileParams | undefined);\n const fallback: string = isOptionsObject\n ? ((paramsOrOptions as { fallback?: string }).fallback ??\n 'No Content Found')\n : fallbackArg;\n const schema: StandardSchemaV1 | undefined = isOptionsObject\n ? (paramsOrOptions as { schema?: StandardSchemaV1 }).schema\n : undefined;\n\n const loaderPromise = injectContentFileLoader();\n const contentRenderer = inject(ContentRenderer);\n const contentFilesMap = toSignal(from(loaderPromise()));\n const input =\n params ||\n toSignal(\n inject(ActivatedRoute).paramMap.pipe(\n map((params) => params.get('slug') as string),\n ),\n { requireSync: true },\n );\n\n return resource({\n params: computed(() => ({ input: input(), files: contentFilesMap() })),\n loader: async ({ params: resourceParams }) => {\n const { input: param, files } = resourceParams;\n\n if (typeof param === 'string') {\n if (param) {\n const file = await getContentFile(files!, param, fallback, schema);\n if (typeof file.content === 'string') {\n const rendered = (await contentRenderer.render(file.content)) as {\n toc?: Array<{ id: string; level: number; text: string }>;\n };\n return {\n ...file,\n toc: rendered.toc ?? [],\n };\n }\n return {\n ...file,\n toc: [],\n };\n }\n\n return {\n filename: '',\n slug: '',\n attributes: {},\n content: fallback,\n toc: [],\n };\n } else {\n const file = await getContentFile(\n files!,\n param.customFilename,\n fallback,\n schema,\n );\n if (typeof file.content === 'string') {\n const rendered = (await contentRenderer.render(file.content)) as {\n toc?: Array<{ id: string; level: number; text: string }>;\n };\n return {\n ...file,\n toc: rendered.toc ?? [],\n };\n }\n return {\n ...file,\n toc: [],\n };\n }\n },\n });\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,qBACd,UACoD;CAEpD,MAAM,cADoB,yBAAqC,EACvB,CAAA,MAAM,UAC5C,WAAW,MAAM,OAAO,SAAY,GAAA,MACrC;AAED,QAAO,SACL,EAAA,cAAA,aAAA,CAAA;;;;ACiBJ,eAAe,mBACb,QACA,YACA,UACA;CACA,MAAM,SAAS,MAAM,OAAO,aAAa,SAAS,WAAW;AAC7D,KAAI,OAAO,OACH,OAAI,IAAA,2BAA2B,OAAO,QAAQ,SAAS;AAG/D,QAAO,OAAO;;AAGhB,SAAS,sBAAsB,UAA0B;AACvD,QAAO,SAAS,QAAQ,qBAAwB,GAAA;;AAGlD,eAAe,eAGb,cACA,MACA,UACA,QAC0D;CAK1D,MAAK,kBAAY,EAAA;CACf,MAAM,YAAA,EAAgB;AAMtB,MAAA,MAAA,CAAA,KAAgB,aAAA,OAAiB,QAAA,aAAA,EAAA;EAE3B,MAAA,gBACH,IAAA,QAAA,2BAAA,eAAA,CASC,QAAO,WAAgB,IAAA;AACvB,kBAAiB,iBAAc;EAI/B,MAAA,OAAc,cAEf,MAAa,IAAA,CACT,KAAA,EACK,QAAA,YAAA,GAAA;AACV,MAAA,QAAc,CAAA,UAAA,MACR,WAAA,QAAA;;CAKV,MAAM,OAAA,gBAAyB,OAAQ,QAAS,WAAG,IAAA;CAGnD,MAAO,WAFD,CAAA,GAAA,KAAqB,MAAA,GAAA,KAAA,WAAsB,CAG/C,MAAO,MAAA,KAAA,gBAA0D,IAAA,UAAA;CAC/D,MAAI,cAAO,WAAgB,gBAAU,YAAA,KAAA;AACnC,KAAA,CAAM,YAQN,QAAO;EACL,UAAU;EACV,YAAA,EAAA;EACA,MAAA;EACA,SAAA;EACD;CAGH,MAAM,eAAa,SACf,QAAM,SAAA,GAAA;CAOV,MAAO,qBAAA,sBAAA,SAAA;AACL,QAAA,aAAU,CAAA,KAAA,OAAA,gBAAA;AACV,MAAA,OAAA,gBAAA,UAAA;GACA,MAAA,EAAA,SAAA,eAAA,SACS,MAAY,yBAAA,aAAA,QAAA,mBAAA,GACtB,oBAAA,YAAA;AAEJ,UAAA;;IAsCa;IAWR;IAQwC;IAGxC;;AAWA,SACJ;GAQK,UAAS;GACN;GAAyB,YAbb,SAChB,MAAA,mBAAyB,QAAA,YAAgB,UAAA,mBAAA,GACzC,YAAkB;GAW2B,SAAA,YAAA;GAAqB;GACtE;;AAGE,SAAW,oBAAoB,iBAAA,cAAA,oBAAA;OAE3B,kBAAmB,mBACnB,OAAI,oBAAwB,YAC1B,EAAA,SAAM,qBAGN,YAAO,mBACF,YAAA,mBACE,cAAS;OACf,SAAA,kBAAA,gBAAA,SAEH;OACK,WAAA,kBACE,gBAAA,YACN,qBAAA;CAGH,MAAA,SAAO,kBACL,gBAAU,SACV,KAAA;OACA,gBAAc,yBAAA;OACd,kBAAS,OAAA,gBAAA;OACJ,kBAAA,SAAA,KAAA,eAAA,CAAA,CAAA;OACN,QAAA,UAAA,SACI,OAAA,eAAA,CAAA,SAAA,KAAA,KAAA,WAAA,OAAA,IAAA,OAAA,CAAA,CAAA,EAAA,EAAA,aAAA,MAAA,CAAA;AACL,QAAM,SAAO;EAMT,QAAO,gBAAiB;GAAA,OAAA,OAAU;GAAA,OAAA,iBAAA;GAAA,EAAA;EACpC,QAAM,OAAY,EAAA,QAAM,qBAAuB;GAGxC,MAAA,EAAA,OAAA,OAAA,UAAA;AACF,OAAA,OAAA,UAAA,UAAA;AACE,QAAS,OAAO;KACtB,MAAA,OAAA,MAAA,eAAA,OAAA,OAAA,UAAA,OAAA;;MAEI,MAAA,WAAA,MAAA,gBAAA,OAAA,KAAA,QAAA;AACF,aAAA;OACE,GAAA;OACN,KAAA,SAAA,OAAA,EAAA;;;AAGL,YAAA"}
1
+ {"version":3,"file":"analogjs-content-resources.mjs","names":[],"sources":["../../resources/src/content-files-resource.ts","../../resources/src/content-file-resource.ts"],"sourcesContent":["import { resource, ResourceRef } from '@angular/core';\nimport type { ContentFile } from '../../src/lib/content-file';\nimport type { InjectContentFilesFilterFunction } from '../../src/lib/inject-content-files';\nimport { injectContentListLoader } from '../../src/lib/content-list-loader';\n\nexport function contentFilesResource<Attributes extends Record<string, any>>(\n filterFn?: InjectContentFilesFilterFunction<Attributes> | undefined,\n): ResourceRef<ContentFile<Attributes>[] | undefined> {\n const contentListLoader = injectContentListLoader<Attributes>();\n const contentList = contentListLoader().then((items) =>\n filterFn ? items.filter(filterFn) : items,\n );\n\n return resource({\n loader: () => contentList,\n });\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport {\n computed,\n inject,\n resource,\n Signal,\n type ResourceRef,\n} from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\n\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { from } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport type { ContentFile } from '../../src/lib/content-file';\nimport { ContentRenderer } from '../../src/lib/content-renderer';\nimport {\n FrontmatterValidationError,\n parseRawContentFile,\n parseRawContentFileAsync,\n} from '../../src/lib/parse-raw-content-file';\nimport { injectContentFileLoader } from '../../src/lib/content-file-loader';\n\nexport interface ContentFileResourceResult<\n Attributes extends Record<string, any> = Record<string, any>,\n> extends ContentFile<Attributes | Record<string, never>> {\n toc: Array<{ id: string; level: number; text: string }>;\n}\n\ntype ContentFileParams =\n | Signal<string | { customFilename: string }>\n | Signal<string>\n | Signal<{ customFilename: string }>;\n\nasync function validateAttributes<TSchema extends StandardSchemaV1>(\n schema: TSchema,\n attributes: unknown,\n filename?: string,\n) {\n const result = await schema['~standard'].validate(attributes);\n if (result.issues) {\n throw new FrontmatterValidationError(result.issues, filename);\n }\n\n return result.value;\n}\n\nfunction getValidationFilename(filename: string): string {\n return filename.replace(/^\\/src\\/content\\//, '');\n}\n\nasync function getContentFile<\n Attributes extends Record<string, any> = Record<string, any>,\n>(\n contentFiles: Record<string, () => Promise<string>>,\n slug: string,\n fallback: string,\n schema?: StandardSchemaV1,\n): Promise<ContentFile<Attributes | Record<string, never>>> {\n // Normalize file keys so both \"/src/content/...\" and \"/<project>/src/content/...\" resolve.\n // This mirrors normalization used elsewhere in the content pipeline.\n const normalizedFiles: Record<string, () => Promise<string>> = {};\n const stemToKey: Record<string, string> = {};\n for (const [key, resolver] of Object.entries(contentFiles)) {\n const normalizedKey = key\n // replace any prefix up to the content directory with /src/content\n // use a non-greedy match so nested paths containing \"/content\" are preserved\n .replace(/^(?:.*?)\\/content(?=\\/)/, '/src/content')\n // normalize duplicate slashes\n .replace(/\\/{2,}/g, '/');\n normalizedFiles[normalizedKey] = resolver;\n // Index by bare filename stem so slug-only lookups work\n const stem = normalizedKey\n .split('/')\n .pop()\n ?.replace(/\\.[^.]+$/, '');\n if (stem && !stemToKey[stem]) {\n stemToKey[stem] = normalizedKey;\n }\n }\n\n // Try direct file first, then directory index variants, then bare slug via stem\n const base = `/src/content/${slug}`.replace(/\\/{2,}/g, '/');\n const candidates = [`${base}.md`, `${base}/index.md`];\n\n const matchKey =\n candidates.find((k) => k in normalizedFiles) ?? stemToKey[slug];\n const contentFile = matchKey ? normalizedFiles[matchKey] : undefined;\n\n if (!contentFile) {\n return {\n filename: base,\n attributes: {},\n slug: '',\n content: fallback,\n } as ContentFile<Attributes | Record<string, never>>;\n }\n\n const resolvedBase = matchKey!.replace(/\\.md$/, '');\n const validationFilename = getValidationFilename(matchKey!);\n\n return contentFile().then(\n async (contentFile: string | { default: any; metadata: any }) => {\n if (typeof contentFile === 'string') {\n const { content, attributes } = schema\n ? await parseRawContentFileAsync(\n contentFile,\n schema,\n validationFilename,\n )\n : parseRawContentFile<Attributes>(contentFile);\n\n return {\n filename: resolvedBase,\n slug,\n attributes,\n content,\n } as ContentFile<Attributes | Record<string, never>>;\n }\n\n const attributes = schema\n ? await validateAttributes(\n schema,\n contentFile.metadata,\n validationFilename,\n )\n : contentFile.metadata;\n\n return {\n filename: resolvedBase,\n slug,\n attributes,\n content: contentFile.default,\n } as ContentFile<Attributes | Record<string, never>>;\n },\n );\n}\n\n/**\n * Resource for requesting an individual content file.\n *\n * @example\n * ```typescript\n * // Without schema (existing behavior)\n * const post = contentFileResource<BlogAttributes>();\n *\n * // With schema validation\n * import * as v from 'valibot';\n * const BlogSchema = v.object({\n * title: v.string(),\n * date: v.pipe(v.string(), v.isoDate()),\n * });\n * const post = contentFileResource({ schema: BlogSchema });\n * ```\n */\nexport function contentFileResource<\n Attributes extends Record<string, any> = Record<string, any>,\n>(\n params?: ContentFileParams,\n fallback?: string,\n): ResourceRef<ContentFileResourceResult<Attributes> | undefined>;\n\nexport function contentFileResource<TSchema extends StandardSchemaV1>(options: {\n params?: ContentFileParams;\n fallback?: string;\n schema: TSchema;\n}): ResourceRef<\n | ContentFileResourceResult<\n StandardSchemaV1.InferOutput<TSchema> & Record<string, any>\n >\n | undefined\n>;\n\nexport function contentFileResource(\n paramsOrOptions?:\n | ContentFileParams\n | {\n params?: ContentFileParams;\n fallback?: string;\n schema?: StandardSchemaV1;\n },\n fallbackArg = 'No Content Found',\n) {\n // Detect options-object form vs legacy positional form\n const isOptionsObject =\n paramsOrOptions &&\n typeof paramsOrOptions === 'object' &&\n !('set' in paramsOrOptions) && // not a Signal\n ('schema' in paramsOrOptions ||\n 'params' in paramsOrOptions ||\n 'fallback' in paramsOrOptions);\n\n const params: ContentFileParams | undefined = isOptionsObject\n ? (paramsOrOptions as { params?: ContentFileParams }).params\n : (paramsOrOptions as ContentFileParams | undefined);\n const fallback: string = isOptionsObject\n ? ((paramsOrOptions as { fallback?: string }).fallback ??\n 'No Content Found')\n : fallbackArg;\n const schema: StandardSchemaV1 | undefined = isOptionsObject\n ? (paramsOrOptions as { schema?: StandardSchemaV1 }).schema\n : undefined;\n\n const loaderPromise = injectContentFileLoader();\n const contentRenderer = inject(ContentRenderer);\n const contentFilesMap = toSignal(from(loaderPromise()));\n const input =\n params ||\n toSignal(\n inject(ActivatedRoute).paramMap.pipe(\n map((params) => params.get('slug') as string),\n ),\n { requireSync: true },\n );\n\n return resource({\n params: computed(() => ({ input: input(), files: contentFilesMap() })),\n loader: async ({ params: resourceParams }) => {\n const { input: param, files } = resourceParams;\n\n if (typeof param === 'string') {\n if (param) {\n const file = await getContentFile(files!, param, fallback, schema);\n if (typeof file.content === 'string') {\n const rendered = (await contentRenderer.render(file.content)) as {\n toc?: Array<{ id: string; level: number; text: string }>;\n };\n return {\n ...file,\n toc: rendered.toc ?? [],\n };\n }\n return {\n ...file,\n toc: [],\n };\n }\n\n return {\n filename: '',\n slug: '',\n attributes: {},\n content: fallback,\n toc: [],\n };\n } else {\n const file = await getContentFile(\n files!,\n param.customFilename,\n fallback,\n schema,\n );\n if (typeof file.content === 'string') {\n const rendered = (await contentRenderer.render(file.content)) as {\n toc?: Array<{ id: string; level: number; text: string }>;\n };\n return {\n ...file,\n toc: rendered.toc ?? [],\n };\n }\n return {\n ...file,\n toc: [],\n };\n }\n },\n });\n}\n"],"mappings":";;;;;;;;;AAKA,SAAgB,qBACd,UACoD;CAEpD,MAAM,cADoB,yBAAqC,EACvB,CAAA,MAAM,UAC5C,WAAW,MAAM,OAAO,SAAY,GAAA,MACrC;AAED,QAAO,SACL,EAAA,cAAA,aAAA,CAAA;;;;ACmBJ,eAAe,mBACb,QACA,YACA,UACA;CACA,MAAM,SAAS,MAAM,OAAO,aAAa,SAAS,WAAW;AAC7D,KAAI,OAAO,OACH,OAAI,IAAA,2BAA2B,OAAO,QAAQ,SAAS;AAG/D,QAAO,OAAO;;AAGhB,SAAS,sBAAsB,UAA0B;AACvD,QAAO,SAAS,QAAQ,qBAAwB,GAAA;;AAGlD,eAAe,eAGb,cACA,MACA,UACA,QAC0D;CAK1D,MAAK,kBAAY,EAAA;CACf,MAAM,YAAA,EAAgB;AAMtB,MAAA,MAAA,CAAA,KAAgB,aAAA,OAAiB,QAAA,aAAA,EAAA;EAE3B,MAAA,gBACH,IAAA,QAAA,2BAAA,eAAA,CASC,QAAO,WAAgB,IAAA;AACvB,kBAAiB,iBAAc;EAI/B,MAAA,OAAc,cAEf,MAAa,IAAA,CACT,KAAA,EACK,QAAA,YAAA,GAAA;AACV,MAAA,QAAc,CAAA,UAAA,MACR,WAAA,QAAA;;CAKV,MAAM,OAAA,gBAAyB,OAAQ,QAAS,WAAG,IAAA;CAGnD,MAAO,WAFD,CAAA,GAAA,KAAqB,MAAA,GAAA,KAAA,WAAsB,CAG/C,MAAO,MAAA,KAAA,gBAA0D,IAAA,UAAA;CAC/D,MAAI,cAAO,WAAgB,gBAAU,YAAA,KAAA;AACnC,KAAA,CAAM,YAQN,QAAO;EACL,UAAU;EACV,YAAA,EAAA;EACA,MAAA;EACA,SAAA;EACD;CAGH,MAAM,eAAa,SACf,QAAM,SAAA,GAAA;CAOV,MAAO,qBAAA,sBAAA,SAAA;AACL,QAAA,aAAU,CAAA,KAAA,OAAA,gBAAA;AACV,MAAA,OAAA,gBAAA,UAAA;GACA,MAAA,EAAA,SAAA,eAAA,SACS,MAAY,yBAAA,aAAA,QAAA,mBAAA,GACtB,oBAAA,YAAA;AAEJ,UAAA;;IAsCa;IAWR;IAQwC;IAGxC;;AAWA,SACJ;GAQK,UAAS;GACN;GAAyB,YAbb,SAChB,MAAA,mBAAyB,QAAA,YAAgB,UAAA,mBAAA,GACzC,YAAkB;GAW2B,SAAA,YAAA;GAAqB;GACtE;;AAGE,SAAW,oBAAoB,iBAAA,cAAA,oBAAA;OAE3B,kBAAmB,mBACnB,OAAI,oBAAwB,YAC1B,EAAA,SAAM,qBAGN,YAAO,mBACF,YAAA,mBACE,cAAS;OACf,SAAA,kBAAA,gBAAA,SAEH;OACK,WAAA,kBACE,gBAAA,YACN,qBAAA;CAGH,MAAA,SAAO,kBACL,gBAAU,SACV,KAAA;OACA,gBAAc,yBAAA;OACd,kBAAS,OAAA,gBAAA;OACJ,kBAAA,SAAA,KAAA,eAAA,CAAA,CAAA;OACN,QAAA,UAAA,SACI,OAAA,eAAA,CAAA,SAAA,KAAA,KAAA,WAAA,OAAA,IAAA,OAAA,CAAA,CAAA,EAAA,EAAA,aAAA,MAAA,CAAA;AACL,QAAM,SAAO;EAMT,QAAO,gBAAiB;GAAA,OAAA,OAAU;GAAA,OAAA,iBAAA;GAAA,EAAA;EACpC,QAAM,OAAY,EAAA,QAAM,qBAAuB;GAGxC,MAAA,EAAA,OAAA,OAAA,UAAA;AACF,OAAA,OAAA,UAAA,UAAA;AACE,QAAS,OAAO;KACtB,MAAA,OAAA,MAAA,eAAA,OAAA,OAAA,UAAA,OAAA;;MAEI,MAAA,WAAA,MAAA,gBAAA,OAAA,KAAA,QAAA;AACF,aAAA;OACE,GAAA;OACN,KAAA,SAAA,OAAA,EAAA;;;AAGL,YAAA"}
@@ -1,4 +1,4 @@
1
- import { ContentRenderer, NoopContentRenderer } from "@analogjs/content";
1
+ import { n as NoopContentRenderer, t as ContentRenderer } from "./content-renderer.mjs";
2
2
  //#region packages/content/shiki-highlighter/src/index.ts
3
3
  function withShikiHighlighter(_opts = {}) {
4
4
  return [{
@@ -1 +1 @@
1
- {"version":3,"file":"analogjs-content-shiki-highlighter.mjs","names":[],"sources":["../../shiki-highlighter/src/index.ts"],"sourcesContent":["import { ContentRenderer, NoopContentRenderer } from '@analogjs/content';\nimport { Provider } from '@angular/core';\nimport type {\n BundledLanguage,\n BundledTheme,\n CodeOptionsMeta,\n CodeOptionsMultipleThemes,\n CodeOptionsSingleTheme,\n CodeToHastOptionsCommon,\n} from 'shiki';\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":";;AAsBA,SAAgB,qBACd,QAAqC,EAAE,EAC3B;AACZ,QACE,CACE;EACU,SAAA;EAEb,UAAA"}
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,EAC3B;AACZ,QACE,CACE;EACU,SAAA;EAEb,UAAA"}
@@ -1,12 +1,13 @@
1
1
  import { n as NoopContentRenderer, t as ContentRenderer } from "./content-renderer.mjs";
2
2
  import { a as injectContentFileLoader, c as injectContentFilesMap, i as CONTENT_FILE_LOADER, l as RenderTaskService, n as injectContentListLoader, o as withContentFileLoader, r as withContentListLoader, s as injectContentFiles, t as CONTENT_LIST_LOADER, u as CONTENT_FILES_TOKEN } from "./content-list-loader.mjs";
3
+ import { n as parseRawContentFile, r as parseRawContentFileAsync, t as FrontmatterValidationError } from "./parse-raw-content-file.mjs";
4
+ import { n as withHighlighter, t as MarkedContentHighlighter } from "./marked-content-highlighter.mjs";
3
5
  import * as i0 from "@angular/core";
4
6
  import { Component, Directive, HostListener, Injectable, InjectionToken, Input, NgZone, PLATFORM_ID, ViewEncapsulation, computed, inject, input } from "@angular/core";
5
7
  import { DOCUMENT, Location, isPlatformBrowser } from "@angular/common";
6
8
  import { ActivatedRoute, Router } from "@angular/router";
7
9
  import { Observable, from, of } from "rxjs";
8
10
  import { catchError, map, switchMap, tap } from "rxjs/operators";
9
- import fm from "front-matter";
10
11
  import { getHeadingList, gfmHeadingId } from "marked-gfm-heading-id";
11
12
  import { marked } from "marked";
12
13
  import { mangle } from "marked-mangle";
@@ -31,7 +32,7 @@ var AnchorNavigationDirective = class AnchorNavigationDirective {
31
32
  static {
32
33
  this.ɵfac = i0.ɵɵngDeclareFactory({
33
34
  minVersion: "12.0.0",
34
- version: "21.2.6",
35
+ version: "21.2.8",
35
36
  ngImport: i0,
36
37
  type: AnchorNavigationDirective,
37
38
  deps: [],
@@ -41,7 +42,7 @@ var AnchorNavigationDirective = class AnchorNavigationDirective {
41
42
  static {
42
43
  this.ɵdir = i0.ɵɵngDeclareDirective({
43
44
  minVersion: "14.0.0",
44
- version: "21.2.6",
45
+ version: "21.2.8",
45
46
  type: AnchorNavigationDirective,
46
47
  isStandalone: true,
47
48
  selector: "[analogAnchorNavigation]",
@@ -52,7 +53,7 @@ var AnchorNavigationDirective = class AnchorNavigationDirective {
52
53
  };
53
54
  i0.ɵɵngDeclareClassMetadata({
54
55
  minVersion: "12.0.0",
55
- version: "21.2.6",
56
+ version: "21.2.8",
56
57
  ngImport: i0,
57
58
  type: AnchorNavigationDirective,
58
59
  decorators: [{
@@ -77,47 +78,6 @@ function isInternalUrl(anchorElement, document) {
77
78
  return anchorElement.host === document.location.host && anchorElement.protocol === document.location.protocol;
78
79
  }
79
80
  //#endregion
80
- //#region packages/content/src/lib/parse-raw-content-file.ts
81
- var FrontmatterValidationError = class extends Error {
82
- constructor(issues, filename) {
83
- const issueMessages = issues.map((i) => {
84
- const path = i.path ? ` at "${i.path.map((p) => typeof p === "object" ? p.key : p).join(".")}"` : "";
85
- return ` - ${i.message}${path}`;
86
- }).join("\n");
87
- const prefix = filename ? `"${filename}" f` : "F";
88
- super(`${prefix}rontmatter validation failed:\n${issueMessages}`);
89
- this.issues = issues;
90
- this.filename = filename;
91
- this.name = "FrontmatterValidationError";
92
- }
93
- };
94
- function parseRawContentFile(rawContentFile, schema, filename) {
95
- const { body, attributes } = fm(rawContentFile);
96
- if (schema) {
97
- const result = schema["~standard"].validate(attributes);
98
- if (result != null && typeof result.then === "function") throw new Error("parseRawContentFile does not support async schema validation. Use parseRawContentFileAsync() for async schemas.");
99
- const syncResult = result;
100
- if (syncResult.issues) throw new FrontmatterValidationError(syncResult.issues, filename);
101
- return {
102
- content: body,
103
- attributes: syncResult.value
104
- };
105
- }
106
- return {
107
- content: body,
108
- attributes
109
- };
110
- }
111
- async function parseRawContentFileAsync(rawContentFile, schema, filename) {
112
- const { body, attributes } = fm(rawContentFile);
113
- const result = await schema["~standard"].validate(attributes);
114
- if (result.issues) throw new FrontmatterValidationError(result.issues, filename);
115
- return {
116
- content: body,
117
- attributes: result.value
118
- };
119
- }
120
- //#endregion
121
81
  //#region packages/content/src/lib/content.ts
122
82
  function getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer) {
123
83
  const normalizedFiles = {};
@@ -190,41 +150,6 @@ function injectContent(param = "slug", fallback = "No Content Found") {
190
150
  } else return getContentFile(contentFiles, "", param.customFilename, fallback, renderTaskService, contentRenderer).pipe(tap(() => renderTaskService.clearRenderTask(task)));
191
151
  }
192
152
  //#endregion
193
- //#region packages/content/src/lib/marked-content-highlighter.ts
194
- var MarkedContentHighlighter = class MarkedContentHighlighter {
195
- static {
196
- this.ɵfac = i0.ɵɵngDeclareFactory({
197
- minVersion: "12.0.0",
198
- version: "21.2.6",
199
- ngImport: i0,
200
- type: MarkedContentHighlighter,
201
- deps: [],
202
- target: i0.ɵɵFactoryTarget.Injectable
203
- });
204
- }
205
- static {
206
- this.ɵprov = i0.ɵɵngDeclareInjectable({
207
- minVersion: "12.0.0",
208
- version: "21.2.6",
209
- ngImport: i0,
210
- type: MarkedContentHighlighter
211
- });
212
- }
213
- };
214
- i0.ɵɵngDeclareClassMetadata({
215
- minVersion: "12.0.0",
216
- version: "21.2.6",
217
- ngImport: i0,
218
- type: MarkedContentHighlighter,
219
- decorators: [{ type: Injectable }]
220
- });
221
- function withHighlighter(provider) {
222
- return {
223
- provide: MarkedContentHighlighter,
224
- ...provider
225
- };
226
- }
227
- //#endregion
228
153
  //#region packages/content/src/lib/marked-setup.service.ts
229
154
  /**
230
155
  * Credit goes to Scully for original implementation
@@ -256,7 +181,7 @@ var MarkedSetupService = class MarkedSetupService {
256
181
  static {
257
182
  this.ɵfac = i0.ɵɵngDeclareFactory({
258
183
  minVersion: "12.0.0",
259
- version: "21.2.6",
184
+ version: "21.2.8",
260
185
  ngImport: i0,
261
186
  type: MarkedSetupService,
262
187
  deps: [],
@@ -266,7 +191,7 @@ var MarkedSetupService = class MarkedSetupService {
266
191
  static {
267
192
  this.ɵprov = i0.ɵɵngDeclareInjectable({
268
193
  minVersion: "12.0.0",
269
- version: "21.2.6",
194
+ version: "21.2.8",
270
195
  ngImport: i0,
271
196
  type: MarkedSetupService
272
197
  });
@@ -274,7 +199,7 @@ var MarkedSetupService = class MarkedSetupService {
274
199
  };
275
200
  i0.ɵɵngDeclareClassMetadata({
276
201
  minVersion: "12.0.0",
277
- version: "21.2.6",
202
+ version: "21.2.8",
278
203
  ngImport: i0,
279
204
  type: MarkedSetupService,
280
205
  decorators: [{ type: Injectable }],
@@ -301,7 +226,7 @@ var MarkdownContentRendererService = class MarkdownContentRendererService {
301
226
  static {
302
227
  this.ɵfac = i0.ɵɵngDeclareFactory({
303
228
  minVersion: "12.0.0",
304
- version: "21.2.6",
229
+ version: "21.2.8",
305
230
  ngImport: i0,
306
231
  type: MarkdownContentRendererService,
307
232
  deps: [],
@@ -311,7 +236,7 @@ var MarkdownContentRendererService = class MarkdownContentRendererService {
311
236
  static {
312
237
  this.ɵprov = i0.ɵɵngDeclareInjectable({
313
238
  minVersion: "12.0.0",
314
- version: "21.2.6",
239
+ version: "21.2.8",
315
240
  ngImport: i0,
316
241
  type: MarkdownContentRendererService
317
242
  });
@@ -319,7 +244,7 @@ var MarkdownContentRendererService = class MarkdownContentRendererService {
319
244
  };
320
245
  i0.ɵɵngDeclareClassMetadata({
321
246
  minVersion: "12.0.0",
322
- version: "21.2.6",
247
+ version: "21.2.8",
323
248
  ngImport: i0,
324
249
  type: MarkdownContentRendererService,
325
250
  decorators: [{ type: Injectable }]
@@ -363,7 +288,7 @@ var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
363
288
  static {
364
289
  this.ɵfac = i0.ɵɵngDeclareFactory({
365
290
  minVersion: "12.0.0",
366
- version: "21.2.6",
291
+ version: "21.2.8",
367
292
  ngImport: i0,
368
293
  type: AnalogMarkdownRouteComponent,
369
294
  deps: [],
@@ -373,7 +298,7 @@ var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
373
298
  static {
374
299
  this.ɵcmp = i0.ɵɵngDeclareComponent({
375
300
  minVersion: "14.0.0",
376
- version: "21.2.6",
301
+ version: "21.2.8",
377
302
  type: AnalogMarkdownRouteComponent,
378
303
  isStandalone: true,
379
304
  selector: "analog-markdown-route",
@@ -389,7 +314,7 @@ var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
389
314
  };
390
315
  i0.ɵɵngDeclareClassMetadata({
391
316
  minVersion: "12.0.0",
392
- version: "21.2.6",
317
+ version: "21.2.8",
393
318
  ngImport: i0,
394
319
  type: AnalogMarkdownRouteComponent,
395
320
  decorators: [{
@@ -446,7 +371,7 @@ var AnalogMarkdownComponent = class AnalogMarkdownComponent {
446
371
  static {
447
372
  this.ɵfac = i0.ɵɵngDeclareFactory({
448
373
  minVersion: "12.0.0",
449
- version: "21.2.6",
374
+ version: "21.2.8",
450
375
  ngImport: i0,
451
376
  type: AnalogMarkdownComponent,
452
377
  deps: [],
@@ -456,7 +381,7 @@ var AnalogMarkdownComponent = class AnalogMarkdownComponent {
456
381
  static {
457
382
  this.ɵcmp = i0.ɵɵngDeclareComponent({
458
383
  minVersion: "17.1.0",
459
- version: "21.2.6",
384
+ version: "21.2.8",
460
385
  type: AnalogMarkdownComponent,
461
386
  isStandalone: true,
462
387
  selector: "analog-markdown",
@@ -487,7 +412,7 @@ var AnalogMarkdownComponent = class AnalogMarkdownComponent {
487
412
  };
488
413
  i0.ɵɵngDeclareClassMetadata({
489
414
  minVersion: "12.0.0",
490
- version: "21.2.6",
415
+ version: "21.2.8",
491
416
  ngImport: i0,
492
417
  type: AnalogMarkdownComponent,
493
418
  decorators: [{
@@ -1 +1 @@
1
- {"version":3,"file":"analogjs-content.mjs","names":["#marked"],"sources":["../../src/lib/anchor-navigation.directive.ts","../../src/lib/parse-raw-content-file.ts","../../src/lib/content.ts","../../src/lib/marked-content-highlighter.ts","../../src/lib/marked-setup.service.ts","../../src/lib/markdown-content-renderer.service.ts","../../src/lib/provide-content.ts","../../src/lib/markdown-route.component.ts","../../src/lib/markdown.component.ts"],"sourcesContent":["import { Directive, HostListener, inject } from '@angular/core';\nimport { DOCUMENT, Location } from '@angular/common';\nimport { Router } from '@angular/router';\n\n@Directive({\n selector: '[analogAnchorNavigation]',\n standalone: true,\n})\nexport class AnchorNavigationDirective {\n private readonly document = inject(DOCUMENT);\n private readonly location = inject(Location);\n private readonly router = inject(Router);\n\n @HostListener('click', ['$event.target'])\n handleNavigation(element: EventTarget | null): boolean {\n if (\n element instanceof HTMLAnchorElement &&\n isInternalUrl(element, this.document) &&\n hasTargetSelf(element) &&\n !hasDownloadAttribute(element)\n ) {\n const { pathname, search, hash } = element;\n const url = this.location.normalize(`${pathname}${search}${hash}`);\n this.router.navigateByUrl(url);\n\n return false;\n }\n\n return true;\n }\n}\n\nfunction hasDownloadAttribute(anchorElement: HTMLAnchorElement): boolean {\n return anchorElement.getAttribute('download') !== null;\n}\n\nfunction hasTargetSelf(anchorElement: HTMLAnchorElement): boolean {\n return !anchorElement.target || anchorElement.target === '_self';\n}\n\nfunction isInternalUrl(\n anchorElement: HTMLAnchorElement,\n document: Document,\n): boolean {\n return (\n anchorElement.host === document.location.host &&\n anchorElement.protocol === document.location.protocol\n );\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport fm from 'front-matter';\n\nexport class FrontmatterValidationError extends Error {\n constructor(\n public readonly issues: ReadonlyArray<StandardSchemaV1.Issue>,\n public readonly filename?: string,\n ) {\n const issueMessages = issues\n .map((i) => {\n const path = i.path\n ? ` at \"${i.path.map((p) => (typeof p === 'object' ? p.key : p)).join('.')}\"`\n : '';\n return ` - ${i.message}${path}`;\n })\n .join('\\n');\n const prefix = filename ? `\"${filename}\" f` : 'F';\n super(`${prefix}rontmatter validation failed:\\n${issueMessages}`);\n this.name = 'FrontmatterValidationError';\n }\n}\n\nexport function parseRawContentFile<\n Attributes extends Record<string, any> = Record<string, any>,\n>(rawContentFile: string): { content: string; attributes: Attributes };\n\nexport function parseRawContentFile<TSchema extends StandardSchemaV1>(\n rawContentFile: string,\n schema: TSchema,\n filename?: string,\n): { content: string; attributes: StandardSchemaV1.InferOutput<TSchema> };\n\nexport function parseRawContentFile(\n rawContentFile: string,\n schema?: StandardSchemaV1,\n filename?: string,\n): { content: string; attributes: unknown } {\n const { body, attributes } = fm(rawContentFile);\n\n if (schema) {\n const result = schema['~standard'].validate(attributes);\n if (\n result != null &&\n typeof (result as PromiseLike<unknown>).then === 'function'\n ) {\n throw new Error(\n 'parseRawContentFile does not support async schema validation. ' +\n 'Use parseRawContentFileAsync() for async schemas.',\n );\n }\n const syncResult = result as StandardSchemaV1.Result<\n StandardSchemaV1.InferOutput<typeof schema>\n >;\n if (syncResult.issues) {\n throw new FrontmatterValidationError(syncResult.issues, filename);\n }\n return { content: body, attributes: syncResult.value };\n }\n\n return { content: body, attributes };\n}\n\nexport async function parseRawContentFileAsync<\n TSchema extends StandardSchemaV1,\n>(\n rawContentFile: string,\n schema: TSchema,\n filename?: string,\n): Promise<{\n content: string;\n attributes: StandardSchemaV1.InferOutput<TSchema>;\n}> {\n const { body, attributes } = fm(rawContentFile);\n const result = await schema['~standard'].validate(attributes);\n if (result.issues) {\n throw new FrontmatterValidationError(result.issues, filename);\n }\n return { content: body, attributes: result.value };\n}\n","/// <reference types=\"vite/client\" />\n\nimport { inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { from, Observable, of } from 'rxjs';\nimport { map, switchMap, tap } from 'rxjs/operators';\n\nimport { ContentFile } from './content-file';\nimport { ContentRenderer } from './content-renderer';\nimport { CONTENT_FILES_TOKEN } from './content-files-token';\nimport { parseRawContentFile } from './parse-raw-content-file';\nimport { waitFor } from './utils/zone-wait-for';\nimport { RenderTaskService } from './render-task.service';\n\nfunction getContentFile<\n Attributes extends Record<string, any> = Record<string, any>,\n>(\n contentFiles: Record<string, () => Promise<string>>,\n prefix: string,\n slug: string,\n fallback: string,\n renderTaskService: RenderTaskService,\n contentRenderer: ContentRenderer,\n): Observable<ContentFile<Attributes | Record<string, never>>> {\n // Normalize file keys so both \"/src/content/...\" and \"/<project>/src/content/...\" resolve.\n const normalizedFiles: Record<string, () => Promise<string>> = {};\n for (const [key, resolver] of Object.entries(contentFiles)) {\n const normalizedKey = key\n .replace(/^(?:.*)\\/content/, '/src/content')\n .replace(/\\/{2,}/g, '/');\n normalizedFiles[normalizedKey] = resolver as () => Promise<string>;\n }\n\n const base = `/src/content/${prefix}${slug}`.replace(/\\/{2,}/g, '/');\n const candidates = [`${base}.md`, `${base}/index.md`];\n\n const matchKey = candidates.find((k) => k in normalizedFiles);\n const contentFile = matchKey ? normalizedFiles[matchKey] : undefined;\n const resolvedBase = (matchKey || `${base}.md`).replace(/\\.md$/, '');\n\n if (!contentFile) {\n return of({\n filename: resolvedBase,\n attributes: {},\n slug: '',\n content: fallback,\n toc: [],\n });\n }\n\n const contentTask = renderTaskService.addRenderTask();\n return new Observable<string | { default: string; metadata: Attributes }>(\n (observer) => {\n const contentResolver = contentFile();\n\n if (import.meta.env.SSR === true) {\n waitFor(contentResolver).then((content) => {\n observer.next(content);\n observer.complete();\n\n setTimeout(() => renderTaskService.clearRenderTask(contentTask), 10);\n });\n } else {\n contentResolver.then((content) => {\n observer.next(content);\n observer.complete();\n });\n }\n },\n ).pipe(\n switchMap((contentFile) => {\n if (typeof contentFile === 'string') {\n const { content, attributes } =\n parseRawContentFile<Attributes>(contentFile);\n return from(contentRenderer.render(content)).pipe(\n map((rendered) => ({\n filename: resolvedBase,\n slug,\n attributes,\n content,\n toc: rendered.toc ?? [],\n })),\n );\n }\n return of({\n filename: resolvedBase,\n slug,\n attributes: contentFile.metadata,\n content: contentFile.default,\n toc: [],\n });\n }),\n );\n}\n\n/**\n * Retrieves the static content using the provided param and/or prefix.\n *\n * @param param route parameter (default: 'slug')\n * @param fallback fallback text if content file is not found (default: 'No Content Found')\n */\nexport function injectContent<\n Attributes extends Record<string, any> = Record<string, any>,\n>(\n param:\n | string\n | {\n param: string;\n subdirectory: string;\n }\n | {\n customFilename: string;\n } = 'slug',\n fallback = 'No Content Found',\n): Observable<ContentFile<Attributes | Record<string, never>>> {\n const contentFiles = inject(CONTENT_FILES_TOKEN);\n const contentRenderer = inject(ContentRenderer);\n const renderTaskService = inject(RenderTaskService);\n const task = renderTaskService.addRenderTask();\n\n if (typeof param === 'string' || 'param' in param) {\n const prefix = typeof param === 'string' ? '' : `${param.subdirectory}/`;\n const route = inject(ActivatedRoute);\n const paramKey = typeof param === 'string' ? param : param.param;\n return route.paramMap.pipe(\n map((params) => params.get(paramKey)),\n switchMap((slug) => {\n if (slug) {\n return getContentFile<Attributes>(\n contentFiles,\n prefix,\n slug,\n fallback,\n renderTaskService,\n contentRenderer,\n );\n }\n return of({\n filename: '',\n slug: '',\n attributes: {},\n content: fallback,\n toc: [],\n });\n }),\n tap(() => renderTaskService.clearRenderTask(task)),\n );\n } else {\n return getContentFile<Attributes>(\n contentFiles,\n '',\n param.customFilename,\n fallback,\n renderTaskService,\n contentRenderer,\n ).pipe(tap(() => renderTaskService.clearRenderTask(task)));\n }\n}\n","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","/**\n * Credit goes to Scully for original implementation\n * https://github.com/scullyio/scully/blob/main/libs/scully/src/lib/fileHanderPlugins/markdown.ts\n */\nimport { inject, Injectable } from '@angular/core';\nimport { marked } from 'marked';\nimport { gfmHeadingId } from 'marked-gfm-heading-id';\nimport { mangle } from 'marked-mangle';\nimport { MarkedContentHighlighter } from './marked-content-highlighter';\n\n@Injectable()\nexport class MarkedSetupService {\n private readonly marked: typeof marked;\n private readonly highlighter = inject(MarkedContentHighlighter, {\n optional: true,\n });\n\n constructor() {\n const renderer = new marked.Renderer();\n renderer.code = ({ text, lang }) => {\n // Let's do a language based detection like on GitHub\n // So we can still have non-interpreted mermaid code\n if (lang === 'mermaid') {\n return '<pre class=\"mermaid\">' + text + '</pre>';\n }\n\n if (!lang) {\n return '<pre><code>' + text + '</code></pre>';\n }\n\n if (this.highlighter?.augmentCodeBlock) {\n return this.highlighter?.augmentCodeBlock(text, lang);\n }\n\n return `<pre class=\"language-${lang}\"><code class=\"language-${lang}\">${text}</code></pre>`;\n };\n\n const extensions = [gfmHeadingId(), mangle()];\n\n if (this.highlighter) {\n extensions.push(this.highlighter.getHighlightExtension());\n }\n\n marked.use(...extensions, {\n renderer,\n pedantic: false,\n gfm: true,\n breaks: false,\n });\n\n this.marked = marked;\n }\n\n getMarkedInstance(): typeof marked {\n return this.marked;\n }\n}\n","import { inject, Injectable } from '@angular/core';\nimport { getHeadingList } from 'marked-gfm-heading-id';\n\nimport {\n ContentRenderer,\n RenderedContent,\n TableOfContentItem,\n} from './content-renderer';\nimport { MarkedSetupService } from './marked-setup.service';\n\n@Injectable()\nexport class MarkdownContentRendererService implements ContentRenderer {\n #marked = inject(MarkedSetupService, { self: true });\n\n async render(content: string): Promise<RenderedContent> {\n const renderedContent = await this.#marked\n .getMarkedInstance()\n .parse(content);\n return {\n content: renderedContent,\n toc: getHeadingList(),\n };\n }\n\n getContentHeadings(content: string): TableOfContentItem[] {\n return [...content.matchAll(/^(#{1,6})\\s+(.+?)\\s*$/gm)].map((match) => ({\n id: match[2]\n .trim()\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/\\s+/g, '-'),\n level: match[1].length,\n text: match[2].trim(),\n }));\n }\n\n // eslint-disable-next-line\n enhance(): void {}\n}\n","import { Provider, InjectionToken } from '@angular/core';\nimport { ContentRenderer, NoopContentRenderer } from './content-renderer';\nimport { RenderTaskService } from './render-task.service';\nimport { withContentFileLoader } from './content-file-loader';\nimport { withContentListLoader } from './content-list-loader';\n\nexport interface MarkdownRendererOptions {\n loadMermaid?: () => Promise<typeof import('mermaid')>;\n}\n\nconst CONTENT_RENDERER_PROVIDERS: Provider[] = [\n {\n provide: ContentRenderer,\n useClass: NoopContentRenderer,\n },\n withContentFileLoader(),\n withContentListLoader(),\n];\n\nexport function withMarkdownRenderer(\n options?: MarkdownRendererOptions,\n): Provider {\n return [\n CONTENT_RENDERER_PROVIDERS,\n options?.loadMermaid\n ? [\n {\n provide: MERMAID_IMPORT_TOKEN,\n useFactory: options.loadMermaid,\n },\n ]\n : [],\n ];\n}\n\nexport function provideContent(...features: Provider[]): Provider[] {\n return [\n { provide: RenderTaskService, useClass: RenderTaskService },\n ...features,\n ];\n}\n\nexport const MERMAID_IMPORT_TOKEN: InjectionToken<\n Promise<typeof import('mermaid')>\n> = new InjectionToken<Promise<typeof import('mermaid')>>('mermaid_import');\n","import {\n AfterViewChecked,\n Component,\n inject,\n Input,\n ViewEncapsulation,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { ActivatedRoute } from '@angular/router';\n\nimport { ContentRenderer } from './content-renderer';\nimport { AnchorNavigationDirective } from './anchor-navigation.directive';\n\n@Component({\n selector: 'analog-markdown-route',\n standalone: true,\n imports: [],\n hostDirectives: [AnchorNavigationDirective],\n preserveWhitespaces: true,\n encapsulation: ViewEncapsulation.None,\n template: `<div [innerHTML]=\"content\" [class]=\"classes\"></div>`,\n})\nexport default class AnalogMarkdownRouteComponent implements AfterViewChecked {\n private sanitizer = inject(DomSanitizer);\n private route = inject(ActivatedRoute);\n contentRenderer: ContentRenderer = inject(ContentRenderer);\n\n protected content: SafeHtml = this.sanitizer.bypassSecurityTrustHtml(\n this.route.snapshot.data['renderedAnalogContent'],\n );\n\n @Input() classes = 'analog-markdown-route';\n\n ngAfterViewChecked(): void {\n this.contentRenderer.enhance();\n }\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport {\n AfterViewChecked,\n Component,\n InputSignal,\n NgZone,\n PLATFORM_ID,\n Signal,\n ViewEncapsulation,\n computed,\n inject,\n input,\n} from '@angular/core';\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { ActivatedRoute, Data } from '@angular/router';\nimport { from, Observable, of } from 'rxjs';\nimport { catchError, map, switchMap } from 'rxjs/operators';\n\nimport { AnchorNavigationDirective } from './anchor-navigation.directive';\nimport { ContentRenderer } from './content-renderer';\nimport { MERMAID_IMPORT_TOKEN } from './provide-content';\n\n@Component({\n selector: 'analog-markdown',\n standalone: true,\n hostDirectives: [AnchorNavigationDirective],\n preserveWhitespaces: true,\n encapsulation: ViewEncapsulation.None,\n template: ` <div [innerHTML]=\"htmlContent()\" [class]=\"classes()\"></div> `,\n})\nexport default class AnalogMarkdownComponent implements AfterViewChecked {\n private sanitizer = inject(DomSanitizer);\n private route = inject(ActivatedRoute);\n private zone = inject(NgZone);\n private readonly platformId = inject(PLATFORM_ID);\n private readonly mermaidImport = inject(MERMAID_IMPORT_TOKEN, {\n optional: true,\n });\n private mermaid: typeof import('mermaid') | undefined;\n\n private contentSource: Signal<SafeHtml | string | undefined> = toSignal(\n this.getContentSource(),\n );\n readonly htmlContent: Signal<SafeHtml | string | undefined> = computed(() => {\n const inputContent = this.content();\n\n if (inputContent) {\n return this.sanitizer.bypassSecurityTrustHtml(inputContent as string);\n }\n\n return this.contentSource();\n });\n readonly content: InputSignal<string | object | null | undefined> = input<\n string | object | null\n >();\n readonly classes: InputSignal<string> = input('analog-markdown');\n\n contentRenderer: ContentRenderer = inject(ContentRenderer);\n\n constructor() {\n if (isPlatformBrowser(this.platformId) && this.mermaidImport) {\n // Mermaid can only be loaded on client side\n this.loadMermaid(this.mermaidImport);\n }\n }\n\n getContentSource(): Observable<SafeHtml | string> {\n return this.route.data.pipe(\n map<Data, string>((data) => data['_analogContent'] ?? ''),\n switchMap((contentString) => this.renderContent(contentString)),\n map((content) => this.sanitizer.bypassSecurityTrustHtml(content)),\n catchError((e) => of(`There was an error ${e}`)),\n );\n }\n\n async renderContent(content: string): Promise<string> {\n const rendered = await this.contentRenderer.render(content);\n return rendered.content;\n }\n\n ngAfterViewChecked(): void {\n this.contentRenderer.enhance();\n this.zone.runOutsideAngular(() => this.mermaid?.default.run());\n }\n\n private loadMermaid(mermaidImport: Promise<typeof import('mermaid')>) {\n this.zone.runOutsideAngular(() =>\n // Wrap into an observable to avoid redundant initialization once\n // the markdown component is destroyed before the promise is resolved.\n from(mermaidImport)\n .pipe(takeUntilDestroyed())\n .subscribe((mermaid) => {\n this.mermaid = mermaid;\n this.mermaid.default.initialize({ startOnLoad: false });\n // Explicitly running mermaid as ngAfterViewChecked\n // has probably already been called\n this.mermaid?.default.run();\n }),\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"analogjs-content.mjs","names":["#marked"],"sources":["../../src/lib/anchor-navigation.directive.ts","../../src/lib/content.ts","../../src/lib/marked-setup.service.ts","../../src/lib/markdown-content-renderer.service.ts","../../src/lib/provide-content.ts","../../src/lib/markdown-route.component.ts","../../src/lib/markdown.component.ts"],"sourcesContent":["import { Directive, HostListener, inject } from '@angular/core';\nimport { DOCUMENT, Location } from '@angular/common';\nimport { Router } from '@angular/router';\n\n@Directive({\n selector: '[analogAnchorNavigation]',\n standalone: true,\n})\nexport class AnchorNavigationDirective {\n private readonly document = inject(DOCUMENT);\n private readonly location = inject(Location);\n private readonly router = inject(Router);\n\n @HostListener('click', ['$event.target'])\n handleNavigation(element: EventTarget | null): boolean {\n if (\n element instanceof HTMLAnchorElement &&\n isInternalUrl(element, this.document) &&\n hasTargetSelf(element) &&\n !hasDownloadAttribute(element)\n ) {\n const { pathname, search, hash } = element;\n const url = this.location.normalize(`${pathname}${search}${hash}`);\n this.router.navigateByUrl(url);\n\n return false;\n }\n\n return true;\n }\n}\n\nfunction hasDownloadAttribute(anchorElement: HTMLAnchorElement): boolean {\n return anchorElement.getAttribute('download') !== null;\n}\n\nfunction hasTargetSelf(anchorElement: HTMLAnchorElement): boolean {\n return !anchorElement.target || anchorElement.target === '_self';\n}\n\nfunction isInternalUrl(\n anchorElement: HTMLAnchorElement,\n document: Document,\n): boolean {\n return (\n anchorElement.host === document.location.host &&\n anchorElement.protocol === document.location.protocol\n );\n}\n","/// <reference types=\"vite/client\" />\n\nimport { inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { from, Observable, of } from 'rxjs';\nimport { map, switchMap, tap } from 'rxjs/operators';\n\nimport { ContentFile } from './content-file';\nimport { ContentRenderer } from './content-renderer';\nimport { CONTENT_FILES_TOKEN } from './content-files-token';\nimport { parseRawContentFile } from './parse-raw-content-file';\nimport { waitFor } from './utils/zone-wait-for';\nimport { RenderTaskService } from './render-task.service';\n\nfunction getContentFile<\n Attributes extends Record<string, any> = Record<string, any>,\n>(\n contentFiles: Record<string, () => Promise<string>>,\n prefix: string,\n slug: string,\n fallback: string,\n renderTaskService: RenderTaskService,\n contentRenderer: ContentRenderer,\n): Observable<ContentFile<Attributes | Record<string, never>>> {\n // Normalize file keys so both \"/src/content/...\" and \"/<project>/src/content/...\" resolve.\n const normalizedFiles: Record<string, () => Promise<string>> = {};\n for (const [key, resolver] of Object.entries(contentFiles)) {\n const normalizedKey = key\n .replace(/^(?:.*)\\/content/, '/src/content')\n .replace(/\\/{2,}/g, '/');\n normalizedFiles[normalizedKey] = resolver as () => Promise<string>;\n }\n\n const base = `/src/content/${prefix}${slug}`.replace(/\\/{2,}/g, '/');\n const candidates = [`${base}.md`, `${base}/index.md`];\n\n const matchKey = candidates.find((k) => k in normalizedFiles);\n const contentFile = matchKey ? normalizedFiles[matchKey] : undefined;\n const resolvedBase = (matchKey || `${base}.md`).replace(/\\.md$/, '');\n\n if (!contentFile) {\n return of({\n filename: resolvedBase,\n attributes: {},\n slug: '',\n content: fallback,\n toc: [],\n });\n }\n\n const contentTask = renderTaskService.addRenderTask();\n return new Observable<string | { default: string; metadata: Attributes }>(\n (observer) => {\n const contentResolver = contentFile();\n\n if (import.meta.env.SSR === true) {\n waitFor(contentResolver).then((content) => {\n observer.next(content);\n observer.complete();\n\n setTimeout(() => renderTaskService.clearRenderTask(contentTask), 10);\n });\n } else {\n contentResolver.then((content) => {\n observer.next(content);\n observer.complete();\n });\n }\n },\n ).pipe(\n switchMap((contentFile) => {\n if (typeof contentFile === 'string') {\n const { content, attributes } =\n parseRawContentFile<Attributes>(contentFile);\n return from(contentRenderer.render(content)).pipe(\n map((rendered) => ({\n filename: resolvedBase,\n slug,\n attributes,\n content,\n toc: rendered.toc ?? [],\n })),\n );\n }\n return of({\n filename: resolvedBase,\n slug,\n attributes: contentFile.metadata,\n content: contentFile.default,\n toc: [],\n });\n }),\n );\n}\n\n/**\n * Retrieves the static content using the provided param and/or prefix.\n *\n * @param param route parameter (default: 'slug')\n * @param fallback fallback text if content file is not found (default: 'No Content Found')\n */\nexport function injectContent<\n Attributes extends Record<string, any> = Record<string, any>,\n>(\n param:\n | string\n | {\n param: string;\n subdirectory: string;\n }\n | {\n customFilename: string;\n } = 'slug',\n fallback = 'No Content Found',\n): Observable<ContentFile<Attributes | Record<string, never>>> {\n const contentFiles = inject(CONTENT_FILES_TOKEN);\n const contentRenderer = inject(ContentRenderer);\n const renderTaskService = inject(RenderTaskService);\n const task = renderTaskService.addRenderTask();\n\n if (typeof param === 'string' || 'param' in param) {\n const prefix = typeof param === 'string' ? '' : `${param.subdirectory}/`;\n const route = inject(ActivatedRoute);\n const paramKey = typeof param === 'string' ? param : param.param;\n return route.paramMap.pipe(\n map((params) => params.get(paramKey)),\n switchMap((slug) => {\n if (slug) {\n return getContentFile<Attributes>(\n contentFiles,\n prefix,\n slug,\n fallback,\n renderTaskService,\n contentRenderer,\n );\n }\n return of({\n filename: '',\n slug: '',\n attributes: {},\n content: fallback,\n toc: [],\n });\n }),\n tap(() => renderTaskService.clearRenderTask(task)),\n );\n } else {\n return getContentFile<Attributes>(\n contentFiles,\n '',\n param.customFilename,\n fallback,\n renderTaskService,\n contentRenderer,\n ).pipe(tap(() => renderTaskService.clearRenderTask(task)));\n }\n}\n","/**\n * Credit goes to Scully for original implementation\n * https://github.com/scullyio/scully/blob/main/libs/scully/src/lib/fileHanderPlugins/markdown.ts\n */\nimport { inject, Injectable } from '@angular/core';\nimport { marked } from 'marked';\nimport { gfmHeadingId } from 'marked-gfm-heading-id';\nimport { mangle } from 'marked-mangle';\nimport { MarkedContentHighlighter } from './marked-content-highlighter';\n\n@Injectable()\nexport class MarkedSetupService {\n private readonly marked: typeof marked;\n private readonly highlighter = inject(MarkedContentHighlighter, {\n optional: true,\n });\n\n constructor() {\n const renderer = new marked.Renderer();\n renderer.code = ({ text, lang }) => {\n // Let's do a language based detection like on GitHub\n // So we can still have non-interpreted mermaid code\n if (lang === 'mermaid') {\n return '<pre class=\"mermaid\">' + text + '</pre>';\n }\n\n if (!lang) {\n return '<pre><code>' + text + '</code></pre>';\n }\n\n if (this.highlighter?.augmentCodeBlock) {\n return this.highlighter?.augmentCodeBlock(text, lang);\n }\n\n return `<pre class=\"language-${lang}\"><code class=\"language-${lang}\">${text}</code></pre>`;\n };\n\n const extensions = [gfmHeadingId(), mangle()];\n\n if (this.highlighter) {\n extensions.push(this.highlighter.getHighlightExtension());\n }\n\n marked.use(...extensions, {\n renderer,\n pedantic: false,\n gfm: true,\n breaks: false,\n });\n\n this.marked = marked;\n }\n\n getMarkedInstance(): typeof marked {\n return this.marked;\n }\n}\n","import { inject, Injectable } from '@angular/core';\nimport { getHeadingList } from 'marked-gfm-heading-id';\n\nimport {\n ContentRenderer,\n RenderedContent,\n TableOfContentItem,\n} from './content-renderer';\nimport { MarkedSetupService } from './marked-setup.service';\n\n@Injectable()\nexport class MarkdownContentRendererService implements ContentRenderer {\n #marked = inject(MarkedSetupService, { self: true });\n\n async render(content: string): Promise<RenderedContent> {\n const renderedContent = await this.#marked\n .getMarkedInstance()\n .parse(content);\n return {\n content: renderedContent,\n toc: getHeadingList(),\n };\n }\n\n getContentHeadings(content: string): TableOfContentItem[] {\n return [...content.matchAll(/^(#{1,6})\\s+(.+?)\\s*$/gm)].map((match) => ({\n id: match[2]\n .trim()\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/\\s+/g, '-'),\n level: match[1].length,\n text: match[2].trim(),\n }));\n }\n\n // eslint-disable-next-line\n enhance(): void {}\n}\n","import { Provider, InjectionToken } from '@angular/core';\nimport { ContentRenderer, NoopContentRenderer } from './content-renderer';\nimport { RenderTaskService } from './render-task.service';\nimport { withContentFileLoader } from './content-file-loader';\nimport { withContentListLoader } from './content-list-loader';\n\nexport interface MarkdownRendererOptions {\n loadMermaid?: () => Promise<typeof import('mermaid')>;\n}\n\nconst CONTENT_RENDERER_PROVIDERS: Provider[] = [\n {\n provide: ContentRenderer,\n useClass: NoopContentRenderer,\n },\n withContentFileLoader(),\n withContentListLoader(),\n];\n\nexport function withMarkdownRenderer(\n options?: MarkdownRendererOptions,\n): Provider {\n return [\n CONTENT_RENDERER_PROVIDERS,\n options?.loadMermaid\n ? [\n {\n provide: MERMAID_IMPORT_TOKEN,\n useFactory: options.loadMermaid,\n },\n ]\n : [],\n ];\n}\n\nexport function provideContent(...features: Provider[]): Provider[] {\n return [\n { provide: RenderTaskService, useClass: RenderTaskService },\n ...features,\n ];\n}\n\nexport const MERMAID_IMPORT_TOKEN: InjectionToken<\n Promise<typeof import('mermaid')>\n> = new InjectionToken<Promise<typeof import('mermaid')>>('mermaid_import');\n","import {\n AfterViewChecked,\n Component,\n inject,\n Input,\n ViewEncapsulation,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { ActivatedRoute } from '@angular/router';\n\nimport { ContentRenderer } from './content-renderer';\nimport { AnchorNavigationDirective } from './anchor-navigation.directive';\n\n@Component({\n selector: 'analog-markdown-route',\n standalone: true,\n imports: [],\n hostDirectives: [AnchorNavigationDirective],\n preserveWhitespaces: true,\n encapsulation: ViewEncapsulation.None,\n template: `<div [innerHTML]=\"content\" [class]=\"classes\"></div>`,\n})\nexport default class AnalogMarkdownRouteComponent implements AfterViewChecked {\n private sanitizer = inject(DomSanitizer);\n private route = inject(ActivatedRoute);\n contentRenderer: ContentRenderer = inject(ContentRenderer);\n\n protected content: SafeHtml = this.sanitizer.bypassSecurityTrustHtml(\n this.route.snapshot.data['renderedAnalogContent'],\n );\n\n @Input() classes = 'analog-markdown-route';\n\n ngAfterViewChecked(): void {\n this.contentRenderer.enhance();\n }\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport {\n AfterViewChecked,\n Component,\n InputSignal,\n NgZone,\n PLATFORM_ID,\n Signal,\n ViewEncapsulation,\n computed,\n inject,\n input,\n} from '@angular/core';\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { ActivatedRoute, Data } from '@angular/router';\nimport { from, Observable, of } from 'rxjs';\nimport { catchError, map, switchMap } from 'rxjs/operators';\n\nimport { AnchorNavigationDirective } from './anchor-navigation.directive';\nimport { ContentRenderer } from './content-renderer';\nimport { MERMAID_IMPORT_TOKEN } from './provide-content';\n\n@Component({\n selector: 'analog-markdown',\n standalone: true,\n hostDirectives: [AnchorNavigationDirective],\n preserveWhitespaces: true,\n encapsulation: ViewEncapsulation.None,\n template: ` <div [innerHTML]=\"htmlContent()\" [class]=\"classes()\"></div> `,\n})\nexport default class AnalogMarkdownComponent implements AfterViewChecked {\n private sanitizer = inject(DomSanitizer);\n private route = inject(ActivatedRoute);\n private zone = inject(NgZone);\n private readonly platformId = inject(PLATFORM_ID);\n private readonly mermaidImport = inject(MERMAID_IMPORT_TOKEN, {\n optional: true,\n });\n private mermaid: typeof import('mermaid') | undefined;\n\n private contentSource: Signal<SafeHtml | string | undefined> = toSignal(\n this.getContentSource(),\n );\n readonly htmlContent: Signal<SafeHtml | string | undefined> = computed(() => {\n const inputContent = this.content();\n\n if (inputContent) {\n return this.sanitizer.bypassSecurityTrustHtml(inputContent as string);\n }\n\n return this.contentSource();\n });\n readonly content: InputSignal<string | object | null | undefined> = input<\n string | object | null\n >();\n readonly classes: InputSignal<string> = input('analog-markdown');\n\n contentRenderer: ContentRenderer = inject(ContentRenderer);\n\n constructor() {\n if (isPlatformBrowser(this.platformId) && this.mermaidImport) {\n // Mermaid can only be loaded on client side\n this.loadMermaid(this.mermaidImport);\n }\n }\n\n getContentSource(): Observable<SafeHtml | string> {\n return this.route.data.pipe(\n map<Data, string>((data) => data['_analogContent'] ?? ''),\n switchMap((contentString) => this.renderContent(contentString)),\n map((content) => this.sanitizer.bypassSecurityTrustHtml(content)),\n catchError((e) => of(`There was an error ${e}`)),\n );\n }\n\n async renderContent(content: string): Promise<string> {\n const rendered = await this.contentRenderer.render(content);\n return rendered.content;\n }\n\n ngAfterViewChecked(): void {\n this.contentRenderer.enhance();\n this.zone.runOutsideAngular(() => this.mermaid?.default.run());\n }\n\n private loadMermaid(mermaidImport: Promise<typeof import('mermaid')>) {\n this.zone.runOutsideAngular(() =>\n // Wrap into an observable to avoid redundant initialization once\n // the markdown component is destroyed before the promise is resolved.\n from(mermaidImport)\n .pipe(takeUntilDestroyed())\n .subscribe((mermaid) => {\n this.mermaid = mermaid;\n this.mermaid.default.initialize({ startOnLoad: false });\n // Explicitly running mermaid as ngAfterViewChecked\n // has probably already been called\n this.mermaid?.default.run();\n }),\n );\n }\n}\n"],"mappings":"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"}
@@ -91,7 +91,7 @@ var RenderTaskService = class RenderTaskService {
91
91
  static {
92
92
  this.ɵfac = i0.ɵɵngDeclareFactory({
93
93
  minVersion: "12.0.0",
94
- version: "21.2.6",
94
+ version: "21.2.8",
95
95
  ngImport: i0,
96
96
  type: RenderTaskService,
97
97
  deps: [],
@@ -101,7 +101,7 @@ var RenderTaskService = class RenderTaskService {
101
101
  static {
102
102
  this.ɵprov = i0.ɵɵngDeclareInjectable({
103
103
  minVersion: "12.0.0",
104
- version: "21.2.6",
104
+ version: "21.2.8",
105
105
  ngImport: i0,
106
106
  type: RenderTaskService
107
107
  });
@@ -109,7 +109,7 @@ var RenderTaskService = class RenderTaskService {
109
109
  };
110
110
  i0.ɵɵngDeclareClassMetadata({
111
111
  minVersion: "12.0.0",
112
- version: "21.2.6",
112
+ version: "21.2.8",
113
113
  ngImport: i0,
114
114
  type: RenderTaskService,
115
115
  decorators: [{ type: Injectable }]
@@ -15,7 +15,7 @@ var ContentRenderer = class ContentRenderer {
15
15
  static {
16
16
  this.ɵfac = i0.ɵɵngDeclareFactory({
17
17
  minVersion: "12.0.0",
18
- version: "21.2.6",
18
+ version: "21.2.8",
19
19
  ngImport: i0,
20
20
  type: ContentRenderer,
21
21
  deps: [],
@@ -25,7 +25,7 @@ var ContentRenderer = class ContentRenderer {
25
25
  static {
26
26
  this.ɵprov = i0.ɵɵngDeclareInjectable({
27
27
  minVersion: "12.0.0",
28
- version: "21.2.6",
28
+ version: "21.2.8",
29
29
  ngImport: i0,
30
30
  type: ContentRenderer
31
31
  });
@@ -33,7 +33,7 @@ var ContentRenderer = class ContentRenderer {
33
33
  };
34
34
  i0.ɵɵngDeclareClassMetadata({
35
35
  minVersion: "12.0.0",
36
- version: "21.2.6",
36
+ version: "21.2.8",
37
37
  ngImport: i0,
38
38
  type: ContentRenderer,
39
39
  decorators: [{ type: Injectable }]
@@ -0,0 +1,40 @@
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: "21.2.8",
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: "21.2.8",
19
+ ngImport: i0,
20
+ type: MarkedContentHighlighter
21
+ });
22
+ }
23
+ };
24
+ i0.ɵɵngDeclareClassMetadata({
25
+ minVersion: "12.0.0",
26
+ version: "21.2.8",
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
@@ -0,0 +1 @@
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":";;;AASO,IAAA,2BAAA,MAAA,yBAAe;;oCADrB;GAAA,YAAY;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAA,MAAA,EAAA;GAAA,QAAA,GAAA,gBAAA;GAAA,CAAA;;;;;;;;;;;AAiBX,GAAA,yBAAO;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAA,YAAA,CAAA,EAAW,MAAA,YAA6B,CAAA;CAAA,CAAA;SAAU,gBAAA,UAAA"}
@@ -0,0 +1,45 @@
1
+ import fm from "front-matter";
2
+ //#region packages/content/src/lib/parse-raw-content-file.ts
3
+ var FrontmatterValidationError = class extends Error {
4
+ constructor(issues, filename) {
5
+ const issueMessages = issues.map((i) => {
6
+ const path = i.path ? ` at "${i.path.map((p) => typeof p === "object" ? p.key : p).join(".")}"` : "";
7
+ return ` - ${i.message}${path}`;
8
+ }).join("\n");
9
+ const prefix = filename ? `"${filename}" f` : "F";
10
+ super(`${prefix}rontmatter validation failed:\n${issueMessages}`);
11
+ this.issues = issues;
12
+ this.filename = filename;
13
+ this.name = "FrontmatterValidationError";
14
+ }
15
+ };
16
+ function parseRawContentFile(rawContentFile, schema, filename) {
17
+ const { body, attributes } = fm(rawContentFile);
18
+ if (schema) {
19
+ const result = schema["~standard"].validate(attributes);
20
+ if (result != null && typeof result.then === "function") throw new Error("parseRawContentFile does not support async schema validation. Use parseRawContentFileAsync() for async schemas.");
21
+ const syncResult = result;
22
+ if (syncResult.issues) throw new FrontmatterValidationError(syncResult.issues, filename);
23
+ return {
24
+ content: body,
25
+ attributes: syncResult.value
26
+ };
27
+ }
28
+ return {
29
+ content: body,
30
+ attributes
31
+ };
32
+ }
33
+ async function parseRawContentFileAsync(rawContentFile, schema, filename) {
34
+ const { body, attributes } = fm(rawContentFile);
35
+ const result = await schema["~standard"].validate(attributes);
36
+ if (result.issues) throw new FrontmatterValidationError(result.issues, filename);
37
+ return {
38
+ content: body,
39
+ attributes: result.value
40
+ };
41
+ }
42
+ //#endregion
43
+ export { parseRawContentFile as n, parseRawContentFileAsync as r, FrontmatterValidationError as t };
44
+
45
+ //# sourceMappingURL=parse-raw-content-file.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-raw-content-file.mjs","names":[],"sources":["../../src/lib/parse-raw-content-file.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport fm from 'front-matter';\n\nexport class FrontmatterValidationError extends Error {\n constructor(\n public readonly issues: ReadonlyArray<StandardSchemaV1.Issue>,\n public readonly filename?: string,\n ) {\n const issueMessages = issues\n .map((i) => {\n const path = i.path\n ? ` at \"${i.path.map((p) => (typeof p === 'object' ? p.key : p)).join('.')}\"`\n : '';\n return ` - ${i.message}${path}`;\n })\n .join('\\n');\n const prefix = filename ? `\"${filename}\" f` : 'F';\n super(`${prefix}rontmatter validation failed:\\n${issueMessages}`);\n this.name = 'FrontmatterValidationError';\n }\n}\n\nexport function parseRawContentFile<\n Attributes extends Record<string, any> = Record<string, any>,\n>(rawContentFile: string): { content: string; attributes: Attributes };\n\nexport function parseRawContentFile<TSchema extends StandardSchemaV1>(\n rawContentFile: string,\n schema: TSchema,\n filename?: string,\n): { content: string; attributes: StandardSchemaV1.InferOutput<TSchema> };\n\nexport function parseRawContentFile(\n rawContentFile: string,\n schema?: StandardSchemaV1,\n filename?: string,\n): { content: string; attributes: unknown } {\n const { body, attributes } = fm(rawContentFile);\n\n if (schema) {\n const result = schema['~standard'].validate(attributes);\n if (\n result != null &&\n typeof (result as PromiseLike<unknown>).then === 'function'\n ) {\n throw new Error(\n 'parseRawContentFile does not support async schema validation. ' +\n 'Use parseRawContentFileAsync() for async schemas.',\n );\n }\n const syncResult = result as StandardSchemaV1.Result<\n StandardSchemaV1.InferOutput<typeof schema>\n >;\n if (syncResult.issues) {\n throw new FrontmatterValidationError(syncResult.issues, filename);\n }\n return { content: body, attributes: syncResult.value };\n }\n\n return { content: body, attributes };\n}\n\nexport async function parseRawContentFileAsync<\n TSchema extends StandardSchemaV1,\n>(\n rawContentFile: string,\n schema: TSchema,\n filename?: string,\n): Promise<{\n content: string;\n attributes: StandardSchemaV1.InferOutput<TSchema>;\n}> {\n const { body, attributes } = fm(rawContentFile);\n const result = await schema['~standard'].validate(attributes);\n if (result.issues) {\n throw new FrontmatterValidationError(result.issues, filename);\n }\n return { content: body, attributes: result.value };\n}\n"],"mappings":";;AAGA,IAAa,6BAAb,cAAgD,MAAM;CACpD,YACE,QACA,UACA;EACM,MAAA,gBAAgB,OAEZ,KAAS,MAAA;GAGR,MAAO,OAAE,EAAA,OAEP,QAAA,EAAA,KAAA,KAAA,MAAA,OAAA,MAAA,WAAA,EAAA,MAAA,EAAA,CAAA,KAAA,IAAA,CAAA,KACE;AACN,UAAO,OAAA,EAAA,UAAA;IAZA,CACA,KAAA,KAAA;EAYX,MAAO,SAAA,WAAA,IAAA,SAAA,OAAA;;;AAcT,OAAA,WAAS;AAKR,OAAE,OAAM;;;AAIZ,SACY,oBACF,gBAAyC,QACjD,UAAA;CACA,MAAM,EAAA,MAAI,eACR,GAAA,eAAA;;EAIE,MAAA,SAAa,OAAA,aAAA,SAAA,WAAA;AAGf,MAAA,UAAW,QACP,OAAI,OAAA,SAAA,WAAA,OAAA,IAAA,MAAA,kHAEL;EAAiB,MAAA,aAAuB;AAAO,MAAA,WAAA,OAAA,OAAA,IAAA,2BAAA,WAAA,QAAA,SAAA;AAG/C,SAAS;GAAA,SAAA;GAAA,YAAA,WAAA;GAAA;;AAAkB,QAAA;EAAA,SAAA;EAAA;EAAA;;AAGtC,eAAsB,yBAGpB,gBACA,QACA,UAIC;CACD,MAAQ,EAAA,MAAM,eAAkB,GAAA,eAAe;CAC/C,MAAM,SAAS,MAAM,OAAO,aAAa,SAAS,WAAW;AAC7D,KAAI,OAAO,OACH,OAAI,IAAA,2BAA2B,OAAO,QAAQ,SAAS;AAE/D,QAAO;EAAA,SAAA;EAAA,YAAA,OAAA;EAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@analogjs/content",
3
- "version": "3.0.0-alpha.25",
3
+ "version": "3.0.0-alpha.27",
4
4
  "description": "Content Rendering for Analog",
5
5
  "type": "module",
6
6
  "author": "Brandon Roberts <robertsbt@gmail.com>",
@@ -113,7 +113,8 @@
113
113
  "tslib": "^2.3.0"
114
114
  },
115
115
  "devDependencies": {
116
- "@analogjs/vite-plugin-angular": "3.0.0-alpha.25"
116
+ "@analogjs/vite-plugin-angular": "3.0.0-alpha.27",
117
+ "@analogjs/vitest-angular": "3.0.0-alpha.27"
117
118
  },
118
119
  "ng-update": {
119
120
  "packageGroup": [
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../content-plugin/src/index.ts"],"mappings":";cACM,QAAA;AAAA"}
@@ -0,0 +1 @@
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"}
@@ -0,0 +1 @@
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,4 +1,4 @@
1
- import { MarkedContentHighlighter } from '@analogjs/content';
1
+ import { MarkedContentHighlighter } from '../../../src/lib/marked-content-highlighter';
2
2
  import * as i0 from "@angular/core";
3
3
  export declare class PrismHighlighter extends MarkedContentHighlighter {
4
4
  augmentCodeBlock(code: string, lang: string): string;
@@ -1,6 +1,6 @@
1
1
  import type { StandardSchemaV1 } from '@standard-schema/spec';
2
2
  import { Signal, type ResourceRef } from '@angular/core';
3
- import { ContentFile } from '@analogjs/content';
3
+ import type { ContentFile } from '../../src/lib/content-file';
4
4
  export interface ContentFileResourceResult<Attributes extends Record<string, any> = Record<string, any>> extends ContentFile<Attributes | Record<string, never>> {
5
5
  toc: Array<{
6
6
  id: string;
@@ -1,3 +1,4 @@
1
1
  import { ResourceRef } from '@angular/core';
2
- import { ContentFile, InjectContentFilesFilterFunction } from '@analogjs/content';
2
+ import type { ContentFile } from '../../src/lib/content-file';
3
+ import type { InjectContentFilesFilterFunction } from '../../src/lib/inject-content-files';
3
4
  export declare function contentFilesResource<Attributes extends Record<string, any>>(filterFn?: InjectContentFilesFilterFunction<Attributes> | undefined): ResourceRef<ContentFile<Attributes>[] | undefined>;