@analogjs/content 3.0.0-alpha.2 → 3.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/fesm2022/analogjs-content-og.mjs +34 -46
  3. package/fesm2022/analogjs-content-prism-highlighter.mjs +81 -68
  4. package/fesm2022/analogjs-content-resources.mjs +107 -122
  5. package/fesm2022/analogjs-content-shiki-highlighter.mjs +9 -14
  6. package/fesm2022/analogjs-content.mjs +735 -618
  7. package/og/package.json +2 -2
  8. package/package.json +11 -11
  9. package/plugin/package.json +1 -2
  10. package/plugin/src/index.d.ts +1 -1
  11. package/plugin/src/index.js +3 -1
  12. package/plugin/src/migrations/update-markdown-version/compat.d.ts +2 -1
  13. package/plugin/src/migrations/update-markdown-version/compat.js +4 -2
  14. package/plugin/src/migrations/update-markdown-version/update-markdown-version.d.ts +1 -1
  15. package/prism-highlighter/package.json +2 -2
  16. package/resources/package.json +2 -2
  17. package/shiki-highlighter/package.json +2 -2
  18. package/types/og/src/index.d.ts +2 -0
  19. package/types/og/src/lib/og.d.ts +5 -0
  20. package/types/og/src/lib/options.d.ts +11 -0
  21. package/types/prism-highlighter/src/index.d.ts +8 -0
  22. package/types/prism-highlighter/src/lib/prism/angular.d.ts +1 -0
  23. package/types/prism-highlighter/src/lib/prism-highlighter.d.ts +8 -0
  24. package/types/resources/src/content-file-resource.d.ts +14 -0
  25. package/types/resources/src/content-files-resource.d.ts +3 -0
  26. package/types/resources/src/index.d.ts +2 -0
  27. package/types/shiki-highlighter/src/index.d.ts +7 -0
  28. package/types/src/index.d.ts +15 -0
  29. package/types/src/lib/anchor-navigation.directive.d.ts +9 -0
  30. package/types/src/lib/content-file-loader.d.ts +6 -0
  31. package/types/src/lib/content-file.d.ts +8 -0
  32. package/types/src/lib/content-files-list-token.d.ts +3 -0
  33. package/types/src/lib/content-files-token.d.ts +3 -0
  34. package/types/src/lib/content-list-loader.d.ts +7 -0
  35. package/types/src/lib/content-renderer.d.ts +33 -0
  36. package/types/src/lib/content.d.ts +14 -0
  37. package/types/src/lib/get-content-files.d.ts +14 -0
  38. package/types/src/lib/inject-content-files.d.ts +4 -0
  39. package/types/src/lib/markdown-content-renderer.service.d.ts +10 -0
  40. package/types/src/lib/markdown-route.component.d.ts +15 -0
  41. package/types/src/lib/markdown.component.d.ts +26 -0
  42. package/types/src/lib/marked-content-highlighter.d.ts +17 -0
  43. package/types/src/lib/marked-setup.service.d.ts +10 -0
  44. package/types/src/lib/parse-raw-content-file.d.ts +4 -0
  45. package/types/src/lib/provide-content.d.ts +7 -0
  46. package/types/src/lib/render-task.service.d.ts +8 -0
  47. package/types/src/lib/utils/zone-wait-for.d.ts +2 -0
  48. package/fesm2022/analogjs-content-og.mjs.map +0 -1
  49. package/fesm2022/analogjs-content-prism-highlighter.mjs.map +0 -1
  50. package/fesm2022/analogjs-content-resources.mjs.map +0 -1
  51. package/fesm2022/analogjs-content-shiki-highlighter.mjs.map +0 -1
  52. package/fesm2022/analogjs-content.mjs.map +0 -1
  53. package/og/README.md +0 -3
  54. package/plugin/src/index.js.map +0 -1
  55. package/plugin/src/migrations/update-markdown-renderer-feature/compat.d.ts +0 -2
  56. package/plugin/src/migrations/update-markdown-renderer-feature/compat.js +0 -6
  57. package/plugin/src/migrations/update-markdown-renderer-feature/compat.js.map +0 -1
  58. package/plugin/src/migrations/update-markdown-renderer-feature/update-markdown-renderer-feature.d.ts +0 -2
  59. package/plugin/src/migrations/update-markdown-renderer-feature/update-markdown-renderer-feature.js +0 -48
  60. package/plugin/src/migrations/update-markdown-renderer-feature/update-markdown-renderer-feature.js.map +0 -1
  61. package/plugin/src/migrations/update-markdown-version/compat.js.map +0 -1
  62. package/plugin/src/migrations/update-markdown-version/update-markdown-version.js.map +0 -1
  63. package/prism-highlighter/README.md +0 -3
  64. package/resources/README.md +0 -3
  65. package/shiki-highlighter/README.md +0 -3
  66. package/types/analogjs-content-og.d.ts +0 -19
  67. package/types/analogjs-content-prism-highlighter.d.ts +0 -15
  68. package/types/analogjs-content-resources.d.ts +0 -20
  69. package/types/analogjs-content-shiki-highlighter.d.ts +0 -11
  70. package/types/analogjs-content.d.ts +0 -168
