@analogjs/content 3.0.0-alpha.26 → 3.0.0-alpha.28
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.
- package/fesm2022/analogjs-content-devtools.mjs +3 -3
- package/fesm2022/analogjs-content-md4x.mjs +6 -6
- package/fesm2022/analogjs-content-mdc.mjs +3 -3
- package/fesm2022/analogjs-content-prism-highlighter.mjs +5 -4
- package/fesm2022/analogjs-content-prism-highlighter.mjs.map +1 -1
- package/fesm2022/analogjs-content-resources.mjs +3 -1
- package/fesm2022/analogjs-content-resources.mjs.map +1 -1
- package/fesm2022/analogjs-content-shiki-highlighter.mjs +1 -1
- package/fesm2022/analogjs-content-shiki-highlighter.mjs.map +1 -1
- package/fesm2022/analogjs-content.mjs +17 -92
- package/fesm2022/analogjs-content.mjs.map +1 -1
- package/fesm2022/content-list-loader.mjs +3 -3
- package/fesm2022/content-renderer.mjs +3 -3
- package/fesm2022/marked-content-highlighter.mjs +40 -0
- package/fesm2022/marked-content-highlighter.mjs.map +1 -0
- package/fesm2022/parse-raw-content-file.mjs +45 -0
- package/fesm2022/parse-raw-content-file.mjs.map +1 -0
- package/package.json +3 -2
- package/plugin/src/index.d.ts.map +1 -0
- package/plugin/src/migrations/update-markdown-version/compat.d.ts.map +1 -0
- package/plugin/src/migrations/update-markdown-version/update-markdown-version.d.ts.map +1 -0
- package/types/prism-highlighter/src/lib/prism-highlighter.d.ts +1 -1
- package/types/resources/src/content-file-resource.d.ts +1 -1
- package/types/resources/src/content-files-resource.d.ts +2 -1
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
3
|
+
"version": "3.0.0-alpha.28",
|
|
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.
|
|
116
|
+
"@analogjs/vite-plugin-angular": "3.0.0-alpha.28",
|
|
117
|
+
"@analogjs/vitest-angular": "3.0.0-alpha.28"
|
|
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 '
|
|
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 '
|
|
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
|
|
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>;
|