ironmark 1.12.3 → 2.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.
Binary file
@@ -9,7 +9,7 @@ export const parseToAst: (a: number, b: number, c: number, d: number, e: number,
9
9
  export const renderAnsi: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number, u: number, v: number, w: number, x: number, y: number) => void;
10
10
  export const renderMarkdown: (a: number, b: number, c: number) => void;
11
11
  export const ironmark_free: (a: number) => void;
12
- export const ironmark_parse: (a: number) => number;
12
+ export const ironmark_render_html: (a: number) => number;
13
13
  export const __wbindgen_add_to_stack_pointer: (a: number) => number;
14
14
  export const __wbindgen_export: (a: number, b: number) => number;
15
15
  export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
package/wasm/shared.js CHANGED
@@ -1,5 +1,7 @@
1
1
  const decoder = new TextDecoder("utf-8");
2
2
 
3
+ // ─── Internal helpers ────────────────────────────────────────────────────────
4
+
3
5
  function toStr(markdown) {
4
6
  if (typeof markdown === "string") return markdown;
5
7
  if (markdown instanceof Uint8Array) return decoder.decode(markdown);
@@ -11,96 +13,108 @@ function toStr(markdown) {
11
13
  throw new TypeError("markdown must be a string, Uint8Array, ArrayBuffer, or Buffer");
12
14
  }
13
15
 
16
+ // ─── Preset resolution ───────────────────────────────────────────────────────
17
+
18
+ const PRESETS = {
19
+ default: {},
20
+ safe: {
21
+ disableRawHtml: true,
22
+ tagFilter: true,
23
+ },
24
+ strict: {
25
+ hardBreaks: false,
26
+ enableHighlight: false,
27
+ enableStrikethrough: false,
28
+ enableUnderline: false,
29
+ enableAutolink: false,
30
+ enableWikiLinks: false,
31
+ enableLatexMath: false,
32
+ permissiveAtxHeaders: false,
33
+ collapseWhitespace: false,
34
+ disableRawHtml: true,
35
+ },
36
+ llm: {
37
+ hardBreaks: false,
38
+ enableHighlight: true,
39
+ enableStrikethrough: true,
40
+ enableUnderline: true,
41
+ enableTables: true,
42
+ enableAutolink: false,
43
+ enableTaskLists: true,
44
+ disableRawHtml: true,
45
+ enableHeadingIds: true,
46
+ enableIndentedCodeBlocks: true,
47
+ noHtmlBlocks: true,
48
+ noHtmlSpans: true,
49
+ tagFilter: true,
50
+ collapseWhitespace: true,
51
+ permissiveAtxHeaders: false,
52
+ enableWikiLinks: false,
53
+ enableLatexMath: false,
54
+ },
55
+ };
56
+
57
+ export function resolveOptions(options) {
58
+ if (options == null) return {};
59
+ const preset = options.preset != null ? (PRESETS[options.preset] ?? {}) : {};
60
+ const safe = options.safe === true ? PRESETS.safe : {};
61
+ const deterministic = options.deterministic === true ? { collapseWhitespace: true } : {};
62
+ const { preset: _p, safe: _s, deterministic: _d, stableAst: _a, ...rest } = options;
63
+ return { ...preset, ...safe, ...deterministic, ...rest };
64
+ }
65
+
14
66
  function optionArgs(markdown, options) {
67
+ const r = resolveOptions(options);
15
68
  return [
16
69
  toStr(markdown),
17
- options?.hardBreaks,
18
- options?.enableHighlight,
19
- options?.enableStrikethrough,
20
- options?.enableUnderline,
21
- options?.enableTables,
22
- options?.enableAutolink,
23
- options?.enableTaskLists,
24
- options?.disableRawHtml,
25
- options?.enableHeadingIds,
26
- options?.enableHeadingAnchors,
27
- options?.enableIndentedCodeBlocks,
28
- options?.noHtmlBlocks,
29
- options?.noHtmlSpans,
30
- options?.tagFilter,
31
- options?.collapseWhitespace,
32
- options?.permissiveAtxHeaders,
33
- options?.enableWikiLinks,
34
- options?.enableLatexMath,
70
+ r.hardBreaks,
71
+ r.enableHighlight,
72
+ r.enableStrikethrough,
73
+ r.enableUnderline,
74
+ r.enableTables,
75
+ r.enableAutolink,
76
+ r.enableTaskLists,
77
+ r.disableRawHtml,
78
+ r.enableHeadingIds,
79
+ r.enableHeadingAnchors,
80
+ r.enableIndentedCodeBlocks,
81
+ r.noHtmlBlocks,
82
+ r.noHtmlSpans,
83
+ r.tagFilter,
84
+ r.collapseWhitespace,
85
+ r.permissiveAtxHeaders,
86
+ r.enableWikiLinks,
87
+ r.enableLatexMath,
35
88
  ];
36
89
  }
37
90
 
38
- export function createParse(wasmParse, wasmParseDefault = null) {
39
- return function parse(markdown, options) {
40
- const input = toStr(markdown);
41
- if (options == null) {
42
- if (wasmParseDefault) return wasmParseDefault(input);
43
- return wasmParse(
44
- input,
45
- undefined,
46
- undefined,
47
- undefined,
48
- undefined,
49
- undefined,
50
- undefined,
51
- undefined,
52
- undefined,
53
- undefined,
54
- undefined,
55
- undefined,
56
- undefined,
57
- undefined,
58
- undefined,
59
- undefined,
60
- undefined,
61
- undefined,
62
- undefined,
63
- );
64
- }
91
+ // ─── Public API factories ─────────────────────────────────────────────────────
92
+
93
+ export function createParseMarkdown(wasmParseToAst) {
94
+ return function parseMarkdown(input, options) {
95
+ return JSON.parse(wasmParseToAst(...optionArgs(input, options)));
96
+ };
97
+ }
98
+
99
+ export function createRenderHtml(wasmParse, wasmParseDefault = null) {
100
+ return function renderHtml(input, options) {
101
+ if (options == null && wasmParseDefault) return wasmParseDefault(toStr(input));
65
102
  return wasmParse(...optionArgs(input, options));
66
103
  };
67
104
  }
68
105
 
69
- export function createParseToAst(wasmParseToAst) {
70
- return function parseToAst(markdown, options) {
71
- const input = toStr(markdown);
72
- if (options == null) {
73
- return wasmParseToAst(
74
- input,
75
- undefined,
76
- undefined,
77
- undefined,
78
- undefined,
79
- undefined,
80
- undefined,
81
- undefined,
82
- undefined,
83
- undefined,
84
- undefined,
85
- undefined,
86
- undefined,
87
- undefined,
88
- undefined,
89
- undefined,
90
- undefined,
91
- undefined,
92
- undefined,
93
- );
94
- }
95
- return wasmParseToAst(...optionArgs(input, options));
106
+ export function createRenderMarkdown(wasmRenderMarkdown) {
107
+ return function renderMarkdown(ast) {
108
+ const json =
109
+ Array.isArray(ast) || (typeof ast === "object" && ast !== null) ? JSON.stringify(ast) : ast;
110
+ return wasmRenderMarkdown(json);
96
111
  };
97
112
  }
98
113
 
99
- export function createRenderAnsi(wasmRenderAnsi) {
100
- return function renderAnsi(markdown, options, ansiOptions) {
114
+ export function createRenderAnsiTerminal(wasmRenderAnsi) {
115
+ return function renderAnsiTerminal(input, options, ansiOptions) {
101
116
  return wasmRenderAnsi(
102
- ...optionArgs(markdown, options),
103
- // width is plain u32 (not Option): 0 = use default (80)
117
+ ...optionArgs(input, options),
104
118
  ansiOptions?.width ?? 0,
105
119
  ansiOptions?.color,
106
120
  ansiOptions?.lineNumbers,
@@ -111,7 +125,7 @@ export function createRenderAnsi(wasmRenderAnsi) {
111
125
 
112
126
  export function createParseHtmlToAst(wasmParseHtmlToAst) {
113
127
  return function parseHtmlToAst(html, preserveUnknownAsHtml) {
114
- return wasmParseHtmlToAst(html, preserveUnknownAsHtml);
128
+ return JSON.parse(wasmParseHtmlToAst(html, preserveUnknownAsHtml));
115
129
  };
116
130
  }
117
131
 
@@ -121,8 +135,115 @@ export function createHtmlToMarkdown(wasmHtmlToMarkdown) {
121
135
  };
122
136
  }
123
137
 
124
- export function createRenderMarkdown(wasmRenderMarkdown) {
125
- return function renderMarkdown(astJson) {
126
- return wasmRenderMarkdown(astJson);
138
+ // ─── Introspection helpers ────────────────────────────────────────────────────
139
+
140
+ export const AST_SCHEMA_VERSION = "2";
141
+
142
+ export function getCapabilities() {
143
+ return {
144
+ astSchemaVersion: AST_SCHEMA_VERSION,
145
+ formats: ["html", "ast", "markdown", "ansi"],
146
+ presets: Object.keys(PRESETS),
147
+ extensions: [
148
+ "hardBreaks",
149
+ "enableHighlight",
150
+ "enableStrikethrough",
151
+ "enableUnderline",
152
+ "enableTables",
153
+ "enableAutolink",
154
+ "enableTaskLists",
155
+ "enableHeadingIds",
156
+ "enableHeadingAnchors",
157
+ "enableIndentedCodeBlocks",
158
+ "enableWikiLinks",
159
+ "enableLatexMath",
160
+ ],
161
+ security: ["disableRawHtml", "noHtmlBlocks", "noHtmlSpans", "tagFilter"],
127
162
  };
128
163
  }
164
+
165
+ export function getAstSchemaVersion() {
166
+ return AST_SCHEMA_VERSION;
167
+ }
168
+
169
+ export function getDefaultOptions() {
170
+ return {
171
+ hardBreaks: true,
172
+ enableHighlight: true,
173
+ enableStrikethrough: true,
174
+ enableUnderline: true,
175
+ enableTables: true,
176
+ enableAutolink: true,
177
+ enableTaskLists: true,
178
+ disableRawHtml: false,
179
+ enableHeadingIds: false,
180
+ enableHeadingAnchors: false,
181
+ enableIndentedCodeBlocks: true,
182
+ noHtmlBlocks: false,
183
+ noHtmlSpans: false,
184
+ tagFilter: false,
185
+ collapseWhitespace: false,
186
+ permissiveAtxHeaders: false,
187
+ enableWikiLinks: false,
188
+ enableLatexMath: false,
189
+ };
190
+ }
191
+
192
+ export function getPresets() {
193
+ return structuredClone(PRESETS);
194
+ }
195
+
196
+ // ─── Utility functions ────────────────────────────────────────────────────────
197
+
198
+ export function extractHeadings(ast) {
199
+ const headings = [];
200
+ const blocks = Array.isArray(ast) ? ast : (ast?.children ?? []);
201
+ function walk(nodes) {
202
+ for (const node of nodes) {
203
+ if (node?.t === "Heading" || node?.type === "Heading") {
204
+ const level = node.level ?? node.l ?? 1;
205
+ const text = extractText(node.children ?? node.c ?? []);
206
+ headings.push({ level, text, id: slugify(text) });
207
+ }
208
+ const children = node?.children ?? node?.c ?? node?.items ?? [];
209
+ if (Array.isArray(children)) walk(children);
210
+ }
211
+ }
212
+ walk(blocks);
213
+ return headings;
214
+ }
215
+
216
+ function extractText(nodes) {
217
+ if (!Array.isArray(nodes)) return String(nodes ?? "");
218
+ return nodes
219
+ .map((n) => {
220
+ if (typeof n === "string") return n;
221
+ const t = n?.t ?? n?.type ?? "";
222
+ if (t === "Text" || t === "Code") return n.text ?? n.value ?? "";
223
+ return extractText(n?.children ?? n?.c ?? []);
224
+ })
225
+ .join("");
226
+ }
227
+
228
+ function slugify(text) {
229
+ return text
230
+ .toLowerCase()
231
+ .replace(/[^\w\s-]/g, "")
232
+ .trim()
233
+ .replace(/[\s_]+/g, "-");
234
+ }
235
+
236
+ export function summarizeAst(ast) {
237
+ const counts = {};
238
+ const blocks = Array.isArray(ast) ? ast : (ast?.children ?? []);
239
+ function walk(nodes) {
240
+ for (const node of nodes) {
241
+ const t = node?.t ?? node?.type ?? "Unknown";
242
+ counts[t] = (counts[t] ?? 0) + 1;
243
+ const children = node?.children ?? node?.c ?? node?.items ?? [];
244
+ if (Array.isArray(children)) walk(children);
245
+ }
246
+ }
247
+ walk(blocks);
248
+ return { blockCount: blocks.length, nodeCounts: counts };
249
+ }
package/wasm/web.js CHANGED
@@ -1,11 +1,17 @@
1
1
  import * as wasmGlue from "./pkg/ironmark_bg.js";
2
2
  import {
3
- createParse,
4
- createParseToAst,
5
- createRenderAnsi,
3
+ createParseMarkdown,
4
+ createRenderHtml,
5
+ createRenderMarkdown,
6
+ createRenderAnsiTerminal,
6
7
  createParseHtmlToAst,
7
8
  createHtmlToMarkdown,
8
- createRenderMarkdown,
9
+ getCapabilities,
10
+ getAstSchemaVersion,
11
+ getDefaultOptions,
12
+ getPresets,
13
+ extractHeadings,
14
+ summarizeAst,
9
15
  } from "./shared.js";
10
16
 
11
17
  let initialized = false;
@@ -34,9 +40,12 @@ export async function init(input) {
34
40
  initialized = true;
35
41
  }
36
42
 
37
- export const parse = createParse(wasmGlue.parse, wasmGlue.parseDefault);
38
- export const parseToAst = createParseToAst(wasmGlue.parseToAst);
39
- export const renderAnsi = createRenderAnsi(wasmGlue.renderAnsi);
43
+ export const parseMarkdown = createParseMarkdown(wasmGlue.parseToAst);
44
+ export const renderHtml = createRenderHtml(wasmGlue.parse, wasmGlue.parseDefault);
45
+ export const renderMarkdown = createRenderMarkdown(wasmGlue.renderMarkdown);
46
+ export const renderAnsiTerminal = createRenderAnsiTerminal(wasmGlue.renderAnsi);
40
47
  export const parseHtmlToAst = createParseHtmlToAst(wasmGlue.parseHtmlToAst);
41
48
  export const htmlToMarkdown = createHtmlToMarkdown(wasmGlue.htmlToMarkdown);
42
- export const renderMarkdown = createRenderMarkdown(wasmGlue.renderMarkdown);
49
+
50
+ export { getCapabilities, getAstSchemaVersion, getDefaultOptions, getPresets };
51
+ export { extractHeadings, summarizeAst };