@@ -1,660 +1,777 @@
1
- import * as i0 from '@angular/core';
2
- import { inject, HostListener, Directive, Injectable, TransferState, makeStateKey, InjectionToken, signal, ɵPendingTasksInternal as _PendingTasksInternal, Input, ViewEncapsulation, Component, NgZone, PLATFORM_ID, computed, input } from '@angular/core';
3
- import { DOCUMENT, Location, AsyncPipe, isPlatformBrowser } from '@angular/common';
4
- import { Router, ActivatedRoute } from '@angular/router';
5
- import { isObservable, firstValueFrom, of, Observable, from } from 'rxjs';
6
- import { switchMap, map, tap, catchError } from 'rxjs/operators';
7
- import fm from 'front-matter';
8
- import { gfmHeadingId, getHeadingList } from 'marked-gfm-heading-id';
9
- import { marked } from 'marked';
10
- import { mangle } from 'marked-mangle';
11
- import { DomSanitizer } from '@angular/platform-browser';
12
- import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
13
-
14
- class AnchorNavigationDirective {
15
- constructor() {
16
- this.document = inject(DOCUMENT);
17
- this.location = inject(Location);
18
- this.router = inject(Router);
19
- }
20
- handleNavigation(element) {
21
- if (element instanceof HTMLAnchorElement &&
22
- isInternalUrl(element, this.document) &&
23
- hasTargetSelf(element) &&
24
- !hasDownloadAttribute(element)) {
25
- const { pathname, search, hash } = element;
26
- const url = this.location.normalize(`${pathname}${search}${hash}`);
27
- this.router.navigateByUrl(url);
28
- return false;
29
- }
30
- return true;
31
- }
32
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: AnchorNavigationDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
33
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: AnchorNavigationDirective, isStandalone: true, selector: "[analogAnchorNavigation]", host: { listeners: { "click": "handleNavigation($event.target)" } }, ngImport: i0 }); }
34
- }
35
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: AnchorNavigationDirective, decorators: [{
36
- type: Directive,
37
- args: [{
38
- selector: '[analogAnchorNavigation]',
39
- standalone: true,
40
- }]
41
- }], propDecorators: { handleNavigation: [{
42
- type: HostListener,
43
- args: ['click', ['$event.target']]
44
- }] } });
1
+ import * as i0 from "@angular/core";
2
+ import { Component, Directive, HostListener, Injectable, InjectionToken, Input, NgZone, PLATFORM_ID, TransferState, ViewEncapsulation, computed, inject, input, makeStateKey, signal, ɵPendingTasksInternal } from "@angular/core";
3
+ import { AsyncPipe, DOCUMENT, Location, isPlatformBrowser } from "@angular/common";
4
+ import { ActivatedRoute, Router } from "@angular/router";
5
+ import { Observable, from, of } from "rxjs";
6
+ import { catchError, map, switchMap, tap } from "rxjs/operators";
7
+ import fm from "front-matter";
8
+ import { getHeadingList, gfmHeadingId } from "marked-gfm-heading-id";
9
+ import { marked } from "marked";
10
+ import { mangle } from "marked-mangle";
11
+ import { DomSanitizer } from "@angular/platform-browser";
12
+ import { takeUntilDestroyed, toSignal } from "@angular/core/rxjs-interop";
13
+ //#region packages/content/src/lib/anchor-navigation.directive.ts
14
+ var AnchorNavigationDirective = class AnchorNavigationDirective {
15
+ constructor() {
16
+ this.document = inject(DOCUMENT);
17
+ this.location = inject(Location);
18
+ this.router = inject(Router);
19
+ }
20
+ handleNavigation(element) {
21
+ if (element instanceof HTMLAnchorElement && isInternalUrl(element, this.document) && hasTargetSelf(element) && !hasDownloadAttribute(element)) {
22
+ const { pathname, search, hash } = element;
23
+ const url = this.location.normalize(`${pathname}${search}${hash}`);
24
+ this.router.navigateByUrl(url);
25
+ return false;
26
+ }
27
+ return true;
28
+ }
29
+ static {
30
+ this.ɵfac = i0.ɵɵngDeclareFactory({
31
+ minVersion: "12.0.0",
32
+ version: "21.1.1",
33
+ ngImport: i0,
34
+ type: AnchorNavigationDirective,
35
+ deps: [],
36
+ target: i0.ɵɵFactoryTarget.Directive
37
+ });
38
+ }
39
+ static {
40
+ this.ɵdir = i0.ɵɵngDeclareDirective({
41
+ minVersion: "14.0.0",
42
+ version: "21.1.1",
43
+ type: AnchorNavigationDirective,
44
+ isStandalone: true,
45
+ selector: "[analogAnchorNavigation]",
46
+ host: { listeners: { "click": "handleNavigation($event.target)" } },
47
+ ngImport: i0
48
+ });
49
+ }
50
+ };
51
+ i0.ɵɵngDeclareClassMetadata({
52
+ minVersion: "12.0.0",
53
+ version: "21.1.1",
54
+ ngImport: i0,
55
+ type: AnchorNavigationDirective,
56
+ decorators: [{
57
+ type: Directive,
58
+ args: [{
59
+ selector: "[analogAnchorNavigation]",
60
+ standalone: true
61
+ }]
62
+ }],
63
+ propDecorators: { handleNavigation: [{
64
+ type: HostListener,
65
+ args: ["click", ["$event.target"]]
66
+ }] }
67
+ });
45
68
  function hasDownloadAttribute(anchorElement) {
46
- return anchorElement.getAttribute('download') !== null;
69
+ return anchorElement.getAttribute("download") !== null;
47
70
  }
48
71
  function hasTargetSelf(anchorElement) {
49
- return !anchorElement.target || anchorElement.target === '_self';
72
+ return !anchorElement.target || anchorElement.target === "_self";
50
73
  }
