md4x 0.0.19 → 0.0.20
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/build/md4x.darwin-arm64.node +0 -0
- package/build/md4x.darwin-x64.node +0 -0
- package/build/md4x.linux-arm.node +0 -0
- package/build/md4x.linux-arm64-musl.node +0 -0
- package/build/md4x.linux-arm64.node +0 -0
- package/build/md4x.linux-x64-musl.node +0 -0
- package/build/md4x.linux-x64.node +0 -0
- package/build/md4x.wasm +0 -0
- package/build/md4x.win32-arm64.node +0 -0
- package/build/md4x.win32-x64.node +0 -0
- package/lib/_shared.mjs +56 -0
- package/lib/napi.d.mts +3 -0
- package/lib/napi.mjs +10 -1
- package/lib/types.d.mts +32 -0
- package/lib/wasm/common.mjs +27 -1
- package/package.json +3 -3
- /package/lib/wasm/{defult.mjs → default.mjs} +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/build/md4x.wasm
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/_shared.mjs
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const decoder = new TextDecoder();
|
|
2
|
+
|
|
3
|
+
export function parseHtmlMeta(bytes) {
|
|
4
|
+
const nullIdx = bytes.indexOf(0);
|
|
5
|
+
if (nullIdx === -1) {
|
|
6
|
+
return { html: decoder.decode(bytes), codeBlocks: [] };
|
|
7
|
+
}
|
|
8
|
+
const htmlBytes = bytes.subarray(0, nullIdx);
|
|
9
|
+
const metaBytes = bytes.subarray(nullIdx + 1);
|
|
10
|
+
const html = decoder.decode(htmlBytes);
|
|
11
|
+
const meta = JSON.parse(decoder.decode(metaBytes));
|
|
12
|
+
const codeBlocks = meta.map((m) => {
|
|
13
|
+
const start = decoder.decode(htmlBytes.subarray(0, m.s)).length;
|
|
14
|
+
const end = decoder.decode(htmlBytes.subarray(0, m.e)).length;
|
|
15
|
+
const block = { start, end, lang: m.l || "" };
|
|
16
|
+
if (m.f) block.filename = m.f;
|
|
17
|
+
if (m.h) block.highlights = m.h;
|
|
18
|
+
return block;
|
|
19
|
+
});
|
|
20
|
+
return { html, codeBlocks };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function parseHtmlWithHighlighting(bytes, highlighter) {
|
|
24
|
+
const { html, codeBlocks } = parseHtmlMeta(bytes);
|
|
25
|
+
if (codeBlocks.length === 0) return html;
|
|
26
|
+
let out = "";
|
|
27
|
+
let pos = 0;
|
|
28
|
+
for (const block of codeBlocks) {
|
|
29
|
+
const code = unescapeHtml(html.slice(block.start, block.end));
|
|
30
|
+
const highlighted = highlighter(code, block);
|
|
31
|
+
if (highlighted === undefined) {
|
|
32
|
+
out += html.slice(pos, block.end);
|
|
33
|
+
} else {
|
|
34
|
+
// Calculate <pre><code...> prefix length to replace the full wrapper
|
|
35
|
+
const preLen = block.lang
|
|
36
|
+
? '<pre><code class="language-'.length + block.lang.length + '">'.length
|
|
37
|
+
: "<pre><code>".length;
|
|
38
|
+
out += html.slice(pos, block.start - preLen);
|
|
39
|
+
out += highlighted;
|
|
40
|
+
pos = block.end + "</code></pre>\n".length;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
pos = block.end;
|
|
44
|
+
}
|
|
45
|
+
out += html.slice(pos);
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function unescapeHtml(str) {
|
|
50
|
+
if (!str.includes("&")) return str;
|
|
51
|
+
return str
|
|
52
|
+
.replaceAll("&", "&")
|
|
53
|
+
.replaceAll("<", "<")
|
|
54
|
+
.replaceAll(">", ">")
|
|
55
|
+
.replaceAll(""", '"');
|
|
56
|
+
}
|
package/lib/napi.d.mts
CHANGED
|
@@ -17,8 +17,11 @@ export type {
|
|
|
17
17
|
RenderOptions,
|
|
18
18
|
} from "./types.mjs";
|
|
19
19
|
|
|
20
|
+
export type * from "./types.mjs";
|
|
21
|
+
|
|
20
22
|
export interface NAPIBinding {
|
|
21
23
|
renderToHtml(input: string, flags?: number): string;
|
|
24
|
+
renderToHtmlMeta(input: string): Buffer;
|
|
22
25
|
renderToAST(input: string, flags?: number): string;
|
|
23
26
|
renderToAnsi(input: string, flags?: number): string;
|
|
24
27
|
renderToMeta(input: string, flags?: number): string;
|
package/lib/napi.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { parseHtmlWithHighlighting } from "./_shared.mjs";
|
|
2
|
+
|
|
1
3
|
// --- internal ---
|
|
2
4
|
|
|
3
5
|
let binding;
|
|
@@ -40,7 +42,14 @@ const HEAL_FLAG = 0x0100;
|
|
|
40
42
|
export function renderToHtml(input, opts) {
|
|
41
43
|
let flags = opts?.full ? 0x0008 : 0;
|
|
42
44
|
if (opts?.heal) flags |= HEAL_FLAG;
|
|
43
|
-
|
|
45
|
+
if (!opts?.highlighter) {
|
|
46
|
+
return getBinding().renderToHtml(str(input), flags);
|
|
47
|
+
}
|
|
48
|
+
const buf = getBinding().renderToHtmlMeta(str(input));
|
|
49
|
+
return parseHtmlWithHighlighting(
|
|
50
|
+
new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength),
|
|
51
|
+
opts.highlighter,
|
|
52
|
+
);
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
export function renderToAST(input, opts) {
|
package/lib/types.d.mts
CHANGED
|
@@ -37,4 +37,36 @@ export interface RenderOptions {
|
|
|
37
37
|
export interface HtmlOptions extends RenderOptions {
|
|
38
38
|
/** Generate a full HTML document with `<!DOCTYPE html>`, `<head>`, and `<body>`. */
|
|
39
39
|
full?: boolean;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Custom highlighter function for fenced code blocks. If provided, this will cause
|
|
43
|
+
*/
|
|
44
|
+
highlighter: CodeBlockHighlighter;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface CodeBlock {
|
|
48
|
+
/** Character offset in HTML string where code content starts (after `<code...>`) */
|
|
49
|
+
start: number;
|
|
50
|
+
/** Character offset in HTML string where code content ends (before `</code>`) */
|
|
51
|
+
end: number;
|
|
52
|
+
/** Language identifier (empty string if none) */
|
|
53
|
+
lang: string;
|
|
54
|
+
/** Filename from `[filename]` syntax */
|
|
55
|
+
filename?: string;
|
|
56
|
+
/** Highlighted line numbers from `{1-3,5}` syntax */
|
|
57
|
+
highlights?: number[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type CodeBlockHighlighter = (
|
|
61
|
+
/** Raw code content (HTML entities unescaped) */
|
|
62
|
+
code: string,
|
|
63
|
+
/** Code block metadata (lang, filename, highlights, offsets) */
|
|
64
|
+
block: CodeBlock,
|
|
65
|
+
) => string | undefined;
|
|
66
|
+
|
|
67
|
+
export interface HtmlWithCodeBlocks {
|
|
68
|
+
/** The HTML string */
|
|
69
|
+
html: string;
|
|
70
|
+
/** Metadata for each fenced code block in document order */
|
|
71
|
+
codeBlocks: CodeBlock[];
|
|
40
72
|
}
|
package/lib/wasm/common.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { parseHtmlWithHighlighting } from "../_shared.mjs";
|
|
2
|
+
|
|
1
3
|
// --- internal ---
|
|
2
4
|
|
|
3
5
|
let _instance;
|
|
@@ -61,7 +63,31 @@ export function renderToHtml(input, opts) {
|
|
|
61
63
|
let flags = opts?.full ? 0x0008 : 0;
|
|
62
64
|
if (opts?.heal) flags |= HEAL_FLAG;
|
|
63
65
|
const exports = _getExports();
|
|
64
|
-
|
|
66
|
+
if (!opts?.highlighter) {
|
|
67
|
+
return render(exports, exports.md4x_to_html, input, flags);
|
|
68
|
+
}
|
|
69
|
+
const {
|
|
70
|
+
memory,
|
|
71
|
+
md4x_alloc,
|
|
72
|
+
md4x_free,
|
|
73
|
+
md4x_to_html_meta,
|
|
74
|
+
md4x_result_ptr,
|
|
75
|
+
md4x_result_size,
|
|
76
|
+
} = exports;
|
|
77
|
+
const encoded = new TextEncoder().encode(str(input));
|
|
78
|
+
const ptr = md4x_alloc(encoded.length);
|
|
79
|
+
new Uint8Array(memory.buffer).set(encoded, ptr);
|
|
80
|
+
const ret = md4x_to_html_meta(ptr, encoded.length);
|
|
81
|
+
md4x_free(ptr);
|
|
82
|
+
if (ret !== 0) {
|
|
83
|
+
throw new Error("md4x: render failed");
|
|
84
|
+
}
|
|
85
|
+
const outPtr = md4x_result_ptr();
|
|
86
|
+
const outSize = md4x_result_size();
|
|
87
|
+
const bytes = new Uint8Array(memory.buffer, outPtr, outSize);
|
|
88
|
+
const result = parseHtmlWithHighlighting(bytes, opts.highlighter);
|
|
89
|
+
md4x_free(outPtr);
|
|
90
|
+
return result;
|
|
65
91
|
}
|
|
66
92
|
|
|
67
93
|
export function renderToAST(input, opts) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "md4x",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"repository": "unjs/md4x",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"./wasm": {
|
|
9
9
|
"types": "./lib/wasm/index.d.mts",
|
|
10
10
|
"unwasm": "./lib/wasm/unwasm.mjs",
|
|
11
|
-
"default": "./lib/wasm/
|
|
11
|
+
"default": "./lib/wasm/default.mjs"
|
|
12
12
|
},
|
|
13
13
|
"./napi": "./lib/napi.mjs",
|
|
14
14
|
"./build/md4x.wasm": "./build/md4x.wasm",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"node": "./lib/napi.mjs",
|
|
17
17
|
"default": {
|
|
18
18
|
"unwasm": "./lib/wasm/unwasm.mjs",
|
|
19
|
-
"default": "./lib/wasm/
|
|
19
|
+
"default": "./lib/wasm/default.mjs"
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
},
|
|
File without changes
|