@analogjs/content 3.0.0-alpha.9 → 3.0.0-alpha.91
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-md4x.mjs +291 -0
- package/fesm2022/analogjs-content-md4x.mjs.map +1 -0
- package/fesm2022/analogjs-content-mdc.mjs +170 -0
- package/fesm2022/analogjs-content-mdc.mjs.map +1 -0
- package/fesm2022/analogjs-content-og.mjs.map +1 -0
- package/fesm2022/analogjs-content-prism-highlighter.mjs +5 -4
- package/fesm2022/analogjs-content-prism-highlighter.mjs.map +1 -0
- package/fesm2022/analogjs-content-resources.mjs +39 -25
- package/fesm2022/analogjs-content-resources.mjs.map +1 -0
- package/fesm2022/analogjs-content-shiki-highlighter.mjs +1 -1
- package/fesm2022/analogjs-content-shiki-highlighter.mjs.map +1 -0
- package/fesm2022/analogjs-content.mjs +62 -357
- package/fesm2022/analogjs-content.mjs.map +1 -0
- package/fesm2022/content-list-loader.mjs +260 -0
- package/fesm2022/content-list-loader.mjs.map +1 -0
- package/fesm2022/content-renderer.mjs +128 -0
- package/fesm2022/content-renderer.mjs.map +1 -0
- 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/md4x/package.json +4 -0
- package/mdc/package.json +4 -0
- package/package.json +58 -36
- package/plugin/migrations.json +1 -1
- package/plugin/package.json +1 -17
- package/plugin/src/index.d.ts +3 -1
- package/plugin/src/index.d.ts.map +1 -0
- package/plugin/src/index.js +4 -3
- package/plugin/src/index.js.map +1 -0
- package/plugin/src/migrations/update-markdown-version/compat.d.ts +5 -2
- package/plugin/src/migrations/update-markdown-version/compat.d.ts.map +1 -0
- package/plugin/src/migrations/update-markdown-version/compat.js +9 -0
- package/plugin/src/migrations/update-markdown-version/compat.js.map +1 -0
- package/plugin/src/migrations/update-markdown-version/update-markdown-version.d.ts +6 -2
- package/plugin/src/migrations/update-markdown-version/update-markdown-version.d.ts.map +1 -0
- package/plugin/src/migrations/update-markdown-version/update-markdown-version.js +21 -0
- package/plugin/src/migrations/update-markdown-version/update-markdown-version.js.map +1 -0
- package/types/md4x/src/index.d.ts +5 -0
- package/types/md4x/src/lib/md4x-content-renderer.service.d.ts +33 -0
- package/types/md4x/src/lib/md4x-wasm-content-renderer.service.d.ts +16 -0
- package/types/md4x/src/lib/provide-md4x.d.ts +26 -0
- package/types/md4x/src/lib/streaming-markdown-renderer.d.ts +21 -0
- package/types/mdc/src/index.d.ts +2 -0
- package/types/mdc/src/lib/mdc-component-registry.d.ts +25 -0
- package/types/mdc/src/lib/mdc-renderer.directive.d.ts +33 -0
- package/types/prism-highlighter/src/lib/prism-highlighter.d.ts +1 -1
- package/types/resources/src/content-file-resource.d.ts +32 -7
- package/types/resources/src/content-files-resource.d.ts +2 -1
- package/types/src/index.d.ts +6 -3
- package/types/src/lib/content-locale.d.ts +68 -0
- package/types/src/lib/get-content-files.d.ts +19 -4
- package/types/src/lib/parse-raw-content-file.d.ts +15 -1
- package/types/src/lib/utils/escape-html.d.ts +7 -0
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { n as NoopContentRenderer, t as ContentRenderer } from "./content-renderer.mjs";
|
|
2
|
+
import { a as injectContentFileLoader, c as injectContentFilesMap, d as CONTENT_LOCALE, f as filterByLocale, h as withLocaleCandidates, i as CONTENT_FILE_LOADER, l as RenderTaskService, m as withLocale, n as injectContentListLoader, o as withContentFileLoader, p as injectContentLocale, 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";
|
|
1
5
|
import * as i0 from "@angular/core";
|
|
2
|
-
import { Component, Directive, HostListener, Injectable, InjectionToken, Input, NgZone, PLATFORM_ID,
|
|
3
|
-
import {
|
|
6
|
+
import { Component, Directive, HostListener, Injectable, InjectionToken, Input, NgZone, PLATFORM_ID, ViewEncapsulation, computed, inject, input } from "@angular/core";
|
|
7
|
+
import { DOCUMENT, Location, isPlatformBrowser } from "@angular/common";
|
|
4
8
|
import { ActivatedRoute, Router } from "@angular/router";
|
|
5
|
-
import { Observable, from, of } from "rxjs";
|
|
9
|
+
import { Observable, firstValueFrom, from, isObservable, of } from "rxjs";
|
|
6
10
|
import { catchError, map, switchMap, tap } from "rxjs/operators";
|
|
7
|
-
import fm from "front-matter";
|
|
8
11
|
import { getHeadingList, gfmHeadingId } from "marked-gfm-heading-id";
|
|
9
12
|
import { marked } from "marked";
|
|
10
13
|
import { mangle } from "marked-mangle";
|
|
@@ -20,7 +23,10 @@ var AnchorNavigationDirective = class AnchorNavigationDirective {
|
|
|
20
23
|
handleNavigation(element) {
|
|
21
24
|
if (element instanceof HTMLAnchorElement && isInternalUrl(element, this.document) && hasTargetSelf(element) && !hasDownloadAttribute(element)) {
|
|
22
25
|
const { pathname, search, hash } = element;
|
|
23
|
-
const
|
|
26
|
+
const isFragmentOnly = element.getAttribute("href")?.startsWith("#");
|
|
27
|
+
const resolvedPathname = isFragmentOnly ? this.document.location.pathname : pathname;
|
|
28
|
+
const resolvedSearch = isFragmentOnly ? this.document.location.search : search;
|
|
29
|
+
const url = this.location.normalize(`${resolvedPathname}${resolvedSearch}${hash}`);
|
|
24
30
|
this.router.navigateByUrl(url);
|
|
25
31
|
return false;
|
|
26
32
|
}
|
|
@@ -29,7 +35,7 @@ var AnchorNavigationDirective = class AnchorNavigationDirective {
|
|
|
29
35
|
static {
|
|
30
36
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
31
37
|
minVersion: "12.0.0",
|
|
32
|
-
version: "
|
|
38
|
+
version: "22.1.5",
|
|
33
39
|
ngImport: i0,
|
|
34
40
|
type: AnchorNavigationDirective,
|
|
35
41
|
deps: [],
|
|
@@ -39,7 +45,7 @@ var AnchorNavigationDirective = class AnchorNavigationDirective {
|
|
|
39
45
|
static {
|
|
40
46
|
this.ɵdir = i0.ɵɵngDeclareDirective({
|
|
41
47
|
minVersion: "14.0.0",
|
|
42
|
-
version: "
|
|
48
|
+
version: "22.1.5",
|
|
43
49
|
type: AnchorNavigationDirective,
|
|
44
50
|
isStandalone: true,
|
|
45
51
|
selector: "[analogAnchorNavigation]",
|
|
@@ -50,7 +56,7 @@ var AnchorNavigationDirective = class AnchorNavigationDirective {
|
|
|
50
56
|
};
|
|
51
57
|
i0.ɵɵngDeclareClassMetadata({
|
|
52
58
|
minVersion: "12.0.0",
|
|
53
|
-
version: "
|
|
59
|
+
version: "22.1.5",
|
|
54
60
|
ngImport: i0,
|
|
55
61
|
type: AnchorNavigationDirective,
|
|
56
62
|
decorators: [{
|
|
@@ -75,269 +81,28 @@ function isInternalUrl(anchorElement, document) {
|
|
|
75
81
|
return anchorElement.host === document.location.host && anchorElement.protocol === document.location.protocol;
|
|
76
82
|
}
|
|
77
83
|
//#endregion
|
|
78
|
-
//#region packages/content/src/lib/
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return [];
|
|
88
|
-
}
|
|
89
|
-
enhance() {}
|
|
90
|
-
static {
|
|
91
|
-
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
92
|
-
minVersion: "12.0.0",
|
|
93
|
-
version: "21.1.1",
|
|
94
|
-
ngImport: i0,
|
|
95
|
-
type: ContentRenderer,
|
|
96
|
-
deps: [],
|
|
97
|
-
target: i0.ɵɵFactoryTarget.Injectable
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
static {
|
|
101
|
-
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
102
|
-
minVersion: "12.0.0",
|
|
103
|
-
version: "21.1.1",
|
|
104
|
-
ngImport: i0,
|
|
105
|
-
type: ContentRenderer
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
110
|
-
minVersion: "12.0.0",
|
|
111
|
-
version: "21.1.1",
|
|
112
|
-
ngImport: i0,
|
|
113
|
-
type: ContentRenderer,
|
|
114
|
-
decorators: [{ type: Injectable }]
|
|
115
|
-
});
|
|
116
|
-
var NoopContentRenderer = class {
|
|
117
|
-
constructor() {
|
|
118
|
-
this.transferState = inject(TransferState);
|
|
119
|
-
this.contentId = 0;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Generates a hash from the content string
|
|
123
|
-
* to be used with the transfer state
|
|
124
|
-
*/
|
|
125
|
-
generateHash(str) {
|
|
126
|
-
let hash = 0;
|
|
127
|
-
for (let i = 0, len = str.length; i < len; i++) {
|
|
128
|
-
const chr = str.charCodeAt(i);
|
|
129
|
-
hash = (hash << 5) - hash + chr;
|
|
130
|
-
hash |= 0;
|
|
131
|
-
}
|
|
132
|
-
return hash;
|
|
133
|
-
}
|
|
134
|
-
async render(content) {
|
|
135
|
-
this.contentId = this.generateHash(content);
|
|
136
|
-
const toc = this.getContentHeadings(content);
|
|
137
|
-
const key = makeStateKey(`content-headings-${this.contentId}`);
|
|
138
|
-
return {
|
|
139
|
-
content,
|
|
140
|
-
toc: this.transferState.get(key, toc)
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
enhance() {}
|
|
144
|
-
getContentHeadings(content) {
|
|
145
|
-
return this.extractHeadings(content);
|
|
146
|
-
}
|
|
147
|
-
extractHeadings(content) {
|
|
148
|
-
const markdownHeadings = this.extractHeadingsFromMarkdown(content);
|
|
149
|
-
if (markdownHeadings.length > 0) return markdownHeadings;
|
|
150
|
-
return this.extractHeadingsFromHtml(content);
|
|
151
|
-
}
|
|
152
|
-
extractHeadingsFromMarkdown(content) {
|
|
153
|
-
const lines = content.split("\n");
|
|
154
|
-
const toc = [];
|
|
155
|
-
const slugCounts = /* @__PURE__ */ new Map();
|
|
156
|
-
for (const line of lines) {
|
|
157
|
-
const match = /^(#{1,6})\s+(.+?)\s*$/.exec(line);
|
|
158
|
-
if (!match) continue;
|
|
159
|
-
const level = match[1].length;
|
|
160
|
-
const text = match[2].trim();
|
|
161
|
-
if (!text) continue;
|
|
162
|
-
const baseSlug = text.toLowerCase().replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-");
|
|
163
|
-
const count = slugCounts.get(baseSlug) ?? 0;
|
|
164
|
-
slugCounts.set(baseSlug, count + 1);
|
|
165
|
-
const id = count === 0 ? baseSlug : `${baseSlug}-${count}`;
|
|
166
|
-
toc.push({
|
|
167
|
-
id,
|
|
168
|
-
level,
|
|
169
|
-
text
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
return toc;
|
|
173
|
-
}
|
|
174
|
-
extractHeadingsFromHtml(content) {
|
|
175
|
-
const toc = [];
|
|
176
|
-
const slugCounts = /* @__PURE__ */ new Map();
|
|
177
|
-
for (const match of content.matchAll(/<h([1-6])([^>]*)>([\s\S]*?)<\/h\1>/gi)) {
|
|
178
|
-
const level = Number(match[1]);
|
|
179
|
-
const attrs = match[2] ?? "";
|
|
180
|
-
const text = (match[3] ?? "").replace(/<[^>]+>/g, "").trim();
|
|
181
|
-
if (!text) continue;
|
|
182
|
-
const idMatch = /\sid=(['"])(.*?)\1/i.exec(attrs) ?? /\sid=([^\s>]+)/i.exec(attrs);
|
|
183
|
-
let id = idMatch?.[2] ?? idMatch?.[1] ?? "";
|
|
184
|
-
if (!id) id = this.makeSlug(text, slugCounts);
|
|
185
|
-
toc.push({
|
|
186
|
-
id,
|
|
187
|
-
level,
|
|
188
|
-
text
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
return toc;
|
|
192
|
-
}
|
|
193
|
-
makeSlug(text, slugCounts) {
|
|
194
|
-
const baseSlug = text.toLowerCase().replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-");
|
|
195
|
-
const count = slugCounts.get(baseSlug) ?? 0;
|
|
196
|
-
slugCounts.set(baseSlug, count + 1);
|
|
197
|
-
return count === 0 ? baseSlug : `${baseSlug}-${count}`;
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
//#endregion
|
|
201
|
-
//#region packages/content/src/lib/get-content-files.ts
|
|
202
|
-
/**
|
|
203
|
-
* Returns the list of content files by filename with ?analog-content-list=true.
|
|
204
|
-
* We use the query param to transform the return into an array of
|
|
205
|
-
* just front matter attributes.
|
|
206
|
-
*
|
|
207
|
-
* @returns
|
|
208
|
-
*/
|
|
209
|
-
var getContentFilesList = () => {
|
|
210
|
-
return {};
|
|
211
|
-
};
|
|
212
|
-
/**
|
|
213
|
-
* Returns the lazy loaded content files for lookups.
|
|
214
|
-
*
|
|
215
|
-
* @returns
|
|
216
|
-
*/
|
|
217
|
-
var getContentFiles = () => {
|
|
218
|
-
return {};
|
|
219
|
-
};
|
|
220
|
-
//#endregion
|
|
221
|
-
//#region packages/content/src/lib/content-files-list-token.ts
|
|
222
|
-
function getSlug(filename) {
|
|
223
|
-
const base = (filename.split(/[/\\]/).pop() || "").trim().replace(/\.[^./\\]+$/, "");
|
|
224
|
-
return base === "index" ? "" : base;
|
|
225
|
-
}
|
|
226
|
-
var CONTENT_FILES_LIST_TOKEN = new InjectionToken("@analogjs/content Content Files List", {
|
|
227
|
-
providedIn: "root",
|
|
228
|
-
factory() {
|
|
229
|
-
const contentFiles = getContentFilesList();
|
|
230
|
-
return Object.keys(contentFiles).map((filename) => {
|
|
231
|
-
const attributes = contentFiles[filename];
|
|
232
|
-
const slug = attributes["slug"];
|
|
233
|
-
return {
|
|
234
|
-
filename,
|
|
235
|
-
attributes,
|
|
236
|
-
slug: slug ? encodeURI(slug) : encodeURI(getSlug(filename))
|
|
237
|
-
};
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
//#endregion
|
|
242
|
-
//#region packages/content/src/lib/content-files-token.ts
|
|
243
|
-
var CONTENT_FILES_TOKEN = new InjectionToken("@analogjs/content Content Files", {
|
|
244
|
-
providedIn: "root",
|
|
245
|
-
factory() {
|
|
246
|
-
const allFiles = { ...getContentFiles() };
|
|
247
|
-
const contentFilesList = inject(CONTENT_FILES_LIST_TOKEN);
|
|
248
|
-
const lookup = {};
|
|
249
|
-
contentFilesList.forEach((item) => {
|
|
250
|
-
const contentFilename = item.filename.replace(/(.*?)\/content/, "/src/content");
|
|
251
|
-
const fileParts = contentFilename.split("/");
|
|
252
|
-
const filePath = fileParts.slice(0, fileParts.length - 1).join("/");
|
|
253
|
-
const fileNameParts = fileParts[fileParts.length - 1].split(".");
|
|
254
|
-
const ext = fileNameParts[fileNameParts.length - 1];
|
|
255
|
-
let slug = item.slug ?? "";
|
|
256
|
-
if (slug === "") slug = "index";
|
|
257
|
-
lookup[contentFilename] = `${slug.includes("/") ? `/src/content/${slug}` : `${filePath}/${slug}`}.${ext}`.replace(/\/{2,}/g, "/");
|
|
258
|
-
});
|
|
259
|
-
const objectUsingSlugAttribute = {};
|
|
260
|
-
Object.entries(allFiles).forEach((entry) => {
|
|
261
|
-
const filename = entry[0];
|
|
262
|
-
const value = entry[1];
|
|
263
|
-
const newFilename = lookup[filename.replace(/^\/(.*?)\/content/, "/src/content")];
|
|
264
|
-
if (newFilename !== void 0) {
|
|
265
|
-
const objectFilename = newFilename.replace(/^\/(.*?)\/content/, "/src/content");
|
|
266
|
-
objectUsingSlugAttribute[objectFilename] = value;
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
return objectUsingSlugAttribute;
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
new InjectionToken("@analogjs/content Content Files", {
|
|
273
|
-
providedIn: "root",
|
|
274
|
-
factory() {
|
|
275
|
-
return signal(inject(CONTENT_FILES_TOKEN));
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
//#endregion
|
|
279
|
-
//#region packages/content/src/lib/parse-raw-content-file.ts
|
|
280
|
-
function parseRawContentFile(rawContentFile) {
|
|
281
|
-
const { body, attributes } = fm(rawContentFile);
|
|
282
|
-
return {
|
|
283
|
-
content: body,
|
|
284
|
-
attributes
|
|
285
|
-
};
|
|
84
|
+
//#region packages/content/src/lib/utils/zone-wait-for.ts
|
|
85
|
+
async function waitFor(prom) {
|
|
86
|
+
if (isObservable(prom)) prom = firstValueFrom(prom);
|
|
87
|
+
if (typeof Zone === "undefined") return prom;
|
|
88
|
+
const macroTask = Zone.current.scheduleMacroTask(`AnalogContentResolve-${Math.random()}`, () => {}, {}, () => {});
|
|
89
|
+
return prom.then((p) => {
|
|
90
|
+
macroTask.invoke();
|
|
91
|
+
return p;
|
|
92
|
+
});
|
|
286
93
|
}
|
|
287
94
|
//#endregion
|
|
288
|
-
//#region packages/content/src/lib/render-task.service.ts
|
|
289
|
-
var RenderTaskService = class RenderTaskService {
|
|
290
|
-
#pendingTasks = inject(ɵPendingTasksInternal);
|
|
291
|
-
addRenderTask() {
|
|
292
|
-
return this.#pendingTasks.add();
|
|
293
|
-
}
|
|
294
|
-
clearRenderTask(clear) {
|
|
295
|
-
if (typeof clear === "function") clear();
|
|
296
|
-
else if (typeof this.#pendingTasks.remove === "function") this.#pendingTasks.remove(clear);
|
|
297
|
-
}
|
|
298
|
-
static {
|
|
299
|
-
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
300
|
-
minVersion: "12.0.0",
|
|
301
|
-
version: "21.1.1",
|
|
302
|
-
ngImport: i0,
|
|
303
|
-
type: RenderTaskService,
|
|
304
|
-
deps: [],
|
|
305
|
-
target: i0.ɵɵFactoryTarget.Injectable
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
static {
|
|
309
|
-
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
310
|
-
minVersion: "12.0.0",
|
|
311
|
-
version: "21.1.1",
|
|
312
|
-
ngImport: i0,
|
|
313
|
-
type: RenderTaskService
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
};
|
|
317
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
318
|
-
minVersion: "12.0.0",
|
|
319
|
-
version: "21.1.1",
|
|
320
|
-
ngImport: i0,
|
|
321
|
-
type: RenderTaskService,
|
|
322
|
-
decorators: [{ type: Injectable }]
|
|
323
|
-
});
|
|
324
|
-
//#endregion
|
|
325
95
|
//#region packages/content/src/lib/content.ts
|
|
326
|
-
function getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer) {
|
|
96
|
+
function getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer, locale) {
|
|
327
97
|
const normalizedFiles = {};
|
|
328
98
|
for (const [key, resolver] of Object.entries(contentFiles)) {
|
|
329
|
-
const normalizedKey = key.replace(/^(
|
|
99
|
+
const normalizedKey = key.replace(/^(?:.*?)\/content(?=\/)/, "/src/content").replace(/\/{2,}/g, "/");
|
|
330
100
|
normalizedFiles[normalizedKey] = resolver;
|
|
331
101
|
}
|
|
332
102
|
const base = `/src/content/${prefix}${slug}`.replace(/\/{2,}/g, "/");
|
|
333
|
-
const matchKey = [
|
|
334
|
-
`${base}.md`,
|
|
335
|
-
`${base}.agx`,
|
|
336
|
-
`${base}/index.md`,
|
|
337
|
-
`${base}/index.agx`
|
|
338
|
-
].find((k) => k in normalizedFiles);
|
|
103
|
+
const matchKey = withLocaleCandidates([`${base}.md`, `${base}/index.md`], locale).find((k) => k in normalizedFiles);
|
|
339
104
|
const contentFile = matchKey ? normalizedFiles[matchKey] : void 0;
|
|
340
|
-
const resolvedBase = (matchKey || `${base}.md`).replace(/\.
|
|
105
|
+
const resolvedBase = (matchKey || `${base}.md`).replace(/\.md$/, "");
|
|
341
106
|
if (!contentFile) return of({
|
|
342
107
|
filename: resolvedBase,
|
|
343
108
|
attributes: {},
|
|
@@ -345,11 +110,12 @@ function getContentFile(contentFiles, prefix, slug, fallback, renderTaskService,
|
|
|
345
110
|
content: fallback,
|
|
346
111
|
toc: []
|
|
347
112
|
});
|
|
348
|
-
renderTaskService.addRenderTask();
|
|
113
|
+
const contentTask = renderTaskService.addRenderTask();
|
|
349
114
|
return new Observable((observer) => {
|
|
350
|
-
contentFile().then((content) => {
|
|
115
|
+
waitFor(contentFile()).then((content) => {
|
|
351
116
|
observer.next(content);
|
|
352
117
|
observer.complete();
|
|
118
|
+
setTimeout(() => renderTaskService.clearRenderTask(contentTask), 10);
|
|
353
119
|
});
|
|
354
120
|
}).pipe(switchMap((contentFile) => {
|
|
355
121
|
if (typeof contentFile === "string") {
|
|
@@ -381,13 +147,14 @@ function injectContent(param = "slug", fallback = "No Content Found") {
|
|
|
381
147
|
const contentFiles = inject(CONTENT_FILES_TOKEN);
|
|
382
148
|
const contentRenderer = inject(ContentRenderer);
|
|
383
149
|
const renderTaskService = inject(RenderTaskService);
|
|
150
|
+
const locale = inject(CONTENT_LOCALE, { optional: true });
|
|
384
151
|
const task = renderTaskService.addRenderTask();
|
|
385
152
|
if (typeof param === "string" || "param" in param) {
|
|
386
153
|
const prefix = typeof param === "string" ? "" : `${param.subdirectory}/`;
|
|
387
154
|
const route = inject(ActivatedRoute);
|
|
388
155
|
const paramKey = typeof param === "string" ? param : param.param;
|
|
389
156
|
return route.paramMap.pipe(map((params) => params.get(paramKey)), switchMap((slug) => {
|
|
390
|
-
if (slug) return getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer);
|
|
157
|
+
if (slug) return getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer, locale);
|
|
391
158
|
return of({
|
|
392
159
|
filename: "",
|
|
393
160
|
slug: "",
|
|
@@ -396,55 +163,20 @@ function injectContent(param = "slug", fallback = "No Content Found") {
|
|
|
396
163
|
toc: []
|
|
397
164
|
});
|
|
398
165
|
}), tap(() => renderTaskService.clearRenderTask(task)));
|
|
399
|
-
} else return getContentFile(contentFiles, "", param.customFilename, fallback, renderTaskService, contentRenderer).pipe(tap(() => renderTaskService.clearRenderTask(task)));
|
|
166
|
+
} else return getContentFile(contentFiles, "", param.customFilename, fallback, renderTaskService, contentRenderer, locale).pipe(tap(() => renderTaskService.clearRenderTask(task)));
|
|
400
167
|
}
|
|
401
168
|
//#endregion
|
|
402
|
-
//#region packages/content/src/lib/
|
|
403
|
-
function
|
|
404
|
-
|
|
405
|
-
const task = renderTaskService.addRenderTask();
|
|
406
|
-
const allContentFiles = inject(CONTENT_FILES_LIST_TOKEN);
|
|
407
|
-
renderTaskService.clearRenderTask(task);
|
|
408
|
-
if (filterFn) return allContentFiles.filter(filterFn);
|
|
409
|
-
return allContentFiles;
|
|
169
|
+
//#region packages/content/src/lib/utils/escape-html.ts
|
|
170
|
+
function escapeHtml(value) {
|
|
171
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'");
|
|
410
172
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
419
|
-
minVersion: "12.0.0",
|
|
420
|
-
version: "21.1.1",
|
|
421
|
-
ngImport: i0,
|
|
422
|
-
type: MarkedContentHighlighter,
|
|
423
|
-
deps: [],
|
|
424
|
-
target: i0.ɵɵFactoryTarget.Injectable
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
static {
|
|
428
|
-
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
429
|
-
minVersion: "12.0.0",
|
|
430
|
-
version: "21.1.1",
|
|
431
|
-
ngImport: i0,
|
|
432
|
-
type: MarkedContentHighlighter
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
};
|
|
436
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
437
|
-
minVersion: "12.0.0",
|
|
438
|
-
version: "21.1.1",
|
|
439
|
-
ngImport: i0,
|
|
440
|
-
type: MarkedContentHighlighter,
|
|
441
|
-
decorators: [{ type: Injectable }]
|
|
442
|
-
});
|
|
443
|
-
function withHighlighter(provider) {
|
|
444
|
-
return {
|
|
445
|
-
provide: MarkedContentHighlighter,
|
|
446
|
-
...provider
|
|
447
|
-
};
|
|
173
|
+
/**
|
|
174
|
+
* Reduces a fenced code-block info string to a safe language identifier so it
|
|
175
|
+
* cannot break out of the `class="language-..."` attribute it is interpolated
|
|
176
|
+
* into.
|
|
177
|
+
*/
|
|
178
|
+
function sanitizeLanguage(lang) {
|
|
179
|
+
return (lang ?? "").match(/^[a-zA-Z0-9-+#.]*/)?.[0] ?? "";
|
|
448
180
|
}
|
|
449
181
|
//#endregion
|
|
450
182
|
//#region packages/content/src/lib/marked-setup.service.ts
|
|
@@ -457,10 +189,11 @@ var MarkedSetupService = class MarkedSetupService {
|
|
|
457
189
|
this.highlighter = inject(MarkedContentHighlighter, { optional: true });
|
|
458
190
|
const renderer = new marked.Renderer();
|
|
459
191
|
renderer.code = ({ text, lang }) => {
|
|
460
|
-
|
|
461
|
-
if (
|
|
462
|
-
if (
|
|
463
|
-
return
|
|
192
|
+
const language = sanitizeLanguage(lang);
|
|
193
|
+
if (language === "mermaid") return "<pre class=\"mermaid\">" + escapeHtml(text) + "</pre>";
|
|
194
|
+
if (!language) return "<pre><code>" + escapeHtml(text) + "</code></pre>";
|
|
195
|
+
if (this.highlighter?.augmentCodeBlock) return this.highlighter?.augmentCodeBlock(text, language);
|
|
196
|
+
return `<pre class="language-${language}"><code class="language-${language}">${escapeHtml(text)}</code></pre>`;
|
|
464
197
|
};
|
|
465
198
|
const extensions = [gfmHeadingId(), mangle()];
|
|
466
199
|
if (this.highlighter) extensions.push(this.highlighter.getHighlightExtension());
|
|
@@ -478,7 +211,7 @@ var MarkedSetupService = class MarkedSetupService {
|
|
|
478
211
|
static {
|
|
479
212
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
480
213
|
minVersion: "12.0.0",
|
|
481
|
-
version: "
|
|
214
|
+
version: "22.1.5",
|
|
482
215
|
ngImport: i0,
|
|
483
216
|
type: MarkedSetupService,
|
|
484
217
|
deps: [],
|
|
@@ -488,7 +221,7 @@ var MarkedSetupService = class MarkedSetupService {
|
|
|
488
221
|
static {
|
|
489
222
|
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
490
223
|
minVersion: "12.0.0",
|
|
491
|
-
version: "
|
|
224
|
+
version: "22.1.5",
|
|
492
225
|
ngImport: i0,
|
|
493
226
|
type: MarkedSetupService
|
|
494
227
|
});
|
|
@@ -496,7 +229,7 @@ var MarkedSetupService = class MarkedSetupService {
|
|
|
496
229
|
};
|
|
497
230
|
i0.ɵɵngDeclareClassMetadata({
|
|
498
231
|
minVersion: "12.0.0",
|
|
499
|
-
version: "
|
|
232
|
+
version: "22.1.5",
|
|
500
233
|
ngImport: i0,
|
|
501
234
|
type: MarkedSetupService,
|
|
502
235
|
decorators: [{ type: Injectable }],
|
|
@@ -523,7 +256,7 @@ var MarkdownContentRendererService = class MarkdownContentRendererService {
|
|
|
523
256
|
static {
|
|
524
257
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
525
258
|
minVersion: "12.0.0",
|
|
526
|
-
version: "
|
|
259
|
+
version: "22.1.5",
|
|
527
260
|
ngImport: i0,
|
|
528
261
|
type: MarkdownContentRendererService,
|
|
529
262
|
deps: [],
|
|
@@ -533,7 +266,7 @@ var MarkdownContentRendererService = class MarkdownContentRendererService {
|
|
|
533
266
|
static {
|
|
534
267
|
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
535
268
|
minVersion: "12.0.0",
|
|
536
|
-
version: "
|
|
269
|
+
version: "22.1.5",
|
|
537
270
|
ngImport: i0,
|
|
538
271
|
type: MarkdownContentRendererService
|
|
539
272
|
});
|
|
@@ -541,40 +274,12 @@ var MarkdownContentRendererService = class MarkdownContentRendererService {
|
|
|
541
274
|
};
|
|
542
275
|
i0.ɵɵngDeclareClassMetadata({
|
|
543
276
|
minVersion: "12.0.0",
|
|
544
|
-
version: "
|
|
277
|
+
version: "22.1.5",
|
|
545
278
|
ngImport: i0,
|
|
546
279
|
type: MarkdownContentRendererService,
|
|
547
280
|
decorators: [{ type: Injectable }]
|
|
548
281
|
});
|
|
549
282
|
//#endregion
|
|
550
|
-
//#region packages/content/src/lib/content-file-loader.ts
|
|
551
|
-
var CONTENT_FILE_LOADER = new InjectionToken("@analogjs/content/resource File Loader");
|
|
552
|
-
function injectContentFileLoader() {
|
|
553
|
-
return inject(CONTENT_FILE_LOADER);
|
|
554
|
-
}
|
|
555
|
-
function withContentFileLoader() {
|
|
556
|
-
return {
|
|
557
|
-
provide: CONTENT_FILE_LOADER,
|
|
558
|
-
useFactory() {
|
|
559
|
-
return async () => injectContentFilesMap();
|
|
560
|
-
}
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
//#endregion
|
|
564
|
-
//#region packages/content/src/lib/content-list-loader.ts
|
|
565
|
-
var CONTENT_LIST_LOADER = new InjectionToken("@analogjs/content/resource List Loader");
|
|
566
|
-
function injectContentListLoader() {
|
|
567
|
-
return inject(CONTENT_LIST_LOADER);
|
|
568
|
-
}
|
|
569
|
-
function withContentListLoader() {
|
|
570
|
-
return {
|
|
571
|
-
provide: CONTENT_LIST_LOADER,
|
|
572
|
-
useFactory() {
|
|
573
|
-
return async () => injectContentFiles();
|
|
574
|
-
}
|
|
575
|
-
};
|
|
576
|
-
}
|
|
577
|
-
//#endregion
|
|
578
283
|
//#region packages/content/src/lib/provide-content.ts
|
|
579
284
|
var CONTENT_RENDERER_PROVIDERS = [
|
|
580
285
|
{
|
|
@@ -613,7 +318,7 @@ var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
|
|
|
613
318
|
static {
|
|
614
319
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
615
320
|
minVersion: "12.0.0",
|
|
616
|
-
version: "
|
|
321
|
+
version: "22.1.5",
|
|
617
322
|
ngImport: i0,
|
|
618
323
|
type: AnalogMarkdownRouteComponent,
|
|
619
324
|
deps: [],
|
|
@@ -623,7 +328,7 @@ var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
|
|
|
623
328
|
static {
|
|
624
329
|
this.ɵcmp = i0.ɵɵngDeclareComponent({
|
|
625
330
|
minVersion: "14.0.0",
|
|
626
|
-
version: "
|
|
331
|
+
version: "22.1.5",
|
|
627
332
|
type: AnalogMarkdownRouteComponent,
|
|
628
333
|
isStandalone: true,
|
|
629
334
|
selector: "analog-markdown-route",
|
|
@@ -639,7 +344,7 @@ var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
|
|
|
639
344
|
};
|
|
640
345
|
i0.ɵɵngDeclareClassMetadata({
|
|
641
346
|
minVersion: "12.0.0",
|
|
642
|
-
version: "
|
|
347
|
+
version: "22.1.5",
|
|
643
348
|
ngImport: i0,
|
|
644
349
|
type: AnalogMarkdownRouteComponent,
|
|
645
350
|
decorators: [{
|
|
@@ -647,7 +352,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
647
352
|
args: [{
|
|
648
353
|
selector: "analog-markdown-route",
|
|
649
354
|
standalone: true,
|
|
650
|
-
imports: [
|
|
355
|
+
imports: [],
|
|
651
356
|
hostDirectives: [AnchorNavigationDirective],
|
|
652
357
|
preserveWhitespaces: true,
|
|
653
358
|
encapsulation: ViewEncapsulation.None,
|
|
@@ -696,7 +401,7 @@ var AnalogMarkdownComponent = class AnalogMarkdownComponent {
|
|
|
696
401
|
static {
|
|
697
402
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
698
403
|
minVersion: "12.0.0",
|
|
699
|
-
version: "
|
|
404
|
+
version: "22.1.5",
|
|
700
405
|
ngImport: i0,
|
|
701
406
|
type: AnalogMarkdownComponent,
|
|
702
407
|
deps: [],
|
|
@@ -706,7 +411,7 @@ var AnalogMarkdownComponent = class AnalogMarkdownComponent {
|
|
|
706
411
|
static {
|
|
707
412
|
this.ɵcmp = i0.ɵɵngDeclareComponent({
|
|
708
413
|
minVersion: "17.1.0",
|
|
709
|
-
version: "
|
|
414
|
+
version: "22.1.5",
|
|
710
415
|
type: AnalogMarkdownComponent,
|
|
711
416
|
isStandalone: true,
|
|
712
417
|
selector: "analog-markdown",
|
|
@@ -737,7 +442,7 @@ var AnalogMarkdownComponent = class AnalogMarkdownComponent {
|
|
|
737
442
|
};
|
|
738
443
|
i0.ɵɵngDeclareClassMetadata({
|
|
739
444
|
minVersion: "12.0.0",
|
|
740
|
-
version: "
|
|
445
|
+
version: "22.1.5",
|
|
741
446
|
ngImport: i0,
|
|
742
447
|
type: AnalogMarkdownComponent,
|
|
743
448
|
decorators: [{
|
|
@@ -772,6 +477,6 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
772
477
|
}
|
|
773
478
|
});
|
|
774
479
|
//#endregion
|
|
775
|
-
export { AnchorNavigationDirective, CONTENT_FILE_LOADER, CONTENT_LIST_LOADER, ContentRenderer, MERMAID_IMPORT_TOKEN, AnalogMarkdownComponent as MarkdownComponent, MarkdownContentRendererService, AnalogMarkdownRouteComponent as MarkdownRouteComponent, MarkedContentHighlighter, MarkedSetupService, NoopContentRenderer, injectContent, injectContentFileLoader, injectContentFiles, injectContentFilesMap, injectContentListLoader, parseRawContentFile, provideContent, withContentFileLoader, withContentListLoader, withHighlighter, withMarkdownRenderer };
|
|
480
|
+
export { AnchorNavigationDirective, CONTENT_FILE_LOADER, CONTENT_LIST_LOADER, CONTENT_LOCALE, ContentRenderer, FrontmatterValidationError, MERMAID_IMPORT_TOKEN, AnalogMarkdownComponent as MarkdownComponent, MarkdownContentRendererService, AnalogMarkdownRouteComponent as MarkdownRouteComponent, MarkedContentHighlighter, MarkedSetupService, NoopContentRenderer, filterByLocale, injectContent, injectContentFileLoader, injectContentFiles, injectContentFilesMap, injectContentListLoader, injectContentLocale, parseRawContentFile, parseRawContentFileAsync, provideContent, withContentFileLoader, withContentListLoader, withHighlighter, withLocale, withLocaleCandidates, withMarkdownRenderer };
|
|
776
481
|
|
|
777
482
|
//# sourceMappingURL=analogjs-content.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analogjs-content.mjs","names":[],"sources":["../../src/lib/anchor-navigation.directive.ts","../../src/lib/utils/zone-wait-for.ts","../../src/lib/content.ts","../../src/lib/utils/escape-html.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 // A `<base>` element makes the browser resolve fragment-only hrefs\n // (e.g. `href=\"#some-id\"`) against the base URL rather than the\n // current document, so `pathname`/`search` come back as the base's\n // rather than the current page's. Fall back to the document's own\n // location in that case, or an in-page anchor link would navigate\n // to the base route and lose the fragment there.\n const isFragmentOnly = element.getAttribute('href')?.startsWith('#');\n const resolvedPathname = isFragmentOnly\n ? this.document.location.pathname\n : pathname;\n const resolvedSearch = isFragmentOnly\n ? this.document.location.search\n : search;\n const url = this.location.normalize(\n `${resolvedPathname}${resolvedSearch}${hash}`,\n );\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 { firstValueFrom, isObservable, Observable } from 'rxjs';\n\ndeclare const Zone: any;\n\nexport async function waitFor<T>(prom: Promise<T> | Observable<T>): Promise<T> {\n if (isObservable(prom)) {\n prom = firstValueFrom(prom);\n }\n\n if (typeof Zone === 'undefined') {\n return prom;\n }\n\n const macroTask = Zone.current.scheduleMacroTask(\n `AnalogContentResolve-${Math.random()}`,\n () => {\n /* noop */\n },\n {},\n () => {\n /* noop */\n },\n );\n return prom.then((p: T) => {\n macroTask.invoke();\n return p;\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_LOCALE, withLocaleCandidates } from './content-locale';\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 locale?: string | null,\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 allCandidates = withLocaleCandidates(candidates, locale);\n const matchKey = allCandidates.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 // `waitFor` is a no-op in non-Zone environments (browser without zone.js),\n // so this branch works for both SSR and client. Keeping a single path also\n // avoids Rolldown evaluating `import.meta.env.SSR` at library-build time\n // and eliminating the task-clearing branch, which caused SSR to hang once\n // the content map resolved a real lazy import.\n waitFor(contentFile()).then((content) => {\n observer.next(content);\n observer.complete();\n\n setTimeout(() => renderTaskService.clearRenderTask(contentTask), 10);\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 locale = inject(CONTENT_LOCALE, { optional: true });\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 locale,\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 locale,\n ).pipe(tap(() => renderTaskService.clearRenderTask(task)));\n }\n}\n","export function escapeHtml(value: string): string {\n return value\n .replaceAll('&', '&')\n .replaceAll('<', '<')\n .replaceAll('>', '>')\n .replaceAll('\"', '"')\n .replaceAll(\"'\", ''');\n}\n\n/**\n * Reduces a fenced code-block info string to a safe language identifier so it\n * cannot break out of the `class=\"language-...\"` attribute it is interpolated\n * into.\n */\nexport function sanitizeLanguage(lang: string | undefined): string {\n return (lang ?? '').match(/^[a-zA-Z0-9-+#.]*/)?.[0] ?? '';\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';\nimport { escapeHtml, sanitizeLanguage } from './utils/escape-html';\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 const language = sanitizeLanguage(lang);\n if (language === 'mermaid') {\n return '<pre class=\"mermaid\">' + escapeHtml(text) + '</pre>';\n }\n\n if (!language) {\n return '<pre><code>' + escapeHtml(text) + '</code></pre>';\n }\n\n if (this.highlighter?.augmentCodeBlock) {\n return this.highlighter?.augmentCodeBlock(text, language);\n }\n\n return `<pre class=\"language-${language}\"><code class=\"language-${language}\">${escapeHtml(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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"}
|