51
74
  function isInternalUrl(anchorElement, document) {
52
- return (anchorElement.host === document.location.host &&
53
- anchorElement.protocol === document.location.protocol);
54
- }
55
-
56
- /// <reference types="vite/client" />
57
- class ContentRenderer {
58
- async render(content) {
59
- return { content, toc: [] };
60
- }
61
- // Backward-compatible API for consumers that read headings directly.
62
- getContentHeadings(_content) {
63
- return [];
64
- }
65
- // eslint-disable-next-line
66
- enhance() { }
67
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ContentRenderer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
68
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ContentRenderer }); }
69
- }
70
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: ContentRenderer, decorators: [{
71
- type: Injectable
72
- }] });
73
- class NoopContentRenderer {
74
- constructor() {
75
- this.transferState = inject(TransferState);
76
- this.contentId = 0;
77
- }
78
- /**
79
- * Generates a hash from the content string
80
- * to be used with the transfer state
81
- */
82
- generateHash(str) {
83
- let hash = 0;
84
- for (let i = 0, len = str.length; i < len; i++) {
85
- let chr = str.charCodeAt(i);
86
- hash = (hash << 5) - hash + chr;
87
- hash |= 0; // Convert to 32bit integer
88
- }
89
- return hash;
90
- }
91
- async render(content) {
92
- this.contentId = this.generateHash(content);
93
- const toc = this.getContentHeadings(content);
94
- const key = makeStateKey(`content-headings-${this.contentId}`);
95
- if (import.meta.env.SSR === true) {
96
- this.transferState.set(key, toc);
97
- return { content, toc };
98
- }
99
- return {
100
- content,
101
- toc: this.transferState.get(key, toc),
102
- };
103
- }
104
- enhance() { }
105
- getContentHeadings(content) {
106
- return this.extractHeadings(content);
107
- }
108
- extractHeadings(content) {
109
- const markdownHeadings = this.extractHeadingsFromMarkdown(content);
110
- if (markdownHeadings.length > 0) {
111
- return markdownHeadings;
112
- }
113
- const htmlHeadings = this.extractHeadingsFromHtml(content);
114
- return htmlHeadings;
115
- }
116
- extractHeadingsFromMarkdown(content) {
117
- const lines = content.split('\n');
118
- const toc = [];
119
- const slugCounts = new Map();
120
- for (const line of lines) {
121
- const match = /^(#{1,6})\s+(.+?)\s*$/.exec(line);
122
- if (!match) {
123
- continue;
124
- }
125
- const level = match[1].length;
126
- const text = match[2].trim();
127
- if (!text) {
128
- continue;
129
- }
130
- const baseSlug = text
131
- .toLowerCase()
132
- .replace(/[^\w\s-]/g, '')
133
- .trim()
134
- .replace(/\s+/g, '-');
135
- const count = slugCounts.get(baseSlug) ?? 0;
136
- slugCounts.set(baseSlug, count + 1);
137
- const id = count === 0 ? baseSlug : `${baseSlug}-${count}`;
138
- toc.push({ id, level, text });
139
- }
140
- return toc;
141
- }
142
- extractHeadingsFromHtml(content) {
143
- const toc = [];
144
- const slugCounts = new Map();
145
- const headingRegex = /<h([1-6])([^>]*)>([\s\S]*?)<\/h\1>/gi;
146
- for (const match of content.matchAll(headingRegex)) {
147
- const level = Number(match[1]);
148
- const attrs = match[2] ?? '';
149
- const rawInner = match[3] ?? '';
150
- const text = rawInner.replace(/<[^>]+>/g, '').trim();
151
- if (!text) {
152
- continue;
153
- }
154
- const idMatch = /\sid=(['"])(.*?)\1/i.exec(attrs) ?? /\sid=([^\s>]+)/i.exec(attrs);
155
- let id = idMatch?.[2] ?? idMatch?.[1] ?? '';
156
- if (!id) {
157
- id = this.makeSlug(text, slugCounts);
158
- }
159
- toc.push({ id, level, text });
160
- }
161
- return toc;
162
- }
163
- makeSlug(text, slugCounts) {
164
- const baseSlug = text
165
- .toLowerCase()
166
- .replace(/[^\w\s-]/g, '')
167
- .trim()
168
- .replace(/\s+/g, '-');
169
- const count = slugCounts.get(baseSlug) ?? 0;
170
- slugCounts.set(baseSlug, count + 1);
171
- return count === 0 ? baseSlug : `${baseSlug}-${count}`;
172
- }
75
+ return anchorElement.host === document.location.host && anchorElement.protocol === document.location.protocol;
173
76
  }
174
-
77
+ //#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
175
202
  /**
176
- * Returns the list of content files by filename with ?analog-content-list=true.
177
- * We use the query param to transform the return into an array of
178
- * just front matter attributes.
179
- *
180
- * @returns
181
- */
182
- const getContentFilesList = () => {
183
- let ANALOG_CONTENT_FILE_LIST = {};
184
- return ANALOG_CONTENT_FILE_LIST;
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 {};
185
211
  };
186
212
  /**
187
- * Returns the lazy loaded content files for lookups.
188
- *
189
- * @returns
190
- */
191
- const getContentFiles = () => {
192
- let ANALOG_CONTENT_ROUTE_FILES = {};
193
- return ANALOG_CONTENT_ROUTE_FILES;
213
+ * Returns the lazy loaded content files for lookups.
214
+ *
215
+ * @returns
216
+ */
217
+ var getContentFiles = () => {
218
+ return {};
194
219
  };
195
-
220
+ //#endregion
221
+ //#region packages/content/src/lib/content-files-list-token.ts
196
222
  function getSlug(filename) {
197
- // Extract the last path segment without its extension.
198
- // Handles names with dots like [[...slug]].md by stripping only the final extension.
199
- const lastSegment = (filename.split(/[/\\]/).pop() || '').trim();
200
- const base = lastSegment.replace(/\.[^./\\]+$/, ''); // strip only the final extension
201
- // Treat index.md as index route => empty slug
202
- return base === 'index' ? '' : base;
223
+ const base = (filename.split(/[/\\]/).pop() || "").trim().replace(/\.[^./\\]+$/, "");
224
+ return base === "index" ? "" : base;
203
225
  }
204
- const CONTENT_FILES_LIST_TOKEN = new InjectionToken('@analogjs/content Content Files List', {
205
- providedIn: 'root',
206
- factory() {
207
- const contentFiles = getContentFilesList();
208
- return Object.keys(contentFiles).map((filename) => {
209
- const attributes = contentFiles[filename];
210
- const slug = attributes['slug'];
211
- return {
212
- filename,
213
- attributes,
214
- slug: slug ? encodeURI(slug) : encodeURI(getSlug(filename)),
215
- };
216
- });
217
- },
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
+ }
218
240
  });
219
-
220
- const CONTENT_FILES_TOKEN = new InjectionToken('@analogjs/content Content Files', {
221
- providedIn: 'root',
222
- factory() {
223
- const contentFiles = getContentFiles();
224
- const allFiles = { ...contentFiles };
225
- const contentFilesList = inject(CONTENT_FILES_LIST_TOKEN);
226
- const lookup = {};
227
- contentFilesList.forEach((item) => {
228
- const contentFilename = item.filename.replace(/(.*?)\/content/, '/src/content');
229
- const fileParts = contentFilename.split('/');
230
- const filePath = fileParts.slice(0, fileParts.length - 1).join('/');
231
- const fileNameParts = fileParts[fileParts.length - 1].split('.');
232
- const ext = fileNameParts[fileNameParts.length - 1];
233
- let slug = (item.slug ?? '');
234
- // Default empty slug to 'index'
235
- if (slug === '') {
236
- slug = 'index';
237
- }
238
- // If slug contains path separators, treat it as root-relative to /src/content
239
- const newBase = slug.includes('/')
240
- ? `/src/content/${slug}`
241
- : `${filePath}/${slug}`;
242
- lookup[contentFilename] = `${newBase}.${ext}`.replace(/\/{2,}/g, '/');
243
- });
244
- const objectUsingSlugAttribute = {};
245
- Object.entries(allFiles).forEach((entry) => {
246
- const filename = entry[0];
247
- const value = entry[1];
248
- const strippedFilename = filename.replace(/^\/(.*?)\/content/, '/src/content');
249
- const newFilename = lookup[strippedFilename];
250
- if (newFilename !== undefined) {
251
- const objectFilename = newFilename.replace(/^\/(.*?)\/content/, '/src/content');
252
- objectUsingSlugAttribute[objectFilename] =
253
- value;
254
- }
255
- });
256
- return objectUsingSlugAttribute;
257
- },
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
+ }
258
271
  });
259
- const CONTENT_FILES_MAP_TOKEN = new InjectionToken('@analogjs/content Content Files', {
260
- providedIn: 'root',
261
- factory() {
262
- return signal(inject(CONTENT_FILES_TOKEN));
263
- },
272
+ new InjectionToken("@analogjs/content Content Files", {
273
+ providedIn: "root",
274
+ factory() {
275
+ return signal(inject(CONTENT_FILES_TOKEN));
276
+ }
264
277
  });
265
-
278
+ //#endregion
279
+ //#region packages/content/src/lib/parse-raw-content-file.ts
266
280
  function parseRawContentFile(rawContentFile) {
267
- const { body, attributes } = fm(rawContentFile);
268
- return { content: body, attributes };
269
- }
270
-
271
- async function waitFor(prom) {
272
- if (isObservable(prom)) {
273
- prom = firstValueFrom(prom);
274
- }
275
- if (typeof Zone === 'undefined') {
276
- return prom;
277
- }
278
- const macroTask = Zone.current.scheduleMacroTask(`AnalogContentResolve-${Math.random()}`, () => { }, {}, () => { });
279
- return prom.then((p) => {
280
- macroTask.invoke();
281
- return p;
282
- });
281
+ const { body, attributes } = fm(rawContentFile);
282
+ return {
283
+ content: body,
284
+ attributes
285
+ };
283
286
  }
284
-
285
- class RenderTaskService {
286
- #pendingTasks = inject(_PendingTasksInternal);
287
- addRenderTask() {
288
- return this.#pendingTasks.add();
289
- }
290
- clearRenderTask(clear) {
291
- if (typeof clear === 'function') {
292
- clear();
293
- }
294
- else if (typeof this.#pendingTasks.remove === 'function') {
295
- this.#pendingTasks.remove(clear);
296
- }
297
- }
298
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: RenderTaskService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
299
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: RenderTaskService }); }
300
- }
301
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: RenderTaskService, decorators: [{
302
- type: Injectable
303
- }] });
304
-
305
- /// <reference types="vite/client" />
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
+ //#region packages/content/src/lib/content.ts
306
326
  function getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer) {
307
- // Normalize file keys so both "/src/content/..." and "/<project>/src/content/..." resolve.
308
- const normalizedFiles = {};
309
- for (const [key, resolver] of Object.entries(contentFiles)) {
310
- const normalizedKey = key
311
- .replace(/^(?:.*)\/content/, '/src/content')
312
- .replace(/\/{2,}/g, '/');
313
- normalizedFiles[normalizedKey] = resolver;
314
- }
315
- const base = `/src/content/${prefix}${slug}`.replace(/\/{2,}/g, '/');
316
- const candidates = [
317
- `${base}.md`,
318
- `${base}.agx`,
319
- `${base}/index.md`,
320
- `${base}/index.agx`,
321
- ];
322
- const matchKey = candidates.find((k) => k in normalizedFiles);
323
- const contentFile = matchKey ? normalizedFiles[matchKey] : undefined;
324
- const resolvedBase = (matchKey || `${base}.md`).replace(/\.(md|agx)$/, '');
325
- if (!contentFile) {
326
- return of({
327
- filename: resolvedBase,
328
- attributes: {},
329
- slug: '',
330
- content: fallback,
331
- toc: [],
332
- });
333
- }
334
- const contentTask = renderTaskService.addRenderTask();
335
- return new Observable((observer) => {
336
- const contentResolver = contentFile();
337
- if (import.meta.env.SSR === true) {
338
- waitFor(contentResolver).then((content) => {
339
- observer.next(content);
340
- observer.complete();
341
- setTimeout(() => renderTaskService.clearRenderTask(contentTask), 10);
342
- });
343
- }
344
- else {
345
- contentResolver.then((content) => {
346
- observer.next(content);
347
- observer.complete();
348
- });
349
- }
350
- }).pipe(switchMap((contentFile) => {
351
- if (typeof contentFile === 'string') {
352
- const { content, attributes } = parseRawContentFile(contentFile);
353
- return from(contentRenderer.render(content)).pipe(map((rendered) => ({
354
- filename: resolvedBase,
355
- slug,
356
- attributes,
357
- content,
358
- toc: rendered.toc ?? [],
359
- })));
360
- }
361
- return of({
362
- filename: resolvedBase,
363
- slug,
364
- attributes: contentFile.metadata,
365
- content: contentFile.default,
366
- toc: [],
367
- });
368
- }));
327
+ const normalizedFiles = {};
328
+ for (const [key, resolver] of Object.entries(contentFiles)) {
329
+ const normalizedKey = key.replace(/^(?:.*)\/content/, "/src/content").replace(/\/{2,}/g, "/");
330
+ normalizedFiles[normalizedKey] = resolver;
331
+ }
332
+ 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);
339
+ const contentFile = matchKey ? normalizedFiles[matchKey] : void 0;
340
+ const resolvedBase = (matchKey || `${base}.md`).replace(/\.(md|agx)$/, "");
341
+ if (!contentFile) return of({
342
+ filename: resolvedBase,
343
+ attributes: {},
344
+ slug: "",
345
+ content: fallback,
346
+ toc: []
347
+ });
348
+ renderTaskService.addRenderTask();
349
+ return new Observable((observer) => {
350
+ contentFile().then((content) => {
351
+ observer.next(content);
352
+ observer.complete();
353
+ });
354
+ }).pipe(switchMap((contentFile) => {
355
+ if (typeof contentFile === "string") {
356
+ const { content, attributes } = parseRawContentFile(contentFile);
357
+ return from(contentRenderer.render(content)).pipe(map((rendered) => ({
358
+ filename: resolvedBase,
359
+ slug,
360
+ attributes,
361
+ content,
362
+ toc: rendered.toc ?? []
363
+ })));
364
+ }
365
+ return of({
366
+ filename: resolvedBase,
367
+ slug,
368
+ attributes: contentFile.metadata,
369
+ content: contentFile.default,
370
+ toc: []
371
+ });
372
+ }));
369
373
  }
