@bernierllc/markdown-parser 1.0.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.
Files changed (61) hide show
  1. package/.eslintrc.js +27 -0
  2. package/README.md +325 -0
  3. package/__tests__/MarkdownParser.test.ts +787 -0
  4. package/__tests__/ast-utils.test.ts +319 -0
  5. package/__tests__/cache.test.ts +243 -0
  6. package/__tests__/plugins.test.ts +282 -0
  7. package/coverage/clover.xml +283 -0
  8. package/coverage/coverage-final.json +7 -0
  9. package/coverage/lcov-report/base.css +224 -0
  10. package/coverage/lcov-report/block-navigation.js +87 -0
  11. package/coverage/lcov-report/favicon.png +0 -0
  12. package/coverage/lcov-report/index.html +146 -0
  13. package/coverage/lcov-report/prettify.css +1 -0
  14. package/coverage/lcov-report/prettify.js +2 -0
  15. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  16. package/coverage/lcov-report/sorter.js +210 -0
  17. package/coverage/lcov-report/src/MarkdownParser.ts.html +1636 -0
  18. package/coverage/lcov-report/src/index.html +116 -0
  19. package/coverage/lcov-report/src/plugins/commonmark.ts.html +154 -0
  20. package/coverage/lcov-report/src/plugins/gfm.ts.html +154 -0
  21. package/coverage/lcov-report/src/plugins/index.html +146 -0
  22. package/coverage/lcov-report/src/plugins/index.ts.html +115 -0
  23. package/coverage/lcov-report/src/utils/ast-utils.ts.html +328 -0
  24. package/coverage/lcov-report/src/utils/cache.ts.html +403 -0
  25. package/coverage/lcov-report/src/utils/index.html +131 -0
  26. package/coverage/lcov.info +457 -0
  27. package/dist/MarkdownParser.d.ts +46 -0
  28. package/dist/MarkdownParser.d.ts.map +1 -0
  29. package/dist/MarkdownParser.js +458 -0
  30. package/dist/index.d.ts +6 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +31 -0
  33. package/dist/plugins/commonmark.d.ts +6 -0
  34. package/dist/plugins/commonmark.d.ts.map +1 -0
  35. package/dist/plugins/commonmark.js +23 -0
  36. package/dist/plugins/gfm.d.ts +6 -0
  37. package/dist/plugins/gfm.d.ts.map +1 -0
  38. package/dist/plugins/gfm.js +23 -0
  39. package/dist/plugins/index.d.ts +3 -0
  40. package/dist/plugins/index.d.ts.map +1 -0
  41. package/dist/plugins/index.js +25 -0
  42. package/dist/types.d.ts +78 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +9 -0
  45. package/dist/utils/ast-utils.d.ts +22 -0
  46. package/dist/utils/ast-utils.d.ts.map +1 -0
  47. package/dist/utils/ast-utils.js +81 -0
  48. package/dist/utils/cache.d.ts +39 -0
  49. package/dist/utils/cache.d.ts.map +1 -0
  50. package/dist/utils/cache.js +91 -0
  51. package/jest.config.cjs +28 -0
  52. package/package.json +44 -0
  53. package/src/MarkdownParser.ts +517 -0
  54. package/src/index.ts +13 -0
  55. package/src/plugins/commonmark.ts +23 -0
  56. package/src/plugins/gfm.ts +23 -0
  57. package/src/plugins/index.ts +10 -0
  58. package/src/types.ts +114 -0
  59. package/src/utils/ast-utils.ts +81 -0
  60. package/src/utils/cache.ts +106 -0
  61. package/tsconfig.json +30 -0
