@ai-matrx/print 0.8.7 → 0.8.8
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/CHANGELOG.md +25 -0
- package/dist/document.cjs +204 -3
- package/dist/document.cjs.map +1 -1
- package/dist/document.js +204 -3
- package/dist/document.js.map +1 -1
- package/dist/markdown.cjs +113 -6
- package/dist/markdown.cjs.map +1 -1
- package/dist/markdown.js +113 -6
- package/dist/markdown.js.map +1 -1
- package/dist/safe-html.cjs +231 -0
- package/dist/safe-html.cjs.map +1 -0
- package/dist/safe-html.d.cts +43 -0
- package/dist/safe-html.d.ts +43 -0
- package/dist/safe-html.js +210 -0
- package/dist/safe-html.js.map +1 -0
- package/package.json +17 -3
package/dist/document.js
CHANGED
|
@@ -87,6 +87,206 @@ function contentColumnWidths(b, n, avail, measure, pad = 10) {
|
|
|
87
87
|
|
|
88
88
|
// src/document/math.ts
|
|
89
89
|
import { listIslands, tokenizeSource } from "@ai-matrx/content-ir/source";
|
|
90
|
+
|
|
91
|
+
// src/safe-html.ts
|
|
92
|
+
import { fromHtml } from "hast-util-from-html";
|
|
93
|
+
import { defaultSchema, sanitize } from "hast-util-sanitize";
|
|
94
|
+
import { toHtml } from "hast-util-to-html";
|
|
95
|
+
var STRIP_WITH_CONTENT = [
|
|
96
|
+
"script",
|
|
97
|
+
"style",
|
|
98
|
+
"noscript",
|
|
99
|
+
"template",
|
|
100
|
+
"iframe",
|
|
101
|
+
"object",
|
|
102
|
+
"embed",
|
|
103
|
+
"textarea",
|
|
104
|
+
"select",
|
|
105
|
+
"head",
|
|
106
|
+
"title"
|
|
107
|
+
];
|
|
108
|
+
var FORBIDDEN_TAGS = [
|
|
109
|
+
...STRIP_WITH_CONTENT,
|
|
110
|
+
"form",
|
|
111
|
+
"meta",
|
|
112
|
+
"base",
|
|
113
|
+
"link",
|
|
114
|
+
"frame",
|
|
115
|
+
"frameset",
|
|
116
|
+
"applet",
|
|
117
|
+
"button",
|
|
118
|
+
"svg",
|
|
119
|
+
"math"
|
|
120
|
+
];
|
|
121
|
+
var baseAttributes = defaultSchema.attributes ?? {};
|
|
122
|
+
var SAFE_HTML_SCHEMA = {
|
|
123
|
+
...defaultSchema,
|
|
124
|
+
tagNames: (defaultSchema.tagNames ?? []).filter((t) => !FORBIDDEN_TAGS.includes(t)),
|
|
125
|
+
strip: STRIP_WITH_CONTENT,
|
|
126
|
+
// Authored anchors keep their names; the GitHub `user-content-` rewrite
|
|
127
|
+
// would also break `<label for>` → `<input id>` pairs.
|
|
128
|
+
clobberPrefix: "",
|
|
129
|
+
clobber: []
|
|
130
|
+
};
|
|
131
|
+
var PRINT_CLASS = /^(?:(?:matrx|print|code|doc|language)-[\w-]*|inline-code|is-checked)$/;
|
|
132
|
+
function withPrintClasses(defs = []) {
|
|
133
|
+
let found = false;
|
|
134
|
+
const out = defs.map((d) => {
|
|
135
|
+
if (Array.isArray(d) && d[0] === "className") {
|
|
136
|
+
found = true;
|
|
137
|
+
return [...d, PRINT_CLASS];
|
|
138
|
+
}
|
|
139
|
+
return d;
|
|
140
|
+
});
|
|
141
|
+
return found ? out : [...out, ["className", PRINT_CLASS]];
|
|
142
|
+
}
|
|
143
|
+
var printAttributes = Object.fromEntries(
|
|
144
|
+
Object.entries(baseAttributes).map(([tag, defs]) => [tag, withPrintClasses(defs)])
|
|
145
|
+
);
|
|
146
|
+
var cellAlign = ["style", /^text-align:\s*(?:left|center|right);?$/];
|
|
147
|
+
var PRINT_HTML_SCHEMA = {
|
|
148
|
+
...SAFE_HTML_SCHEMA,
|
|
149
|
+
tagNames: [
|
|
150
|
+
.../* @__PURE__ */ new Set([...SAFE_HTML_SCHEMA.tagNames ?? [], "section", "figure", "figcaption", "label"])
|
|
151
|
+
],
|
|
152
|
+
attributes: {
|
|
153
|
+
...printAttributes,
|
|
154
|
+
"*": [
|
|
155
|
+
...baseAttributes["*"] ?? [],
|
|
156
|
+
["className", PRINT_CLASS],
|
|
157
|
+
"role",
|
|
158
|
+
"ariaLabel",
|
|
159
|
+
"ariaHidden",
|
|
160
|
+
"dataLabel",
|
|
161
|
+
"dataLanguage",
|
|
162
|
+
"dataArtifactType"
|
|
163
|
+
],
|
|
164
|
+
// Table-cell alignment is the one inline style the converter writes.
|
|
165
|
+
td: withPrintClasses([...baseAttributes["td"] ?? [], [...cellAlign]]),
|
|
166
|
+
th: withPrintClasses([...baseAttributes["th"] ?? [], [...cellAlign]]),
|
|
167
|
+
// The flashcard flip is a checkbox + label pair (GitHub forces `disabled`).
|
|
168
|
+
input: withPrintClasses([["type", "checkbox"], "checked"]),
|
|
169
|
+
label: withPrintClasses(["htmlFor"])
|
|
170
|
+
},
|
|
171
|
+
required: { input: { type: "checkbox" } },
|
|
172
|
+
protocols: {
|
|
173
|
+
...defaultSchema.protocols,
|
|
174
|
+
href: [...defaultSchema.protocols?.href ?? [], "tel"],
|
|
175
|
+
// Embedded images (`data:image/png;base64,…`) — an <img> never runs script.
|
|
176
|
+
src: [...defaultSchema.protocols?.src ?? [], "data"]
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
function sanitizeHtmlFragment(html, schema = SAFE_HTML_SCHEMA) {
|
|
180
|
+
if (!html) return "";
|
|
181
|
+
const tree = sanitize(fromHtml(html, { fragment: true }), schema);
|
|
182
|
+
return toHtml(tree, { characterReferences: { useNamedReferences: true } });
|
|
183
|
+
}
|
|
184
|
+
var MATHML_TAGS = [
|
|
185
|
+
"math",
|
|
186
|
+
"maction",
|
|
187
|
+
"annotation",
|
|
188
|
+
"menclose",
|
|
189
|
+
"merror",
|
|
190
|
+
"mfrac",
|
|
191
|
+
"mglyph",
|
|
192
|
+
"mi",
|
|
193
|
+
"mlabeledtr",
|
|
194
|
+
"mmultiscripts",
|
|
195
|
+
"mn",
|
|
196
|
+
"mo",
|
|
197
|
+
"mover",
|
|
198
|
+
"mpadded",
|
|
199
|
+
"mphantom",
|
|
200
|
+
"mprescripts",
|
|
201
|
+
"none",
|
|
202
|
+
"mroot",
|
|
203
|
+
"mrow",
|
|
204
|
+
"ms",
|
|
205
|
+
"mspace",
|
|
206
|
+
"msqrt",
|
|
207
|
+
"mstyle",
|
|
208
|
+
"msub",
|
|
209
|
+
"msubsup",
|
|
210
|
+
"msup",
|
|
211
|
+
"mtable",
|
|
212
|
+
"mtd",
|
|
213
|
+
"mtext",
|
|
214
|
+
"mtr",
|
|
215
|
+
"munder",
|
|
216
|
+
"munderover",
|
|
217
|
+
"semantics"
|
|
218
|
+
];
|
|
219
|
+
var MATHML_ATTRIBUTES = [
|
|
220
|
+
"xmlns",
|
|
221
|
+
"display",
|
|
222
|
+
"displaystyle",
|
|
223
|
+
"mathvariant",
|
|
224
|
+
"mathsize",
|
|
225
|
+
"mathcolor",
|
|
226
|
+
"mathbackground",
|
|
227
|
+
"scriptlevel",
|
|
228
|
+
"dir",
|
|
229
|
+
"fence",
|
|
230
|
+
"form",
|
|
231
|
+
"largeop",
|
|
232
|
+
"lspace",
|
|
233
|
+
"rspace",
|
|
234
|
+
"movablelimits",
|
|
235
|
+
"separator",
|
|
236
|
+
"stretchy",
|
|
237
|
+
"symmetric",
|
|
238
|
+
"maxsize",
|
|
239
|
+
"minsize",
|
|
240
|
+
"accent",
|
|
241
|
+
"accentunder",
|
|
242
|
+
"align",
|
|
243
|
+
"columnalign",
|
|
244
|
+
"rowalign",
|
|
245
|
+
"columnspacing",
|
|
246
|
+
"rowspacing",
|
|
247
|
+
"columnlines",
|
|
248
|
+
"rowlines",
|
|
249
|
+
"frame",
|
|
250
|
+
"framespacing",
|
|
251
|
+
"equalrows",
|
|
252
|
+
"equalcolumns",
|
|
253
|
+
"linethickness",
|
|
254
|
+
"numalign",
|
|
255
|
+
"denomalign",
|
|
256
|
+
"bevelled",
|
|
257
|
+
"notation",
|
|
258
|
+
"width",
|
|
259
|
+
"height",
|
|
260
|
+
"depth",
|
|
261
|
+
"voffset",
|
|
262
|
+
"lquote",
|
|
263
|
+
"rquote",
|
|
264
|
+
"columnspan",
|
|
265
|
+
"rowspan",
|
|
266
|
+
"encoding",
|
|
267
|
+
"open",
|
|
268
|
+
"close",
|
|
269
|
+
"separators",
|
|
270
|
+
"actiontype",
|
|
271
|
+
"selection",
|
|
272
|
+
"mslinebreak",
|
|
273
|
+
"linebreak",
|
|
274
|
+
"indentalign",
|
|
275
|
+
"data*"
|
|
276
|
+
];
|
|
277
|
+
var MATHML_SCHEMA = {
|
|
278
|
+
tagNames: MATHML_TAGS,
|
|
279
|
+
attributes: { "*": MATHML_ATTRIBUTES },
|
|
280
|
+
strip: ["script", "style"],
|
|
281
|
+
clobberPrefix: "",
|
|
282
|
+
clobber: [],
|
|
283
|
+
protocols: {}
|
|
284
|
+
};
|
|
285
|
+
function sanitizeMathml(mathml) {
|
|
286
|
+
return sanitizeHtmlFragment(mathml, MATHML_SCHEMA);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// src/document/math.ts
|
|
90
290
|
var MATH_OPEN = "\uE100";
|
|
91
291
|
var MATH_CLOSE = "\uE101";
|
|
92
292
|
var MATH_TOKEN_RE = /\uE100(\d+)\uE101/g;
|
|
@@ -153,10 +353,10 @@ async function typesetMathSpans(spans) {
|
|
|
153
353
|
const mathml = mj.mml(s.tex, s.display);
|
|
154
354
|
const err = /<merror[\s\S]*?<mtext[^>]*>([\s\S]*?)<\/mtext>/.exec(mathml);
|
|
155
355
|
if (err) {
|
|
156
|
-
out.set(key, { mathml, error: decodeXml(err[1]) });
|
|
356
|
+
out.set(key, { mathml: sanitizeMathml(mathml), error: decodeXml(err[1]) });
|
|
157
357
|
continue;
|
|
158
358
|
}
|
|
159
|
-
const entry = { mathml: mathml.replace(/\n\s*/g, "") };
|
|
359
|
+
const entry = { mathml: sanitizeMathml(mathml.replace(/\n\s*/g, "")) };
|
|
160
360
|
if (s.display) {
|
|
161
361
|
const svg = mj.svg(s.tex, true);
|
|
162
362
|
entry.svg = svg;
|
|
@@ -3354,7 +3554,7 @@ function coverHtml(s, x) {
|
|
|
3354
3554
|
s.title ?? ""
|
|
3355
3555
|
)}</h1>${s.subtitle ? `<p class="doc-cover-subtitle">${escapeHtml(s.subtitle)}</p>` : ""}${s.author ? `<p class="doc-cover-author">${escapeHtml(s.author)}</p>` : ""}${s.date ? `<p class="doc-cover-date">${escapeHtml(s.date)}</p>` : ""}</section>`;
|
|
3356
3556
|
}
|
|
3357
|
-
var cssString = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, " ")}"`;
|
|
3557
|
+
var cssString = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, " ").replace(/</g, "\\3C ").replace(/>/g, "\\3E ")}"`;
|
|
3358
3558
|
function marginContent(template, s) {
|
|
3359
3559
|
if (!template) return "none";
|
|
3360
3560
|
return templateParts(template, s).map((p) => "field" in p ? `counter(${p.field})` : cssString(p.text)).join(" ");
|
|
@@ -4884,6 +5084,7 @@ function looksLikeJson(body) {
|
|
|
4884
5084
|
return false;
|
|
4885
5085
|
}
|
|
4886
5086
|
}
|
|
5087
|
+
var ALLOWED_TAGS = new Set(PRINT_HTML_SCHEMA.tagNames ?? []);
|
|
4887
5088
|
var LINK_URL = String.raw`((?:[^()\s]|\([^()\s]*\))+)(?:\s+"[^"]*")?`;
|
|
4888
5089
|
var IMAGE_RE = new RegExp(String.raw`!\[([^\]]*)\]\(` + LINK_URL + String.raw`\)`, "g");
|
|
4889
5090
|
var LINK_RE = new RegExp(String.raw`\[([^\]]+)\]\(` + LINK_URL + String.raw`\)`, "g");
|