370
374
  /**
371
- * Retrieves the static content using the provided param and/or prefix.
372
- *
373
- * @param param route parameter (default: 'slug')
374
- * @param fallback fallback text if content file is not found (default: 'No Content Found')
375
- */
376
- function injectContent(param = 'slug', fallback = 'No Content Found') {
377
- const contentFiles = inject(CONTENT_FILES_TOKEN);
378
- const contentRenderer = inject(ContentRenderer);
379
- const renderTaskService = inject(RenderTaskService);
380
- const task = renderTaskService.addRenderTask();
381
- if (typeof param === 'string' || 'param' in param) {
382
- const prefix = typeof param === 'string' ? '' : `${param.subdirectory}/`;
383
- const route = inject(ActivatedRoute);
384
- const paramKey = typeof param === 'string' ? param : param.param;
385
- return route.paramMap.pipe(map((params) => params.get(paramKey)), switchMap((slug) => {
386
- if (slug) {
387
- return getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer);
388
- }
389
- return of({
390
- filename: '',
391
- slug: '',
392
- attributes: {},
393
- content: fallback,
394
- toc: [],
395
- });
396
- }), tap(() => renderTaskService.clearRenderTask(task)));
397
- }
398
- else {
399
- return getContentFile(contentFiles, '', param.customFilename, fallback, renderTaskService, contentRenderer).pipe(tap(() => renderTaskService.clearRenderTask(task)));
400
- }
375
+ * Retrieves the static content using the provided param and/or prefix.
376
+ *
377
+ * @param param route parameter (default: 'slug')
378
+ * @param fallback fallback text if content file is not found (default: 'No Content Found')
379
+ */
380
+ function injectContent(param = "slug", fallback = "No Content Found") {
381
+ const contentFiles = inject(CONTENT_FILES_TOKEN);
382
+ const contentRenderer = inject(ContentRenderer);
383
+ const renderTaskService = inject(RenderTaskService);
384
+ const task = renderTaskService.addRenderTask();
385
+ if (typeof param === "string" || "param" in param) {
386
+ const prefix = typeof param === "string" ? "" : `${param.subdirectory}/`;
387
+ const route = inject(ActivatedRoute);
388
+ const paramKey = typeof param === "string" ? param : param.param;
389
+ return route.paramMap.pipe(map((params) => params.get(paramKey)), switchMap((slug) => {
390
+ if (slug) return getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer);
391
+ return of({
392
+ filename: "",
393
+ slug: "",
394
+ attributes: {},
395
+ content: fallback,
396
+ toc: []
397
+ });
398
+ }), tap(() => renderTaskService.clearRenderTask(task)));
399
+ } else return getContentFile(contentFiles, "", param.customFilename, fallback, renderTaskService, contentRenderer).pipe(tap(() => renderTaskService.clearRenderTask(task)));
401
400
  }
