quikdown 1.0.1
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.txt +24 -0
- package/README.md +381 -0
- package/dist/quikdown.cjs +587 -0
- package/dist/quikdown.esm.js +585 -0
- package/dist/quikdown.esm.min.js +8 -0
- package/dist/quikdown.esm.min.js.map +1 -0
- package/dist/quikdown.umd.js +593 -0
- package/dist/quikdown.umd.min.js +8 -0
- package/dist/quikdown.umd.min.js.map +1 -0
- package/package.json +116 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, deftio llc & Manu Chatterjee
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
16
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
17
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
19
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
20
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
21
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
22
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
23
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
24
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
# quikdown
|
|
2
|
+
|
|
3
|
+
[](https://github.com/deftio/quikdown/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/quikdown)
|
|
5
|
+
[](https://github.com/deftio/quikdown)
|
|
6
|
+
[](https://opensource.org/licenses/BSD-2-Clause)
|
|
7
|
+
[](https://github.com/deftio/quikdown/tree/main/dist)
|
|
8
|
+
|
|
9
|
+
A lightweight, fast markdown parser with built-in XSS protection. Quikdown works in both browser and Node.js environments. Via its fenced plug-in support it can support highlighted code blocks, diagrams, and other custom fenced content.
|
|
10
|
+
|
|
11
|
+
📚 **[View Live Examples](https://deftio.github.io/quikdown/)** - Interactive examples on giithub of quikdown's features
|
|
12
|
+
📚 **[View Local Examples](examples/)** - Interactive demos of quikdown's features
|
|
13
|
+
📖 **[Read Documentation](docs/)** - Architecture, security, API reference, and plugin guide
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- 🚀 **Lightweight** - Under 10KB minified (currently 8.7KB)
|
|
18
|
+
- 🔒 **Secure by default** - Built-in XSS protection with URL sanitization
|
|
19
|
+
- 🎨 **Flexible styling** - Inline styles or CSS classes
|
|
20
|
+
- 🔌 **Plugin system** - Extensible fence block handlers
|
|
21
|
+
- 📦 **Zero dependencies** - No external libraries required
|
|
22
|
+
- 🌐 **Universal** - Works in browsers and Node.js
|
|
23
|
+
- ⚡ **Fast** - Optimized regex-based parsing
|
|
24
|
+
- 📝 **CommonMark subset** - Supports essential markdown features
|
|
25
|
+
- ✅ **Task Lists** - GitHub-style checkboxes
|
|
26
|
+
- 🔗 **Autolinks** - Automatic URL detection
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install quikdown
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or via CDN:
|
|
35
|
+
```html
|
|
36
|
+
<script src="https://unpkg.com/quikdown/dist/quikdown.umd.js"></script>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
### Basic Usage
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
import quikdown from 'quikdown';
|
|
45
|
+
|
|
46
|
+
const markdown = '# Hello World\n\nThis is **bold** text.';
|
|
47
|
+
const html = quikdown(markdown);
|
|
48
|
+
console.log(html);
|
|
49
|
+
// Output: <h1>Hello World</h1><p>This is <strong>bold</strong> text.</p>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### With Options
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const html = quikdown(markdown, {
|
|
56
|
+
inline_styles: true, // Use inline styles instead of classes
|
|
57
|
+
fence_plugin: myFenceHandler // Custom code fence handler
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Supported Markdown
|
|
62
|
+
|
|
63
|
+
quikdown supports a practical subset of CommonMark:
|
|
64
|
+
|
|
65
|
+
### Text Formatting
|
|
66
|
+
- **Bold**: `**text**` or `__text__`
|
|
67
|
+
- *Italic*: `*text*` or `_text_`
|
|
68
|
+
- ~~Strikethrough~~: `~~text~~`
|
|
69
|
+
- `Code`: `` `code` ``
|
|
70
|
+
|
|
71
|
+
### Headings
|
|
72
|
+
```markdown
|
|
73
|
+
# H1 Heading
|
|
74
|
+
## H2 Heading
|
|
75
|
+
### H3 Heading
|
|
76
|
+
#### H4 Heading
|
|
77
|
+
##### H5 Heading
|
|
78
|
+
###### H6 Heading
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Lists
|
|
82
|
+
|
|
83
|
+
Unordered:
|
|
84
|
+
```markdown
|
|
85
|
+
- Item 1
|
|
86
|
+
- Item 2
|
|
87
|
+
- Nested item
|
|
88
|
+
* Also works with asterisks
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Ordered:
|
|
92
|
+
```markdown
|
|
93
|
+
1. First item
|
|
94
|
+
2. Second item
|
|
95
|
+
1. Nested item
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Task Lists:
|
|
99
|
+
```markdown
|
|
100
|
+
- [x] Completed task
|
|
101
|
+
- [ ] Pending task
|
|
102
|
+
- [ ] Another todo
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Links and Images
|
|
106
|
+
```markdown
|
|
107
|
+
[Link text](https://example.com)
|
|
108
|
+

|
|
109
|
+
|
|
110
|
+
// Autolinks - URLs are automatically linked
|
|
111
|
+
Visit https://github.com for more info
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Code Blocks
|
|
115
|
+
````markdown
|
|
116
|
+
```javascript
|
|
117
|
+
console.log('Hello, world!');
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
// Also supports ~~~ fences
|
|
121
|
+
~~~python
|
|
122
|
+
print("Hello, world!")
|
|
123
|
+
~~~
|
|
124
|
+
````
|
|
125
|
+
|
|
126
|
+
### Tables
|
|
127
|
+
```markdown
|
|
128
|
+
| Header 1 | Header 2 |
|
|
129
|
+
|----------|----------|
|
|
130
|
+
| Cell 1 | Cell 2 |
|
|
131
|
+
| Cell 3 | Cell 4 |
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Other Elements
|
|
135
|
+
- **Blockquotes**: `> Quote text`
|
|
136
|
+
- **Horizontal rules**: `---` or `***` or `___`
|
|
137
|
+
- **Line breaks**: Two spaces at end of line or `<br>`
|
|
138
|
+
|
|
139
|
+
## Configuration Options
|
|
140
|
+
|
|
141
|
+
### `inline_styles` (boolean)
|
|
142
|
+
When `true`, uses inline styles for formatting. When `false`, uses CSS classes.
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
// With inline_styles: true
|
|
146
|
+
quikdown('**bold**', { inline_styles: true });
|
|
147
|
+
// Output: <strong style="font-weight: bold;">bold</strong>
|
|
148
|
+
|
|
149
|
+
// With inline_styles: false (default)
|
|
150
|
+
quikdown('**bold**', { inline_styles: false });
|
|
151
|
+
// Output: <strong>bold</strong>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### `fence_plugin` (function)
|
|
155
|
+
Custom handler for fenced code blocks. Useful for syntax highlighting or diagrams.
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
function fencePlugin(code, language) {
|
|
159
|
+
if (language === 'mermaid') {
|
|
160
|
+
return `<div class="mermaid">${code}</div>`;
|
|
161
|
+
}
|
|
162
|
+
// Return undefined to use default handling
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const html = quikdown(markdown, { fence_plugin: fencePlugin });
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Plugin System
|
|
169
|
+
|
|
170
|
+
For a complete plugin development guide, see [docs/plugin-guide.md](docs/plugin-guide.md)
|
|
171
|
+
|
|
172
|
+
### Creating a Fence Plugin
|
|
173
|
+
|
|
174
|
+
Fence plugins allow you to customize how code blocks are rendered:
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
function myFencePlugin(code, language) {
|
|
178
|
+
// Handle specific languages
|
|
179
|
+
if (language === 'graph') {
|
|
180
|
+
return renderGraph(code);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Add syntax highlighting
|
|
184
|
+
if (language && hljs.getLanguage(language)) {
|
|
185
|
+
const highlighted = hljs.highlight(code, { language }).value;
|
|
186
|
+
return `<pre><code class="language-${language}">${highlighted}</code></pre>`;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Return undefined for default handling
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Example: Mermaid Diagrams
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
function mermaidPlugin(code, language) {
|
|
198
|
+
if (language === 'mermaid') {
|
|
199
|
+
const id = 'mermaid-' + Math.random().toString(36).substr(2, 9);
|
|
200
|
+
// Render with mermaid.js after DOM update
|
|
201
|
+
setTimeout(() => {
|
|
202
|
+
mermaid.render(id + '-svg', code).then(result => {
|
|
203
|
+
document.getElementById(id).innerHTML = result.svg;
|
|
204
|
+
});
|
|
205
|
+
}, 0);
|
|
206
|
+
return `<div id="${id}" class="mermaid">Loading diagram...</div>`;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const html = quikdown(markdownWithMermaid, {
|
|
211
|
+
fence_plugin: mermaidPlugin
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Security
|
|
216
|
+
|
|
217
|
+
For detailed security information, see [docs/security.md](docs/security.md)
|
|
218
|
+
|
|
219
|
+
quikdown includes built-in XSS protection:
|
|
220
|
+
|
|
221
|
+
- All HTML tags in markdown are escaped by default
|
|
222
|
+
- Attributes are sanitized
|
|
223
|
+
- JavaScript URLs are blocked
|
|
224
|
+
- Only safe markdown constructs are converted to HTML
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
const unsafe = '<script>alert("XSS")</script> **bold**';
|
|
228
|
+
const safe = quikdown(unsafe);
|
|
229
|
+
// Output: <script>alert("XSS")</script> <strong>bold</strong>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## API Reference
|
|
233
|
+
|
|
234
|
+
For complete API documentation, see [docs/api-reference.md](docs/api-reference.md)
|
|
235
|
+
|
|
236
|
+
### `quikdown(markdown, options?)`
|
|
237
|
+
|
|
238
|
+
Main function to convert markdown to HTML.
|
|
239
|
+
|
|
240
|
+
**Parameters:**
|
|
241
|
+
- `markdown` (string): The markdown text to convert
|
|
242
|
+
- `options` (object, optional):
|
|
243
|
+
- `inline_styles` (boolean): Use inline styles instead of classes
|
|
244
|
+
- `fence_plugin` (function): Custom fence block handler
|
|
245
|
+
|
|
246
|
+
**Returns:** HTML string
|
|
247
|
+
|
|
248
|
+
### `quikdown.configure(options)`
|
|
249
|
+
|
|
250
|
+
Creates a configured instance of the parser.
|
|
251
|
+
|
|
252
|
+
```javascript
|
|
253
|
+
const myParser = quikdown.configure({
|
|
254
|
+
inline_styles: true,
|
|
255
|
+
fence_plugin: myPlugin
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Use the configured parser
|
|
259
|
+
const html = myParser(markdown);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### `quikdown.emitStyles()`
|
|
263
|
+
|
|
264
|
+
Returns CSS styles for quikdown HTML output when not using inline styles.
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
const styles = quikdown.emitStyles();
|
|
268
|
+
// Add to your stylesheet or <style> tag
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Browser Usage
|
|
272
|
+
|
|
273
|
+
### Via Script Tag
|
|
274
|
+
|
|
275
|
+
```html
|
|
276
|
+
<!DOCTYPE html>
|
|
277
|
+
<html>
|
|
278
|
+
<head>
|
|
279
|
+
<script src="https://unpkg.com/quikdown/dist/quikdown.umd.js"></script>
|
|
280
|
+
</head>
|
|
281
|
+
<body>
|
|
282
|
+
<div id="output"></div>
|
|
283
|
+
<script>
|
|
284
|
+
const markdown = '# Hello quikdown!';
|
|
285
|
+
const html = quikdown(markdown, { inline_styles: true });
|
|
286
|
+
document.getElementById('output').innerHTML = html;
|
|
287
|
+
</script>
|
|
288
|
+
</body>
|
|
289
|
+
</html>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### ES Modules
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
import quikdown from 'quikdown';
|
|
296
|
+
|
|
297
|
+
const html = quikdown('**Hello** world!');
|
|
298
|
+
document.body.innerHTML = html;
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Node.js Usage
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
const quikdown = require('quikdown');
|
|
305
|
+
|
|
306
|
+
const markdown = '# Server-side Markdown';
|
|
307
|
+
const html = quikdown(markdown);
|
|
308
|
+
|
|
309
|
+
// Use in Express, etc.
|
|
310
|
+
res.send(html);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Performance
|
|
314
|
+
|
|
315
|
+
quikdown is optimized for speed:
|
|
316
|
+
|
|
317
|
+
- Single-pass regex parsing
|
|
318
|
+
- Minimal memory allocation
|
|
319
|
+
- No AST generation
|
|
320
|
+
- Efficient string operations
|
|
321
|
+
|
|
322
|
+
Benchmarks show quikdown performs comparably to larger markdown parsers while maintaining a much smaller footprint.
|
|
323
|
+
|
|
324
|
+
## Limitations
|
|
325
|
+
|
|
326
|
+
quikdown intentionally doesn't support:
|
|
327
|
+
|
|
328
|
+
- HTML blocks (for security)
|
|
329
|
+
- Reference-style links
|
|
330
|
+
- Footnotes
|
|
331
|
+
- Definition lists
|
|
332
|
+
- Complex table alignment
|
|
333
|
+
- Nested blockquotes with different markers
|
|
334
|
+
|
|
335
|
+
These omissions keep the parser small, fast, and secure.
|
|
336
|
+
|
|
337
|
+
## Contributing
|
|
338
|
+
|
|
339
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
340
|
+
|
|
341
|
+
1. Fork the repository
|
|
342
|
+
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
|
343
|
+
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
344
|
+
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
|
345
|
+
5. Open a Pull Request
|
|
346
|
+
|
|
347
|
+
## Testing
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
# Run tests
|
|
351
|
+
npm test
|
|
352
|
+
|
|
353
|
+
# Watch mode
|
|
354
|
+
npm run test:watch
|
|
355
|
+
|
|
356
|
+
# Coverage report
|
|
357
|
+
npm run test:coverage
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## License
|
|
361
|
+
|
|
362
|
+
BSD 2-Clause License - see [LICENSE.txt](LICENSE.txt) file for details.
|
|
363
|
+
|
|
364
|
+
## Acknowledgments
|
|
365
|
+
|
|
366
|
+
- Inspired by the simplicity of early markdown parsers
|
|
367
|
+
- Built for the [QuikChat](https://github.com/deftio/quikchat) project
|
|
368
|
+
- CommonMark spec for markdown standardization
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
Choose quikdown when you need:
|
|
372
|
+
- A lightweight solution
|
|
373
|
+
- Built-in security
|
|
374
|
+
- Simple plugin system
|
|
375
|
+
- Zero dependencies
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
## Support
|
|
379
|
+
|
|
380
|
+
- 🐛 Issues: [GitHub Issues](https://github.com/deftio/quikdown/issues)
|
|
381
|
+
|