@vakra-dev/supermarkdown 0.0.1 → 0.0.3

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/README.md ADDED
@@ -0,0 +1,343 @@
1
+ # supermarkdown
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@vakra-dev/supermarkdown.svg)](https://www.npmjs.com/package/@vakra-dev/supermarkdown)
4
+ [![crates.io](https://img.shields.io/crates/v/supermarkdown.svg)](https://crates.io/crates/supermarkdown)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ High-performance HTML to Markdown converter with full GitHub Flavored Markdown support. Written in Rust, available for Node.js and as a native Rust crate.
8
+
9
+ ## Features
10
+
11
+ - **Fast** - Written in Rust with O(n) algorithms, significantly faster than JavaScript alternatives
12
+ - **Full GFM Support** - Tables with alignment, strikethrough, autolinks, fenced code blocks
13
+ - **Accurate** - Handles malformed HTML gracefully via html5ever
14
+ - **Configurable** - Multiple heading styles, link styles, custom selectors
15
+ - **Zero Dependencies** - Single native binary, no JavaScript runtime overhead
16
+ - **Cross-Platform** - Pre-built binaries for Windows, macOS, and Linux (x64 & ARM64)
17
+ - **TypeScript Ready** - Full type definitions included
18
+ - **Async Support** - Non-blocking conversion for large documents
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install @vakra-dev/supermarkdown
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```javascript
29
+ import { convert } from "@vakra-dev/supermarkdown";
30
+
31
+ const html = `
32
+ <h1>Hello World</h1>
33
+ <p>This is a <strong>test</strong> with a <a href="https://example.com">link</a>.</p>
34
+ `;
35
+
36
+ const markdown = convert(html);
37
+ console.log(markdown);
38
+ // # Hello World
39
+ //
40
+ // This is a **test** with a [link](https://example.com).
41
+ ```
42
+
43
+ ## Usage
44
+
45
+ ### Basic Conversion
46
+
47
+ ```javascript
48
+ import { convert } from "@vakra-dev/supermarkdown";
49
+
50
+ const markdown = convert("<h1>Title</h1><p>Paragraph</p>");
51
+ ```
52
+
53
+ ### With Options
54
+
55
+ ```javascript
56
+ import { convert } from "@vakra-dev/supermarkdown";
57
+
58
+ const markdown = convert(html, {
59
+ headingStyle: "setext", // 'atx' (default) or 'setext'
60
+ linkStyle: "referenced", // 'inline' (default) or 'referenced'
61
+ excludeSelectors: ["nav", ".sidebar", "#ads"],
62
+ includeSelectors: [".important"], // Override excludes for specific elements
63
+ });
64
+ ```
65
+
66
+ ### Async Conversion
67
+
68
+ For large documents, use `convertAsync` to avoid blocking the main thread:
69
+
70
+ ```javascript
71
+ import { convertAsync } from "@vakra-dev/supermarkdown";
72
+
73
+ const markdown = await convertAsync(largeHtml);
74
+
75
+ // Process multiple documents in parallel
76
+ const results = await Promise.all([
77
+ convertAsync(html1),
78
+ convertAsync(html2),
79
+ convertAsync(html3),
80
+ ]);
81
+ ```
82
+
83
+ ## API Reference
84
+
85
+ ### `convert(html, options?)`
86
+
87
+ Converts HTML to Markdown synchronously.
88
+
89
+ **Parameters:**
90
+
91
+ - `html` (string) - The HTML string to convert
92
+ - `options` (object, optional) - Conversion options
93
+
94
+ **Returns:** string - The converted Markdown
95
+
96
+ ### `convertAsync(html, options?)`
97
+
98
+ Converts HTML to Markdown asynchronously.
99
+
100
+ **Parameters:**
101
+
102
+ - `html` (string) - The HTML string to convert
103
+ - `options` (object, optional) - Conversion options
104
+
105
+ **Returns:** Promise<string> - The converted Markdown
106
+
107
+ ### Options
108
+
109
+ | Option | Type | Default | Description |
110
+ | ------------------ | ---------------------------- | ----------- | ------------------------------------------------ |
111
+ | `headingStyle` | `'atx'` \| `'setext'` | `'atx'` | ATX uses `#` prefix, Setext uses underlines |
112
+ | `linkStyle` | `'inline'` \| `'referenced'` | `'inline'` | Inline: `[text](url)`, Referenced: `[text][1]` |
113
+ | `codeFence` | `` '`' `` \| `'~'` | `` '`' `` | Character for fenced code blocks |
114
+ | `bulletMarker` | `'-'` \| `'*'` \| `'+'` | `'-'` | Character for unordered list items |
115
+ | `baseUrl` | `string` | `undefined` | Base URL for resolving relative links |
116
+ | `excludeSelectors` | `string[]` | `[]` | CSS selectors for elements to exclude |
117
+ | `includeSelectors` | `string[]` | `[]` | CSS selectors to force keep (overrides excludes) |
118
+
119
+ ## Supported Elements
120
+
121
+ ### Block Elements
122
+
123
+ | HTML | Markdown |
124
+ | -------------------------- | ---------------------------------------------- |
125
+ | `<h1>` - `<h6>` | `#` headings or setext underlines |
126
+ | `<p>` | Paragraphs with blank lines |
127
+ | `<blockquote>` | `>` quoted blocks (supports nesting) |
128
+ | `<ul>`, `<ol>` | `-` or `1.` lists (supports `start` attribute) |
129
+ | `<pre><code>` | Fenced code blocks with language detection |
130
+ | `<table>` | GFM tables with alignment and captions |
131
+ | `<hr>` | `---` horizontal rules |
132
+ | `<dl>`, `<dt>`, `<dd>` | Definition lists |
133
+ | `<details>`, `<summary>` | Collapsible sections |
134
+ | `<figure>`, `<figcaption>` | Images with captions |
135
+
136
+ ### Inline Elements
137
+
138
+ | HTML | Markdown |
139
+ | -------------------------- | --------------------------------------- |
140
+ | `<a>` | `[text](url)`, `[text][ref]`, or `<url>` (autolink) |
141
+ | `<img>` | `![alt](src)` |
142
+ | `<strong>`, `<b>` | `**bold**` |
143
+ | `<em>`, `<i>` | `*italic*` |
144
+ | `<code>` | `` `code` `` (handles nested backticks) |
145
+ | `<del>`, `<s>`, `<strike>` | `~~strikethrough~~` |
146
+ | `<sub>` | `<sub>subscript</sub>` |
147
+ | `<sup>` | `<sup>superscript</sup>` |
148
+ | `<br>` | Line breaks |
149
+
150
+ ### HTML Passthrough
151
+
152
+ Elements without Markdown equivalents are preserved as HTML:
153
+
154
+ - `<kbd>` - Keyboard input
155
+ - `<mark>` - Highlighted text
156
+ - `<abbr>` - Abbreviations (preserves `title` attribute)
157
+ - `<samp>` - Sample output
158
+ - `<var>` - Variables
159
+
160
+ ## Advanced Features
161
+
162
+ ### Table Alignment
163
+
164
+ Extracts alignment from `align` attribute or `text-align` style:
165
+
166
+ ```html
167
+ <table>
168
+ <tr>
169
+ <th align="left">Left</th>
170
+ <th align="center">Center</th>
171
+ <th align="right">Right</th>
172
+ </tr>
173
+ </table>
174
+ ```
175
+
176
+ Output:
177
+
178
+ ```markdown
179
+ | Left | Center | Right |
180
+ | :--- | :----: | ----: |
181
+ ```
182
+
183
+ ### Ordered List Start
184
+
185
+ Respects the `start` attribute on ordered lists:
186
+
187
+ ```html
188
+ <ol start="5">
189
+ <li>Fifth item</li>
190
+ <li>Sixth item</li>
191
+ </ol>
192
+ ```
193
+
194
+ Output:
195
+
196
+ ```markdown
197
+ 5. Fifth item
198
+ 6. Sixth item
199
+ ```
200
+
201
+ ### Autolinks
202
+
203
+ When a link's text matches its URL or email, autolink syntax is used:
204
+
205
+ ```html
206
+ <a href="https://example.com">https://example.com</a>
207
+ <a href="mailto:test@example.com">test@example.com</a>
208
+ ```
209
+
210
+ Output:
211
+
212
+ ```markdown
213
+ <https://example.com>
214
+ <test@example.com>
215
+ ```
216
+
217
+ ### Code Block Language Detection
218
+
219
+ Automatically detects language from class names:
220
+
221
+ - `language-*` (e.g., `language-rust`)
222
+ - `lang-*` (e.g., `lang-python`)
223
+ - `highlight-*` (e.g., `highlight-go`)
224
+ - `hljs-*` (highlight.js classes, excluding token classes like `hljs-keyword`)
225
+ - Bare language names (e.g., `javascript`, `python`) as fallback
226
+
227
+ ```html
228
+ <pre><code class="language-rust">fn main() {}</code></pre>
229
+ ```
230
+
231
+ Output:
232
+
233
+ ````markdown
234
+ ```rust
235
+ fn main() {}
236
+ ```
237
+ ````
238
+
239
+ Code blocks containing backticks automatically use more backticks as delimiters.
240
+
241
+ ### Line Number Handling
242
+
243
+ Line number gutters are automatically stripped from code blocks. Elements with these class patterns are skipped:
244
+
245
+ - `gutter`
246
+ - `line-number`
247
+ - `line-numbers`
248
+ - `lineno`
249
+ - `linenumber`
250
+
251
+ ### URL Encoding
252
+
253
+ Spaces and parentheses in URLs are automatically percent-encoded:
254
+
255
+ ```javascript
256
+ // <a href="https://example.com/path (1)">link</a>
257
+ // → [link](https://example.com/path%20%281%29)
258
+ ```
259
+
260
+ ### Selector-Based Filtering
261
+
262
+ Remove unwanted elements like navigation, ads, or sidebars:
263
+
264
+ ```javascript
265
+ const markdown = convert(html, {
266
+ excludeSelectors: [
267
+ "nav",
268
+ "header",
269
+ "footer",
270
+ ".sidebar",
271
+ ".advertisement",
272
+ "#cookie-banner",
273
+ ],
274
+ includeSelectors: [".main-content"],
275
+ });
276
+ ```
277
+
278
+ ## Limitations
279
+
280
+ Some HTML features cannot be fully represented in Markdown:
281
+
282
+ | Feature | Behavior |
283
+ | ----------------------- | ------------------------------------------ |
284
+ | Table colspan/rowspan | Content placed in first cell |
285
+ | Nested tables | Inner tables converted inline |
286
+ | Form elements | Skipped |
287
+ | iframe/video/audio | Skipped (no standard Markdown equivalent) |
288
+ | CSS styling | Ignored (except `text-align` for tables) |
289
+ | Empty elements | Removed from output |
290
+
291
+ ## Rust Usage
292
+
293
+ Add to your `Cargo.toml`:
294
+
295
+ ```toml
296
+ [dependencies]
297
+ supermarkdown = "0.0.2"
298
+ ```
299
+
300
+ ```rust
301
+ use supermarkdown::{convert, convert_with_options, Options, HeadingStyle};
302
+
303
+ // Basic conversion
304
+ let markdown = convert("<h1>Hello</h1>");
305
+
306
+ // With options
307
+ let options = Options::new()
308
+ .heading_style(HeadingStyle::Setext)
309
+ .exclude_selectors(vec!["nav".to_string()]);
310
+
311
+ let markdown = convert_with_options("<h1>Hello</h1>", &options);
312
+ ```
313
+
314
+ ## Performance
315
+
316
+ supermarkdown is designed for high performance:
317
+
318
+ - **Single-pass parsing** - O(n) HTML traversal
319
+ - **Pre-computed metadata** - List indices and CSS selectors computed in one pass
320
+ - **Zero-copy where possible** - Minimal string allocations
321
+ - **Native code** - No JavaScript runtime overhead
322
+
323
+ ## Contributing
324
+
325
+ Contributions are welcome! Please feel free to submit a Pull Request.
326
+
327
+ ```bash
328
+ # Clone the repository
329
+ git clone https://github.com/vakra-dev/supermarkdown.git
330
+ cd supermarkdown
331
+
332
+ # Run tests
333
+ cargo test
334
+
335
+ # Build Node.js bindings
336
+ cd crates/supermarkdown-napi
337
+ npm install
338
+ npm run build
339
+ ```
340
+
341
+ ## License
342
+
343
+ MIT License - see [LICENSE](LICENSE) for details.
package/index.js CHANGED
@@ -37,7 +37,7 @@ switch (platform) {
37
37
  if (localFileExisted) {
38
38
  nativeBinding = require('./supermarkdown.android-arm64.node')
39
39
  } else {
40
- nativeBinding = require('supermarkdown-android-arm64')
40
+ nativeBinding = require('@vakra-dev/supermarkdown-android-arm64')
41
41
  }
42
42
  } catch (e) {
43
43
  loadError = e
@@ -49,7 +49,7 @@ switch (platform) {
49
49
  if (localFileExisted) {
50
50
  nativeBinding = require('./supermarkdown.android-arm-eabi.node')
51
51
  } else {
52
- nativeBinding = require('supermarkdown-android-arm-eabi')
52
+ nativeBinding = require('@vakra-dev/supermarkdown-android-arm-eabi')
53
53
  }
54
54
  } catch (e) {
55
55
  loadError = e
@@ -69,7 +69,7 @@ switch (platform) {
69
69
  if (localFileExisted) {
70
70
  nativeBinding = require('./supermarkdown.win32-x64-msvc.node')
71
71
  } else {
72
- nativeBinding = require('supermarkdown-win32-x64-msvc')
72
+ nativeBinding = require('@vakra-dev/supermarkdown-win32-x64-msvc')
73
73
  }
74
74
  } catch (e) {
75
75
  loadError = e
@@ -83,7 +83,7 @@ switch (platform) {
83
83
  if (localFileExisted) {
84
84
  nativeBinding = require('./supermarkdown.win32-ia32-msvc.node')
85
85
  } else {
86
- nativeBinding = require('supermarkdown-win32-ia32-msvc')
86
+ nativeBinding = require('@vakra-dev/supermarkdown-win32-ia32-msvc')
87
87
  }
88
88
  } catch (e) {
89
89
  loadError = e
@@ -97,7 +97,7 @@ switch (platform) {
97
97
  if (localFileExisted) {
98
98
  nativeBinding = require('./supermarkdown.win32-arm64-msvc.node')
99
99
  } else {
100
- nativeBinding = require('supermarkdown-win32-arm64-msvc')
100
+ nativeBinding = require('@vakra-dev/supermarkdown-win32-arm64-msvc')
101
101
  }
102
102
  } catch (e) {
103
103
  loadError = e
@@ -113,7 +113,7 @@ switch (platform) {
113
113
  if (localFileExisted) {
114
114
  nativeBinding = require('./supermarkdown.darwin-universal.node')
115
115
  } else {
116
- nativeBinding = require('supermarkdown-darwin-universal')
116
+ nativeBinding = require('@vakra-dev/supermarkdown-darwin-universal')
117
117
  }
118
118
  break
119
119
  } catch {}
@@ -124,7 +124,7 @@ switch (platform) {
124
124
  if (localFileExisted) {
125
125
  nativeBinding = require('./supermarkdown.darwin-x64.node')
126
126
  } else {
127
- nativeBinding = require('supermarkdown-darwin-x64')
127
+ nativeBinding = require('@vakra-dev/supermarkdown-darwin-x64')
128
128
  }
129
129
  } catch (e) {
130
130
  loadError = e
@@ -138,7 +138,7 @@ switch (platform) {
138
138
  if (localFileExisted) {
139
139
  nativeBinding = require('./supermarkdown.darwin-arm64.node')
140
140
  } else {
141
- nativeBinding = require('supermarkdown-darwin-arm64')
141
+ nativeBinding = require('@vakra-dev/supermarkdown-darwin-arm64')
142
142
  }
143
143
  } catch (e) {
144
144
  loadError = e
@@ -157,7 +157,7 @@ switch (platform) {
157
157
  if (localFileExisted) {
158
158
  nativeBinding = require('./supermarkdown.freebsd-x64.node')
159
159
  } else {
160
- nativeBinding = require('supermarkdown-freebsd-x64')
160
+ nativeBinding = require('@vakra-dev/supermarkdown-freebsd-x64')
161
161
  }
162
162
  } catch (e) {
163
163
  loadError = e
@@ -174,7 +174,7 @@ switch (platform) {
174
174
  if (localFileExisted) {
175
175
  nativeBinding = require('./supermarkdown.linux-x64-musl.node')
176
176
  } else {
177
- nativeBinding = require('supermarkdown-linux-x64-musl')
177
+ nativeBinding = require('@vakra-dev/supermarkdown-linux-x64-musl')
178
178
  }
179
179
  } catch (e) {
180
180
  loadError = e
@@ -187,7 +187,7 @@ switch (platform) {
187
187
  if (localFileExisted) {
188
188
  nativeBinding = require('./supermarkdown.linux-x64-gnu.node')
189
189
  } else {
190
- nativeBinding = require('supermarkdown-linux-x64-gnu')
190
+ nativeBinding = require('@vakra-dev/supermarkdown-linux-x64-gnu')
191
191
  }
192
192
  } catch (e) {
193
193
  loadError = e
@@ -203,7 +203,7 @@ switch (platform) {
203
203
  if (localFileExisted) {
204
204
  nativeBinding = require('./supermarkdown.linux-arm64-musl.node')
205
205
  } else {
206
- nativeBinding = require('supermarkdown-linux-arm64-musl')
206
+ nativeBinding = require('@vakra-dev/supermarkdown-linux-arm64-musl')
207
207
  }
208
208
  } catch (e) {
209
209
  loadError = e
@@ -216,7 +216,7 @@ switch (platform) {
216
216
  if (localFileExisted) {
217
217
  nativeBinding = require('./supermarkdown.linux-arm64-gnu.node')
218
218
  } else {
219
- nativeBinding = require('supermarkdown-linux-arm64-gnu')
219
+ nativeBinding = require('@vakra-dev/supermarkdown-linux-arm64-gnu')
220
220
  }
221
221
  } catch (e) {
222
222
  loadError = e
@@ -232,7 +232,7 @@ switch (platform) {
232
232
  if (localFileExisted) {
233
233
  nativeBinding = require('./supermarkdown.linux-arm-musleabihf.node')
234
234
  } else {
235
- nativeBinding = require('supermarkdown-linux-arm-musleabihf')
235
+ nativeBinding = require('@vakra-dev/supermarkdown-linux-arm-musleabihf')
236
236
  }
237
237
  } catch (e) {
238
238
  loadError = e
@@ -245,7 +245,7 @@ switch (platform) {
245
245
  if (localFileExisted) {
246
246
  nativeBinding = require('./supermarkdown.linux-arm-gnueabihf.node')
247
247
  } else {
248
- nativeBinding = require('supermarkdown-linux-arm-gnueabihf')
248
+ nativeBinding = require('@vakra-dev/supermarkdown-linux-arm-gnueabihf')
249
249
  }
250
250
  } catch (e) {
251
251
  loadError = e
@@ -261,7 +261,7 @@ switch (platform) {
261
261
  if (localFileExisted) {
262
262
  nativeBinding = require('./supermarkdown.linux-riscv64-musl.node')
263
263
  } else {
264
- nativeBinding = require('supermarkdown-linux-riscv64-musl')
264
+ nativeBinding = require('@vakra-dev/supermarkdown-linux-riscv64-musl')
265
265
  }
266
266
  } catch (e) {
267
267
  loadError = e
@@ -274,7 +274,7 @@ switch (platform) {
274
274
  if (localFileExisted) {
275
275
  nativeBinding = require('./supermarkdown.linux-riscv64-gnu.node')
276
276
  } else {
277
- nativeBinding = require('supermarkdown-linux-riscv64-gnu')
277
+ nativeBinding = require('@vakra-dev/supermarkdown-linux-riscv64-gnu')
278
278
  }
279
279
  } catch (e) {
280
280
  loadError = e
@@ -289,7 +289,7 @@ switch (platform) {
289
289
  if (localFileExisted) {
290
290
  nativeBinding = require('./supermarkdown.linux-s390x-gnu.node')
291
291
  } else {
292
- nativeBinding = require('supermarkdown-linux-s390x-gnu')
292
+ nativeBinding = require('@vakra-dev/supermarkdown-linux-s390x-gnu')
293
293
  }
294
294
  } catch (e) {
295
295
  loadError = e
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vakra-dev/supermarkdown",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "High-performance HTML to Markdown converter with full GFM support",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -26,7 +26,8 @@
26
26
  "files": [
27
27
  "index.js",
28
28
  "index.d.ts",
29
- "*.node"
29
+ "*.node",
30
+ "README.md"
30
31
  ],
31
32
  "napi": {
32
33
  "name": "supermarkdown",
@@ -48,7 +49,7 @@
48
49
  "artifacts": "napi artifacts",
49
50
  "build": "napi build --platform --release",
50
51
  "build:debug": "napi build --platform",
51
- "prepublishOnly": "napi prepublish -t npm",
52
+ "prepublishOnly": "napi prepublish -t npm --skip-gh-release",
52
53
  "test": "ava",
53
54
  "universal": "napi universal",
54
55
  "version": "napi version"
@@ -61,13 +62,13 @@
61
62
  "timeout": "3m"
62
63
  },
63
64
  "optionalDependencies": {
64
- "@vakra-dev/supermarkdown-win32-x64-msvc": "0.0.1",
65
- "@vakra-dev/supermarkdown-darwin-x64": "0.0.1",
66
- "@vakra-dev/supermarkdown-linux-x64-gnu": "0.0.1",
67
- "@vakra-dev/supermarkdown-linux-x64-musl": "0.0.1",
68
- "@vakra-dev/supermarkdown-linux-arm64-gnu": "0.0.1",
69
- "@vakra-dev/supermarkdown-linux-arm64-musl": "0.0.1",
70
- "@vakra-dev/supermarkdown-darwin-arm64": "0.0.1",
71
- "@vakra-dev/supermarkdown-win32-arm64-msvc": "0.0.1"
65
+ "@vakra-dev/supermarkdown-win32-x64-msvc": "0.0.2",
66
+ "@vakra-dev/supermarkdown-darwin-x64": "0.0.2",
67
+ "@vakra-dev/supermarkdown-linux-x64-gnu": "0.0.2",
68
+ "@vakra-dev/supermarkdown-linux-x64-musl": "0.0.2",
69
+ "@vakra-dev/supermarkdown-linux-arm64-gnu": "0.0.2",
70
+ "@vakra-dev/supermarkdown-linux-arm64-musl": "0.0.2",
71
+ "@vakra-dev/supermarkdown-darwin-arm64": "0.0.2",
72
+ "@vakra-dev/supermarkdown-win32-arm64-msvc": "0.0.2"
72
73
  }
73
- }
74
+ }
Binary file
Binary file
Binary file