402
-
401
+ //#endregion
402
+ //#region packages/content/src/lib/inject-content-files.ts
403
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) {
409
- const filteredContentFiles = allContentFiles.filter(filterFn);
410
- return filteredContentFiles;
411
- }
412
- return allContentFiles;
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;
413
410
  }
414
411
  function injectContentFilesMap() {
415
- return inject(CONTENT_FILES_TOKEN);
412
+ return inject(CONTENT_FILES_TOKEN);
416
413
  }
417
-
418
- class MarkedContentHighlighter {
419
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: MarkedContentHighlighter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
420
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: MarkedContentHighlighter }); }
421
- }
422
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: MarkedContentHighlighter, decorators: [{
423
- type: Injectable
424
- }] });
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
+ });
425
443
  function withHighlighter(provider) {
426
- return { provide: MarkedContentHighlighter, ...provider };
444
+ return {
445
+ provide: MarkedContentHighlighter,
446
+ ...provider
447
+ };
427
448
  }
428
-
449
+ //#endregion
450
+ //#region packages/content/src/lib/marked-setup.service.ts
429
451
  /**
430
- * Credit goes to Scully for original implementation
431
- * https://github.com/scullyio/scully/blob/main/libs/scully/src/lib/fileHanderPlugins/markdown.ts
432
- */
433
- class MarkedSetupService {
434
- constructor() {
435
- this.highlighter = inject(MarkedContentHighlighter, {
436
- optional: true,
437
- });
438
- const renderer = new marked.Renderer();
439
- renderer.code = ({ text, lang }) => {
440
- // Let's do a language based detection like on GitHub
441
- // So we can still have non-interpreted mermaid code
442
- if (lang === 'mermaid') {
443
- return '<pre class="mermaid">' + text + '</pre>';
444
- }
445
- if (!lang) {
446
- return '<pre><code>' + text + '</code></pre>';
447
- }
448
- if (this.highlighter?.augmentCodeBlock) {
449
- return this.highlighter?.augmentCodeBlock(text, lang);
450
- }
451
- return `<pre class="language-${lang}"><code class="language-${lang}">${text}</code></pre>`;
452
- };
453
- const extensions = [gfmHeadingId(), mangle()];
454
- if (this.highlighter) {
455
- extensions.push(this.highlighter.getHighlightExtension());
456
- }
457
- marked.use(...extensions, {
458
- renderer,
459
- pedantic: false,
460
- gfm: true,
461
- breaks: false,
462
- });
463
- this.marked = marked;
464
- }
465
- getMarkedInstance() {
466
- return this.marked;
467
- }
468
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: MarkedSetupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
469
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: MarkedSetupService }); }
470
- }
471
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: MarkedSetupService, decorators: [{
472
- type: Injectable
473
- }], ctorParameters: () => [] });
474
-
475
- class MarkdownContentRendererService {
476
- #marked = inject(MarkedSetupService, { self: true });
477
- async render(content) {
478
- const renderedContent = await this.#marked
479
- .getMarkedInstance()
480
- .parse(content);
481
- return {
482
- content: renderedContent,
483
- toc: getHeadingList(),
484
- };
485
- }
486
- getContentHeadings(content) {
487
- return [...content.matchAll(/^(#{1,6})\s+(.+?)\s*$/gm)].map((match) => ({
488
- id: match[2]
489
- .trim()
490
- .toLowerCase()
491
- .replace(/[^\w\s-]/g, '')
492
- .replace(/\s+/g, '-'),
493
- level: match[1].length,
494
- text: match[2].trim(),
495
- }));
496
- }
497
- // eslint-disable-next-line
498
- enhance() { }
499
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: MarkdownContentRendererService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
500
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: MarkdownContentRendererService }); }
501
- }
502
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: MarkdownContentRendererService, decorators: [{
503
- type: Injectable
504
- }] });
505
-
506
- const CONTENT_FILE_LOADER = new InjectionToken('@analogjs/content/resource File Loader');
452
+ * Credit goes to Scully for original implementation
453
+ * https://github.com/scullyio/scully/blob/main/libs/scully/src/lib/fileHanderPlugins/markdown.ts
454
+ */
455
+ var MarkedSetupService = class MarkedSetupService {
456
+ constructor() {
457
+ this.highlighter = inject(MarkedContentHighlighter, { optional: true });
458
+ const renderer = new marked.Renderer();
459
+ renderer.code = ({ text, lang }) => {
460
+ if (lang === "mermaid") return "<pre class=\"mermaid\">" + text + "</pre>";
461
+ if (!lang) return "<pre><code>" + text + "</code></pre>";
462
+ if (this.highlighter?.augmentCodeBlock) return this.highlighter?.augmentCodeBlock(text, lang);
463
+ return `<pre class="language-${lang}"><code class="language-${lang}">${text}</code></pre>`;
464
+ };
465
+ const extensions = [gfmHeadingId(), mangle()];
466
+ if (this.highlighter) extensions.push(this.highlighter.getHighlightExtension());
467
+ marked.use(...extensions, {
468
+ renderer,
469
+ pedantic: false,
470
+ gfm: true,
471
+ breaks: false
472
+ });
473
+ this.marked = marked;
474
+ }
475
+ getMarkedInstance() {
476
+ return this.marked;
477
+ }
478
+ static {
479
+ this.ɵfac = i0.ɵɵngDeclareFactory({
480
+ minVersion: "12.0.0",
481
+ version: "21.1.1",
482
+ ngImport: i0,
483
+ type: MarkedSetupService,
484
+ deps: [],
485
+ target: i0.ɵɵFactoryTarget.Injectable
486
+ });
487
+ }
488
+ static {
489
+ this.ɵprov = i0.ɵɵngDeclareInjectable({
490
+ minVersion: "12.0.0",
491
+ version: "21.1.1",
492
+ ngImport: i0,
493
+ type: MarkedSetupService
494
+ });
495
+ }
496
+ };
497
+ i0.ɵɵngDeclareClassMetadata({
498
+ minVersion: "12.0.0",
499
+ version: "21.1.1",
500
+ ngImport: i0,
501
+ type: MarkedSetupService,
502
+ decorators: [{ type: Injectable }],
503
+ ctorParameters: () => []
504
+ });
505
+ //#endregion
506
+ //#region packages/content/src/lib/markdown-content-renderer.service.ts
507
+ var MarkdownContentRendererService = class MarkdownContentRendererService {
508
+ #marked = inject(MarkedSetupService, { self: true });
509
+ async render(content) {
510
+ return {
511
+ content: await this.#marked.getMarkedInstance().parse(content),
512
+ toc: getHeadingList()
513
+ };
514
+ }
515
+ getContentHeadings(content) {
516
+ return [...content.matchAll(/^(#{1,6})\s+(.+?)\s*$/gm)].map((match) => ({
517
+ id: match[2].trim().toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-"),
518
+ level: match[1].length,
519
+ text: match[2].trim()
520
+ }));
521
+ }
522
+ enhance() {}
523
+ static {
524
+ this.ɵfac = i0.ɵɵngDeclareFactory({
525
+ minVersion: "12.0.0",
526
+ version: "21.1.1",
527
+ ngImport: i0,
528
+ type: MarkdownContentRendererService,
529
+ deps: [],
530
+ target: i0.ɵɵFactoryTarget.Injectable
531
+ });
532
+ }
533
+ static {
534
+ this.ɵprov = i0.ɵɵngDeclareInjectable({
535
+ minVersion: "12.0.0",
536
+ version: "21.1.1",
537
+ ngImport: i0,
538
+ type: MarkdownContentRendererService
539
+ });
540
+ }
541
+ };
542
+ i0.ɵɵngDeclareClassMetadata({
543
+ minVersion: "12.0.0",
544
+ version: "21.1.1",
545
+ ngImport: i0,
546
+ type: MarkdownContentRendererService,
547
+ decorators: [{ type: Injectable }]
548
+ });
549
+ //#endregion
550
+ //#region packages/content/src/lib/content-file-loader.ts
551
+ var CONTENT_FILE_LOADER = new InjectionToken("@analogjs/content/resource File Loader");
507
552
  function injectContentFileLoader() {
508
- return inject(CONTENT_FILE_LOADER);
553
+ return inject(CONTENT_FILE_LOADER);
509
554
  }
