@memberjunction/ng-markdown 0.0.1 → 2.126.0

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.
@@ -0,0 +1,101 @@
1
+ import { MarkdownConfig, HeadingInfo } from '../types/markdown.types';
2
+ import 'prismjs/components/prism-typescript';
3
+ import 'prismjs/components/prism-javascript';
4
+ import 'prismjs/components/prism-css';
5
+ import 'prismjs/components/prism-scss';
6
+ import 'prismjs/components/prism-json';
7
+ import 'prismjs/components/prism-bash';
8
+ import 'prismjs/components/prism-sql';
9
+ import 'prismjs/components/prism-python';
10
+ import 'prismjs/components/prism-csharp';
11
+ import 'prismjs/components/prism-java';
12
+ import 'prismjs/components/prism-markup';
13
+ import 'prismjs/components/prism-yaml';
14
+ import 'prismjs/components/prism-markdown';
15
+ import 'prismjs/components/prism-graphql';
16
+ import * as i0 from "@angular/core";
17
+ type ResolvedMarkdownConfig = Required<Omit<MarkdownConfig, 'autoExpandLevels'>> & {
18
+ autoExpandLevels?: number[];
19
+ };
20
+ /**
21
+ * Service for parsing and rendering markdown content.
22
+ * Uses marked.js with various extensions for syntax highlighting,
23
+ * diagrams, alerts, and more.
24
+ */
25
+ export declare class MarkdownService {
26
+ private marked;
27
+ private mermaidInitialized;
28
+ private currentConfig;
29
+ private headingList;
30
+ constructor();
31
+ /**
32
+ * Configure the marked instance with the provided options
33
+ */
34
+ configureMarked(config: MarkdownConfig): void;
35
+ /**
36
+ * Initialize Mermaid with the current theme configuration
37
+ */
38
+ private initializeMermaid;
39
+ /**
40
+ * Parse markdown to HTML
41
+ * @param markdown The markdown string to parse
42
+ * @param config Optional config overrides for this parse operation
43
+ * @returns The rendered HTML string
44
+ */
45
+ parse(markdown: string, config?: Partial<MarkdownConfig>): string;
46
+ /**
47
+ * Parse markdown asynchronously (useful for large documents)
48
+ */
49
+ parseAsync(markdown: string, config?: Partial<MarkdownConfig>): Promise<string>;
50
+ /**
51
+ * Render Mermaid diagrams in a container element
52
+ * Call this after the HTML has been inserted into the DOM
53
+ * @param container The DOM element containing mermaid code blocks
54
+ */
55
+ renderMermaid(container: HTMLElement): Promise<boolean>;
56
+ /**
57
+ * Highlight code blocks with Prism
58
+ * Call this after the HTML has been inserted into the DOM
59
+ * @param container The DOM element containing code blocks
60
+ */
61
+ highlightCode(container: HTMLElement): void;
62
+ /**
63
+ * Add copy buttons to code blocks
64
+ * @param container The DOM element containing code blocks
65
+ */
66
+ addCodeCopyButtons(container: HTMLElement): void;
67
+ /**
68
+ * Initialize collapsible heading functionality
69
+ * This method is a no-op - the component handles event binding
70
+ * @param container The DOM element containing collapsible sections
71
+ */
72
+ initializeCollapsibleHeadings(_container: HTMLElement): void;
73
+ /**
74
+ * Get the list of headings from the last parsed document
75
+ * Useful for building table of contents
76
+ */
77
+ getHeadingList(): HeadingInfo[];
78
+ /**
79
+ * Get the current configuration
80
+ */
81
+ getConfig(): ResolvedMarkdownConfig;
82
+ /**
83
+ * Reset configuration to defaults
84
+ */
85
+ resetConfig(): void;
86
+ /**
87
+ * Check if a language is supported by Prism
88
+ */
89
+ isLanguageSupported(lang: string): boolean;
90
+ /**
91
+ * Get list of supported Prism languages
92
+ */
93
+ getSupportedLanguages(): string[];
94
+ /**
95
+ * Escape HTML entities for safe display
96
+ */
97
+ private escapeHtml;
98
+ static ɵfac: i0.ɵɵFactoryDeclaration<MarkdownService, never>;
99
+ static ɵprov: i0.ɵɵInjectableDeclaration<MarkdownService>;
100
+ }
101
+ export {};
@@ -0,0 +1,310 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { Marked } from 'marked';
3
+ import { markedHighlight } from 'marked-highlight';
4
+ import { gfmHeadingId, getHeadingList } from 'marked-gfm-heading-id';
5
+ import markedAlert from 'marked-alert';
6
+ import { markedSmartypants } from 'marked-smartypants';
7
+ import Prism from 'prismjs';
8
+ import mermaid from 'mermaid';
9
+ import { DEFAULT_MARKDOWN_CONFIG } from '../types/markdown.types';
10
+ import { createCollapsibleHeadingsExtension } from '../extensions/collapsible-headings.extension';
11
+ import { createSvgRendererExtension } from '../extensions/svg-renderer.extension';
12
+ // Import common Prism language components
13
+ // Additional languages can be imported by the consuming application
14
+ import 'prismjs/components/prism-typescript';
15
+ import 'prismjs/components/prism-javascript';
16
+ import 'prismjs/components/prism-css';
17
+ import 'prismjs/components/prism-scss';
18
+ import 'prismjs/components/prism-json';
19
+ import 'prismjs/components/prism-bash';
20
+ import 'prismjs/components/prism-sql';
21
+ import 'prismjs/components/prism-python';
22
+ import 'prismjs/components/prism-csharp';
23
+ import 'prismjs/components/prism-java';
24
+ import 'prismjs/components/prism-markup';
25
+ import 'prismjs/components/prism-yaml';
26
+ import 'prismjs/components/prism-markdown';
27
+ import 'prismjs/components/prism-graphql';
28
+ import * as i0 from "@angular/core";
29
+ /**
30
+ * Service for parsing and rendering markdown content.
31
+ * Uses marked.js with various extensions for syntax highlighting,
32
+ * diagrams, alerts, and more.
33
+ */
34
+ export class MarkdownService {
35
+ constructor() {
36
+ this.mermaidInitialized = false;
37
+ this.currentConfig = { ...DEFAULT_MARKDOWN_CONFIG };
38
+ this.headingList = [];
39
+ this.marked = new Marked();
40
+ this.configureMarked(this.currentConfig);
41
+ }
42
+ /**
43
+ * Configure the marked instance with the provided options
44
+ */
45
+ configureMarked(config) {
46
+ this.currentConfig = { ...DEFAULT_MARKDOWN_CONFIG, ...config };
47
+ // Create a fresh Marked instance
48
+ this.marked = new Marked();
49
+ // Configure base options
50
+ this.marked.setOptions({
51
+ gfm: true,
52
+ breaks: true
53
+ });
54
+ // Apply extensions based on config
55
+ const extensions = [];
56
+ // SVG code block renderer - MUST be before syntax highlighting
57
+ // so it can intercept svg blocks before Prism processes them
58
+ if (this.currentConfig.enableSvgRenderer) {
59
+ extensions.push(createSvgRendererExtension());
60
+ }
61
+ // Syntax highlighting with Prism
62
+ if (this.currentConfig.enableHighlight) {
63
+ extensions.push(markedHighlight({
64
+ langPrefix: 'language-',
65
+ highlight: (code, lang) => {
66
+ // Skip SVG blocks - they're handled by the SVG renderer
67
+ if (lang === 'svg' && this.currentConfig.enableSvgRenderer) {
68
+ return code;
69
+ }
70
+ if (lang && Prism.languages[lang]) {
71
+ try {
72
+ return Prism.highlight(code, Prism.languages[lang], lang);
73
+ }
74
+ catch (e) {
75
+ console.warn(`Prism highlighting failed for language: ${lang}`, e);
76
+ }
77
+ }
78
+ // Return code as-is if language not found or highlighting fails
79
+ return code;
80
+ }
81
+ }));
82
+ }
83
+ // GitHub-style heading IDs
84
+ if (this.currentConfig.enableHeadingIds) {
85
+ extensions.push(gfmHeadingId({
86
+ prefix: this.currentConfig.headingIdPrefix
87
+ }));
88
+ }
89
+ // GitHub-style alerts
90
+ if (this.currentConfig.enableAlerts) {
91
+ extensions.push(markedAlert());
92
+ }
93
+ // Collapsible headings (custom extension)
94
+ if (this.currentConfig.enableCollapsibleHeadings) {
95
+ extensions.push(createCollapsibleHeadingsExtension({
96
+ startLevel: this.currentConfig.collapsibleHeadingLevel,
97
+ defaultExpanded: this.currentConfig.collapsibleDefaultExpanded,
98
+ autoExpandLevels: this.currentConfig.autoExpandLevels
99
+ }));
100
+ }
101
+ // Smartypants for typography (curly quotes, em/en dashes, ellipses)
102
+ if (this.currentConfig.enableSmartypants) {
103
+ extensions.push(markedSmartypants());
104
+ }
105
+ // Apply all extensions
106
+ if (extensions.length > 0) {
107
+ this.marked.use(...extensions);
108
+ }
109
+ }
110
+ /**
111
+ * Initialize Mermaid with the current theme configuration
112
+ */
113
+ initializeMermaid() {
114
+ if (this.mermaidInitialized)
115
+ return;
116
+ mermaid.initialize({
117
+ startOnLoad: false,
118
+ theme: this.currentConfig.mermaidTheme,
119
+ securityLevel: 'loose',
120
+ fontFamily: 'inherit'
121
+ });
122
+ this.mermaidInitialized = true;
123
+ }
124
+ /**
125
+ * Parse markdown to HTML
126
+ * @param markdown The markdown string to parse
127
+ * @param config Optional config overrides for this parse operation
128
+ * @returns The rendered HTML string
129
+ */
130
+ parse(markdown, config) {
131
+ if (!markdown)
132
+ return '';
133
+ // Apply config overrides if provided
134
+ if (config) {
135
+ this.configureMarked({ ...this.currentConfig, ...config });
136
+ }
137
+ try {
138
+ const html = this.marked.parse(markdown);
139
+ // Capture heading list after parsing
140
+ if (this.currentConfig.enableHeadingIds) {
141
+ this.headingList = getHeadingList();
142
+ }
143
+ return html;
144
+ }
145
+ catch (error) {
146
+ console.error('Markdown parsing error:', error);
147
+ return `<pre class="markdown-error">${this.escapeHtml(markdown)}</pre>`;
148
+ }
149
+ }
150
+ /**
151
+ * Parse markdown asynchronously (useful for large documents)
152
+ */
153
+ async parseAsync(markdown, config) {
154
+ return this.parse(markdown, config);
155
+ }
156
+ /**
157
+ * Render Mermaid diagrams in a container element
158
+ * Call this after the HTML has been inserted into the DOM
159
+ * @param container The DOM element containing mermaid code blocks
160
+ */
161
+ async renderMermaid(container) {
162
+ if (!this.currentConfig.enableMermaid)
163
+ return false;
164
+ this.initializeMermaid();
165
+ // Find all mermaid code blocks
166
+ const mermaidBlocks = container.querySelectorAll('pre > code.language-mermaid, .mermaid');
167
+ if (mermaidBlocks.length === 0)
168
+ return false;
169
+ for (let i = 0; i < mermaidBlocks.length; i++) {
170
+ const block = mermaidBlocks[i];
171
+ const code = block.textContent || '';
172
+ if (!code.trim())
173
+ continue;
174
+ try {
175
+ // Create a unique ID for this diagram
176
+ const id = `mermaid-${Date.now()}-${i}`;
177
+ // Render the diagram
178
+ const { svg } = await mermaid.render(id, code);
179
+ // Replace the code block with the rendered SVG
180
+ const wrapper = document.createElement('div');
181
+ wrapper.className = 'mermaid-diagram';
182
+ wrapper.innerHTML = svg;
183
+ // Replace the pre element (parent of code) or the mermaid element itself
184
+ const elementToReplace = block.tagName === 'CODE' ? block.parentElement : block;
185
+ elementToReplace?.parentNode?.replaceChild(wrapper, elementToReplace);
186
+ }
187
+ catch (error) {
188
+ console.warn('Mermaid rendering failed:', error);
189
+ // Add error class to show it failed
190
+ const parent = block.tagName === 'CODE' ? block.parentElement : block;
191
+ parent?.classList.add('mermaid-error');
192
+ }
193
+ }
194
+ return true;
195
+ }
196
+ /**
197
+ * Highlight code blocks with Prism
198
+ * Call this after the HTML has been inserted into the DOM
199
+ * @param container The DOM element containing code blocks
200
+ */
201
+ highlightCode(container) {
202
+ if (!this.currentConfig.enableHighlight)
203
+ return;
204
+ // Prism.highlightAllUnder handles finding and highlighting code blocks
205
+ Prism.highlightAllUnder(container);
206
+ }
207
+ /**
208
+ * Add copy buttons to code blocks
209
+ * @param container The DOM element containing code blocks
210
+ */
211
+ addCodeCopyButtons(container) {
212
+ if (!this.currentConfig.enableCodeCopy)
213
+ return;
214
+ const codeBlocks = container.querySelectorAll('pre > code');
215
+ codeBlocks.forEach((codeBlock) => {
216
+ const pre = codeBlock.parentElement;
217
+ if (!pre || pre.querySelector('.code-copy-btn'))
218
+ return; // Already has button
219
+ // Create copy button
220
+ const button = document.createElement('button');
221
+ button.className = 'code-copy-btn';
222
+ button.innerHTML = '<i class="fas fa-copy"></i>';
223
+ button.title = 'Copy code';
224
+ button.type = 'button';
225
+ button.addEventListener('click', async () => {
226
+ const code = codeBlock.textContent || '';
227
+ try {
228
+ await navigator.clipboard.writeText(code);
229
+ button.innerHTML = '<i class="fas fa-check"></i>';
230
+ button.classList.add('copied');
231
+ setTimeout(() => {
232
+ button.innerHTML = '<i class="fas fa-copy"></i>';
233
+ button.classList.remove('copied');
234
+ }, 2000);
235
+ }
236
+ catch (err) {
237
+ console.error('Failed to copy code:', err);
238
+ button.innerHTML = '<i class="fas fa-times"></i>';
239
+ setTimeout(() => {
240
+ button.innerHTML = '<i class="fas fa-copy"></i>';
241
+ }, 2000);
242
+ }
243
+ });
244
+ // Add toolbar wrapper
245
+ const toolbar = document.createElement('div');
246
+ toolbar.className = 'code-toolbar';
247
+ toolbar.appendChild(button);
248
+ // Make pre position relative for absolute positioning of toolbar
249
+ pre.style.position = 'relative';
250
+ pre.appendChild(toolbar);
251
+ });
252
+ }
253
+ /**
254
+ * Initialize collapsible heading functionality
255
+ * This method is a no-op - the component handles event binding
256
+ * @param container The DOM element containing collapsible sections
257
+ */
258
+ initializeCollapsibleHeadings(_container) {
259
+ // Event binding is handled by the component's setupCollapsibleListeners
260
+ // This method exists for API compatibility but does nothing
261
+ }
262
+ /**
263
+ * Get the list of headings from the last parsed document
264
+ * Useful for building table of contents
265
+ */
266
+ getHeadingList() {
267
+ return this.headingList;
268
+ }
269
+ /**
270
+ * Get the current configuration
271
+ */
272
+ getConfig() {
273
+ return { ...this.currentConfig };
274
+ }
275
+ /**
276
+ * Reset configuration to defaults
277
+ */
278
+ resetConfig() {
279
+ this.configureMarked(DEFAULT_MARKDOWN_CONFIG);
280
+ }
281
+ /**
282
+ * Check if a language is supported by Prism
283
+ */
284
+ isLanguageSupported(lang) {
285
+ return !!Prism.languages[lang];
286
+ }
287
+ /**
288
+ * Get list of supported Prism languages
289
+ */
290
+ getSupportedLanguages() {
291
+ return Object.keys(Prism.languages).filter(lang => typeof Prism.languages[lang] === 'object');
292
+ }
293
+ /**
294
+ * Escape HTML entities for safe display
295
+ */
296
+ escapeHtml(text) {
297
+ const div = document.createElement('div');
298
+ div.textContent = text;
299
+ return div.innerHTML;
300
+ }
301
+ static { this.ɵfac = function MarkdownService_Factory(t) { return new (t || MarkdownService)(); }; }
302
+ static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: MarkdownService, factory: MarkdownService.ɵfac, providedIn: 'root' }); }
303
+ }
304
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MarkdownService, [{
305
+ type: Injectable,
306
+ args: [{
307
+ providedIn: 'root'
308
+ }]
309
+ }], () => [], null); })();
310
+ //# sourceMappingURL=markdown.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.service.js","sourceRoot":"","sources":["../../../src/lib/services/markdown.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport { Marked } from 'marked';\nimport { markedHighlight } from 'marked-highlight';\nimport { gfmHeadingId, getHeadingList } from 'marked-gfm-heading-id';\nimport markedAlert from 'marked-alert';\nimport { markedSmartypants } from 'marked-smartypants';\nimport Prism from 'prismjs';\nimport mermaid from 'mermaid';\nimport {\n MarkdownConfig,\n DEFAULT_MARKDOWN_CONFIG,\n HeadingInfo,\n MarkdownRenderEvent\n} from '../types/markdown.types';\nimport { createCollapsibleHeadingsExtension } from '../extensions/collapsible-headings.extension';\nimport { createSvgRendererExtension } from '../extensions/svg-renderer.extension';\n\n// Import common Prism language components\n// Additional languages can be imported by the consuming application\nimport 'prismjs/components/prism-typescript';\nimport 'prismjs/components/prism-javascript';\nimport 'prismjs/components/prism-css';\nimport 'prismjs/components/prism-scss';\nimport 'prismjs/components/prism-json';\nimport 'prismjs/components/prism-bash';\nimport 'prismjs/components/prism-sql';\nimport 'prismjs/components/prism-python';\nimport 'prismjs/components/prism-csharp';\nimport 'prismjs/components/prism-java';\nimport 'prismjs/components/prism-markup';\nimport 'prismjs/components/prism-yaml';\nimport 'prismjs/components/prism-markdown';\nimport 'prismjs/components/prism-graphql';\n\n// Type for config with optional autoExpandLevels\ntype ResolvedMarkdownConfig = Required<Omit<MarkdownConfig, 'autoExpandLevels'>> & { autoExpandLevels?: number[] };\n\n/**\n * Service for parsing and rendering markdown content.\n * Uses marked.js with various extensions for syntax highlighting,\n * diagrams, alerts, and more.\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class MarkdownService {\n private marked: Marked;\n private mermaidInitialized = false;\n private currentConfig: ResolvedMarkdownConfig = { ...DEFAULT_MARKDOWN_CONFIG };\n private headingList: HeadingInfo[] = [];\n\n constructor() {\n this.marked = new Marked();\n this.configureMarked(this.currentConfig);\n }\n\n /**\n * Configure the marked instance with the provided options\n */\n public configureMarked(config: MarkdownConfig): void {\n this.currentConfig = { ...DEFAULT_MARKDOWN_CONFIG, ...config };\n\n // Create a fresh Marked instance\n this.marked = new Marked();\n\n // Configure base options\n this.marked.setOptions({\n gfm: true,\n breaks: true\n });\n\n // Apply extensions based on config\n const extensions: any[] = [];\n\n // SVG code block renderer - MUST be before syntax highlighting\n // so it can intercept svg blocks before Prism processes them\n if (this.currentConfig.enableSvgRenderer) {\n extensions.push(createSvgRendererExtension());\n }\n\n // Syntax highlighting with Prism\n if (this.currentConfig.enableHighlight) {\n extensions.push(\n markedHighlight({\n langPrefix: 'language-',\n highlight: (code: string, lang: string) => {\n // Skip SVG blocks - they're handled by the SVG renderer\n if (lang === 'svg' && this.currentConfig.enableSvgRenderer) {\n return code;\n }\n if (lang && Prism.languages[lang]) {\n try {\n return Prism.highlight(code, Prism.languages[lang], lang);\n } catch (e) {\n console.warn(`Prism highlighting failed for language: ${lang}`, e);\n }\n }\n // Return code as-is if language not found or highlighting fails\n return code;\n }\n })\n );\n }\n\n // GitHub-style heading IDs\n if (this.currentConfig.enableHeadingIds) {\n extensions.push(\n gfmHeadingId({\n prefix: this.currentConfig.headingIdPrefix\n })\n );\n }\n\n // GitHub-style alerts\n if (this.currentConfig.enableAlerts) {\n extensions.push(markedAlert());\n }\n\n // Collapsible headings (custom extension)\n if (this.currentConfig.enableCollapsibleHeadings) {\n extensions.push(\n createCollapsibleHeadingsExtension({\n startLevel: this.currentConfig.collapsibleHeadingLevel,\n defaultExpanded: this.currentConfig.collapsibleDefaultExpanded,\n autoExpandLevels: this.currentConfig.autoExpandLevels\n })\n );\n }\n\n // Smartypants for typography (curly quotes, em/en dashes, ellipses)\n if (this.currentConfig.enableSmartypants) {\n extensions.push(markedSmartypants());\n }\n\n // Apply all extensions\n if (extensions.length > 0) {\n this.marked.use(...extensions);\n }\n }\n\n /**\n * Initialize Mermaid with the current theme configuration\n */\n private initializeMermaid(): void {\n if (this.mermaidInitialized) return;\n\n mermaid.initialize({\n startOnLoad: false,\n theme: this.currentConfig.mermaidTheme,\n securityLevel: 'loose',\n fontFamily: 'inherit'\n });\n\n this.mermaidInitialized = true;\n }\n\n /**\n * Parse markdown to HTML\n * @param markdown The markdown string to parse\n * @param config Optional config overrides for this parse operation\n * @returns The rendered HTML string\n */\n public parse(markdown: string, config?: Partial<MarkdownConfig>): string {\n if (!markdown) return '';\n\n // Apply config overrides if provided\n if (config) {\n this.configureMarked({ ...this.currentConfig, ...config });\n }\n\n try {\n const html = this.marked.parse(markdown) as string;\n\n // Capture heading list after parsing\n if (this.currentConfig.enableHeadingIds) {\n this.headingList = getHeadingList() as HeadingInfo[];\n }\n\n return html;\n } catch (error) {\n console.error('Markdown parsing error:', error);\n return `<pre class=\"markdown-error\">${this.escapeHtml(markdown)}</pre>`;\n }\n }\n\n /**\n * Parse markdown asynchronously (useful for large documents)\n */\n public async parseAsync(markdown: string, config?: Partial<MarkdownConfig>): Promise<string> {\n return this.parse(markdown, config);\n }\n\n /**\n * Render Mermaid diagrams in a container element\n * Call this after the HTML has been inserted into the DOM\n * @param container The DOM element containing mermaid code blocks\n */\n public async renderMermaid(container: HTMLElement): Promise<boolean> {\n if (!this.currentConfig.enableMermaid) return false;\n\n this.initializeMermaid();\n\n // Find all mermaid code blocks\n const mermaidBlocks = container.querySelectorAll('pre > code.language-mermaid, .mermaid');\n\n if (mermaidBlocks.length === 0) return false;\n\n for (let i = 0; i < mermaidBlocks.length; i++) {\n const block = mermaidBlocks[i];\n const code = block.textContent || '';\n\n if (!code.trim()) continue;\n\n try {\n // Create a unique ID for this diagram\n const id = `mermaid-${Date.now()}-${i}`;\n\n // Render the diagram\n const { svg } = await mermaid.render(id, code);\n\n // Replace the code block with the rendered SVG\n const wrapper = document.createElement('div');\n wrapper.className = 'mermaid-diagram';\n wrapper.innerHTML = svg;\n\n // Replace the pre element (parent of code) or the mermaid element itself\n const elementToReplace = block.tagName === 'CODE' ? block.parentElement : block;\n elementToReplace?.parentNode?.replaceChild(wrapper, elementToReplace);\n } catch (error) {\n console.warn('Mermaid rendering failed:', error);\n // Add error class to show it failed\n const parent = block.tagName === 'CODE' ? block.parentElement : block;\n parent?.classList.add('mermaid-error');\n }\n }\n\n return true;\n }\n\n /**\n * Highlight code blocks with Prism\n * Call this after the HTML has been inserted into the DOM\n * @param container The DOM element containing code blocks\n */\n public highlightCode(container: HTMLElement): void {\n if (!this.currentConfig.enableHighlight) return;\n\n // Prism.highlightAllUnder handles finding and highlighting code blocks\n Prism.highlightAllUnder(container);\n }\n\n /**\n * Add copy buttons to code blocks\n * @param container The DOM element containing code blocks\n */\n public addCodeCopyButtons(container: HTMLElement): void {\n if (!this.currentConfig.enableCodeCopy) return;\n\n const codeBlocks = container.querySelectorAll('pre > code');\n\n codeBlocks.forEach((codeBlock) => {\n const pre = codeBlock.parentElement;\n if (!pre || pre.querySelector('.code-copy-btn')) return; // Already has button\n\n // Create copy button\n const button = document.createElement('button');\n button.className = 'code-copy-btn';\n button.innerHTML = '<i class=\"fas fa-copy\"></i>';\n button.title = 'Copy code';\n button.type = 'button';\n\n button.addEventListener('click', async () => {\n const code = codeBlock.textContent || '';\n\n try {\n await navigator.clipboard.writeText(code);\n button.innerHTML = '<i class=\"fas fa-check\"></i>';\n button.classList.add('copied');\n\n setTimeout(() => {\n button.innerHTML = '<i class=\"fas fa-copy\"></i>';\n button.classList.remove('copied');\n }, 2000);\n } catch (err) {\n console.error('Failed to copy code:', err);\n button.innerHTML = '<i class=\"fas fa-times\"></i>';\n\n setTimeout(() => {\n button.innerHTML = '<i class=\"fas fa-copy\"></i>';\n }, 2000);\n }\n });\n\n // Add toolbar wrapper\n const toolbar = document.createElement('div');\n toolbar.className = 'code-toolbar';\n toolbar.appendChild(button);\n\n // Make pre position relative for absolute positioning of toolbar\n pre.style.position = 'relative';\n pre.appendChild(toolbar);\n });\n }\n\n /**\n * Initialize collapsible heading functionality\n * This method is a no-op - the component handles event binding\n * @param container The DOM element containing collapsible sections\n */\n public initializeCollapsibleHeadings(_container: HTMLElement): void {\n // Event binding is handled by the component's setupCollapsibleListeners\n // This method exists for API compatibility but does nothing\n }\n\n /**\n * Get the list of headings from the last parsed document\n * Useful for building table of contents\n */\n public getHeadingList(): HeadingInfo[] {\n return this.headingList;\n }\n\n /**\n * Get the current configuration\n */\n public getConfig(): ResolvedMarkdownConfig {\n return { ...this.currentConfig };\n }\n\n /**\n * Reset configuration to defaults\n */\n public resetConfig(): void {\n this.configureMarked(DEFAULT_MARKDOWN_CONFIG);\n }\n\n /**\n * Check if a language is supported by Prism\n */\n public isLanguageSupported(lang: string): boolean {\n return !!Prism.languages[lang];\n }\n\n /**\n * Get list of supported Prism languages\n */\n public getSupportedLanguages(): string[] {\n return Object.keys(Prism.languages).filter(\n lang => typeof Prism.languages[lang] === 'object'\n );\n }\n\n /**\n * Escape HTML entities for safe display\n */\n private escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n}\n"]}
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Configuration options for the markdown component
3
+ */
4
+ export interface MarkdownConfig {
5
+ /**
6
+ * Enable Prism.js syntax highlighting for code blocks
7
+ * @default true
8
+ */
9
+ enableHighlight?: boolean;
10
+ /**
11
+ * Enable Mermaid diagram rendering
12
+ * @default true
13
+ */
14
+ enableMermaid?: boolean;
15
+ /**
16
+ * Enable copy-to-clipboard button on code blocks
17
+ * @default true
18
+ */
19
+ enableCodeCopy?: boolean;
20
+ /**
21
+ * Enable collapsible heading sections
22
+ * @default false
23
+ */
24
+ enableCollapsibleHeadings?: boolean;
25
+ /**
26
+ * Heading level at which to start collapsing (1-6)
27
+ * Only applies when enableCollapsibleHeadings is true
28
+ * @default 2
29
+ */
30
+ collapsibleHeadingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
31
+ /**
32
+ * Whether collapsible sections should be expanded by default
33
+ * @default true
34
+ */
35
+ collapsibleDefaultExpanded?: boolean;
36
+ /**
37
+ * Specify which heading levels should start expanded.
38
+ * Array of heading levels (2-6) that should be expanded by default.
39
+ * Takes precedence over collapsibleDefaultExpanded for specified levels.
40
+ *
41
+ * Examples:
42
+ * - [2] = Only h2 expanded, h3-h6 collapsed
43
+ * - [2, 3] = h2 and h3 expanded, h4-h6 collapsed
44
+ * - [] = All collapsed (same as collapsibleDefaultExpanded: false)
45
+ * - undefined = Uses collapsibleDefaultExpanded for all levels
46
+ *
47
+ * @default undefined (uses collapsibleDefaultExpanded)
48
+ */
49
+ autoExpandLevels?: number[];
50
+ /**
51
+ * Enable GitHub-style alerts ([!NOTE], [!WARNING], etc.)
52
+ * @default true
53
+ */
54
+ enableAlerts?: boolean;
55
+ /**
56
+ * Enable smartypants for typography (curly quotes, em/en dashes, ellipses)
57
+ * Converts:
58
+ * - "quotes" to "curly quotes"
59
+ * - -- to en-dash (–)
60
+ * - --- to em-dash (—)
61
+ * - ... to ellipsis (…)
62
+ * @default true
63
+ */
64
+ enableSmartypants?: boolean;
65
+ /**
66
+ * Enable SVG code block rendering
67
+ * When enabled, ```svg code blocks are rendered as actual SVG images
68
+ * @default true
69
+ */
70
+ enableSvgRenderer?: boolean;
71
+ /**
72
+ * Enable raw HTML passthrough in markdown content.
73
+ * When enabled, HTML tags in the markdown are rendered as actual HTML
74
+ * instead of being sanitized/stripped.
75
+ *
76
+ * Note: Even with enableHtml=true, scripts and event handlers are stripped
77
+ * unless enableJavaScript is also true.
78
+ *
79
+ * @default false
80
+ */
81
+ enableHtml?: boolean;
82
+ /**
83
+ * Enable JavaScript execution in HTML content.
84
+ * When enabled, <script> tags and on* event handlers are allowed.
85
+ *
86
+ * WARNING: This is a major security risk. Only enable for fully trusted content.
87
+ * In most cases, you want enableHtml=true with enableJavaScript=false.
88
+ *
89
+ * @default false
90
+ */
91
+ enableJavaScript?: boolean;
92
+ /**
93
+ * Enable GitHub-style heading IDs for anchor links
94
+ * @default true
95
+ */
96
+ enableHeadingIds?: boolean;
97
+ /**
98
+ * Prefix for heading IDs to avoid conflicts
99
+ * @default ''
100
+ */
101
+ headingIdPrefix?: string;
102
+ /**
103
+ * Enable line numbers in code blocks
104
+ * @default false
105
+ */
106
+ enableLineNumbers?: boolean;
107
+ /**
108
+ * Custom CSS class to apply to the markdown container
109
+ */
110
+ containerClass?: string;
111
+ /**
112
+ * Prism.js theme to use (must be loaded in angular.json or via CSS import)
113
+ * Common themes: 'prism', 'prism-dark', 'prism-okaidia', 'prism-tomorrow', 'prism-coy'
114
+ */
115
+ prismTheme?: string;
116
+ /**
117
+ * Mermaid theme configuration
118
+ * @default 'default'
119
+ */
120
+ mermaidTheme?: 'default' | 'dark' | 'forest' | 'neutral' | 'base';
121
+ /**
122
+ * Whether to sanitize HTML output
123
+ * Set to false only if you trust the markdown source completely
124
+ * @default true
125
+ */
126
+ sanitize?: boolean;
127
+ }
128
+ /**
129
+ * Default configuration values
130
+ */
131
+ export declare const DEFAULT_MARKDOWN_CONFIG: Required<Omit<MarkdownConfig, 'autoExpandLevels'>> & {
132
+ autoExpandLevels?: number[];
133
+ };
134
+ /**
135
+ * Event emitted when markdown rendering is complete
136
+ */
137
+ export interface MarkdownRenderEvent {
138
+ /**
139
+ * The rendered HTML string
140
+ */
141
+ html: string;
142
+ /**
143
+ * Time taken to render in milliseconds
144
+ */
145
+ renderTime: number;
146
+ /**
147
+ * Whether mermaid diagrams were rendered
148
+ */
149
+ hasMermaid: boolean;
150
+ /**
151
+ * Whether code blocks were highlighted
152
+ */
153
+ hasCodeBlocks: boolean;
154
+ /**
155
+ * List of heading IDs generated (for TOC building)
156
+ */
157
+ headingIds: HeadingInfo[];
158
+ }
159
+ /**
160
+ * Information about a heading in the document
161
+ */
162
+ export interface HeadingInfo {
163
+ /**
164
+ * The heading ID (for anchor links)
165
+ */
166
+ id: string;
167
+ /**
168
+ * The heading text content
169
+ */
170
+ text: string;
171
+ /**
172
+ * The heading level (1-6)
173
+ */
174
+ level: number;
175
+ /**
176
+ * The raw markdown text
177
+ */
178
+ raw: string;
179
+ }
180
+ /**
181
+ * Alert types supported by marked-alert
182
+ */
183
+ export type AlertType = 'note' | 'tip' | 'important' | 'warning' | 'caution';
184
+ /**
185
+ * Configuration for a custom alert variant
186
+ */
187
+ export interface AlertVariant {
188
+ type: string;
189
+ icon: string;
190
+ titleClassName?: string;
191
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Default configuration values
3
+ */
4
+ export const DEFAULT_MARKDOWN_CONFIG = {
5
+ enableHighlight: true,
6
+ enableMermaid: true,
7
+ enableCodeCopy: true,
8
+ enableCollapsibleHeadings: false,
9
+ collapsibleHeadingLevel: 2,
10
+ collapsibleDefaultExpanded: true,
11
+ autoExpandLevels: undefined,
12
+ enableAlerts: true,
13
+ enableSmartypants: true,
14
+ enableSvgRenderer: true,
15
+ enableHtml: false,
16
+ enableJavaScript: false,
17
+ enableHeadingIds: true,
18
+ headingIdPrefix: '',
19
+ enableLineNumbers: false,
20
+ containerClass: '',
21
+ prismTheme: 'prism-okaidia',
22
+ mermaidTheme: 'default',
23
+ sanitize: true
24
+ };
25
+ //# sourceMappingURL=markdown.types.js.map