@ai-matrx/print 0.8.6 → 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/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(" ");
@@ -4814,7 +5014,8 @@ import { gfm } from "micromark-extension-gfm";
4814
5014
  import { escapeHtml as escapeHtml3 } from "@ai-matrx/kit/html-escape";
4815
5015
  function removeThinkingContent(content) {
4816
5016
  if (!content) return "";
4817
- let result = content.replace(/\n*<thinking>[\s\S]*?<\/thinking>\n*/gi, "\n").replace(/\n*<think>[\s\S]*?<\/think>\n*/gi, "\n").replace(/\n*<reasoning>[\s\S]*?<\/reasoning>\n*/gi, "\n");
5017
+ const hide = (_match, before, after) => before.length >= 2 || after.length >= 2 ? "\n\n" : "\n";
5018
+ let result = content.replace(/(\n*)<thinking>[\s\S]*?<\/thinking>(\n*)/gi, hide).replace(/(\n*)<think>[\s\S]*?<\/think>(\n*)/gi, hide).replace(/(\n*)<reasoning>[\s\S]*?<\/reasoning>(\n*)/gi, hide);
4818
5019
  result = result.replace(/\n{3,}/g, "\n\n");
4819
5020
  return result.trim();
4820
5021
  }
@@ -4883,6 +5084,7 @@ function looksLikeJson(body) {
4883
5084
  return false;
4884
5085
  }
4885
5086
  }
5087
+ var ALLOWED_TAGS = new Set(PRINT_HTML_SCHEMA.tagNames ?? []);
4886
5088
  var LINK_URL = String.raw`((?:[^()\s]|\([^()\s]*\))+)(?:\s+"[^"]*")?`;
4887
5089
  var IMAGE_RE = new RegExp(String.raw`!\[([^\]]*)\]\(` + LINK_URL + String.raw`\)`, "g");
4888
5090
  var LINK_RE = new RegExp(String.raw`\[([^\]]+)\]\(` + LINK_URL + String.raw`\)`, "g");