510
555
  function withContentFileLoader() {
511
- return {
512
- provide: CONTENT_FILE_LOADER,
513
- useFactory() {
514
- return async () => injectContentFilesMap();
515
- },
516
- };
556
+ return {
557
+ provide: CONTENT_FILE_LOADER,
558
+ useFactory() {
559
+ return async () => injectContentFilesMap();
560
+ }
561
+ };
517
562
  }
518
-
519
- const CONTENT_LIST_LOADER = new InjectionToken('@analogjs/content/resource List Loader');
563
+ //#endregion
564
+ //#region packages/content/src/lib/content-list-loader.ts
565
+ var CONTENT_LIST_LOADER = new InjectionToken("@analogjs/content/resource List Loader");
520
566
  function injectContentListLoader() {
521
- return inject(CONTENT_LIST_LOADER);
567
+ return inject(CONTENT_LIST_LOADER);
522
568
  }
523
569
  function withContentListLoader() {
524
- return {
525
- provide: CONTENT_LIST_LOADER,
526
- useFactory() {
527
- return async () => injectContentFiles();
528
- },
529
- };
570
+ return {
571
+ provide: CONTENT_LIST_LOADER,
572
+ useFactory() {
573
+ return async () => injectContentFiles();
574
+ }
575
+ };
530
576
  }
