auwla-markdown 0.0.2 → 0.0.4

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.
@@ -0,0 +1,10 @@
1
+ import type { HighlighterAdapter } from '../types';
2
+ import type { BundledLanguage, BundledTheme } from 'shiki';
3
+ export interface ShikiAdapterOptions {
4
+ theme?: BundledTheme | {
5
+ light: BundledTheme;
6
+ dark: BundledTheme;
7
+ };
8
+ langs?: BundledLanguage[];
9
+ }
10
+ export declare function shikiHighlighter(options?: ShikiAdapterOptions): HighlighterAdapter;
@@ -0,0 +1,3 @@
1
+ import type { MarkdownConfig, MarkdownEngine } from './types';
2
+ /** Configures and returns an isolated instance of the Markdown parsing engine. */
3
+ export declare function createMDConfig(config?: MarkdownConfig): MarkdownEngine;
@@ -0,0 +1,11 @@
1
+ import type { ComponentRenderer, MarkdownFeatures } from './types';
2
+ export declare const defaultComponents: Record<string, ComponentRenderer>;
3
+ /**
4
+ * Preprocesses component-like tags (=<TagName>) inside a raw markdown string.
5
+ * Looks up default and custom components, compiles, and injects HTML.
6
+ */
7
+ export declare function preprocessComponents(rawMarkdown: string, parseFn: (str: string) => Promise<string>, parseInlineFn: (str: string) => Promise<string>, features?: MarkdownFeatures, customComponents?: Record<string, ComponentRenderer>): Promise<string>;
8
+ /** Custom Marked renderer for a button that copies code snippets to clipboard. */
9
+ export declare function copyCodeButtonRenderer(info: any): string;
10
+ /** Custom Marked renderer for adding hoverable anchors pointing to header IDs. */
11
+ export declare function headerAnchorsRenderer(this: any, info: any): string;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Parses header-based metadata blocks (e.g. key: value lines enclosed within =<Header> ... =</Header> tags)
3
+ * at the top of a Markdown document and removes them from the parsed content body.
4
+ */
5
+ export declare function extractFrontmatter(rawString: string): {
6
+ content: string;
7
+ meta: Record<string, any>;
8
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Scans a Markdown content string and extracts all headings (level 1-6)
3
+ * to populate the table of contents. Supports both standard # headers and custom tag-based headings (=<h1>...=</h1>).
4
+ */
5
+ export declare function extractHeadings(content: string): Array<{
6
+ level: number;
7
+ text: string;
8
+ id: string;
9
+ }>;
package/dist/index.js ADDED
@@ -0,0 +1,435 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ // src/engine.ts
5
+ import { Marked } from "marked";
6
+ import { markedHighlight } from "marked-highlight";
7
+
8
+ // src/frontmatter.ts
9
+ function extractFrontmatter(rawString) {
10
+ const match = rawString.match(/^=<Header(?:[^>]*)>\r?\n([\s\S]*?)\r?\n=<\/Header>\r?\n([\s\S]*)$/);
11
+ if (!match)
12
+ return { content: rawString, meta: {} };
13
+ const rawMeta = match[1];
14
+ const content = match[2];
15
+ const meta = {};
16
+ for (const line of rawMeta.split(`
17
+ `)) {
18
+ const sep = line.indexOf(":");
19
+ if (sep === -1)
20
+ continue;
21
+ const key = line.slice(0, sep).trim();
22
+ const val = line.slice(sep + 1).trim();
23
+ if (val === "true") {
24
+ meta[key] = true;
25
+ } else if (val === "false") {
26
+ meta[key] = false;
27
+ } else if (!isNaN(Number(val)) && val !== "") {
28
+ meta[key] = Number(val);
29
+ } else {
30
+ meta[key] = val.replace(/^["']|["']$/g, "");
31
+ }
32
+ }
33
+ return { content, meta };
34
+ }
35
+
36
+ // src/headings.ts
37
+ function extractHeadings(content) {
38
+ const headings = [];
39
+ const lines = content.split(`
40
+ `);
41
+ let inCodeBlock = false;
42
+ for (const line of lines) {
43
+ const trimmed = line.trim();
44
+ if (trimmed.startsWith("```")) {
45
+ inCodeBlock = !inCodeBlock;
46
+ continue;
47
+ }
48
+ if (inCodeBlock)
49
+ continue;
50
+ const tagMatch = trimmed.match(/^=<h([1-6])(?:[^>]*?)>(.*?)=<\/h\1>$/);
51
+ if (tagMatch) {
52
+ const level = parseInt(tagMatch[1], 10);
53
+ const text = tagMatch[2].trim();
54
+ const id = text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-");
55
+ headings.push({ level, text, id });
56
+ continue;
57
+ }
58
+ const match = line.match(/^(#{1,6})\s+(.+)$/);
59
+ if (match) {
60
+ const level = match[1].length;
61
+ const text = match[2].trim();
62
+ const id = text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-");
63
+ headings.push({ level, text, id });
64
+ }
65
+ }
66
+ return headings;
67
+ }
68
+
69
+ // src/features.ts
70
+ var inlineWrapperTags = new Set(["h1", "h2", "h3", "h4", "h5", "h6", "p", "span", "a", "li"]);
71
+ var defaultComponents = {
72
+ Callout: async (props, rawContent, parse, parseInline, features) => {
73
+ const type = props.type || "note";
74
+ const title = props.title || type.toUpperCase();
75
+ const htmlContent = await parse(rawContent);
76
+ const isCollapsible = "collapsible" in props && props.collapsible !== "false";
77
+ const isCollapsed = props.collapsed === "true";
78
+ const customClass = props.class ? ` ${props.class}` : "";
79
+ const className = `callout callout-${type.toLowerCase()}${customClass}`;
80
+ const otherAttrs = Object.entries(props).filter(([k]) => !["value", "type", "title", "collapsible", "collapsed", "class"].includes(k)).map(([k, v]) => `${k}="${v}"`).join(" ");
81
+ const attrString = otherAttrs ? ` ${otherAttrs}` : "";
82
+ if (isCollapsible) {
83
+ const openAttr = isCollapsed ? "" : " open";
84
+ return `<details class="${className}"${openAttr}${attrString}><summary class="callout-title">${title}</summary><div class="callout-content">${htmlContent}</div></details>`;
85
+ }
86
+ return `<div class="${className}"${attrString}><div class="callout-title">${title}</div><div class="callout-content">${htmlContent}</div></div>`;
87
+ },
88
+ Tabs: async (props, rawContent, parse, parseInline, features) => {
89
+ const content = await parse(rawContent);
90
+ const regex = /<div class="tab-panel[^"]*"\s+data-title="([^"]*)"/g;
91
+ const titles = [];
92
+ let match;
93
+ while ((match = regex.exec(content)) !== null) {
94
+ titles.push(match[1]);
95
+ }
96
+ if (titles.length === 0)
97
+ return content;
98
+ const tabButtons = titles.map((title, idx) => {
99
+ const activeClass = idx === 0 ? "active" : "";
100
+ const clickHandler = `const c = this.closest('.tabs-container'); c.querySelectorAll('.tab-btn').forEach((b, i) => { b.classList.toggle('active', b === this); c.querySelectorAll('.tab-panel')[i].style.display = (b === this) ? 'block' : 'none'; })`;
101
+ return `<button class="tab-btn ${activeClass}" onclick="${clickHandler}">${title}</button>`;
102
+ }).join("");
103
+ let panelIndex = 0;
104
+ const adjustedContent = content.replace(/class="tab-panel([^"]*)"/g, (match2, customClasses) => {
105
+ const activeClass = panelIndex === 0 ? " active" : "";
106
+ const display = panelIndex === 0 ? "block" : "none";
107
+ panelIndex++;
108
+ return `class="tab-panel${customClasses}${activeClass}" style="display: ${display};"`;
109
+ });
110
+ const customClass = props.class ? ` ${props.class}` : "";
111
+ const className = `tabs-container${customClass}`;
112
+ const otherAttrs = Object.entries(props).filter(([k]) => !["value", "class"].includes(k)).map(([k, v]) => `${k}="${v}"`).join(" ");
113
+ const attrString = otherAttrs ? ` ${otherAttrs}` : "";
114
+ return `<div class="${className}"${attrString}><div class="tabs-header">${tabButtons}</div><div class="tabs-content">${adjustedContent}</div></div>`;
115
+ },
116
+ Tab: async (props, rawContent, parse, parseInline, features) => {
117
+ const title = props.title || "";
118
+ const content = await parse(rawContent);
119
+ const customClass = props.class ? ` ${props.class}` : "";
120
+ const className = `tab-panel${customClass}`;
121
+ const otherAttrs = Object.entries(props).filter(([k]) => !["value", "title", "class"].includes(k)).map(([k, v]) => `${k}="${v}"`).join(" ");
122
+ const attrString = otherAttrs ? ` ${otherAttrs}` : "";
123
+ return `<div class="${className}" data-title="${title}"${attrString}>${content}</div>`;
124
+ },
125
+ Table: async (props, rawContent, parse, parseInline, features) => {
126
+ const content = await parseInline(rawContent);
127
+ const defaultClass = "auwla-table";
128
+ const customClass = props.class ? ` ${props.class}` : "";
129
+ const mergedClass = `${defaultClass}${customClass}`;
130
+ const attrPairs = Object.entries(props).filter(([k]) => k !== "value" && k !== "class").map(([k, v]) => `${k}="${v}"`).join(" ");
131
+ const attrString = attrPairs ? ` ${attrPairs}` : "";
132
+ return `<table class="${mergedClass}"${attrString}>${content}</table>`;
133
+ },
134
+ Row: async (props, rawContent, parse, parseInline, features) => {
135
+ const content = await parseInline(rawContent);
136
+ const attrPairs = Object.entries(props).filter(([k]) => k !== "value").map(([k, v]) => `${k}="${v}"`).join(" ");
137
+ const attrString = attrPairs ? ` ${attrPairs}` : "";
138
+ return `<tr${attrString}>${content}</tr>`;
139
+ },
140
+ Column: async (props, rawContent, parse, parseInline, features) => {
141
+ const content = await parseInline(rawContent);
142
+ const attrPairs = Object.entries(props).filter(([k]) => k !== "value").map(([k, v]) => `${k}="${v}"`).join(" ");
143
+ const attrString = attrPairs ? ` ${attrPairs}` : "";
144
+ return `<th${attrString}>${content}</th>`;
145
+ },
146
+ Cell: async (props, rawContent, parse, parseInline, features) => {
147
+ const content = await parseInline(rawContent);
148
+ const attrPairs = Object.entries(props).filter(([k]) => k !== "value").map(([k, v]) => `${k}="${v}"`).join(" ");
149
+ const attrString = attrPairs ? ` ${attrPairs}` : "";
150
+ return `<td${attrString}>${content}</td>`;
151
+ }
152
+ };
153
+ function parseAttributes(attrString) {
154
+ const attrs = {};
155
+ const trimmed = attrString.trim();
156
+ if (!trimmed)
157
+ return attrs;
158
+ if (trimmed.startsWith("=")) {
159
+ const match2 = trimmed.match(/^=\s*(?:"(.*?)"|'(.*?)'|([^\s>]+))/);
160
+ if (match2) {
161
+ attrs.value = match2[1] ?? match2[2] ?? match2[3] ?? "";
162
+ return attrs;
163
+ }
164
+ }
165
+ const regex = /(\w+)(?:\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]+)))?/g;
166
+ let match;
167
+ while ((match = regex.exec(attrString)) !== null) {
168
+ const key = match[1];
169
+ const val = match[2] ?? match[3] ?? match[4] ?? "true";
170
+ attrs[key] = val;
171
+ }
172
+ return attrs;
173
+ }
174
+ async function renderComponent(tagName, props, rawContent, parseFn, parseInlineFn, features, customComponents) {
175
+ if (customComponents[tagName]) {
176
+ return await customComponents[tagName](props, rawContent, parseFn, parseInlineFn, features);
177
+ }
178
+ if (defaultComponents[tagName]) {
179
+ return await defaultComponents[tagName](props, rawContent, parseFn, parseInlineFn, features);
180
+ }
181
+ const isInline = inlineWrapperTags.has(tagName.toLowerCase());
182
+ const compiledContent = isInline ? await parseInlineFn(rawContent) : await parseFn(rawContent);
183
+ if (isInline && tagName.toLowerCase().startsWith("h") && tagName.length === 2 && !isNaN(Number(tagName.slice(1)))) {
184
+ const depth = tagName.toLowerCase().slice(1);
185
+ const plainText = compiledContent.replace(/<[^>]*>/g, "");
186
+ const id = props.id || plainText.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-");
187
+ const idAttr = `id="${id}"`;
188
+ const classAttr = props.class ? `class="${props.class}"` : "";
189
+ const otherAttrs = Object.entries(props).filter(([k]) => k !== "value" && k !== "id" && k !== "class").map(([k, v]) => `${k}="${v}"`).join(" ");
190
+ const attrString2 = [idAttr, classAttr, otherAttrs].filter(Boolean).map((s) => s.trim()).join(" ");
191
+ const finalAttrString = attrString2 ? ` ${attrString2}` : "";
192
+ if (features?.headerAnchors) {
193
+ return `<h${depth}${finalAttrString}><a href="#${id}" class="header-anchor" aria-hidden="true">#</a>${compiledContent}</h${depth}>`;
194
+ } else {
195
+ return `<h${depth}${finalAttrString}>${compiledContent}</h${depth}>`;
196
+ }
197
+ }
198
+ const attrPairs = Object.entries(props).filter(([k]) => k !== "value").map(([k, v]) => `${k}="${v}"`).join(" ");
199
+ const attrString = attrPairs ? ` ${attrPairs}` : "";
200
+ return `<${tagName}${attrString}>${compiledContent}</${tagName}>`;
201
+ }
202
+ async function preprocessComponents(rawMarkdown, parseFn, parseInlineFn, features = {}, customComponents = {}) {
203
+ const lines = rawMarkdown.split(`
204
+ `);
205
+ const result = [];
206
+ const stack = [];
207
+ for (const line of lines) {
208
+ const trimmed = line.trim();
209
+ const singleLineMatch = trimmed.match(/^=<(\w+)([^>]*?)>(.*?)=<\/\1>$/);
210
+ if (singleLineMatch) {
211
+ const tagName = singleLineMatch[1];
212
+ const attrString = singleLineMatch[2] || "";
213
+ const innerContent = singleLineMatch[3] || "";
214
+ const props = parseAttributes(attrString);
215
+ const html = await renderComponent(tagName, props, innerContent, parseFn, parseInlineFn, features, customComponents);
216
+ if (stack.length > 0) {
217
+ stack[stack.length - 1].contentLines.push(html);
218
+ } else {
219
+ result.push(html);
220
+ }
221
+ continue;
222
+ }
223
+ if (trimmed.startsWith("=<") && trimmed.endsWith("/>")) {
224
+ const match = trimmed.match(/^=<(\w+)([^>]*?)\/>$/);
225
+ if (match) {
226
+ const tagName = match[1];
227
+ const attrString = match[2] || "";
228
+ const props = parseAttributes(attrString);
229
+ const html = await renderComponent(tagName, props, "", parseFn, parseInlineFn, features, customComponents);
230
+ if (stack.length > 0) {
231
+ stack[stack.length - 1].contentLines.push(html);
232
+ } else {
233
+ result.push(html);
234
+ }
235
+ continue;
236
+ }
237
+ }
238
+ if (trimmed.startsWith("=<") && !trimmed.startsWith("=</") && trimmed.endsWith(">")) {
239
+ const match = trimmed.match(/^=<(\w+)([^>]*?)>$/);
240
+ if (match) {
241
+ const tagName = match[1];
242
+ const attrString = match[2] || "";
243
+ const props = parseAttributes(attrString);
244
+ stack.push({
245
+ tagName,
246
+ props,
247
+ contentLines: []
248
+ });
249
+ continue;
250
+ }
251
+ }
252
+ if (trimmed.startsWith("=</") && trimmed.endsWith(">")) {
253
+ const match = trimmed.match(/^=<\/(.*?)>$/);
254
+ if (match) {
255
+ const tagName = match[1].trim();
256
+ if (stack.length > 0 && stack[stack.length - 1].tagName === tagName) {
257
+ const block = stack.pop();
258
+ const rawContent = block.contentLines.join(`
259
+ `);
260
+ const html = await renderComponent(block.tagName, block.props, rawContent, parseFn, parseInlineFn, features, customComponents);
261
+ if (stack.length > 0) {
262
+ stack[stack.length - 1].contentLines.push(html);
263
+ } else {
264
+ result.push(html);
265
+ }
266
+ continue;
267
+ }
268
+ }
269
+ }
270
+ if (stack.length > 0) {
271
+ stack[stack.length - 1].contentLines.push(line);
272
+ } else {
273
+ result.push(line);
274
+ }
275
+ }
276
+ while (stack.length > 0) {
277
+ const block = stack.pop();
278
+ result.push(`=<${block.tagName}>`);
279
+ result.push(block.contentLines.join(`
280
+ `));
281
+ result.push(`=</${block.tagName}>`);
282
+ }
283
+ return result.join(`
284
+ `);
285
+ }
286
+ function extractRawCode(raw) {
287
+ if (raw.startsWith("```") || raw.startsWith("~~~")) {
288
+ const lines = raw.split(`
289
+ `);
290
+ return lines.slice(1, -1).join(`
291
+ `);
292
+ }
293
+ return raw;
294
+ }
295
+ function parseCodeMeta(langString) {
296
+ const parts = langString.trim().split(/\s+/);
297
+ const lang = parts[0] || "";
298
+ let filename;
299
+ const highlightedLines = new Set;
300
+ for (const part of parts.slice(1)) {
301
+ if (part.startsWith("[") && part.endsWith("]")) {
302
+ filename = part.slice(1, -1);
303
+ } else if (part.startsWith("{") && part.endsWith("}")) {
304
+ const ranges = part.slice(1, -1).split(",");
305
+ for (const range of ranges) {
306
+ if (range.includes("-")) {
307
+ const [startStr, endStr] = range.split("-");
308
+ const start = parseInt(startStr || "0", 10);
309
+ const end = parseInt(endStr || "0", 10);
310
+ if (!isNaN(start) && !isNaN(end)) {
311
+ for (let i = start;i <= end; i++) {
312
+ highlightedLines.add(i);
313
+ }
314
+ }
315
+ } else {
316
+ const val = parseInt(range, 10);
317
+ if (!isNaN(val)) {
318
+ highlightedLines.add(val);
319
+ }
320
+ }
321
+ }
322
+ }
323
+ }
324
+ return { lang, filename, highlightedLines };
325
+ }
326
+ function injectHighlightedLines(html, highlightedLines) {
327
+ if (highlightedLines.size === 0)
328
+ return html;
329
+ if (html.includes('class="line"')) {
330
+ let lineIndex = 0;
331
+ return html.replace(/class="line"/g, () => {
332
+ lineIndex++;
333
+ if (highlightedLines.has(lineIndex)) {
334
+ return 'class="line highlighted-line"';
335
+ }
336
+ return 'class="line"';
337
+ });
338
+ }
339
+ const lines = html.split(`
340
+ `);
341
+ const processed = lines.map((line, idx) => {
342
+ const lineNum = idx + 1;
343
+ if (highlightedLines.has(lineNum)) {
344
+ return `<div class="highlighted-line">${line}</div>`;
345
+ }
346
+ return line;
347
+ });
348
+ return processed.join(`
349
+ `);
350
+ }
351
+ function copyCodeButtonRenderer(info) {
352
+ const rawCode = extractRawCode(info.raw);
353
+ const escapedCode = encodeURIComponent(rawCode).replace(/'/g, "%27");
354
+ const { lang, filename, highlightedLines } = parseCodeMeta(info.lang ?? "");
355
+ let codeContent = info.text.trim().startsWith("<pre") ? info.text : `<pre><code class="language-${lang}">${info.text}</code></pre>`;
356
+ codeContent = injectHighlightedLines(codeContent, highlightedLines);
357
+ const filenameHeader = filename ? `<div class="code-block-filename">${filename}</div>` : "";
358
+ return `<div class="code-block-wrapper" style="position: relative;">${filenameHeader}<button onclick="navigator.clipboard.writeText(decodeURIComponent('${escapedCode}')); this.textContent = 'Copied!'; setTimeout(() => this.textContent = 'Copy', 2000)" class="copy-code-btn" style="position: absolute; right: 0.5rem; top: ${filename ? "2.5rem" : "0.5rem"}; z-index: 10;">Copy</button>${codeContent}</div>`;
359
+ }
360
+ function headerAnchorsRenderer(info) {
361
+ const text = info.text ?? (this.parser ? this.parser.parseInline(info.tokens) : info.raw);
362
+ const depth = info.depth;
363
+ const id = text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-");
364
+ return `<h${depth} id="${id}"><a href="#${id}" class="header-anchor" aria-hidden="true">#</a>${text}</h${depth}>`;
365
+ }
366
+
367
+ // src/engine.ts
368
+ function createMDConfig(config = {}) {
369
+ const markedInstance = new Marked({
370
+ gfm: true
371
+ });
372
+ if (config.highlighter) {
373
+ markedInstance.use(markedHighlight({
374
+ async: true,
375
+ highlight: async (code, lang) => {
376
+ if (!lang)
377
+ return code;
378
+ return await config.highlighter(code, lang);
379
+ }
380
+ }));
381
+ }
382
+ const customRenderer = {};
383
+ if (config.features?.headerAnchors) {
384
+ customRenderer.heading = headerAnchorsRenderer;
385
+ }
386
+ if (config.features?.copyCodeButton) {
387
+ customRenderer.code = copyCodeButtonRenderer;
388
+ }
389
+ if (Object.keys(customRenderer).length > 0) {
390
+ markedInstance.use({ renderer: customRenderer });
391
+ }
392
+ return {
393
+ parse: async (rawString) => {
394
+ let { content, meta } = extractFrontmatter(rawString);
395
+ const headings = extractHeadings(content);
396
+ content = await preprocessComponents(content, async (str) => await markedInstance.parse(str), async (str) => await markedInstance.parseInline(str), config.features, config.components);
397
+ const html = await markedInstance.parse(content);
398
+ return {
399
+ html,
400
+ meta,
401
+ headings
402
+ };
403
+ }
404
+ };
405
+ }
406
+ // src/adapters/shiki.ts
407
+ function shikiHighlighter(options = {}) {
408
+ let shikiInstance = null;
409
+ const theme = options.theme || "github-dark";
410
+ return async (code, language) => {
411
+ const { createHighlighter } = await import("shiki");
412
+ if (!shikiInstance) {
413
+ shikiInstance = await createHighlighter({
414
+ themes: typeof theme === "string" ? [theme] : [theme.light, theme.dark],
415
+ langs: options.langs || [language, "javascript", "typescript", "bash", "html", "css"]
416
+ });
417
+ }
418
+ if (!shikiInstance.getLoadedLanguages().includes(language)) {
419
+ await shikiInstance.loadLanguage(language).catch(() => {});
420
+ }
421
+ const shikiOptions = {
422
+ lang: language
423
+ };
424
+ if (typeof theme === "string") {
425
+ shikiOptions.theme = theme;
426
+ } else {
427
+ shikiOptions.themes = theme;
428
+ }
429
+ return shikiInstance.codeToHtml(code, shikiOptions);
430
+ };
431
+ }
432
+ export {
433
+ shikiHighlighter,
434
+ createMDConfig
435
+ };
@@ -0,0 +1,25 @@
1
+ export type HighlighterAdapter = (code: string, language: string) => Promise<string> | string;
2
+ export interface MarkdownFeatures {
3
+ copyCodeButton?: boolean;
4
+ tabs?: boolean;
5
+ callouts?: boolean;
6
+ headerAnchors?: boolean;
7
+ }
8
+ export type ComponentRenderer = (props: Record<string, string>, rawContent: string, parseFn: (str: string) => Promise<string>, parseInlineFn: (str: string) => Promise<string>, features?: MarkdownFeatures) => Promise<string> | string;
9
+ export interface MarkdownConfig {
10
+ highlighter?: HighlighterAdapter | false;
11
+ features?: MarkdownFeatures;
12
+ components?: Record<string, ComponentRenderer>;
13
+ }
14
+ export interface ParsedMarkdown {
15
+ html: string;
16
+ meta: Record<string, any>;
17
+ headings: Array<{
18
+ level: number;
19
+ text: string;
20
+ id: string;
21
+ }>;
22
+ }
23
+ export interface MarkdownEngine {
24
+ parse: (rawString: string) => Promise<ParsedMarkdown>;
25
+ }
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "auwla-markdown",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "type": "module",
8
+ "files": [
9
+ "dist"
10
+ ],
8
11
  "devDependencies": {
9
12
  "@types/bun": "latest",
10
13
  "@types/prismjs": "^1.26.6",
@@ -27,6 +30,6 @@
27
30
  "marked-highlight": "^2.2.4"
28
31
  },
29
32
  "scripts": {
30
- "build": "tsc --project tsconfig.lib.json"
33
+ "build": "bun -e \"import { rmSync } from 'fs'; rmSync('dist', { recursive: true, force: true })\" && bun build src/index.ts --outdir dist --target node --external shiki --external prismjs --external marked --external marked-highlight && tsc --project tsconfig.lib.json --emitDeclarationOnly"
31
34
  }
32
35
  }