package/.eslintrc.js ADDED
@@ -0,0 +1,27 @@
1
+ /*
2
+ Copyright (c) 2025 Bernier LLC
3
+
4
+ This file is licensed to the client under a limited-use license.
5
+ The client may use and modify this code *only within the scope of the project it was delivered for*.
6
+ Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
7
+ */
8
+
9
+ module.exports = {
10
+ parser: '@typescript-eslint/parser',
11
+ parserOptions: {
12
+ ecmaVersion: 2020,
13
+ sourceType: 'module',
14
+ },
15
+ extends: [
16
+ 'eslint:recommended',
17
+ 'plugin:@typescript-eslint/recommended',
18
+ ],
19
+ rules: {
20
+ '@typescript-eslint/no-explicit-any': 'error',
21
+ '@typescript-eslint/explicit-function-return-type': 'error',
22
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
23
+ '@typescript-eslint/no-unnecessary-type-assertion': 'off',
24
+ 'no-regex-spaces': 'off',
25
+ 'no-useless-escape': 'off',
26
+ },
27
+ };
package/README.md ADDED
@@ -0,0 +1,325 @@
1
+ # @bernierllc/markdown-parser
2
+
3
+ High-performance markdown parser with CommonMark, GitHub-Flavored Markdown (GFM), and plugin support. Converts markdown text to Abstract Syntax Tree (AST) format for further processing.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @bernierllc/markdown-parser
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **CommonMark Support** - Full CommonMark v0.31.2 specification compliance
14
+ - **GitHub-Flavored Markdown** - Task lists, tables, strikethrough, autolinks
15
+ - **Plugin System** - Extend parser with custom transformations
16
+ - **Caching** - Optional in-memory caching with TTL and size limits
17
+ - **Performance** - Fast parsing with position tracking
18
+ - **TypeScript** - Strict typing with comprehensive type definitions
19
+ - **Zero Dependencies** - Only uses @bernierllc packages
20
+
21
+ ## Usage
22
+
23
+ ### Basic Parsing
24
+
25
+ ```typescript
26
+ import { MarkdownParser } from '@bernierllc/markdown-parser';
27
+
28
+ const parser = new MarkdownParser();
29
+
30
+ const result = await parser.parse('# Hello World\n\nThis is **bold** text.');
31
+
32
+ if (result.success) {
33
+ console.log('Parsed AST:', result.ast);
34
+ console.log('Node count:', result.metadata.nodeCount);
35
+ console.log('Parse time:', result.metadata.parseTime, 'ms');
36
+ }
37
+ ```
38
+
39
+ ### With Caching
40
+
41
+ ```typescript
42
+ const parser = new MarkdownParser({
43
+ cache: {
44
+ enabled: true,
45
+ maxSize: 1000, // Maximum 1000 cached documents
46
+ ttl: 3600, // Cache for 1 hour
47
+ },
48
+ });
49
+
50
+ // First parse - not cached
51
+ const result1 = await parser.parse('# Document');
52
+ console.log('Cached:', result1.metadata.cached); // false
53
+
54
+ // Second parse - cached
55
+ const result2 = await parser.parse('# Document');
56
+ console.log('Cached:', result2.metadata.cached); // true
57
+ console.log('Faster:', result2.metadata.parseTime < result1.metadata.parseTime); // true
58
+ ```
59
+
60
+ ### With Custom Plugins
61
+
62
+ ```typescript
63
+ import { MarkdownParser, MarkdownPlugin, transformNodes } from '@bernierllc/markdown-parser';
64
+
65
+ // Create a plugin that converts all text to uppercase
66
+ const uppercasePlugin: MarkdownPlugin = {
67
+ name: 'uppercase',
68
+ version: '1.0.0',
69
+ transform: (ast) => {
70
+ return transformNodes(ast, (node) => {
71
+ if (node.type === 'text' && node.value) {
72
+ return { ...node, value: node.value.toUpperCase() };
73
+ }
74
+ return node;
75
+ });
76
+ },
77
+ };
78
+
79
+ const parser = new MarkdownParser({
80
+ plugins: [uppercasePlugin],
81
+ });
82
+
83
+ const result = await parser.parse('# hello world');
84
+ // Result: heading with text "HELLO WORLD"
85
+ ```
86
+
87
+ ### GFM Features
88
+
89
+ ```typescript
90
+ const parser = new MarkdownParser({ gfm: true });
91
+
92
+ // Task lists
93
+ const tasks = await parser.parse(`
94
+ - [ ] Unchecked task
95
+ - [x] Checked task
96
+ `);
97
+
98
+ // Tables
99
+ const table = await parser.parse(`
100
+ | Header 1 | Header 2 |
101
+ | -------- | -------- |
102
+ | Cell 1 | Cell 2 |
103
+ `);
104
+
105
+ // Strikethrough
106
+ const strikethrough = await parser.parse('This is ~~deleted~~ text');
107
+
108
+ // Autolinks
109
+ const autolink = await parser.parse('Visit https://example.com for more');
110
+ ```
111
+
112
+ ### With Logger
113
+
114
+ ```typescript
115
+ import { Logger } from '@bernierllc/logger';
116
+
117
+ const logger = new Logger({ level: 'debug' });
118
+
119
+ const parser = new MarkdownParser({ logger });
120
+
121
+ await parser.parse('# Test');
122
+ // Logs: "Markdown parsed successfully" with metadata
123
+ ```
124
+
125
+ ## API Reference
126
+
127
+ ### `MarkdownParser`
128
+
129
+ Main parser class for converting markdown to AST.
130
+
131
+ #### Constructor
132
+
133
+ ```typescript
134
+ new MarkdownParser(config?: MarkdownParserConfig)
135
+ ```
136
+
137
+ **Config Options:**
138
+ - `gfm?: boolean` - Enable GitHub-Flavored Markdown (default: `true`)
139
+ - `commonmark?: boolean` - Enable CommonMark strict mode (default: `true`)
140
+ - `plugins?: MarkdownPlugin[]` - Custom plugins to apply (default: `[]`)
141
+ - `cache?: CacheConfig` - Caching configuration
142
+ - `enabled: boolean` - Enable caching
143
+ - `maxSize?: number` - Maximum cache entries (default: `1000`)
144
+ - `ttl?: number` - Time to live in seconds (default: `3600`)
145
+ - `logger?: Logger` - Logger instance for debug output
146
+
147
+ #### Methods
148
+
149
+ ##### `parse(markdown: string): Promise<ParseResult>`
150
+
151
+ Parse markdown string to AST.
152
+
153
+ **Returns:**
154
+ ```typescript
155
+ {
156
+ success: boolean;
157
+ ast?: ASTNode;
158
+ error?: string;
159
+ metadata?: {
160
+ parseTime: number; // Milliseconds
161
+ nodeCount: number; // Total nodes in AST
162
+ cached: boolean; // Whether result was cached
163
+ };
164
+ }
165
+ ```
166
+
167
+ ##### `clearCache(): void`
168
+
169
+ Clear all cached parse results.
170
+
171
+ ##### `getCacheStats(): { size: number; enabled: boolean }`
172
+
173
+ Get current cache statistics.
174
+
175
+ ##### `pruneCache(): number`
176
+
177
+ Remove expired cache entries. Returns number of entries removed.
178
+
179
+ ### AST Node Types
180
+
181
+ The parser generates nodes with the following structure:
182
+
183
+ ```typescript
184
+ interface ASTNode {
185
+ type: NodeType;
186
+ value?: string;
187
+ children?: ASTNode[];
188
+ attributes?: Record<string, unknown>;
189
+ position?: Position;
190
+ }
191
+ ```
192
+
193
+ **Supported Node Types:**
194
+ - Block: `root`, `heading`, `paragraph`, `blockquote`, `list`, `listItem`, `codeBlock`, `table`, `tableRow`, `tableCell`, `horizontalRule`
195
+ - Inline: `text`, `emphasis`, `strong`, `code`, `link`, `image`, `lineBreak`
196
+ - GFM: `strikethrough`, `taskList`, `taskListItem`, `autolink`
197
+
198
+ ### Plugin Interface
199
+
200
+ ```typescript
201
+ interface MarkdownPlugin {
202
+ name: string;
203
+ version: string;
204
+ transform: (ast: ASTNode) => ASTNode;
205
+ }
206
+ ```
207
+
208
+ ### Utility Functions
209
+
210
+ #### `countNodes(node: ASTNode): number`
211
+
212
+ Count total nodes in AST tree.
213
+
214
+ #### `visitNodes(node: ASTNode, visitor: (node: ASTNode) => void): void`
215
+
216
+ Visit each node in AST tree with callback.
217
+
218
+ #### `transformNodes(node: ASTNode, transformer: (node: ASTNode) => ASTNode): ASTNode`
219
+
220
+ Transform AST nodes recursively.
221
+
222
+ #### `findNodes(node: ASTNode, predicate: (node: ASTNode) => boolean): ASTNode[]`
223
+
224
+ Find all nodes matching predicate.
225
+
226
+ #### `cloneNode(node: ASTNode): ASTNode`
227
+
228
+ Create deep copy of AST node.
229
+
230
+ ## Examples
231
+
232
+ ### Example 1: Parsing Headers
233
+
234
+ ```typescript
235
+ const parser = new MarkdownParser();
236
+ const result = await parser.parse(`
237
+ # Heading 1
238
+ ## Heading 2
239
+ ### Heading 3
240
+ `);
241
+
242
+ // Find all headings
243
+ const headings = findNodes(result.ast!, (node) => node.type === 'heading');
244
+ console.log('Found', headings.length, 'headings');
245
+ ```
246
+
247
+ ### Example 2: Extract All Links
248
+
249
+ ```typescript
250
+ const parser = new MarkdownParser();
251
+ const result = await parser.parse('Check [Google](https://google.com) and [GitHub](https://github.com)');
252
+
253
+ const links = findNodes(result.ast!, (node) => node.type === 'link');
254
+ links.forEach((link) => {
255
+ console.log('Link:', link.attributes.href);
256
+ });
257
+ ```
258
+
259
+ ### Example 3: Count Code Blocks
260
+
261
+ ```typescript
262
+ const parser = new MarkdownParser();
263
+ const result = await parser.parse(`
264
+ \`\`\`javascript
265
+ const x = 1;
266
+ \`\`\`
267
+
268
+ \`\`\`python
269
+ print("hello")
270
+ \`\`\`
271
+ `);
272
+
273
+ const codeBlocks = findNodes(result.ast!, (node) => node.type === 'codeBlock');
274
+ console.log('Found', codeBlocks.length, 'code blocks');
275
+ ```
276
+
277
+ ### Example 4: Performance Monitoring
278
+
279
+ ```typescript
280
+ const parser = new MarkdownParser({
281
+ cache: { enabled: true },
282
+ });
283
+
284
+ const markdown = '# Heading\n\n' + 'Paragraph text. '.repeat(1000);
285
+
286
+ // First parse
287
+ const result1 = await parser.parse(markdown);
288
+ console.log('First parse:', result1.metadata.parseTime, 'ms');
289
+
290
+ // Cached parse
291
+ const result2 = await parser.parse(markdown);
292
+ console.log('Cached parse:', result2.metadata.parseTime, 'ms');
293
+ console.log('Speedup:', result1.metadata.parseTime / result2.metadata.parseTime, 'x');
294
+ ```
295
+
296
+ ## Integration Status
297
+
298
+ - **Logger**: ✅ Integrated - Uses `@bernierllc/logger` for debug output
299
+ - **Docs-Suite**: ✅ Ready - Complete TypeScript definitions and JSDoc
300
+ - **NeverHub**: ⚠️ Optional - Core package, standalone operation
301
+
302
+ ## Performance
303
+
304
+ - **Large documents**: Parses 1000 headings in <1 second
305
+ - **Caching**: 10-100x speedup for repeated parsing
306
+ - **Memory efficient**: Configurable cache size limits
307
+ - **Non-blocking**: Async API for integration with event loops
308
+
309
+ ## Related Packages
310
+
311
+ - [@bernierllc/markdown-renderer](../markdown-renderer) - Renders AST to HTML
312
+ - [@bernierllc/logger](../logger) - Structured logging
313
+ - [@bernierllc/crypto-utils](../crypto-utils) - Hash generation for cache keys
314
+
315
+ ## License
316
+
317
+ Copyright (c) 2025 Bernier LLC
318
+
319
+ This file is licensed to the client under a limited-use license. The client may use and modify this code *only within the scope of the project it was delivered for*. Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
320
+
321
+ ## See Also
322
+
323
+ - [CommonMark Specification](https://spec.commonmark.org/)
324
+ - [GitHub-Flavored Markdown Spec](https://github.github.com/gfm/)
325
+ - [Content Management Suite](../../suite/content-management-suite)