indusagi-coding-agent 0.1.22 → 0.1.24
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/CHANGELOG.md +72 -11
- package/README.md +2 -36
- package/dist/cli/args.d.ts +117 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +231 -64
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts +58 -2
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +130 -12
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/file-processor.d.ts +70 -2
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +240 -15
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/list-models.d.ts +63 -3
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +202 -27
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/login-handler.d.ts +82 -8
- package/dist/cli/login-handler.d.ts.map +1 -1
- package/dist/cli/login-handler.js +410 -77
- package/dist/cli/login-handler.js.map +1 -1
- package/dist/cli/session-picker.d.ts +74 -2
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +236 -12
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/core/agent-session.d.ts +214 -9
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +214 -9
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts +302 -12
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +302 -12
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/diagnostics.d.ts +191 -0
- package/dist/core/diagnostics.d.ts.map +1 -1
- package/dist/core/diagnostics.js +142 -0
- package/dist/core/diagnostics.js.map +1 -1
- package/dist/core/event-bus.d.ts +146 -0
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js +93 -0
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/export-html/ansi-to-html.d.ts +4 -0
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
- package/dist/core/export-html/ansi-to-html.js +4 -0
- package/dist/core/export-html/ansi-to-html.js.map +1 -1
- package/dist/core/export-html/index.d.ts +128 -0
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +128 -0
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts +4 -0
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +4 -0
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/keybindings.d.ts +142 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +142 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-registry.d.ts +98 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +98 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +99 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +99 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +0 -2
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +127 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +125 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/skills.js.map +1 -1
- package/dist/core/subagents.js.map +1 -1
- package/dist/core/tools/bash.d.ts +391 -11
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +269 -2
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts +284 -6
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +238 -0
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts +169 -5
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +136 -0
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +285 -5
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +247 -0
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +0 -18
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -23
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +6 -0
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +6 -0
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts +308 -7
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +231 -0
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/webfetch.d.ts +118 -3
- package/dist/core/tools/webfetch.d.ts.map +1 -1
- package/dist/core/tools/webfetch.js +118 -3
- package/dist/core/tools/webfetch.js.map +1 -1
- package/dist/core/tools/websearch.d.ts +130 -3
- package/dist/core/tools/websearch.d.ts.map +1 -1
- package/dist/core/tools/websearch.js +130 -3
- package/dist/core/tools/websearch.js.map +1 -1
- package/dist/core/tools/write.d.ts +251 -5
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +210 -0
- package/dist/core/tools/write.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +164 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +164 -1
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +297 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +297 -1
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +251 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +186 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +186 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1567 -13
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1567 -13
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +422 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +422 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts +538 -5
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +538 -5
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +921 -8
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +921 -8
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +802 -9
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +802 -9
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +356 -3
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js +356 -3
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/shared.d.ts +386 -0
- package/dist/modes/shared.d.ts.map +1 -0
- package/dist/modes/shared.js +543 -0
- package/dist/modes/shared.js.map +1 -0
- package/dist/utils/array.d.ts +389 -0
- package/dist/utils/array.d.ts.map +1 -0
- package/dist/utils/array.js +585 -0
- package/dist/utils/array.js.map +1 -0
- package/dist/utils/color-formatter.d.ts +318 -0
- package/dist/utils/color-formatter.d.ts.map +1 -0
- package/dist/utils/color-formatter.js +442 -0
- package/dist/utils/color-formatter.js.map +1 -0
- package/dist/utils/data-transformer.d.ts +326 -0
- package/dist/utils/data-transformer.d.ts.map +1 -0
- package/dist/utils/data-transformer.js +512 -0
- package/dist/utils/data-transformer.js.map +1 -0
- package/dist/utils/date-formatter.d.ts +281 -0
- package/dist/utils/date-formatter.d.ts.map +1 -0
- package/dist/utils/date-formatter.js +503 -0
- package/dist/utils/date-formatter.js.map +1 -0
- package/dist/utils/error-handler.d.ts +541 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +726 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/file-operations.d.ts +297 -0
- package/dist/utils/file-operations.d.ts.map +1 -0
- package/dist/utils/file-operations.js +505 -0
- package/dist/utils/file-operations.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +268 -6
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +500 -21
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/json-formatter.d.ts +259 -0
- package/dist/utils/json-formatter.d.ts.map +1 -0
- package/dist/utils/json-formatter.js +517 -0
- package/dist/utils/json-formatter.js.map +1 -0
- package/dist/utils/logger.d.ts +176 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +346 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/markdown-formatter.d.ts +211 -0
- package/dist/utils/markdown-formatter.d.ts.map +1 -0
- package/dist/utils/markdown-formatter.js +482 -0
- package/dist/utils/markdown-formatter.js.map +1 -0
- package/dist/utils/path-validator.d.ts +603 -0
- package/dist/utils/path-validator.d.ts.map +1 -0
- package/dist/utils/path-validator.js +870 -0
- package/dist/utils/path-validator.js.map +1 -0
- package/dist/utils/string-formatter.d.ts +609 -0
- package/dist/utils/string-formatter.d.ts.map +1 -0
- package/dist/utils/string-formatter.js +806 -0
- package/dist/utils/string-formatter.js.map +1 -0
- package/dist/utils/type-guards.d.ts +629 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +662 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/docs/COMPLETE-GUIDE.md +300 -0
- package/docs/MODES-ARCHITECTURE.md +565 -0
- package/docs/PRINT-MODE-GUIDE.md +456 -0
- package/docs/README.md +1 -2
- package/docs/RPC-GUIDE.md +705 -0
- package/docs/UTILS-IMPLEMENTATION-SUMMARY.md +647 -0
- package/docs/UTILS-MODULE-OVERVIEW.md +1480 -0
- package/docs/UTILS-QA-CHECKLIST.md +1061 -0
- package/docs/UTILS-USAGE-GUIDE.md +1419 -0
- package/package.json +3 -3
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Comprehensive markdown processing and conversion utilities
|
|
3
|
+
*
|
|
4
|
+
* This module provides:
|
|
5
|
+
* - Markdown to plain text conversion
|
|
6
|
+
* - Code block extraction and parsing
|
|
7
|
+
* - Link extraction and validation
|
|
8
|
+
* - Heading parsing and extraction
|
|
9
|
+
* - Markdown validation
|
|
10
|
+
* - Markdown parsing and tokenization
|
|
11
|
+
* - HTML generation from markdown
|
|
12
|
+
* - Table parsing and extraction
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* import { toPlainText, extractCodeBlocks, extractLinks, parseMarkdown } from './markdown-formatter';
|
|
16
|
+
*
|
|
17
|
+
* const md = '# Title\n\nSome **bold** text with [link](https://example.com)';
|
|
18
|
+
* const plain = toPlainText(md);
|
|
19
|
+
* const links = extractLinks(md);
|
|
20
|
+
*
|
|
21
|
+
* @author indusagi
|
|
22
|
+
* @version 1.0.0
|
|
23
|
+
*/
|
|
24
|
+
/** Code block data */
|
|
25
|
+
export interface CodeBlock {
|
|
26
|
+
/** Code block language/type */
|
|
27
|
+
language: string;
|
|
28
|
+
/** Code content */
|
|
29
|
+
code: string;
|
|
30
|
+
/** Line number where block starts */
|
|
31
|
+
startLine: number;
|
|
32
|
+
/** Line number where block ends */
|
|
33
|
+
endLine: number;
|
|
34
|
+
}
|
|
35
|
+
/** Link data */
|
|
36
|
+
export interface Link {
|
|
37
|
+
/** Link text */
|
|
38
|
+
text: string;
|
|
39
|
+
/** Link URL */
|
|
40
|
+
url: string;
|
|
41
|
+
/** Link title if present */
|
|
42
|
+
title?: string;
|
|
43
|
+
}
|
|
44
|
+
/** Heading data */
|
|
45
|
+
export interface Heading {
|
|
46
|
+
/** Heading level (1-6) */
|
|
47
|
+
level: number;
|
|
48
|
+
/** Heading text */
|
|
49
|
+
text: string;
|
|
50
|
+
/** Line number */
|
|
51
|
+
line: number;
|
|
52
|
+
/** Slug for anchor */
|
|
53
|
+
slug: string;
|
|
54
|
+
}
|
|
55
|
+
/** Markdown token */
|
|
56
|
+
export interface Token {
|
|
57
|
+
type: string;
|
|
58
|
+
content: string;
|
|
59
|
+
metadata?: Record<string, any>;
|
|
60
|
+
}
|
|
61
|
+
/** Table data */
|
|
62
|
+
export interface TableData {
|
|
63
|
+
/** Table headers */
|
|
64
|
+
headers: string[];
|
|
65
|
+
/** Table rows */
|
|
66
|
+
rows: string[][];
|
|
67
|
+
/** Column alignments */
|
|
68
|
+
align?: ('left' | 'center' | 'right')[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Convert markdown to plain text
|
|
72
|
+
* @param markdown - Markdown string
|
|
73
|
+
* @returns Plain text version
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* const md = '# Title\n\nSome **bold** text\n\n> Quote';
|
|
77
|
+
* const plain = toPlainText(md);
|
|
78
|
+
* // 'Title\n\nSome bold text\n\nQuote'
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* const md = '[Link](http://example.com) and `code`';
|
|
82
|
+
* const plain = toPlainText(md);
|
|
83
|
+
* // 'Link and code'
|
|
84
|
+
*/
|
|
85
|
+
export declare function toPlainText(markdown: string): string;
|
|
86
|
+
/**
|
|
87
|
+
* Extract all code blocks from markdown
|
|
88
|
+
* @param markdown - Markdown string
|
|
89
|
+
* @returns Array of code blocks
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* const md = '```js\nconst x = 1;\n```\n\n```python\ny = 2\n```';
|
|
93
|
+
* const blocks = extractCodeBlocks(md);
|
|
94
|
+
* // [
|
|
95
|
+
* // { language: 'js', code: 'const x = 1;', startLine: 0, endLine: 2 },
|
|
96
|
+
* // { language: 'python', code: 'y = 2', startLine: 4, endLine: 6 }
|
|
97
|
+
* // ]
|
|
98
|
+
*/
|
|
99
|
+
export declare function extractCodeBlocks(markdown: string): CodeBlock[];
|
|
100
|
+
/**
|
|
101
|
+
* Extract all links from markdown
|
|
102
|
+
* @param markdown - Markdown string
|
|
103
|
+
* @returns Array of links
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* const md = '[Google](https://google.com) and [Docs](https://docs.example.com "My Docs")';
|
|
107
|
+
* const links = extractLinks(md);
|
|
108
|
+
* // [
|
|
109
|
+
* // { text: 'Google', url: 'https://google.com' },
|
|
110
|
+
* // { text: 'Docs', url: 'https://docs.example.com', title: 'My Docs' }
|
|
111
|
+
* // ]
|
|
112
|
+
*/
|
|
113
|
+
export declare function extractLinks(markdown: string): Link[];
|
|
114
|
+
/**
|
|
115
|
+
* Extract all headings from markdown
|
|
116
|
+
* @param markdown - Markdown string
|
|
117
|
+
* @returns Array of headings
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* const md = '# Main\n## Section\n### Subsection';
|
|
121
|
+
* const headings = extractHeadings(md);
|
|
122
|
+
* // [
|
|
123
|
+
* // { level: 1, text: 'Main', line: 0, slug: 'main' },
|
|
124
|
+
* // { level: 2, text: 'Section', line: 1, slug: 'section' },
|
|
125
|
+
* // { level: 3, text: 'Subsection', line: 2, slug: 'subsection' }
|
|
126
|
+
* // ]
|
|
127
|
+
*/
|
|
128
|
+
export declare function extractHeadings(markdown: string): Heading[];
|
|
129
|
+
/**
|
|
130
|
+
* Validate markdown structure
|
|
131
|
+
* @param markdown - Markdown to validate
|
|
132
|
+
* @returns Array of validation issues
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* const md = '# Title\n\n```js\ncode\n'; // Missing closing ```
|
|
136
|
+
* const issues = validateMarkdown(md);
|
|
137
|
+
* // [{ message: 'Unclosed code block', type: 'codeBlock' }]
|
|
138
|
+
*/
|
|
139
|
+
export declare function validateMarkdown(markdown: string): Array<{
|
|
140
|
+
message: string;
|
|
141
|
+
type: string;
|
|
142
|
+
}>;
|
|
143
|
+
/**
|
|
144
|
+
* Parse markdown into tokens
|
|
145
|
+
* @param markdown - Markdown string
|
|
146
|
+
* @returns Array of tokens
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* const tokens = parseMarkdown('# Title\n\nParagraph');
|
|
150
|
+
*/
|
|
151
|
+
export declare function parseMarkdown(markdown: string): Token[];
|
|
152
|
+
/**
|
|
153
|
+
* Convert markdown to HTML
|
|
154
|
+
* @param markdown - Markdown string
|
|
155
|
+
* @returns HTML string
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* const html = toHtml('# Title\n\n**Bold** text');
|
|
159
|
+
* // '<h1>Title</h1><p><strong>Bold</strong> text</p>'
|
|
160
|
+
*/
|
|
161
|
+
export declare function toHtml(markdown: string): string;
|
|
162
|
+
/**
|
|
163
|
+
* Extract images from markdown
|
|
164
|
+
* @param markdown - Markdown string
|
|
165
|
+
* @returns Array of image objects
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* const md = ' and ';
|
|
169
|
+
* const images = extractImages(md);
|
|
170
|
+
* // [
|
|
171
|
+
* // { alt: 'Alt 1', src: 'image1.png' },
|
|
172
|
+
* // { alt: 'Alt 2', src: 'image2.jpg' }
|
|
173
|
+
* // ]
|
|
174
|
+
*/
|
|
175
|
+
export declare function extractImages(markdown: string): Array<{
|
|
176
|
+
alt: string;
|
|
177
|
+
src: string;
|
|
178
|
+
}>;
|
|
179
|
+
/**
|
|
180
|
+
* Parse markdown table
|
|
181
|
+
* @param markdown - Markdown string containing table
|
|
182
|
+
* @returns Table data
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* const md = '| Name | Age |\\n|------|-----|\\n| John | 30 |';
|
|
186
|
+
* const table = parseTable(md);
|
|
187
|
+
*/
|
|
188
|
+
export declare function parseTable(markdown: string): TableData | null;
|
|
189
|
+
/**
|
|
190
|
+
* Generate table of contents from markdown
|
|
191
|
+
* @param markdown - Markdown string
|
|
192
|
+
* @returns Markdown table of contents
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* const md = '# Main\n## Section 1\n## Section 2\n### Subsection';
|
|
196
|
+
* const toc = generateTOC(md);
|
|
197
|
+
* // '- [Main](#main)\n - [Section 1](#section-1)\n - [Section 2](#section-2)\n - [Subsection](#subsection)'
|
|
198
|
+
*/
|
|
199
|
+
export declare function generateTOC(markdown: string): string;
|
|
200
|
+
/**
|
|
201
|
+
* Add line numbers to code block
|
|
202
|
+
* @param code - Code string
|
|
203
|
+
* @returns Code with line numbers
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* const code = 'line 1\\nline 2\\nline 3';
|
|
207
|
+
* const numbered = addLineNumbers(code);
|
|
208
|
+
* // '1 | line 1\\n2 | line 2\\n3 | line 3'
|
|
209
|
+
*/
|
|
210
|
+
export declare function addLineNumbers(code: string): string;
|
|
211
|
+
//# sourceMappingURL=markdown-formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-formatter.d.ts","sourceRoot":"","sources":["../../src/utils/markdown-formatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,sBAAsB;AACtB,MAAM,WAAW,SAAS;IACxB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gBAAgB;AAChB,MAAM,WAAW,IAAI;IACnB,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,mBAAmB;AACnB,MAAM,WAAW,OAAO;IACtB,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAqB;AACrB,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,iBAAiB;AACjB,MAAM,WAAW,SAAS;IACxB,oBAAoB;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB;IACjB,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IACjB,wBAAwB;IACxB,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC,EAAE,CAAC;CACzC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA+CpD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CAkC/D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,CAerD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,CAyB3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAsC3F;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE,CAoFvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA4C/C;AAsBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAanF;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAqC7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUpD;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKnD"}
|
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Comprehensive markdown processing and conversion utilities
|
|
3
|
+
*
|
|
4
|
+
* This module provides:
|
|
5
|
+
* - Markdown to plain text conversion
|
|
6
|
+
* - Code block extraction and parsing
|
|
7
|
+
* - Link extraction and validation
|
|
8
|
+
* - Heading parsing and extraction
|
|
9
|
+
* - Markdown validation
|
|
10
|
+
* - Markdown parsing and tokenization
|
|
11
|
+
* - HTML generation from markdown
|
|
12
|
+
* - Table parsing and extraction
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* import { toPlainText, extractCodeBlocks, extractLinks, parseMarkdown } from './markdown-formatter';
|
|
16
|
+
*
|
|
17
|
+
* const md = '# Title\n\nSome **bold** text with [link](https://example.com)';
|
|
18
|
+
* const plain = toPlainText(md);
|
|
19
|
+
* const links = extractLinks(md);
|
|
20
|
+
*
|
|
21
|
+
* @author indusagi
|
|
22
|
+
* @version 1.0.0
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Convert markdown to plain text
|
|
26
|
+
* @param markdown - Markdown string
|
|
27
|
+
* @returns Plain text version
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* const md = '# Title\n\nSome **bold** text\n\n> Quote';
|
|
31
|
+
* const plain = toPlainText(md);
|
|
32
|
+
* // 'Title\n\nSome bold text\n\nQuote'
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const md = '[Link](http://example.com) and `code`';
|
|
36
|
+
* const plain = toPlainText(md);
|
|
37
|
+
* // 'Link and code'
|
|
38
|
+
*/
|
|
39
|
+
export function toPlainText(markdown) {
|
|
40
|
+
let text = markdown;
|
|
41
|
+
// Remove headings but keep text
|
|
42
|
+
text = text.replace(/^#+\s+/gm, '');
|
|
43
|
+
// Remove bold
|
|
44
|
+
text = text.replace(/\*\*(.+?)\*\*/g, '$1');
|
|
45
|
+
text = text.replace(/__(.+?)__/g, '$1');
|
|
46
|
+
// Remove italic
|
|
47
|
+
text = text.replace(/\*(.+?)\*/g, '$1');
|
|
48
|
+
text = text.replace(/_(.+?)_/g, '$1');
|
|
49
|
+
// Remove strikethrough
|
|
50
|
+
text = text.replace(/~~(.+?)~~/g, '$1');
|
|
51
|
+
// Remove inline code
|
|
52
|
+
text = text.replace(/`([^`]+)`/g, '$1');
|
|
53
|
+
// Remove code blocks
|
|
54
|
+
text = text.replace(/```[\s\S]*?```/g, '');
|
|
55
|
+
// Remove links but keep text
|
|
56
|
+
text = text.replace(/\[([^\]]+)\]\([^\)]+\)/g, '$1');
|
|
57
|
+
// Remove images
|
|
58
|
+
text = text.replace(/!\[([^\]]*)\]\([^\)]+\)/g, '');
|
|
59
|
+
// Remove block quotes
|
|
60
|
+
text = text.replace(/^>\s+/gm, '');
|
|
61
|
+
// Remove lists
|
|
62
|
+
text = text.replace(/^[\s]*[-*+]\s+/gm, '');
|
|
63
|
+
text = text.replace(/^\d+\.\s+/gm, '');
|
|
64
|
+
// Remove HTML tags
|
|
65
|
+
text = text.replace(/<[^>]+>/g, '');
|
|
66
|
+
// Remove horizontal rules
|
|
67
|
+
text = text.replace(/^([-*_])\1{2,}$/gm, '');
|
|
68
|
+
// Clean up extra whitespace
|
|
69
|
+
text = text.replace(/\n\n\n+/g, '\n\n');
|
|
70
|
+
text = text.trim();
|
|
71
|
+
return text;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Extract all code blocks from markdown
|
|
75
|
+
* @param markdown - Markdown string
|
|
76
|
+
* @returns Array of code blocks
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* const md = '```js\nconst x = 1;\n```\n\n```python\ny = 2\n```';
|
|
80
|
+
* const blocks = extractCodeBlocks(md);
|
|
81
|
+
* // [
|
|
82
|
+
* // { language: 'js', code: 'const x = 1;', startLine: 0, endLine: 2 },
|
|
83
|
+
* // { language: 'python', code: 'y = 2', startLine: 4, endLine: 6 }
|
|
84
|
+
* // ]
|
|
85
|
+
*/
|
|
86
|
+
export function extractCodeBlocks(markdown) {
|
|
87
|
+
const blocks = [];
|
|
88
|
+
const lines = markdown.split('\n');
|
|
89
|
+
let inCodeBlock = false;
|
|
90
|
+
let language = '';
|
|
91
|
+
let code = [];
|
|
92
|
+
let startLine = 0;
|
|
93
|
+
for (let i = 0; i < lines.length; i++) {
|
|
94
|
+
const line = lines[i];
|
|
95
|
+
if (line.startsWith('```')) {
|
|
96
|
+
if (!inCodeBlock) {
|
|
97
|
+
// Start of code block
|
|
98
|
+
inCodeBlock = true;
|
|
99
|
+
language = line.slice(3).trim();
|
|
100
|
+
startLine = i;
|
|
101
|
+
code = [];
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// End of code block
|
|
105
|
+
inCodeBlock = false;
|
|
106
|
+
blocks.push({
|
|
107
|
+
language,
|
|
108
|
+
code: code.join('\n'),
|
|
109
|
+
startLine,
|
|
110
|
+
endLine: i,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else if (inCodeBlock) {
|
|
115
|
+
code.push(line);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return blocks;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Extract all links from markdown
|
|
122
|
+
* @param markdown - Markdown string
|
|
123
|
+
* @returns Array of links
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* const md = '[Google](https://google.com) and [Docs](https://docs.example.com "My Docs")';
|
|
127
|
+
* const links = extractLinks(md);
|
|
128
|
+
* // [
|
|
129
|
+
* // { text: 'Google', url: 'https://google.com' },
|
|
130
|
+
* // { text: 'Docs', url: 'https://docs.example.com', title: 'My Docs' }
|
|
131
|
+
* // ]
|
|
132
|
+
*/
|
|
133
|
+
export function extractLinks(markdown) {
|
|
134
|
+
const links = [];
|
|
135
|
+
// Match [text](url "title") or [text](url)
|
|
136
|
+
const pattern = /\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/g;
|
|
137
|
+
let match;
|
|
138
|
+
while ((match = pattern.exec(markdown)) !== null) {
|
|
139
|
+
links.push({
|
|
140
|
+
text: match[1],
|
|
141
|
+
url: match[2],
|
|
142
|
+
title: match[3],
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return links;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Extract all headings from markdown
|
|
149
|
+
* @param markdown - Markdown string
|
|
150
|
+
* @returns Array of headings
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* const md = '# Main\n## Section\n### Subsection';
|
|
154
|
+
* const headings = extractHeadings(md);
|
|
155
|
+
* // [
|
|
156
|
+
* // { level: 1, text: 'Main', line: 0, slug: 'main' },
|
|
157
|
+
* // { level: 2, text: 'Section', line: 1, slug: 'section' },
|
|
158
|
+
* // { level: 3, text: 'Subsection', line: 2, slug: 'subsection' }
|
|
159
|
+
* // ]
|
|
160
|
+
*/
|
|
161
|
+
export function extractHeadings(markdown) {
|
|
162
|
+
const headings = [];
|
|
163
|
+
const lines = markdown.split('\n');
|
|
164
|
+
lines.forEach((line, index) => {
|
|
165
|
+
const match = line.match(/^(#+)\s+(.+)$/);
|
|
166
|
+
if (match) {
|
|
167
|
+
const level = match[1].length;
|
|
168
|
+
const text = match[2];
|
|
169
|
+
const slug = text
|
|
170
|
+
.toLowerCase()
|
|
171
|
+
.replace(/[^\w\s-]/g, '')
|
|
172
|
+
.replace(/\s+/g, '-')
|
|
173
|
+
.replace(/-+/g, '-');
|
|
174
|
+
headings.push({
|
|
175
|
+
level,
|
|
176
|
+
text,
|
|
177
|
+
line: index,
|
|
178
|
+
slug,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
return headings;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Validate markdown structure
|
|
186
|
+
* @param markdown - Markdown to validate
|
|
187
|
+
* @returns Array of validation issues
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* const md = '# Title\n\n```js\ncode\n'; // Missing closing ```
|
|
191
|
+
* const issues = validateMarkdown(md);
|
|
192
|
+
* // [{ message: 'Unclosed code block', type: 'codeBlock' }]
|
|
193
|
+
*/
|
|
194
|
+
export function validateMarkdown(markdown) {
|
|
195
|
+
const issues = [];
|
|
196
|
+
// Check for unclosed code blocks
|
|
197
|
+
const codeBlockCount = (markdown.match(/```/g) || []).length;
|
|
198
|
+
if (codeBlockCount % 2 !== 0) {
|
|
199
|
+
issues.push({
|
|
200
|
+
message: 'Unclosed code block',
|
|
201
|
+
type: 'codeBlock',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
// Check for mismatched brackets
|
|
205
|
+
let brackets = 0;
|
|
206
|
+
for (const char of markdown) {
|
|
207
|
+
if (char === '[')
|
|
208
|
+
brackets++;
|
|
209
|
+
if (char === ']')
|
|
210
|
+
brackets--;
|
|
211
|
+
}
|
|
212
|
+
if (brackets !== 0) {
|
|
213
|
+
issues.push({
|
|
214
|
+
message: 'Mismatched square brackets',
|
|
215
|
+
type: 'brackets',
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
// Check for invalid links
|
|
219
|
+
const linkPattern = /\[([^\]]*)\]\(([^)]*)\)/g;
|
|
220
|
+
let match;
|
|
221
|
+
while ((match = linkPattern.exec(markdown)) !== null) {
|
|
222
|
+
if (!match[1] || !match[2]) {
|
|
223
|
+
issues.push({
|
|
224
|
+
message: `Invalid link: [${match[1]}](${match[2]})`,
|
|
225
|
+
type: 'link',
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return issues;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Parse markdown into tokens
|
|
233
|
+
* @param markdown - Markdown string
|
|
234
|
+
* @returns Array of tokens
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* const tokens = parseMarkdown('# Title\n\nParagraph');
|
|
238
|
+
*/
|
|
239
|
+
export function parseMarkdown(markdown) {
|
|
240
|
+
const tokens = [];
|
|
241
|
+
const lines = markdown.split('\n');
|
|
242
|
+
let i = 0;
|
|
243
|
+
while (i < lines.length) {
|
|
244
|
+
const line = lines[i];
|
|
245
|
+
// Heading
|
|
246
|
+
if (line.match(/^#+\s+/)) {
|
|
247
|
+
const match = line.match(/^(#+)\s+(.+)$/);
|
|
248
|
+
if (match) {
|
|
249
|
+
tokens.push({
|
|
250
|
+
type: 'heading',
|
|
251
|
+
content: match[2],
|
|
252
|
+
metadata: { level: match[1].length },
|
|
253
|
+
});
|
|
254
|
+
i++;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// Code block
|
|
259
|
+
if (line.startsWith('```')) {
|
|
260
|
+
const language = line.slice(3).trim();
|
|
261
|
+
const code = [];
|
|
262
|
+
i++;
|
|
263
|
+
while (i < lines.length && !lines[i].startsWith('```')) {
|
|
264
|
+
code.push(lines[i]);
|
|
265
|
+
i++;
|
|
266
|
+
}
|
|
267
|
+
tokens.push({
|
|
268
|
+
type: 'codeBlock',
|
|
269
|
+
content: code.join('\n'),
|
|
270
|
+
metadata: { language },
|
|
271
|
+
});
|
|
272
|
+
i++;
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
// Block quote
|
|
276
|
+
if (line.startsWith('>')) {
|
|
277
|
+
tokens.push({
|
|
278
|
+
type: 'blockquote',
|
|
279
|
+
content: line.slice(1).trim(),
|
|
280
|
+
});
|
|
281
|
+
i++;
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
// List item
|
|
285
|
+
if (line.match(/^[\s]*[-*+]\s+/) || line.match(/^\d+\.\s+/)) {
|
|
286
|
+
tokens.push({
|
|
287
|
+
type: 'listItem',
|
|
288
|
+
content: line.replace(/^[\s]*[-*+]\s+|^\d+\.\s+/, ''),
|
|
289
|
+
});
|
|
290
|
+
i++;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
// Paragraph
|
|
294
|
+
if (line.trim()) {
|
|
295
|
+
tokens.push({
|
|
296
|
+
type: 'paragraph',
|
|
297
|
+
content: line,
|
|
298
|
+
});
|
|
299
|
+
i++;
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
// Empty line
|
|
303
|
+
if (!line.trim()) {
|
|
304
|
+
tokens.push({
|
|
305
|
+
type: 'blank',
|
|
306
|
+
content: '',
|
|
307
|
+
});
|
|
308
|
+
i++;
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
i++;
|
|
312
|
+
}
|
|
313
|
+
return tokens;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Convert markdown to HTML
|
|
317
|
+
* @param markdown - Markdown string
|
|
318
|
+
* @returns HTML string
|
|
319
|
+
*
|
|
320
|
+
* @example
|
|
321
|
+
* const html = toHtml('# Title\n\n**Bold** text');
|
|
322
|
+
* // '<h1>Title</h1><p><strong>Bold</strong> text</p>'
|
|
323
|
+
*/
|
|
324
|
+
export function toHtml(markdown) {
|
|
325
|
+
let html = markdown;
|
|
326
|
+
// Headings
|
|
327
|
+
html = html.replace(/^######\s+(.+)$/gm, '<h6>$1</h6>');
|
|
328
|
+
html = html.replace(/^#####\s+(.+)$/gm, '<h5>$1</h5>');
|
|
329
|
+
html = html.replace(/^####\s+(.+)$/gm, '<h4>$1</h4>');
|
|
330
|
+
html = html.replace(/^###\s+(.+)$/gm, '<h3>$1</h3>');
|
|
331
|
+
html = html.replace(/^##\s+(.+)$/gm, '<h2>$1</h2>');
|
|
332
|
+
html = html.replace(/^#\s+(.+)$/gm, '<h1>$1</h1>');
|
|
333
|
+
// Code blocks
|
|
334
|
+
html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
|
|
335
|
+
return `<pre><code class="language-${lang || 'text'}">${escapeHtml(code.trim())}</code></pre>`;
|
|
336
|
+
});
|
|
337
|
+
// Bold
|
|
338
|
+
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
|
339
|
+
html = html.replace(/__(.+?)__/g, '<strong>$1</strong>');
|
|
340
|
+
// Italic
|
|
341
|
+
html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
|
|
342
|
+
html = html.replace(/_(.+?)_/g, '<em>$1</em>');
|
|
343
|
+
// Strikethrough
|
|
344
|
+
html = html.replace(/~~(.+?)~~/g, '<del>$1</del>');
|
|
345
|
+
// Inline code
|
|
346
|
+
html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
347
|
+
// Links
|
|
348
|
+
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
|
|
349
|
+
// Images
|
|
350
|
+
html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1">');
|
|
351
|
+
// Block quotes
|
|
352
|
+
html = html.replace(/^>\s+(.+)$/gm, '<blockquote>$1</blockquote>');
|
|
353
|
+
// Paragraphs
|
|
354
|
+
html = html.replace(/\n\n/g, '</p><p>');
|
|
355
|
+
html = `<p>${html}</p>`;
|
|
356
|
+
return html;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Escape HTML special characters
|
|
360
|
+
* @param text - Text to escape
|
|
361
|
+
* @returns Escaped text
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* escapeHtml('<script>alert("xss")</script>');
|
|
365
|
+
* // '<script>alert("xss")</script>'
|
|
366
|
+
*/
|
|
367
|
+
function escapeHtml(text) {
|
|
368
|
+
const map = {
|
|
369
|
+
'&': '&',
|
|
370
|
+
'<': '<',
|
|
371
|
+
'>': '>',
|
|
372
|
+
'"': '"',
|
|
373
|
+
"'": ''',
|
|
374
|
+
};
|
|
375
|
+
return text.replace(/[&<>"']/g, (char) => map[char]);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Extract images from markdown
|
|
379
|
+
* @param markdown - Markdown string
|
|
380
|
+
* @returns Array of image objects
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* const md = ' and ';
|
|
384
|
+
* const images = extractImages(md);
|
|
385
|
+
* // [
|
|
386
|
+
* // { alt: 'Alt 1', src: 'image1.png' },
|
|
387
|
+
* // { alt: 'Alt 2', src: 'image2.jpg' }
|
|
388
|
+
* // ]
|
|
389
|
+
*/
|
|
390
|
+
export function extractImages(markdown) {
|
|
391
|
+
const images = [];
|
|
392
|
+
const pattern = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
393
|
+
let match;
|
|
394
|
+
while ((match = pattern.exec(markdown)) !== null) {
|
|
395
|
+
images.push({
|
|
396
|
+
alt: match[1],
|
|
397
|
+
src: match[2],
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
return images;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Parse markdown table
|
|
404
|
+
* @param markdown - Markdown string containing table
|
|
405
|
+
* @returns Table data
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* const md = '| Name | Age |\\n|------|-----|\\n| John | 30 |';
|
|
409
|
+
* const table = parseTable(md);
|
|
410
|
+
*/
|
|
411
|
+
export function parseTable(markdown) {
|
|
412
|
+
const lines = markdown.split('\n').filter((line) => line.includes('|'));
|
|
413
|
+
if (lines.length < 2)
|
|
414
|
+
return null;
|
|
415
|
+
// Parse header
|
|
416
|
+
const headerLine = lines[0];
|
|
417
|
+
const headers = headerLine
|
|
418
|
+
.split('|')
|
|
419
|
+
.map((h) => h.trim())
|
|
420
|
+
.filter(Boolean);
|
|
421
|
+
// Parse alignment if present
|
|
422
|
+
let align;
|
|
423
|
+
if (lines.length > 1 && lines[1].includes('-')) {
|
|
424
|
+
const alignLine = lines[1];
|
|
425
|
+
align = alignLine
|
|
426
|
+
.split('|')
|
|
427
|
+
.map((a) => {
|
|
428
|
+
const trimmed = a.trim();
|
|
429
|
+
if (trimmed.startsWith(':') && trimmed.endsWith(':'))
|
|
430
|
+
return 'center';
|
|
431
|
+
if (trimmed.endsWith(':'))
|
|
432
|
+
return 'right';
|
|
433
|
+
if (trimmed.startsWith(':'))
|
|
434
|
+
return 'left';
|
|
435
|
+
return 'left';
|
|
436
|
+
})
|
|
437
|
+
.filter(Boolean);
|
|
438
|
+
}
|
|
439
|
+
// Parse rows
|
|
440
|
+
const startRow = lines.length > 1 && lines[1].includes('-') ? 2 : 1;
|
|
441
|
+
const rows = lines.slice(startRow).map((line) => line
|
|
442
|
+
.split('|')
|
|
443
|
+
.map((cell) => cell.trim())
|
|
444
|
+
.filter(Boolean));
|
|
445
|
+
return { headers, rows, align };
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Generate table of contents from markdown
|
|
449
|
+
* @param markdown - Markdown string
|
|
450
|
+
* @returns Markdown table of contents
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* const md = '# Main\n## Section 1\n## Section 2\n### Subsection';
|
|
454
|
+
* const toc = generateTOC(md);
|
|
455
|
+
* // '- [Main](#main)\n - [Section 1](#section-1)\n - [Section 2](#section-2)\n - [Subsection](#subsection)'
|
|
456
|
+
*/
|
|
457
|
+
export function generateTOC(markdown) {
|
|
458
|
+
const headings = extractHeadings(markdown);
|
|
459
|
+
const lines = [];
|
|
460
|
+
for (const heading of headings) {
|
|
461
|
+
const indent = ' '.repeat(heading.level - 1);
|
|
462
|
+
lines.push(`${indent}- [${heading.text}](#${heading.slug})`);
|
|
463
|
+
}
|
|
464
|
+
return lines.join('\n');
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Add line numbers to code block
|
|
468
|
+
* @param code - Code string
|
|
469
|
+
* @returns Code with line numbers
|
|
470
|
+
*
|
|
471
|
+
* @example
|
|
472
|
+
* const code = 'line 1\\nline 2\\nline 3';
|
|
473
|
+
* const numbered = addLineNumbers(code);
|
|
474
|
+
* // '1 | line 1\\n2 | line 2\\n3 | line 3'
|
|
475
|
+
*/
|
|
476
|
+
export function addLineNumbers(code) {
|
|
477
|
+
return code
|
|
478
|
+
.split('\n')
|
|
479
|
+
.map((line, index) => `${index + 1} | ${line}`)
|
|
480
|
+
.join('\n');
|
|
481
|
+
}
|
|
482
|
+
//# sourceMappingURL=markdown-formatter.js.map
|