@analogjs/content 3.0.0-alpha.4 → 3.0.0-alpha.41
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/devtools/package.json +4 -0
- package/fesm2022/analogjs-content-devtools.mjs +162 -0
- package/fesm2022/analogjs-content-devtools.mjs.map +1 -0
- 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 +29 -353
- package/fesm2022/analogjs-content.mjs.map +1 -0
- package/fesm2022/content-list-loader.mjs +248 -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 +71 -36
- package/plugin/migrations.json +1 -1
- package/plugin/package.json +2 -21
- package/plugin/src/index.d.ts +3 -1
- package/plugin/src/index.d.ts.map +1 -0
- package/plugin/src/index.js +5 -4
- 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 +8 -7
- 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 +18 -20
- package/plugin/src/migrations/update-markdown-version/update-markdown-version.js.map +1 -0
- package/src/lib/devtools/content-devtools-client.ts +215 -0
- package/src/lib/devtools/content-devtools.styles.css +194 -0
- package/types/devtools/src/index.d.ts +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/devtools/content-devtools-plugin.d.ts +23 -0
- package/types/src/lib/devtools/content-devtools-renderer.d.ts +23 -0
- package/types/src/lib/devtools/index.d.ts +23 -0
- package/types/src/lib/parse-raw-content-file.d.ts +15 -1
- package/plugin/README.md +0 -11
|
@@ -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
9
|
import { Observable, from, 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";
|
|
@@ -29,7 +32,7 @@ var AnchorNavigationDirective = class AnchorNavigationDirective {
|
|
|
29
32
|
static {
|
|
30
33
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
31
34
|
minVersion: "12.0.0",
|
|
32
|
-
version: "21.
|
|
35
|
+
version: "21.2.8",
|
|
33
36
|
ngImport: i0,
|
|
34
37
|
type: AnchorNavigationDirective,
|
|
35
38
|
deps: [],
|
|
@@ -39,7 +42,7 @@ var AnchorNavigationDirective = class AnchorNavigationDirective {
|
|
|
39
42
|
static {
|
|
40
43
|
this.ɵdir = i0.ɵɵngDeclareDirective({
|
|
41
44
|
minVersion: "14.0.0",
|
|
42
|
-
version: "21.
|
|
45
|
+
version: "21.2.8",
|
|
43
46
|
type: AnchorNavigationDirective,
|
|
44
47
|
isStandalone: true,
|
|
45
48
|
selector: "[analogAnchorNavigation]",
|
|
@@ -50,7 +53,7 @@ var AnchorNavigationDirective = class AnchorNavigationDirective {
|
|
|
50
53
|
};
|
|
51
54
|
i0.ɵɵngDeclareClassMetadata({
|
|
52
55
|
minVersion: "12.0.0",
|
|
53
|
-
version: "21.
|
|
56
|
+
version: "21.2.8",
|
|
54
57
|
ngImport: i0,
|
|
55
58
|
type: AnchorNavigationDirective,
|
|
56
59
|
decorators: [{
|
|
@@ -75,269 +78,17 @@ function isInternalUrl(anchorElement, document) {
|
|
|
75
78
|
return anchorElement.host === document.location.host && anchorElement.protocol === document.location.protocol;
|
|
76
79
|
}
|
|
77
80
|
//#endregion
|
|
78
|
-
//#region packages/content/src/lib/content-renderer.ts
|
|
79
|
-
var ContentRenderer = class ContentRenderer {
|
|
80
|
-
async render(content) {
|
|
81
|
-
return {
|
|
82
|
-
content,
|
|
83
|
-
toc: []
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
getContentHeadings(_content) {
|
|
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
|
-
};
|
|
286
|
-
}
|
|
287
|
-
//#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
81
|
//#region packages/content/src/lib/content.ts
|
|
326
|
-
function getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer) {
|
|
82
|
+
function getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer, locale) {
|
|
327
83
|
const normalizedFiles = {};
|
|
328
84
|
for (const [key, resolver] of Object.entries(contentFiles)) {
|
|
329
85
|
const normalizedKey = key.replace(/^(?:.*)\/content/, "/src/content").replace(/\/{2,}/g, "/");
|
|
330
86
|
normalizedFiles[normalizedKey] = resolver;
|
|
331
87
|
}
|
|
332
88
|
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);
|
|
89
|
+
const matchKey = withLocaleCandidates([`${base}.md`, `${base}/index.md`], locale).find((k) => k in normalizedFiles);
|
|
339
90
|
const contentFile = matchKey ? normalizedFiles[matchKey] : void 0;
|
|
340
|
-
const resolvedBase = (matchKey || `${base}.md`).replace(/\.
|
|
91
|
+
const resolvedBase = (matchKey || `${base}.md`).replace(/\.md$/, "");
|
|
341
92
|
if (!contentFile) return of({
|
|
342
93
|
filename: resolvedBase,
|
|
343
94
|
attributes: {},
|
|
@@ -381,13 +132,14 @@ function injectContent(param = "slug", fallback = "No Content Found") {
|
|
|
381
132
|
const contentFiles = inject(CONTENT_FILES_TOKEN);
|
|
382
133
|
const contentRenderer = inject(ContentRenderer);
|
|
383
134
|
const renderTaskService = inject(RenderTaskService);
|
|
135
|
+
const locale = inject(CONTENT_LOCALE, { optional: true });
|
|
384
136
|
const task = renderTaskService.addRenderTask();
|
|
385
137
|
if (typeof param === "string" || "param" in param) {
|
|
386
138
|
const prefix = typeof param === "string" ? "" : `${param.subdirectory}/`;
|
|
387
139
|
const route = inject(ActivatedRoute);
|
|
388
140
|
const paramKey = typeof param === "string" ? param : param.param;
|
|
389
141
|
return route.paramMap.pipe(map((params) => params.get(paramKey)), switchMap((slug) => {
|
|
390
|
-
if (slug) return getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer);
|
|
142
|
+
if (slug) return getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer, locale);
|
|
391
143
|
return of({
|
|
392
144
|
filename: "",
|
|
393
145
|
slug: "",
|
|
@@ -396,55 +148,7 @@ function injectContent(param = "slug", fallback = "No Content Found") {
|
|
|
396
148
|
toc: []
|
|
397
149
|
});
|
|
398
150
|
}), tap(() => renderTaskService.clearRenderTask(task)));
|
|
399
|
-
} else return getContentFile(contentFiles, "", param.customFilename, fallback, renderTaskService, contentRenderer).pipe(tap(() => renderTaskService.clearRenderTask(task)));
|
|
400
|
-
}
|
|
401
|
-
//#endregion
|
|
402
|
-
//#region packages/content/src/lib/inject-content-files.ts
|
|
403
|
-
function injectContentFiles(filterFn) {
|
|
404
|
-
const renderTaskService = inject(RenderTaskService);
|
|
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;
|
|
410
|
-
}
|
|
411
|
-
function injectContentFilesMap() {
|
|
412
|
-
return inject(CONTENT_FILES_TOKEN);
|
|
413
|
-
}
|
|
414
|
-
//#endregion
|
|
415
|
-
//#region packages/content/src/lib/marked-content-highlighter.ts
|
|
416
|
-
var MarkedContentHighlighter = class MarkedContentHighlighter {
|
|
417
|
-
static {
|
|
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
|
-
};
|
|
151
|
+
} else return getContentFile(contentFiles, "", param.customFilename, fallback, renderTaskService, contentRenderer, locale).pipe(tap(() => renderTaskService.clearRenderTask(task)));
|
|
448
152
|
}
|
|
449
153
|
//#endregion
|
|
450
154
|
//#region packages/content/src/lib/marked-setup.service.ts
|
|
@@ -478,7 +182,7 @@ var MarkedSetupService = class MarkedSetupService {
|
|
|
478
182
|
static {
|
|
479
183
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
480
184
|
minVersion: "12.0.0",
|
|
481
|
-
version: "21.
|
|
185
|
+
version: "21.2.8",
|
|
482
186
|
ngImport: i0,
|
|
483
187
|
type: MarkedSetupService,
|
|
484
188
|
deps: [],
|
|
@@ -488,7 +192,7 @@ var MarkedSetupService = class MarkedSetupService {
|
|
|
488
192
|
static {
|
|
489
193
|
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
490
194
|
minVersion: "12.0.0",
|
|
491
|
-
version: "21.
|
|
195
|
+
version: "21.2.8",
|
|
492
196
|
ngImport: i0,
|
|
493
197
|
type: MarkedSetupService
|
|
494
198
|
});
|
|
@@ -496,7 +200,7 @@ var MarkedSetupService = class MarkedSetupService {
|
|
|
496
200
|
};
|
|
497
201
|
i0.ɵɵngDeclareClassMetadata({
|
|
498
202
|
minVersion: "12.0.0",
|
|
499
|
-
version: "21.
|
|
203
|
+
version: "21.2.8",
|
|
500
204
|
ngImport: i0,
|
|
501
205
|
type: MarkedSetupService,
|
|
502
206
|
decorators: [{ type: Injectable }],
|
|
@@ -523,7 +227,7 @@ var MarkdownContentRendererService = class MarkdownContentRendererService {
|
|
|
523
227
|
static {
|
|
524
228
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
525
229
|
minVersion: "12.0.0",
|
|
526
|
-
version: "21.
|
|
230
|
+
version: "21.2.8",
|
|
527
231
|
ngImport: i0,
|
|
528
232
|
type: MarkdownContentRendererService,
|
|
529
233
|
deps: [],
|
|
@@ -533,7 +237,7 @@ var MarkdownContentRendererService = class MarkdownContentRendererService {
|
|
|
533
237
|
static {
|
|
534
238
|
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
535
239
|
minVersion: "12.0.0",
|
|
536
|
-
version: "21.
|
|
240
|
+
version: "21.2.8",
|
|
537
241
|
ngImport: i0,
|
|
538
242
|
type: MarkdownContentRendererService
|
|
539
243
|
});
|
|
@@ -541,40 +245,12 @@ var MarkdownContentRendererService = class MarkdownContentRendererService {
|
|
|
541
245
|
};
|
|
542
246
|
i0.ɵɵngDeclareClassMetadata({
|
|
543
247
|
minVersion: "12.0.0",
|
|
544
|
-
version: "21.
|
|
248
|
+
version: "21.2.8",
|
|
545
249
|
ngImport: i0,
|
|
546
250
|
type: MarkdownContentRendererService,
|
|
547
251
|
decorators: [{ type: Injectable }]
|
|
548
252
|
});
|
|
549
253
|
//#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
254
|
//#region packages/content/src/lib/provide-content.ts
|
|
579
255
|
var CONTENT_RENDERER_PROVIDERS = [
|
|
580
256
|
{
|
|
@@ -613,7 +289,7 @@ var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
|
|
|
613
289
|
static {
|
|
614
290
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
615
291
|
minVersion: "12.0.0",
|
|
616
|
-
version: "21.
|
|
292
|
+
version: "21.2.8",
|
|
617
293
|
ngImport: i0,
|
|
618
294
|
type: AnalogMarkdownRouteComponent,
|
|
619
295
|
deps: [],
|
|
@@ -623,7 +299,7 @@ var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
|
|
|
623
299
|
static {
|
|
624
300
|
this.ɵcmp = i0.ɵɵngDeclareComponent({
|
|
625
301
|
minVersion: "14.0.0",
|
|
626
|
-
version: "21.
|
|
302
|
+
version: "21.2.8",
|
|
627
303
|
type: AnalogMarkdownRouteComponent,
|
|
628
304
|
isStandalone: true,
|
|
629
305
|
selector: "analog-markdown-route",
|
|
@@ -639,7 +315,7 @@ var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
|
|
|
639
315
|
};
|
|
640
316
|
i0.ɵɵngDeclareClassMetadata({
|
|
641
317
|
minVersion: "12.0.0",
|
|
642
|
-
version: "21.
|
|
318
|
+
version: "21.2.8",
|
|
643
319
|
ngImport: i0,
|
|
644
320
|
type: AnalogMarkdownRouteComponent,
|
|
645
321
|
decorators: [{
|
|
@@ -647,7 +323,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
647
323
|
args: [{
|
|
648
324
|
selector: "analog-markdown-route",
|
|
649
325
|
standalone: true,
|
|
650
|
-
imports: [
|
|
326
|
+
imports: [],
|
|
651
327
|
hostDirectives: [AnchorNavigationDirective],
|
|
652
328
|
preserveWhitespaces: true,
|
|
653
329
|
encapsulation: ViewEncapsulation.None,
|
|
@@ -696,7 +372,7 @@ var AnalogMarkdownComponent = class AnalogMarkdownComponent {
|
|
|
696
372
|
static {
|
|
697
373
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
698
374
|
minVersion: "12.0.0",
|
|
699
|
-
version: "21.
|
|
375
|
+
version: "21.2.8",
|
|
700
376
|
ngImport: i0,
|
|
701
377
|
type: AnalogMarkdownComponent,
|
|
702
378
|
deps: [],
|
|
@@ -706,7 +382,7 @@ var AnalogMarkdownComponent = class AnalogMarkdownComponent {
|
|
|
706
382
|
static {
|
|
707
383
|
this.ɵcmp = i0.ɵɵngDeclareComponent({
|
|
708
384
|
minVersion: "17.1.0",
|
|
709
|
-
version: "21.
|
|
385
|
+
version: "21.2.8",
|
|
710
386
|
type: AnalogMarkdownComponent,
|
|
711
387
|
isStandalone: true,
|
|
712
388
|
selector: "analog-markdown",
|
|
@@ -737,7 +413,7 @@ var AnalogMarkdownComponent = class AnalogMarkdownComponent {
|
|
|
737
413
|
};
|
|
738
414
|
i0.ɵɵngDeclareClassMetadata({
|
|
739
415
|
minVersion: "12.0.0",
|
|
740
|
-
version: "21.
|
|
416
|
+
version: "21.2.8",
|
|
741
417
|
ngImport: i0,
|
|
742
418
|
type: AnalogMarkdownComponent,
|
|
743
419
|
decorators: [{
|
|
@@ -772,6 +448,6 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
772
448
|
}
|
|
773
449
|
});
|
|
774
450
|
//#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 };
|
|
451
|
+
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
452
|
|
|
777
453
|
//# sourceMappingURL=analogjs-content.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
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_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 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 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","/**\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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"}
|