@analogjs/content 2.4.0-beta.9 → 3.0.0-alpha.10
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/LICENSE +21 -0
- package/fesm2022/analogjs-content-og.mjs +34 -46
- package/fesm2022/analogjs-content-prism-highlighter.mjs +81 -68
- package/fesm2022/analogjs-content-resources.mjs +115 -124
- package/fesm2022/analogjs-content-shiki-highlighter.mjs +9 -14
- package/fesm2022/analogjs-content.mjs +767 -618
- package/og/package.json +2 -2
- package/package.json +20 -8
- package/prism-highlighter/package.json +2 -2
- package/resources/package.json +2 -2
- package/shiki-highlighter/package.json +2 -2
- package/types/og/src/index.d.ts +2 -0
- package/types/og/src/lib/og.d.ts +5 -0
- package/types/og/src/lib/options.d.ts +11 -0
- package/types/prism-highlighter/src/index.d.ts +8 -0
- package/types/prism-highlighter/src/lib/prism/angular.d.ts +1 -0
- package/types/prism-highlighter/src/lib/prism-highlighter.d.ts +8 -0
- package/types/resources/src/content-file-resource.d.ts +37 -0
- package/types/resources/src/content-files-resource.d.ts +3 -0
- package/types/resources/src/index.d.ts +2 -0
- package/types/shiki-highlighter/src/index.d.ts +7 -0
- package/types/src/index.d.ts +16 -0
- package/types/src/lib/anchor-navigation.directive.d.ts +9 -0
- package/types/src/lib/content-file-loader.d.ts +6 -0
- package/types/src/lib/content-file.d.ts +8 -0
- package/types/src/lib/content-files-list-token.d.ts +3 -0
- package/types/src/lib/content-files-token.d.ts +3 -0
- package/types/src/lib/content-list-loader.d.ts +7 -0
- package/types/src/lib/content-renderer.d.ts +33 -0
- package/types/src/lib/content.d.ts +14 -0
- package/types/src/lib/get-content-files.d.ts +14 -0
- package/types/src/lib/inject-content-files.d.ts +4 -0
- package/types/src/lib/markdown-content-renderer.service.d.ts +10 -0
- package/types/src/lib/markdown-route.component.d.ts +15 -0
- package/types/src/lib/markdown.component.d.ts +26 -0
- package/types/src/lib/marked-content-highlighter.d.ts +17 -0
- package/types/src/lib/marked-setup.service.d.ts +10 -0
- package/types/src/lib/parse-raw-content-file.d.ts +18 -0
- package/types/src/lib/provide-content.d.ts +7 -0
- package/types/src/lib/render-task.service.d.ts +8 -0
- package/types/src/lib/utils/zone-wait-for.d.ts +2 -0
- package/fesm2022/analogjs-content-og.mjs.map +0 -1
- package/fesm2022/analogjs-content-prism-highlighter.mjs.map +0 -1
- package/fesm2022/analogjs-content-resources.mjs.map +0 -1
- package/fesm2022/analogjs-content-shiki-highlighter.mjs.map +0 -1
- package/fesm2022/analogjs-content.mjs.map +0 -1
- package/og/README.md +0 -3
- package/plugin/README.md +0 -11
- package/plugin/migrations.json +0 -75
- package/plugin/package.json +0 -23
- package/plugin/src/index.d.ts +0 -2
- package/plugin/src/index.js +0 -4
- package/plugin/src/index.js.map +0 -1
- package/plugin/src/migrations/update-markdown-renderer-feature/compat.d.ts +0 -2
- package/plugin/src/migrations/update-markdown-renderer-feature/compat.js +0 -6
- package/plugin/src/migrations/update-markdown-renderer-feature/compat.js.map +0 -1
- package/plugin/src/migrations/update-markdown-renderer-feature/update-markdown-renderer-feature.d.ts +0 -2
- package/plugin/src/migrations/update-markdown-renderer-feature/update-markdown-renderer-feature.js +0 -48
- package/plugin/src/migrations/update-markdown-renderer-feature/update-markdown-renderer-feature.js.map +0 -1
- package/plugin/src/migrations/update-markdown-version/compat.d.ts +0 -2
- package/plugin/src/migrations/update-markdown-version/compat.js +0 -6
- package/plugin/src/migrations/update-markdown-version/compat.js.map +0 -1
- package/plugin/src/migrations/update-markdown-version/update-markdown-version.d.ts +0 -2
- package/plugin/src/migrations/update-markdown-version/update-markdown-version.js +0 -23
- package/plugin/src/migrations/update-markdown-version/update-markdown-version.js.map +0 -1
- package/prism-highlighter/README.md +0 -3
- package/resources/README.md +0 -3
- package/shiki-highlighter/README.md +0 -3
- package/types/analogjs-content-og.d.ts +0 -19
- package/types/analogjs-content-prism-highlighter.d.ts +0 -15
- package/types/analogjs-content-resources.d.ts +0 -20
- package/types/analogjs-content-shiki-highlighter.d.ts +0 -11
- package/types/analogjs-content.d.ts +0 -168
|
@@ -1,660 +1,809 @@
|
|
|
1
|
-
import * as i0 from
|
|
2
|
-
import {
|
|
3
|
-
import { DOCUMENT, Location,
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import fm from
|
|
8
|
-
import {
|
|
9
|
-
import { marked } from
|
|
10
|
-
import { mangle } from
|
|
11
|
-
import { DomSanitizer } from
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
class AnchorNavigationDirective {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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 { 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
|
-
|
|
69
|
+
return anchorElement.getAttribute("download") !== null;
|
|
47
70
|
}
|
|
48
71
|
function hasTargetSelf(anchorElement) {
|
|
49
|
-
|
|
72
|
+
return !anchorElement.target || anchorElement.target === "_self";
|
|
50
73
|
}
|
|
51
74
|
function isInternalUrl(anchorElement, document) {
|
|
52
|
-
|
|
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 }); }
|
|
75
|
+
return anchorElement.host === document.location.host && anchorElement.protocol === document.location.protocol;
|
|
69
76
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
|
|
198
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
272
|
+
new InjectionToken("@analogjs/content Content Files", {
|
|
273
|
+
providedIn: "root",
|
|
274
|
+
factory() {
|
|
275
|
+
return signal(inject(CONTENT_FILES_TOKEN));
|
|
276
|
+
}
|
|
264
277
|
});
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
278
|
+
//#endregion
|
|
279
|
+
//#region packages/content/src/lib/parse-raw-content-file.ts
|
|
280
|
+
var FrontmatterValidationError = class extends Error {
|
|
281
|
+
constructor(issues, filename) {
|
|
282
|
+
const issueMessages = issues.map((i) => {
|
|
283
|
+
const path = i.path ? ` at "${i.path.map((p) => typeof p === "object" ? p.key : p).join(".")}"` : "";
|
|
284
|
+
return ` - ${i.message}${path}`;
|
|
285
|
+
}).join("\n");
|
|
286
|
+
const prefix = filename ? `"${filename}" f` : "F";
|
|
287
|
+
super(`${prefix}rontmatter validation failed:\n${issueMessages}`);
|
|
288
|
+
this.issues = issues;
|
|
289
|
+
this.filename = filename;
|
|
290
|
+
this.name = "FrontmatterValidationError";
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
function parseRawContentFile(rawContentFile, schema, filename) {
|
|
294
|
+
const { body, attributes } = fm(rawContentFile);
|
|
295
|
+
if (schema) {
|
|
296
|
+
const result = schema["~standard"].validate(attributes);
|
|
297
|
+
if (result != null && typeof result.then === "function") throw new Error("parseRawContentFile does not support async schema validation. Use parseRawContentFileAsync() for async schemas.");
|
|
298
|
+
const syncResult = result;
|
|
299
|
+
if (syncResult.issues) throw new FrontmatterValidationError(syncResult.issues, filename);
|
|
300
|
+
return {
|
|
301
|
+
content: body,
|
|
302
|
+
attributes: syncResult.value
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
content: body,
|
|
307
|
+
attributes
|
|
308
|
+
};
|
|
283
309
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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 }); }
|
|
310
|
+
async function parseRawContentFileAsync(rawContentFile, schema, filename) {
|
|
311
|
+
const { body, attributes } = fm(rawContentFile);
|
|
312
|
+
const result = await schema["~standard"].validate(attributes);
|
|
313
|
+
if (result.issues) throw new FrontmatterValidationError(result.issues, filename);
|
|
314
|
+
return {
|
|
315
|
+
content: body,
|
|
316
|
+
attributes: result.value
|
|
317
|
+
};
|
|
300
318
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
319
|
+
//#endregion
|
|
320
|
+
//#region packages/content/src/lib/render-task.service.ts
|
|
321
|
+
var RenderTaskService = class RenderTaskService {
|
|
322
|
+
#pendingTasks = inject(ɵPendingTasksInternal);
|
|
323
|
+
addRenderTask() {
|
|
324
|
+
return this.#pendingTasks.add();
|
|
325
|
+
}
|
|
326
|
+
clearRenderTask(clear) {
|
|
327
|
+
if (typeof clear === "function") clear();
|
|
328
|
+
else if (typeof this.#pendingTasks.remove === "function") this.#pendingTasks.remove(clear);
|
|
329
|
+
}
|
|
330
|
+
static {
|
|
331
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
332
|
+
minVersion: "12.0.0",
|
|
333
|
+
version: "21.1.1",
|
|
334
|
+
ngImport: i0,
|
|
335
|
+
type: RenderTaskService,
|
|
336
|
+
deps: [],
|
|
337
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
static {
|
|
341
|
+
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
342
|
+
minVersion: "12.0.0",
|
|
343
|
+
version: "21.1.1",
|
|
344
|
+
ngImport: i0,
|
|
345
|
+
type: RenderTaskService
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
350
|
+
minVersion: "12.0.0",
|
|
351
|
+
version: "21.1.1",
|
|
352
|
+
ngImport: i0,
|
|
353
|
+
type: RenderTaskService,
|
|
354
|
+
decorators: [{ type: Injectable }]
|
|
355
|
+
});
|
|
356
|
+
//#endregion
|
|
357
|
+
//#region packages/content/src/lib/content.ts
|
|
306
358
|
function getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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
|
-
}));
|
|
359
|
+
const normalizedFiles = {};
|
|
360
|
+
for (const [key, resolver] of Object.entries(contentFiles)) {
|
|
361
|
+
const normalizedKey = key.replace(/^(?:.*)\/content/, "/src/content").replace(/\/{2,}/g, "/");
|
|
362
|
+
normalizedFiles[normalizedKey] = resolver;
|
|
363
|
+
}
|
|
364
|
+
const base = `/src/content/${prefix}${slug}`.replace(/\/{2,}/g, "/");
|
|
365
|
+
const matchKey = [
|
|
366
|
+
`${base}.md`,
|
|
367
|
+
`${base}.agx`,
|
|
368
|
+
`${base}/index.md`,
|
|
369
|
+
`${base}/index.agx`
|
|
370
|
+
].find((k) => k in normalizedFiles);
|
|
371
|
+
const contentFile = matchKey ? normalizedFiles[matchKey] : void 0;
|
|
372
|
+
const resolvedBase = (matchKey || `${base}.md`).replace(/\.(md|agx)$/, "");
|
|
373
|
+
if (!contentFile) return of({
|
|
374
|
+
filename: resolvedBase,
|
|
375
|
+
attributes: {},
|
|
376
|
+
slug: "",
|
|
377
|
+
content: fallback,
|
|
378
|
+
toc: []
|
|
379
|
+
});
|
|
380
|
+
renderTaskService.addRenderTask();
|
|
381
|
+
return new Observable((observer) => {
|
|
382
|
+
contentFile().then((content) => {
|
|
383
|
+
observer.next(content);
|
|
384
|
+
observer.complete();
|
|
385
|
+
});
|
|
386
|
+
}).pipe(switchMap((contentFile) => {
|
|
387
|
+
if (typeof contentFile === "string") {
|
|
388
|
+
const { content, attributes } = parseRawContentFile(contentFile);
|
|
389
|
+
return from(contentRenderer.render(content)).pipe(map((rendered) => ({
|
|
390
|
+
filename: resolvedBase,
|
|
391
|
+
slug,
|
|
392
|
+
attributes,
|
|
393
|
+
content,
|
|
394
|
+
toc: rendered.toc ?? []
|
|
395
|
+
})));
|
|
396
|
+
}
|
|
397
|
+
return of({
|
|
398
|
+
filename: resolvedBase,
|
|
399
|
+
slug,
|
|
400
|
+
attributes: contentFile.metadata,
|
|
401
|
+
content: contentFile.default,
|
|
402
|
+
toc: []
|
|
403
|
+
});
|
|
404
|
+
}));
|
|
369
405
|
}
|
|
370
406
|
/**
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
function injectContent(param =
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
}), tap(() => renderTaskService.clearRenderTask(task)));
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
return getContentFile(contentFiles, '', param.customFilename, fallback, renderTaskService, contentRenderer).pipe(tap(() => renderTaskService.clearRenderTask(task)));
|
|
400
|
-
}
|
|
407
|
+
* Retrieves the static content using the provided param and/or prefix.
|
|
408
|
+
*
|
|
409
|
+
* @param param route parameter (default: 'slug')
|
|
410
|
+
* @param fallback fallback text if content file is not found (default: 'No Content Found')
|
|
411
|
+
*/
|
|
412
|
+
function injectContent(param = "slug", fallback = "No Content Found") {
|
|
413
|
+
const contentFiles = inject(CONTENT_FILES_TOKEN);
|
|
414
|
+
const contentRenderer = inject(ContentRenderer);
|
|
415
|
+
const renderTaskService = inject(RenderTaskService);
|
|
416
|
+
const task = renderTaskService.addRenderTask();
|
|
417
|
+
if (typeof param === "string" || "param" in param) {
|
|
418
|
+
const prefix = typeof param === "string" ? "" : `${param.subdirectory}/`;
|
|
419
|
+
const route = inject(ActivatedRoute);
|
|
420
|
+
const paramKey = typeof param === "string" ? param : param.param;
|
|
421
|
+
return route.paramMap.pipe(map((params) => params.get(paramKey)), switchMap((slug) => {
|
|
422
|
+
if (slug) return getContentFile(contentFiles, prefix, slug, fallback, renderTaskService, contentRenderer);
|
|
423
|
+
return of({
|
|
424
|
+
filename: "",
|
|
425
|
+
slug: "",
|
|
426
|
+
attributes: {},
|
|
427
|
+
content: fallback,
|
|
428
|
+
toc: []
|
|
429
|
+
});
|
|
430
|
+
}), tap(() => renderTaskService.clearRenderTask(task)));
|
|
431
|
+
} else return getContentFile(contentFiles, "", param.customFilename, fallback, renderTaskService, contentRenderer).pipe(tap(() => renderTaskService.clearRenderTask(task)));
|
|
401
432
|
}
|
|
402
|
-
|
|
433
|
+
//#endregion
|
|
434
|
+
//#region packages/content/src/lib/inject-content-files.ts
|
|
403
435
|
function injectContentFiles(filterFn) {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
return filteredContentFiles;
|
|
411
|
-
}
|
|
412
|
-
return allContentFiles;
|
|
436
|
+
const renderTaskService = inject(RenderTaskService);
|
|
437
|
+
const task = renderTaskService.addRenderTask();
|
|
438
|
+
const allContentFiles = inject(CONTENT_FILES_LIST_TOKEN);
|
|
439
|
+
renderTaskService.clearRenderTask(task);
|
|
440
|
+
if (filterFn) return allContentFiles.filter(filterFn);
|
|
441
|
+
return allContentFiles;
|
|
413
442
|
}
|
|
414
443
|
function injectContentFilesMap() {
|
|
415
|
-
|
|
416
|
-
}
|
|
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 }); }
|
|
444
|
+
return inject(CONTENT_FILES_TOKEN);
|
|
421
445
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
446
|
+
//#endregion
|
|
447
|
+
//#region packages/content/src/lib/marked-content-highlighter.ts
|
|
448
|
+
var MarkedContentHighlighter = class MarkedContentHighlighter {
|
|
449
|
+
static {
|
|
450
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
451
|
+
minVersion: "12.0.0",
|
|
452
|
+
version: "21.1.1",
|
|
453
|
+
ngImport: i0,
|
|
454
|
+
type: MarkedContentHighlighter,
|
|
455
|
+
deps: [],
|
|
456
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
static {
|
|
460
|
+
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
461
|
+
minVersion: "12.0.0",
|
|
462
|
+
version: "21.1.1",
|
|
463
|
+
ngImport: i0,
|
|
464
|
+
type: MarkedContentHighlighter
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
469
|
+
minVersion: "12.0.0",
|
|
470
|
+
version: "21.1.1",
|
|
471
|
+
ngImport: i0,
|
|
472
|
+
type: MarkedContentHighlighter,
|
|
473
|
+
decorators: [{ type: Injectable }]
|
|
474
|
+
});
|
|
425
475
|
function withHighlighter(provider) {
|
|
426
|
-
|
|
476
|
+
return {
|
|
477
|
+
provide: MarkedContentHighlighter,
|
|
478
|
+
...provider
|
|
479
|
+
};
|
|
427
480
|
}
|
|
428
|
-
|
|
481
|
+
//#endregion
|
|
482
|
+
//#region packages/content/src/lib/marked-setup.service.ts
|
|
429
483
|
/**
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
class MarkedSetupService {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
i0.ɵɵ
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
484
|
+
* Credit goes to Scully for original implementation
|
|
485
|
+
* https://github.com/scullyio/scully/blob/main/libs/scully/src/lib/fileHanderPlugins/markdown.ts
|
|
486
|
+
*/
|
|
487
|
+
var MarkedSetupService = class MarkedSetupService {
|
|
488
|
+
constructor() {
|
|
489
|
+
this.highlighter = inject(MarkedContentHighlighter, { optional: true });
|
|
490
|
+
const renderer = new marked.Renderer();
|
|
491
|
+
renderer.code = ({ text, lang }) => {
|
|
492
|
+
if (lang === "mermaid") return "<pre class=\"mermaid\">" + text + "</pre>";
|
|
493
|
+
if (!lang) return "<pre><code>" + text + "</code></pre>";
|
|
494
|
+
if (this.highlighter?.augmentCodeBlock) return this.highlighter?.augmentCodeBlock(text, lang);
|
|
495
|
+
return `<pre class="language-${lang}"><code class="language-${lang}">${text}</code></pre>`;
|
|
496
|
+
};
|
|
497
|
+
const extensions = [gfmHeadingId(), mangle()];
|
|
498
|
+
if (this.highlighter) extensions.push(this.highlighter.getHighlightExtension());
|
|
499
|
+
marked.use(...extensions, {
|
|
500
|
+
renderer,
|
|
501
|
+
pedantic: false,
|
|
502
|
+
gfm: true,
|
|
503
|
+
breaks: false
|
|
504
|
+
});
|
|
505
|
+
this.marked = marked;
|
|
506
|
+
}
|
|
507
|
+
getMarkedInstance() {
|
|
508
|
+
return this.marked;
|
|
509
|
+
}
|
|
510
|
+
static {
|
|
511
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
512
|
+
minVersion: "12.0.0",
|
|
513
|
+
version: "21.1.1",
|
|
514
|
+
ngImport: i0,
|
|
515
|
+
type: MarkedSetupService,
|
|
516
|
+
deps: [],
|
|
517
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
static {
|
|
521
|
+
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
522
|
+
minVersion: "12.0.0",
|
|
523
|
+
version: "21.1.1",
|
|
524
|
+
ngImport: i0,
|
|
525
|
+
type: MarkedSetupService
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
530
|
+
minVersion: "12.0.0",
|
|
531
|
+
version: "21.1.1",
|
|
532
|
+
ngImport: i0,
|
|
533
|
+
type: MarkedSetupService,
|
|
534
|
+
decorators: [{ type: Injectable }],
|
|
535
|
+
ctorParameters: () => []
|
|
536
|
+
});
|
|
537
|
+
//#endregion
|
|
538
|
+
//#region packages/content/src/lib/markdown-content-renderer.service.ts
|
|
539
|
+
var MarkdownContentRendererService = class MarkdownContentRendererService {
|
|
540
|
+
#marked = inject(MarkedSetupService, { self: true });
|
|
541
|
+
async render(content) {
|
|
542
|
+
return {
|
|
543
|
+
content: await this.#marked.getMarkedInstance().parse(content),
|
|
544
|
+
toc: getHeadingList()
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
getContentHeadings(content) {
|
|
548
|
+
return [...content.matchAll(/^(#{1,6})\s+(.+?)\s*$/gm)].map((match) => ({
|
|
549
|
+
id: match[2].trim().toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-"),
|
|
550
|
+
level: match[1].length,
|
|
551
|
+
text: match[2].trim()
|
|
552
|
+
}));
|
|
553
|
+
}
|
|
554
|
+
enhance() {}
|
|
555
|
+
static {
|
|
556
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
557
|
+
minVersion: "12.0.0",
|
|
558
|
+
version: "21.1.1",
|
|
559
|
+
ngImport: i0,
|
|
560
|
+
type: MarkdownContentRendererService,
|
|
561
|
+
deps: [],
|
|
562
|
+
target: i0.ɵɵFactoryTarget.Injectable
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
static {
|
|
566
|
+
this.ɵprov = i0.ɵɵngDeclareInjectable({
|
|
567
|
+
minVersion: "12.0.0",
|
|
568
|
+
version: "21.1.1",
|
|
569
|
+
ngImport: i0,
|
|
570
|
+
type: MarkdownContentRendererService
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
575
|
+
minVersion: "12.0.0",
|
|
576
|
+
version: "21.1.1",
|
|
577
|
+
ngImport: i0,
|
|
578
|
+
type: MarkdownContentRendererService,
|
|
579
|
+
decorators: [{ type: Injectable }]
|
|
580
|
+
});
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region packages/content/src/lib/content-file-loader.ts
|
|
583
|
+
var CONTENT_FILE_LOADER = new InjectionToken("@analogjs/content/resource File Loader");
|
|
507
584
|
function injectContentFileLoader() {
|
|
508
|
-
|
|
585
|
+
return inject(CONTENT_FILE_LOADER);
|
|
509
586
|
}
|
|
510
587
|
function withContentFileLoader() {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
588
|
+
return {
|
|
589
|
+
provide: CONTENT_FILE_LOADER,
|
|
590
|
+
useFactory() {
|
|
591
|
+
return async () => injectContentFilesMap();
|
|
592
|
+
}
|
|
593
|
+
};
|
|
517
594
|
}
|
|
518
|
-
|
|
519
|
-
|
|
595
|
+
//#endregion
|
|
596
|
+
//#region packages/content/src/lib/content-list-loader.ts
|
|
597
|
+
var CONTENT_LIST_LOADER = new InjectionToken("@analogjs/content/resource List Loader");
|
|
520
598
|
function injectContentListLoader() {
|
|
521
|
-
|
|
599
|
+
return inject(CONTENT_LIST_LOADER);
|
|
522
600
|
}
|
|
523
601
|
function withContentListLoader() {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
602
|
+
return {
|
|
603
|
+
provide: CONTENT_LIST_LOADER,
|
|
604
|
+
useFactory() {
|
|
605
|
+
return async () => injectContentFiles();
|
|
606
|
+
}
|
|
607
|
+
};
|
|
530
608
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
609
|
+
//#endregion
|
|
610
|
+
//#region packages/content/src/lib/provide-content.ts
|
|
611
|
+
var CONTENT_RENDERER_PROVIDERS = [
|
|
612
|
+
{
|
|
613
|
+
provide: ContentRenderer,
|
|
614
|
+
useClass: NoopContentRenderer
|
|
615
|
+
},
|
|
616
|
+
withContentFileLoader(),
|
|
617
|
+
withContentListLoader()
|
|
539
618
|
];
|
|
540
619
|
function withMarkdownRenderer(options) {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
{
|
|
546
|
-
provide: MERMAID_IMPORT_TOKEN,
|
|
547
|
-
useFactory: options.loadMermaid,
|
|
548
|
-
},
|
|
549
|
-
]
|
|
550
|
-
: [],
|
|
551
|
-
];
|
|
620
|
+
return [CONTENT_RENDERER_PROVIDERS, options?.loadMermaid ? [{
|
|
621
|
+
provide: MERMAID_IMPORT_TOKEN,
|
|
622
|
+
useFactory: options.loadMermaid
|
|
623
|
+
}] : []];
|
|
552
624
|
}
|
|
553
625
|
function provideContent(...features) {
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
}
|
|
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 }); }
|
|
626
|
+
return [{
|
|
627
|
+
provide: RenderTaskService,
|
|
628
|
+
useClass: RenderTaskService
|
|
629
|
+
}, ...features];
|
|
574
630
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
631
|
+
var MERMAID_IMPORT_TOKEN = new InjectionToken("mermaid_import");
|
|
632
|
+
//#endregion
|
|
633
|
+
//#region packages/content/src/lib/markdown-route.component.ts
|
|
634
|
+
var AnalogMarkdownRouteComponent = class AnalogMarkdownRouteComponent {
|
|
635
|
+
constructor() {
|
|
636
|
+
this.sanitizer = inject(DomSanitizer);
|
|
637
|
+
this.route = inject(ActivatedRoute);
|
|
638
|
+
this.contentRenderer = inject(ContentRenderer);
|
|
639
|
+
this.content = this.sanitizer.bypassSecurityTrustHtml(this.route.snapshot.data["renderedAnalogContent"]);
|
|
640
|
+
this.classes = "analog-markdown-route";
|
|
641
|
+
}
|
|
642
|
+
ngAfterViewChecked() {
|
|
643
|
+
this.contentRenderer.enhance();
|
|
644
|
+
}
|
|
645
|
+
static {
|
|
646
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
647
|
+
minVersion: "12.0.0",
|
|
648
|
+
version: "21.1.1",
|
|
649
|
+
ngImport: i0,
|
|
650
|
+
type: AnalogMarkdownRouteComponent,
|
|
651
|
+
deps: [],
|
|
652
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
static {
|
|
656
|
+
this.ɵcmp = i0.ɵɵngDeclareComponent({
|
|
657
|
+
minVersion: "14.0.0",
|
|
658
|
+
version: "21.1.1",
|
|
659
|
+
type: AnalogMarkdownRouteComponent,
|
|
660
|
+
isStandalone: true,
|
|
661
|
+
selector: "analog-markdown-route",
|
|
662
|
+
inputs: { classes: "classes" },
|
|
663
|
+
hostDirectives: [{ directive: AnchorNavigationDirective }],
|
|
664
|
+
ngImport: i0,
|
|
665
|
+
template: `<div [innerHTML]="content" [class]="classes"></div>`,
|
|
666
|
+
isInline: true,
|
|
667
|
+
encapsulation: i0.ViewEncapsulation.None,
|
|
668
|
+
preserveWhitespaces: true
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
673
|
+
minVersion: "12.0.0",
|
|
674
|
+
version: "21.1.1",
|
|
675
|
+
ngImport: i0,
|
|
676
|
+
type: AnalogMarkdownRouteComponent,
|
|
677
|
+
decorators: [{
|
|
678
|
+
type: Component,
|
|
679
|
+
args: [{
|
|
680
|
+
selector: "analog-markdown-route",
|
|
681
|
+
standalone: true,
|
|
682
|
+
imports: [],
|
|
683
|
+
hostDirectives: [AnchorNavigationDirective],
|
|
684
|
+
preserveWhitespaces: true,
|
|
685
|
+
encapsulation: ViewEncapsulation.None,
|
|
686
|
+
template: `<div [innerHTML]="content" [class]="classes"></div>`
|
|
687
|
+
}]
|
|
688
|
+
}],
|
|
689
|
+
propDecorators: { classes: [{ type: Input }] }
|
|
690
|
+
});
|
|
691
|
+
//#endregion
|
|
692
|
+
//#region packages/content/src/lib/markdown.component.ts
|
|
693
|
+
var AnalogMarkdownComponent = class AnalogMarkdownComponent {
|
|
694
|
+
constructor() {
|
|
695
|
+
this.sanitizer = inject(DomSanitizer);
|
|
696
|
+
this.route = inject(ActivatedRoute);
|
|
697
|
+
this.zone = inject(NgZone);
|
|
698
|
+
this.platformId = inject(PLATFORM_ID);
|
|
699
|
+
this.mermaidImport = inject(MERMAID_IMPORT_TOKEN, { optional: true });
|
|
700
|
+
this.contentSource = toSignal(this.getContentSource());
|
|
701
|
+
this.htmlContent = computed(() => {
|
|
702
|
+
const inputContent = this.content();
|
|
703
|
+
if (inputContent) return this.sanitizer.bypassSecurityTrustHtml(inputContent);
|
|
704
|
+
return this.contentSource();
|
|
705
|
+
}, ...[]);
|
|
706
|
+
this.content = input(...[]);
|
|
707
|
+
this.classes = input("analog-markdown", ...[]);
|
|
708
|
+
this.contentRenderer = inject(ContentRenderer);
|
|
709
|
+
if (isPlatformBrowser(this.platformId) && this.mermaidImport) this.loadMermaid(this.mermaidImport);
|
|
710
|
+
}
|
|
711
|
+
getContentSource() {
|
|
712
|
+
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}`)));
|
|
713
|
+
}
|
|
714
|
+
async renderContent(content) {
|
|
715
|
+
return (await this.contentRenderer.render(content)).content;
|
|
716
|
+
}
|
|
717
|
+
ngAfterViewChecked() {
|
|
718
|
+
this.contentRenderer.enhance();
|
|
719
|
+
this.zone.runOutsideAngular(() => this.mermaid?.default.run());
|
|
720
|
+
}
|
|
721
|
+
loadMermaid(mermaidImport) {
|
|
722
|
+
this.zone.runOutsideAngular(() => from(mermaidImport).pipe(takeUntilDestroyed()).subscribe((mermaid) => {
|
|
723
|
+
this.mermaid = mermaid;
|
|
724
|
+
this.mermaid.default.initialize({ startOnLoad: false });
|
|
725
|
+
this.mermaid?.default.run();
|
|
726
|
+
}));
|
|
727
|
+
}
|
|
728
|
+
static {
|
|
729
|
+
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
730
|
+
minVersion: "12.0.0",
|
|
731
|
+
version: "21.1.1",
|
|
732
|
+
ngImport: i0,
|
|
733
|
+
type: AnalogMarkdownComponent,
|
|
734
|
+
deps: [],
|
|
735
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
static {
|
|
739
|
+
this.ɵcmp = i0.ɵɵngDeclareComponent({
|
|
740
|
+
minVersion: "17.1.0",
|
|
741
|
+
version: "21.1.1",
|
|
742
|
+
type: AnalogMarkdownComponent,
|
|
743
|
+
isStandalone: true,
|
|
744
|
+
selector: "analog-markdown",
|
|
745
|
+
inputs: {
|
|
746
|
+
content: {
|
|
747
|
+
classPropertyName: "content",
|
|
748
|
+
publicName: "content",
|
|
749
|
+
isSignal: true,
|
|
750
|
+
isRequired: false,
|
|
751
|
+
transformFunction: null
|
|
752
|
+
},
|
|
753
|
+
classes: {
|
|
754
|
+
classPropertyName: "classes",
|
|
755
|
+
publicName: "classes",
|
|
756
|
+
isSignal: true,
|
|
757
|
+
isRequired: false,
|
|
758
|
+
transformFunction: null
|
|
759
|
+
}
|
|
760
|
+
},
|
|
761
|
+
hostDirectives: [{ directive: AnchorNavigationDirective }],
|
|
762
|
+
ngImport: i0,
|
|
763
|
+
template: ` <div [innerHTML]="htmlContent()" [class]="classes()"></div> `,
|
|
764
|
+
isInline: true,
|
|
765
|
+
encapsulation: i0.ViewEncapsulation.None,
|
|
766
|
+
preserveWhitespaces: true
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
771
|
+
minVersion: "12.0.0",
|
|
772
|
+
version: "21.1.1",
|
|
773
|
+
ngImport: i0,
|
|
774
|
+
type: AnalogMarkdownComponent,
|
|
775
|
+
decorators: [{
|
|
776
|
+
type: Component,
|
|
777
|
+
args: [{
|
|
778
|
+
selector: "analog-markdown",
|
|
779
|
+
standalone: true,
|
|
780
|
+
hostDirectives: [AnchorNavigationDirective],
|
|
781
|
+
preserveWhitespaces: true,
|
|
782
|
+
encapsulation: ViewEncapsulation.None,
|
|
783
|
+
template: ` <div [innerHTML]="htmlContent()" [class]="classes()"></div> `
|
|
784
|
+
}]
|
|
785
|
+
}],
|
|
786
|
+
ctorParameters: () => [],
|
|
787
|
+
propDecorators: {
|
|
788
|
+
content: [{
|
|
789
|
+
type: i0.Input,
|
|
790
|
+
args: [{
|
|
791
|
+
isSignal: true,
|
|
792
|
+
alias: "content",
|
|
793
|
+
required: false
|
|
794
|
+
}]
|
|
795
|
+
}],
|
|
796
|
+
classes: [{
|
|
797
|
+
type: i0.Input,
|
|
798
|
+
args: [{
|
|
799
|
+
isSignal: true,
|
|
800
|
+
alias: "classes",
|
|
801
|
+
required: false
|
|
802
|
+
}]
|
|
803
|
+
}]
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
//#endregion
|
|
807
|
+
export { AnchorNavigationDirective, CONTENT_FILE_LOADER, CONTENT_LIST_LOADER, ContentRenderer, FrontmatterValidationError, MERMAID_IMPORT_TOKEN, AnalogMarkdownComponent as MarkdownComponent, MarkdownContentRendererService, AnalogMarkdownRouteComponent as MarkdownRouteComponent, MarkedContentHighlighter, MarkedSetupService, NoopContentRenderer, injectContent, injectContentFileLoader, injectContentFiles, injectContentFilesMap, injectContentListLoader, parseRawContentFile, parseRawContentFileAsync, provideContent, withContentFileLoader, withContentListLoader, withHighlighter, withMarkdownRenderer };
|
|
658
808
|
|
|
659
|
-
|
|
660
|
-
//# sourceMappingURL=analogjs-content.mjs.map
|
|
809
|
+
//# sourceMappingURL=analogjs-content.mjs.map
|