531
-
532
- const CONTENT_RENDERER_PROVIDERS = [
533
- {
534
- provide: ContentRenderer,
535
- useClass: NoopContentRenderer,
536
- },
537
- withContentFileLoader(),
538
- withContentListLoader(),
577
+ //#endregion
578
+ //#region packages/content/src/lib/provide-content.ts
579
+ var CONTENT_RENDERER_PROVIDERS = [
580
+ {
581
+ provide: ContentRenderer,
582
+ useClass: NoopContentRenderer
583
+ },
584
+ withContentFileLoader(),
585
+ withContentListLoader()
539
586
  ];
540
587
  function withMarkdownRenderer(options) {
541
- return [
542
- CONTENT_RENDERER_PROVIDERS,
543
- options?.loadMermaid
544
- ? [
545
- {
546
- provide: MERMAID_IMPORT_TOKEN,
547
- useFactory: options.loadMermaid,
548
- },
549
- ]
550
- : [],
551
- ];
588
+ return [CONTENT_RENDERER_PROVIDERS, options?.loadMermaid ? [{
589
+ provide: MERMAID_IMPORT_TOKEN,
590
+ useFactory: options.loadMermaid
591
+ }] : []];
552
592
  }
553
593
  function provideContent(...features) {
554
- return [
555
- { provide: RenderTaskService, useClass: RenderTaskService },
556
- ...features,
557
- ];
594
+ return [{
595
+ provide: RenderTaskService,
596
+ useClass: RenderTaskService
597
+ }, ...features];
558
598
  }
559
- const MERMAID_IMPORT_TOKEN = new InjectionToken('mermaid_import');
560
-
561
- class AnalogMarkdownRouteComponent {
562
- constructor() {
563
- this.sanitizer = inject(DomSanitizer);
564
- this.route = inject(ActivatedRoute);
565
- this.contentRenderer = inject(ContentRenderer);
566
- this.content = this.sanitizer.bypassSecurityTrustHtml(this.route.snapshot.data['renderedAnalogContent']);
567
- this.classes = 'analog-markdown-route';
568
- }
569
- ngAfterViewChecked() {
570
- this.contentRenderer.enhance();
571
- }
572
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: AnalogMarkdownRouteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
573
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.1", type: AnalogMarkdownRouteComponent, isStandalone: true, selector: "analog-markdown-route", inputs: { classes: "classes" }, hostDirectives: [{ directive: AnchorNavigationDirective }], ngImport: i0, template: `<div [innerHTML]="content" [class]="classes"></div>`, isInline: true, encapsulation: i0.ViewEncapsulation.None, preserveWhitespaces: true }); }
574
- }
575
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: AnalogMarkdownRouteComponent, decorators: [{
576
- type: Component,
577
- args: [{
578
- selector: 'analog-markdown-route',
579
- standalone: true,
580
- imports: [AsyncPipe],
581
- hostDirectives: [AnchorNavigationDirective],
582
- preserveWhitespaces: true,
583
- encapsulation: ViewEncapsulation.None,
584
- template: `<div [innerHTML]="content" [class]="classes"></div>`,
585
- }]
586
- }], propDecorators: { classes: [{
587
- type: Input
588
- }] } });
589
-
590
- class AnalogMarkdownComponent {
591
- constructor() {
592
- this.sanitizer = inject(DomSanitizer);
593
- this.route = inject(ActivatedRoute);
594
- this.zone = inject(NgZone);
595
- this.platformId = inject(PLATFORM_ID);
596
- this.mermaidImport = inject(MERMAID_IMPORT_TOKEN, {
597
- optional: true,
598
- });
599
- this.contentSource = toSignal(this.getContentSource());
600
- this.htmlContent = computed(() => {
601
- const inputContent = this.content();
602
- if (inputContent) {
603
- return this.sanitizer.bypassSecurityTrustHtml(inputContent);
604
- }
605
- return this.contentSource();
606
- }, ...(ngDevMode ? [{ debugName: "htmlContent" }] : []));
607
- this.content = input(...(ngDevMode ? [undefined, { debugName: "content" }] : []));
608
- this.classes = input('analog-markdown', ...(ngDevMode ? [{ debugName: "classes" }] : []));
609
- this.contentRenderer = inject(ContentRenderer);
610
- if (isPlatformBrowser(this.platformId) && this.mermaidImport) {
611
- // Mermaid can only be loaded on client side
612
- this.loadMermaid(this.mermaidImport);
613
- }
614
- }
615
- getContentSource() {
616
- return this.route.data.pipe(map((data) => data['_analogContent'] ?? ''), switchMap((contentString) => this.renderContent(contentString)), map((content) => this.sanitizer.bypassSecurityTrustHtml(content)), catchError((e) => of(`There was an error ${e}`)));
617
- }
618
- async renderContent(content) {
619
- const rendered = await this.contentRenderer.render(content);
620
- return rendered.content;
621
- }
622
- ngAfterViewChecked() {
623
- this.contentRenderer.enhance();
624
- this.zone.runOutsideAngular(() => this.mermaid?.default.run());
625
- }
626
- loadMermaid(mermaidImport) {
627
- this.zone.runOutsideAngular(() =>
628
- // Wrap into an observable to avoid redundant initialization once
629
- // the markdown component is destroyed before the promise is resolved.
630
- from(mermaidImport)
631
- .pipe(takeUntilDestroyed())
632
- .subscribe((mermaid) => {
633
- this.mermaid = mermaid;
634
- this.mermaid.default.initialize({ startOnLoad: false });
635
- // Explicitly running mermaid as ngAfterViewChecked
636
- // has probably already been called
637
- this.mermaid?.default.run();
638
- }));
639
- }
640
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: AnalogMarkdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
641
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.1", type: AnalogMarkdownComponent, isStandalone: true, selector: "analog-markdown", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, classes: { classPropertyName: "classes", publicName: "classes", isSignal: true, isRequired: false, transformFunction: null } }, hostDirectives: [{ directive: AnchorNavigationDirective }], ngImport: i0, template: ` <div [innerHTML]="htmlContent()" [class]="classes()"></div> `, isInline: true, encapsulation: i0.ViewEncapsulation.None, preserveWhitespaces: true }); }
642
- }
643
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: AnalogMarkdownComponent, decorators: [{
644
- type: Component,
645
- args: [{
646
- selector: 'analog-markdown',
647
- standalone: true,
648
- hostDirectives: [AnchorNavigationDirective],
649
- preserveWhitespaces: true,
650
- encapsulation: ViewEncapsulation.None,
651
- template: ` <div [innerHTML]="htmlContent()" [class]="classes()"></div> `,
652
- }]
653
- }], ctorParameters: () => [], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], classes: [{ type: i0.Input, args: [{ isSignal: true, alias: "classes", required: false }] }] } });
654
-
655
- /**
656
- * Generated bundle index. Do not edit.
657
- */
658
-
599
+ var MERMAID_IMPORT_TOKEN = new InjectionToken("mermaid_import");
600
+ //#endregion
601
+ //#region packages/content/src/lib/markdown-route.component.ts
602
+ var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
603
+ constructor() {
604
+ this.sanitizer = inject(DomSanitizer);
605
+ this.route = inject(ActivatedRoute);
606
+ this.contentRenderer = inject(ContentRenderer);
607
+ this.content = this.sanitizer.bypassSecurityTrustHtml(this.route.snapshot.data["renderedAnalogContent"]);
608
+ this.classes = "analog-markdown-route";
609
+ }
610
+ ngAfterViewChecked() {
611
+ this.contentRenderer.enhance();
612
+ }
613
+ static {
614
+ this.ɵfac = i0.ɵɵngDeclareFactory({
615
+ minVersion: "12.0.0",
616
+ version: "21.1.1",
617
+ ngImport: i0,
618
+ type: AnalogMarkdownRouteComponent,
619
+ deps: [],
620
+ target: i0.ɵɵFactoryTarget.Component
621
+ });
622
+ }
623
+ static {
624
+ this.ɵcmp = i0.ɵɵngDeclareComponent({
625
+ minVersion: "14.0.0",
626
+ version: "21.1.1",
627
+ type: AnalogMarkdownRouteComponent,
628
+ isStandalone: true,
629
+ selector: "analog-markdown-route",
630
+ inputs: { classes: "classes" },
631
+ hostDirectives: [{ directive: AnchorNavigationDirective }],
632
+ ngImport: i0,
633
+ template: `<div [innerHTML]="content" [class]="classes"></div>`,
634
+ isInline: true,
635
+ encapsulation: i0.ViewEncapsulation.None,
636
+ preserveWhitespaces: true
637
+ });
638
+ }
639
+ };
640
+ i0.ɵɵngDeclareClassMetadata({
641
+ minVersion: "12.0.0",
642
+ version: "21.1.1",
643
+ ngImport: i0,
644
+ type: AnalogMarkdownRouteComponent,
645
+ decorators: [{
646
+ type: Component,
647
+ args: [{
648
+ selector: "analog-markdown-route",
649
+ standalone: true,
650
+ imports: [AsyncPipe],
651
+ hostDirectives: [AnchorNavigationDirective],
652
+ preserveWhitespaces: true,
653
+ encapsulation: ViewEncapsulation.None,
654
+ template: `<div [innerHTML]="content" [class]="classes"></div>`
655
+ }]
656
+ }],
657
+ propDecorators: { classes: [{ type: Input }] }
658
+ });
659
+ //#endregion
660
+ //#region packages/content/src/lib/markdown.component.ts
661
+ var AnalogMarkdownComponent = class AnalogMarkdownComponent {
662
+ constructor() {
663
+ this.sanitizer = inject(DomSanitizer);
664
+ this.route = inject(ActivatedRoute);
665
+ this.zone = inject(NgZone);
666
+ this.platformId = inject(PLATFORM_ID);
667
+ this.mermaidImport = inject(MERMAID_IMPORT_TOKEN, { optional: true });
668
+ this.contentSource = toSignal(this.getContentSource());
669
+ this.htmlContent = computed(() => {
670
+ const inputContent = this.content();
671
+ if (inputContent) return this.sanitizer.bypassSecurityTrustHtml(inputContent);
672
+ return this.contentSource();
673
+ }, ...[]);
674
+ this.content = input(...[]);
675
+ this.classes = input("analog-markdown", ...[]);
676
+ this.contentRenderer = inject(ContentRenderer);
677
+ if (isPlatformBrowser(this.platformId) && this.mermaidImport) this.loadMermaid(this.mermaidImport);
678
+ }
679
+ getContentSource() {
680
+ return this.route.data.pipe(map((data) => data["_analogContent"] ?? ""), switchMap((contentString) => this.renderContent(contentString)), map((content) => this.sanitizer.bypassSecurityTrustHtml(content)), catchError((e) => of(`There was an error ${e}`)));
681
+ }
682
+ async renderContent(content) {
683
+ return (await this.contentRenderer.render(content)).content;
684
+ }
685
+ ngAfterViewChecked() {
686
+ this.contentRenderer.enhance();
687
+ this.zone.runOutsideAngular(() => this.mermaid?.default.run());
688
+ }
689
+ loadMermaid(mermaidImport) {
690
+ this.zone.runOutsideAngular(() => from(mermaidImport).pipe(takeUntilDestroyed()).subscribe((mermaid) => {
691
+ this.mermaid = mermaid;
692
+ this.mermaid.default.initialize({ startOnLoad: false });
693
+ this.mermaid?.default.run();
694
+ }));
695
+ }
696
+ static {
697
+ this.ɵfac = i0.ɵɵngDeclareFactory({
698
+ minVersion: "12.0.0",
699
+ version: "21.1.1",
700
+ ngImport: i0,
701
+ type: AnalogMarkdownComponent,
702
+ deps: [],
703
+ target: i0.ɵɵFactoryTarget.Component
704
+ });
705
+ }
706
+ static {
707
+ this.ɵcmp = i0.ɵɵngDeclareComponent({
708
+ minVersion: "17.1.0",
709
+ version: "21.1.1",
710
+ type: AnalogMarkdownComponent,
711
+ isStandalone: true,
712
+ selector: "analog-markdown",
713
+ inputs: {
714
+ content: {
715
+ classPropertyName: "content",
716
+ publicName: "content",
717
+ isSignal: true,
718
+ isRequired: false,
719
+ transformFunction: null
720
+ },
721
+ classes: {
722
+ classPropertyName: "classes",
723
+ publicName: "classes",
724
+ isSignal: true,
725
+ isRequired: false,
726
+ transformFunction: null
727
+ }
728
+ },
729
+ hostDirectives: [{ directive: AnchorNavigationDirective }],
730
+ ngImport: i0,
731
+ template: ` <div [innerHTML]="htmlContent()" [class]="classes()"></div> `,
732
+ isInline: true,
733
+ encapsulation: i0.ViewEncapsulation.None,
734
+ preserveWhitespaces: true
735
+ });
736
+ }
737
+ };
738
+ i0.ɵɵngDeclareClassMetadata({
739
+ minVersion: "12.0.0",
740
+ version: "21.1.1",
741
+ ngImport: i0,
742
+ type: AnalogMarkdownComponent,
743
+ decorators: [{
744
+ type: Component,
745
+ args: [{
746
+ selector: "analog-markdown",
747
+ standalone: true,
748
+ hostDirectives: [AnchorNavigationDirective],
749
+ preserveWhitespaces: true,
750
+ encapsulation: ViewEncapsulation.None,
751
+ template: ` <div [innerHTML]="htmlContent()" [class]="classes()"></div> `
752
+ }]
753
+ }],
754
+ ctorParameters: () => [],
755
+ propDecorators: {
756
+ content: [{
757
+ type: i0.Input,
758
+ args: [{
759
+ isSignal: true,
760
+ alias: "content",
761
+ required: false
762
+ }]
763
+ }],
764
+ classes: [{
765
+ type: i0.Input,
766
+ args: [{
767
+ isSignal: true,
768
+ alias: "classes",
769
+ required: false
770
+ }]
771
+ }]
772
+ }
773
+ });
774
+ //#endregion
659
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 };
660
- //# sourceMappingURL=analogjs-content.mjs.map
776
+
777
+ //# sourceMappingURL=analogjs-content.mjs.map