@dogsbay/render-html 0.0.0-stage → 0.2.0-beta.116
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 +50 -2
- package/assets/favicon.svg +28 -0
- package/css/code-rich.css +88 -0
- package/css/docs.css +207 -0
- package/css/steps.css +149 -0
- package/css/theme-default.css +239 -0
- package/css/theme-mintlify.css +243 -0
- package/dist/alert-icons.d.ts +6 -0
- package/dist/alert-icons.js +22 -0
- package/dist/badge-variants.d.ts +19 -0
- package/dist/badge-variants.js +33 -0
- package/dist/code-markers.d.ts +29 -0
- package/dist/code-markers.js +66 -0
- package/dist/css-tools.d.ts +12 -0
- package/dist/css-tools.js +75 -0
- package/dist/favicon.d.ts +13 -0
- package/dist/favicon.js +13 -0
- package/dist/file-tree.d.ts +14 -0
- package/dist/file-tree.js +20 -0
- package/dist/html.d.ts +17 -0
- package/dist/html.js +53 -0
- package/dist/icons.d.ts +8 -0
- package/dist/icons.js +65 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -0
- package/dist/kbd-variants.d.ts +2 -0
- package/dist/kbd-variants.js +3 -0
- package/dist/lines.d.ts +62 -0
- package/dist/lines.js +119 -0
- package/dist/math.d.ts +1 -0
- package/dist/math.js +13 -0
- package/dist/render.d.ts +114 -0
- package/dist/render.js +830 -0
- package/dist/sanitize.d.ts +13 -0
- package/dist/sanitize.js +230 -0
- package/dist/tone-classes.d.ts +1 -0
- package/dist/tone-classes.js +15 -0
- package/dist/url.d.ts +10 -0
- package/dist/url.js +29 -0
- package/package.json +61 -3
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TreeNode } from "@dogsbay/types";
|
|
2
|
+
/** What sanitizing removed, by kind; the caller reports it (@dogsbay/render's report codes). */
|
|
3
|
+
export type SanitizeWarningCode = "html-sanitized" | "attribute-dropped" | "unsafe-url" | "image-remote";
|
|
4
|
+
export type Warn = (code: SanitizeWarningCode, message: string) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Whether a URL is safe to put in an href or src: http(s), mailto, a fragment,
|
|
7
|
+
* a relative path, or (for images only) a raster data: URI.
|
|
8
|
+
*/
|
|
9
|
+
export declare function safeUrl(raw: string, kind: "link" | "image"): boolean;
|
|
10
|
+
/** Raw HTML through the allowlist. Text is re-escaped; unknown elements keep their text. */
|
|
11
|
+
export declare function sanitizeHtml(html: string, warn: Warn): string;
|
|
12
|
+
/** A sanitized copy of the tree. */
|
|
13
|
+
export declare function sanitizeTree(nodes: TreeNode[], warn: Warn): TreeNode[];
|
package/dist/sanitize.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitizing for untrusted input, on the parsed tree rather than the output.
|
|
3
|
+
* render-html escapes everything it writes itself, so what can carry markup or
|
|
4
|
+
* script into the page is limited to:
|
|
5
|
+
* - raw HTML (`html` and `html-inline` nodes), filtered here to an allowlist
|
|
6
|
+
* of elements and attributes;
|
|
7
|
+
* - URLs (http, https, mailto, tel, relative, #) in directive attributes and inline links/images (`:::card{href}`,
|
|
8
|
+
* link buttons), which never pass markdown-it's link validation;
|
|
9
|
+
* - `class` and `style` from attribute blocks: a class like `bg-[url(…)]`
|
|
10
|
+
* becomes real CSS once the page's classes are compiled, and fetches.
|
|
11
|
+
* Shared by @dogsbay/render (single pages), dogsbay-ssg and the Astro pipeline
|
|
12
|
+
* (content.html: sanitize). In @dogsbay/render the page's CSP (document.ts) is the second line: it blocks scripts that are
|
|
13
|
+
* not ours and every external request, even if something gets past this.
|
|
14
|
+
*/
|
|
15
|
+
import { Parser } from "htmlparser2";
|
|
16
|
+
const ELEMENTS = new Set([
|
|
17
|
+
"a", "abbr", "b", "bdi", "bdo", "blockquote", "br", "caption", "cite", "code", "col", "colgroup",
|
|
18
|
+
"dd", "del", "details", "dfn", "div", "dl", "dt", "em", "figcaption", "figure",
|
|
19
|
+
"h1", "h2", "h3", "h4", "h5", "h6", "hr", "i", "img", "ins", "kbd", "li", "mark", "ol", "p", "pre",
|
|
20
|
+
"q", "rp", "rt", "ruby", "s", "samp", "small", "span", "strong", "sub", "summary", "sup",
|
|
21
|
+
"table", "tbody", "td", "tfoot", "th", "thead", "time", "tr", "u", "ul", "var", "wbr",
|
|
22
|
+
]);
|
|
23
|
+
/** Elements dropped together with everything inside them. */
|
|
24
|
+
const DROP_WITH_CONTENT = new Set(["script", "style", "iframe", "object", "embed", "template", "noscript", "svg", "math", "frame", "frameset", "noembed", "textarea", "select", "button", "form", "input"]);
|
|
25
|
+
const VOID = new Set(["br", "col", "hr", "img", "wbr"]);
|
|
26
|
+
const GLOBAL_ATTRS = new Set(["id", "title", "lang", "dir"]);
|
|
27
|
+
const ATTRS = {
|
|
28
|
+
a: new Set(["href", "rel"]),
|
|
29
|
+
img: new Set(["src", "alt", "width", "height"]),
|
|
30
|
+
td: new Set(["colspan", "rowspan", "headers"]),
|
|
31
|
+
th: new Set(["colspan", "rowspan", "headers", "scope"]),
|
|
32
|
+
col: new Set(["span"]),
|
|
33
|
+
colgroup: new Set(["span"]),
|
|
34
|
+
ol: new Set(["start", "reversed", "type"]),
|
|
35
|
+
li: new Set(["value"]),
|
|
36
|
+
time: new Set(["datetime"]),
|
|
37
|
+
details: new Set(["open"]),
|
|
38
|
+
q: new Set(["cite"]),
|
|
39
|
+
blockquote: new Set(["cite"]),
|
|
40
|
+
del: new Set(["cite", "datetime"]),
|
|
41
|
+
ins: new Set(["cite", "datetime"]),
|
|
42
|
+
};
|
|
43
|
+
const URL_ATTRS = new Set(["href", "src", "cite"]);
|
|
44
|
+
/** Node types whose `html` field is source text, not markup. */
|
|
45
|
+
const TEXT_HTML_TYPES = new Set(["code", "math", "math-block", "diagram"]);
|
|
46
|
+
/** Prop keys on directive nodes that hold a URL. */
|
|
47
|
+
const URL_PROPS = new Set(["href", "src", "url", "link", "poster", "image", "logo"]);
|
|
48
|
+
const escAttr = (s) => s.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
49
|
+
const escText = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
50
|
+
/** Ids the page's own components use (render-html RESERVED_ID): raw HTML may not take them. */
|
|
51
|
+
const RESERVED_ID = /^(db-|tab-\d|tabpanel-\d|acc-\d|accpanel-\d|fn-|fnref-)/;
|
|
52
|
+
/**
|
|
53
|
+
* Whether a URL is safe to put in an href or src: http(s), mailto, a fragment,
|
|
54
|
+
* a relative path, or (for images only) a raster data: URI.
|
|
55
|
+
*/
|
|
56
|
+
export function safeUrl(raw, kind) {
|
|
57
|
+
// Browsers ignore control characters and whitespace inside a scheme ("java\tscript:").
|
|
58
|
+
const v = raw.replace(/[\u0000- \u007f-\u009f]/g, "").toLowerCase();
|
|
59
|
+
const scheme = /^([a-z][a-z0-9+.-]*):/.exec(v)?.[1];
|
|
60
|
+
if (!scheme)
|
|
61
|
+
return !v.startsWith("//") || kind === "link"; // relative; protocol-relative only as a link
|
|
62
|
+
if (scheme === "http" || scheme === "https")
|
|
63
|
+
return true;
|
|
64
|
+
if ((scheme === "mailto" || scheme === "tel") && kind === "link")
|
|
65
|
+
return true;
|
|
66
|
+
if (scheme === "data" && kind === "image")
|
|
67
|
+
return /^data:image\/(png|jpeg|gif|webp);/.test(v);
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
/** Raw HTML through the allowlist. Text is re-escaped; unknown elements keep their text. */
|
|
71
|
+
export function sanitizeHtml(html, warn) {
|
|
72
|
+
// Inline raw HTML arrives one tag per node, so a closing tag is often alone; the
|
|
73
|
+
// parser ignores an unmatched closer, which would leave the allowed element open.
|
|
74
|
+
const closer = /^\s*<\/([a-zA-Z][a-zA-Z0-9]*)\s*>\s*$/.exec(html);
|
|
75
|
+
if (closer) {
|
|
76
|
+
const name = closer[1].toLowerCase();
|
|
77
|
+
return ELEMENTS.has(name) && !VOID.has(name) ? `</${name}>` : "";
|
|
78
|
+
}
|
|
79
|
+
let out = "";
|
|
80
|
+
let dropDepth = 0;
|
|
81
|
+
const dropped = new Set();
|
|
82
|
+
const parser = new Parser({
|
|
83
|
+
onopentag(name, attribs) {
|
|
84
|
+
if (dropDepth > 0 || DROP_WITH_CONTENT.has(name)) {
|
|
85
|
+
if (!VOID.has(name))
|
|
86
|
+
dropDepth++;
|
|
87
|
+
dropped.add(name);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (!ELEMENTS.has(name)) {
|
|
91
|
+
dropped.add(name);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const allowed = ATTRS[name];
|
|
95
|
+
let attrs = "";
|
|
96
|
+
for (const [k, v] of Object.entries(attribs)) {
|
|
97
|
+
const key = k.toLowerCase();
|
|
98
|
+
if (!GLOBAL_ATTRS.has(key) && !allowed?.has(key)) {
|
|
99
|
+
if (key.startsWith("on") || key === "style" || key === "class" || key === "srcset")
|
|
100
|
+
dropped.add(`${name}[${key}]`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (key === "id" && RESERVED_ID.test(v)) {
|
|
104
|
+
dropped.add(`${name}[id=${v.slice(0, 40)}]`);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (URL_ATTRS.has(key) && !safeUrl(v, name === "img" && key === "src" ? "image" : "link")) {
|
|
108
|
+
dropped.add(`${name}[${key}=${v.slice(0, 40)}]`);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (name === "img" && key === "src" && /^(https?:)?\/\//i.test(v))
|
|
112
|
+
warn("image-remote", `"${v.slice(0, 80)}" (raw HTML): remote images are not loaded`);
|
|
113
|
+
attrs += ` ${key}="${escAttr(v)}"`;
|
|
114
|
+
}
|
|
115
|
+
out += `<${name}${attrs}>`;
|
|
116
|
+
},
|
|
117
|
+
ontext(text) {
|
|
118
|
+
if (dropDepth === 0)
|
|
119
|
+
out += escText(text);
|
|
120
|
+
},
|
|
121
|
+
onclosetag(name, isImplied) {
|
|
122
|
+
if (dropDepth > 0) {
|
|
123
|
+
if (!VOID.has(name))
|
|
124
|
+
dropDepth--;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (ELEMENTS.has(name) && !VOID.has(name) && !isImplied)
|
|
128
|
+
out += `</${name}>`;
|
|
129
|
+
},
|
|
130
|
+
}, { decodeEntities: true, lowerCaseTags: true, lowerCaseAttributeNames: true, recognizeSelfClosing: true });
|
|
131
|
+
parser.write(html);
|
|
132
|
+
parser.end();
|
|
133
|
+
if (dropped.size)
|
|
134
|
+
warn("html-sanitized", `raw HTML: removed ${[...dropped].join(", ")}`);
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
function cleanProps(props, where, warn) {
|
|
138
|
+
if (!props)
|
|
139
|
+
return props;
|
|
140
|
+
const out = {};
|
|
141
|
+
for (const [k, v] of Object.entries(props)) {
|
|
142
|
+
// copyText would make the copy button copy something other than the code shown;
|
|
143
|
+
// data-* attributes can steer the page's element scripts; aria-* (aria-hidden) can
|
|
144
|
+
// hide content from assistive technology.
|
|
145
|
+
// svg: a diagram's prebuilt SVG is written as markup, unfiltered.
|
|
146
|
+
if (k === "class" || k === "className" || k === "style" || k === "svg" || k.startsWith("on") || k === "copyText" || k.startsWith("data-") || k.startsWith("aria-")) {
|
|
147
|
+
warn("attribute-dropped", `${where}: dropped the "${k}" attribute (not allowed in a sanitized page)`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// Footnote ids (fn-1, fnref-1) are the parser's own, not authored.
|
|
151
|
+
if (k === "id" && typeof v === "string" && RESERVED_ID.test(v) && !where.startsWith("footnote")) {
|
|
152
|
+
warn("attribute-dropped", `${where}: dropped id="${v.slice(0, 40)}" (reserved for the page's own components)`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (URL_PROPS.has(k) && typeof v === "string" && !safeUrl(v, k === "src" || k === "poster" || k === "image" || k === "logo" ? "image" : "link")) {
|
|
156
|
+
warn("unsafe-url", `${where}: removed ${k}="${v.slice(0, 60)}" (only http, https, mailto and relative links are allowed)`);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
out[k] = v;
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
/** An inline fragment that opens an element whose content is dropped: the name, unless it also closes it. */
|
|
164
|
+
function opensDropped(html) {
|
|
165
|
+
const m = /^\s*<([a-zA-Z][a-zA-Z0-9]*)\b[^>]*>/.exec(html);
|
|
166
|
+
if (!m)
|
|
167
|
+
return undefined;
|
|
168
|
+
const name = m[1].toLowerCase();
|
|
169
|
+
if (!DROP_WITH_CONTENT.has(name) || /\/>\s*$/.test(m[0]))
|
|
170
|
+
return undefined;
|
|
171
|
+
return new RegExp(`</${name}\\s*>`, "i").test(html) ? undefined : name;
|
|
172
|
+
}
|
|
173
|
+
function inline(nodes, warn) {
|
|
174
|
+
if (!nodes)
|
|
175
|
+
return nodes;
|
|
176
|
+
// Inline raw HTML is split into one node per tag, so `<script>` … `</script>` are
|
|
177
|
+
// separate nodes: everything between an opened dropped element and its closer goes too.
|
|
178
|
+
let skipping;
|
|
179
|
+
const kept = nodes.filter((n) => {
|
|
180
|
+
const html = n.type === "html-inline" ? String(n.html ?? "") : "";
|
|
181
|
+
if (skipping) {
|
|
182
|
+
if (new RegExp(`^\\s*</${skipping}\\s*>`, "i").test(html))
|
|
183
|
+
skipping = undefined;
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
if (html) {
|
|
187
|
+
const name = opensDropped(html);
|
|
188
|
+
if (name) {
|
|
189
|
+
warn("html-sanitized", `raw HTML: removed ${name}`);
|
|
190
|
+
skipping = name;
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return true;
|
|
195
|
+
});
|
|
196
|
+
return kept.map((n) => {
|
|
197
|
+
const node = { ...n };
|
|
198
|
+
if (node.type === "html-inline" && typeof node.html === "string")
|
|
199
|
+
node.html = sanitizeHtml(node.html, warn);
|
|
200
|
+
if (node.type === "link" && typeof node.href === "string" && !safeUrl(node.href, "link")) {
|
|
201
|
+
warn("unsafe-url", `link: removed href="${node.href.slice(0, 60)}"`);
|
|
202
|
+
node.href = "#";
|
|
203
|
+
}
|
|
204
|
+
if (node.type === "image" && typeof node.src === "string" && !safeUrl(node.src, "image")) {
|
|
205
|
+
warn("unsafe-url", `image: removed src="${node.src.slice(0, 60)}"`);
|
|
206
|
+
node.src = "";
|
|
207
|
+
}
|
|
208
|
+
if (node.attrs && typeof node.attrs === "object")
|
|
209
|
+
node.attrs = cleanProps(node.attrs, node.type, warn);
|
|
210
|
+
if (Array.isArray(node.children))
|
|
211
|
+
node.children = inline(node.children, warn);
|
|
212
|
+
return node;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/** A sanitized copy of the tree. */
|
|
216
|
+
export function sanitizeTree(nodes, warn) {
|
|
217
|
+
return nodes.map((n) => {
|
|
218
|
+
const node = { ...n };
|
|
219
|
+
// Any node carrying raw HTML (html, html-block, html-container under a <details>…).
|
|
220
|
+
// Code and math keep their source text in `html`; it is escaped when written.
|
|
221
|
+
if (typeof node.html === "string" && !TEXT_HTML_TYPES.has(node.type))
|
|
222
|
+
node.html = sanitizeHtml(node.html, warn);
|
|
223
|
+
node.props = cleanProps(node.props, node.type, warn);
|
|
224
|
+
if (node.inline)
|
|
225
|
+
node.inline = inline(node.inline, warn);
|
|
226
|
+
if (node.children)
|
|
227
|
+
node.children = sanitizeTree(node.children, warn);
|
|
228
|
+
return node;
|
|
229
|
+
});
|
|
230
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const TONE_CLASSES: Record<string, string>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Generated by packages/render-html/scripts/sync-sources.mjs from @dogsbay/format-astro TONE_CLASSES. Do not edit.
|
|
2
|
+
export const TONE_CLASSES = {
|
|
3
|
+
"primary": "bg-primary text-primary-foreground",
|
|
4
|
+
"primary-strong": "bg-primary/80 text-primary-foreground",
|
|
5
|
+
"primary-medium": "bg-primary/60 text-primary-foreground",
|
|
6
|
+
"primary-half": "bg-primary/50 text-primary-foreground",
|
|
7
|
+
"primary-light": "bg-primary/20 text-primary",
|
|
8
|
+
"primary-soft": "bg-primary/10 text-primary",
|
|
9
|
+
"muted": "bg-muted text-muted-foreground",
|
|
10
|
+
"blue": "bg-blue-500/15 text-blue-700 dark:text-blue-300",
|
|
11
|
+
"amber": "bg-amber-500/15 text-amber-700 dark:text-amber-300",
|
|
12
|
+
"green": "bg-green-500/15 text-green-700 dark:text-green-300",
|
|
13
|
+
"purple": "bg-purple-500/15 text-purple-700 dark:text-purple-300",
|
|
14
|
+
"red": "bg-red-500/15 text-red-700 dark:text-red-300"
|
|
15
|
+
};
|
package/dist/url.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A URL that runs script or carries a document of its own: javascript:, vbscript:,
|
|
3
|
+
* a data: link, or a data: "image" that is not an image. render-html
|
|
4
|
+
* refuses these wherever it writes a link or an image: they are never legitimate
|
|
5
|
+
* in docs, and directive attributes (`:::card{href}`) never meet markdown-it's link
|
|
6
|
+
* check. Other schemes (ftp:, vscode:) are allowed; the strict allowlist is
|
|
7
|
+
* `safeUrl` in ./sanitize.js. Character references are decoded first, for URLs
|
|
8
|
+
* taken from raw HTML.
|
|
9
|
+
*/
|
|
10
|
+
export declare function scriptUrl(raw: string, kind: "link" | "image"): boolean;
|
package/dist/url.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one URL check render-html applies whatever the caller's settings
|
|
3
|
+
* (dogsbay-ssg plans/html-safety.md): serialize-core's `isSafeHref`, the check the
|
|
4
|
+
* Astro serializer applies to the same links, so both pipelines refuse the same URLs.
|
|
5
|
+
*/
|
|
6
|
+
import { isSafeHref } from "@dogsbay/serialize-core";
|
|
7
|
+
/** Character references a browser decodes in an attribute before reading a scheme ("java	script:"). */
|
|
8
|
+
const SCHEME_REFS = /&(?:#(\d+)|#x([0-9a-f]+)|(tab|newline|colon));?/gi;
|
|
9
|
+
/**
|
|
10
|
+
* A URL that runs script or carries a document of its own: javascript:, vbscript:,
|
|
11
|
+
* a data: link, or a data: "image" that is not an image. render-html
|
|
12
|
+
* refuses these wherever it writes a link or an image: they are never legitimate
|
|
13
|
+
* in docs, and directive attributes (`:::card{href}`) never meet markdown-it's link
|
|
14
|
+
* check. Other schemes (ftp:, vscode:) are allowed; the strict allowlist is
|
|
15
|
+
* `safeUrl` in ./sanitize.js. Character references are decoded first, for URLs
|
|
16
|
+
* taken from raw HTML.
|
|
17
|
+
*/
|
|
18
|
+
export function scriptUrl(raw, kind) {
|
|
19
|
+
const v = raw.replace(SCHEME_REFS, (_, dec, hex, named) => {
|
|
20
|
+
if (named)
|
|
21
|
+
return { tab: "\t", newline: "\n", colon: ":" }[named.toLowerCase()];
|
|
22
|
+
const cp = Number.parseInt(dec ?? hex, dec ? 10 : 16);
|
|
23
|
+
return cp > 0 && cp <= 0x10ffff ? String.fromCodePoint(cp) : "";
|
|
24
|
+
});
|
|
25
|
+
// An <img> never runs script, SVG included, so any data:image/ is kept (isSafeHref allows raster only).
|
|
26
|
+
if (kind === "image" && /^data:image\//i.test(v.replace(/[\u0000-\u0020\u007f]+/g, "")))
|
|
27
|
+
return false;
|
|
28
|
+
return !isSafeHref(v, kind);
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,64 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/render-html",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0-beta.116",
|
|
4
|
+
"description": "Dogsbay MD TreeNode → HTML with the Astro components' markup and classes. No highlighter, math or CSS compiler unless you pass one; Worker- and browser-safe",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./math": {
|
|
14
|
+
"types": "./dist/math.d.ts",
|
|
15
|
+
"import": "./dist/math.js"
|
|
16
|
+
},
|
|
17
|
+
"./css/*": "./css/*",
|
|
18
|
+
"./assets/*": "./assets/*",
|
|
19
|
+
"./*": {
|
|
20
|
+
"types": "./dist/*.d.ts",
|
|
21
|
+
"import": "./dist/*.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"css",
|
|
27
|
+
"assets",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"htmlparser2": "^10.1.0",
|
|
32
|
+
"@dogsbay/format-dogsbay-md": "0.2.0-beta.116",
|
|
33
|
+
"@dogsbay/serialize-core": "0.2.0-beta.116",
|
|
34
|
+
"@dogsbay/types": "0.2.0-beta.116"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"katex": "^0.16.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependenciesMeta": {
|
|
40
|
+
"katex": {
|
|
41
|
+
"optional": true
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.20.1",
|
|
46
|
+
"esbuild": "^0.25.0",
|
|
47
|
+
"katex": "^0.16.47",
|
|
48
|
+
"typescript": "^5.9.3",
|
|
49
|
+
"vitest": "^4.1.10"
|
|
50
|
+
},
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "https://github.com/dogsbay/dogsbay.git",
|
|
55
|
+
"directory": "packages/render-html"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsc",
|
|
59
|
+
"sync-sources": "node scripts/sync-sources.mjs",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"test:watch": "vitest",
|
|
62
|
+
"typecheck": "tsc --noEmit"
|
|
63
|
+
}
|
|
6
64
|
}
|