@entropicwarrior/sdoc 0.2.9 → 0.2.11
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.
|
@@ -421,7 +421,7 @@ Content of Section B.
|
|
|
421
421
|
```
|
|
422
422
|
````
|
|
423
423
|
|
|
424
|
-
For security, \`<script>\`
|
|
424
|
+
For security, the following are stripped before rendering: \`<script>\` tags, \`<foreignObject>\` tags, event-handler attributes (\`onload\`, \`onclick\`, etc.), and \`javascript:\` URLs. Content outside the \`<svg>\` root element is discarded. All other SVG elements and attributes pass through as-is.
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
# Math Blocks @math-blocks
|
|
@@ -608,9 +608,9 @@ Content of Section B.
|
|
|
608
608
|
- Optional language tag after the opening fence
|
|
609
609
|
- The special language tag `math` renders the block as a display equation via KaTeX (no copy button)
|
|
610
610
|
- The special language tag `mermaid` renders the block as an SVG diagram via the Mermaid library
|
|
611
|
-
- The special language tag `svg` renders the block as an inline SVG graphic. Script
|
|
611
|
+
- The special language tag `svg` renders the block as an inline SVG graphic. Script tags, foreignObject tags, event-handler attributes, and javascript: URLs are stripped for security.
|
|
612
612
|
- Fences may use more than three backticks (e.g. four or five) to nest code blocks that themselves contain triple backticks. The closing fence must match the opening fence length.
|
|
613
|
-
- Code blocks display a copy-to-clipboard button (visible on hover) in all rendered HTML output
|
|
613
|
+
- Code blocks display a copy-to-clipboard button (visible on hover) in all rendered HTML output, except for `math`, `mermaid`, and `svg` blocks which render without it
|
|
614
614
|
}
|
|
615
615
|
|
|
616
616
|
# Include by Link @code-includes
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@entropicwarrior/sdoc",
|
|
3
3
|
"displayName": "SDOC - Docs for Human/Agent Teams",
|
|
4
4
|
"description": "A plain-text documentation format with explicit brace scoping — deterministic parsing, AI-agent efficiency, and 10-50x token savings vs Markdown.",
|
|
5
|
-
"version": "0.2.
|
|
5
|
+
"version": "0.2.11",
|
|
6
6
|
"publisher": "entropicwarrior-msenfin",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
package/src/sdoc.js
CHANGED
|
@@ -1391,11 +1391,32 @@ function escapeHtml(value) {
|
|
|
1391
1391
|
}
|
|
1392
1392
|
|
|
1393
1393
|
function sanitizeSvg(svg) {
|
|
1394
|
-
return
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1394
|
+
if (typeof svg !== "string") return "";
|
|
1395
|
+
|
|
1396
|
+
// Enforce a single <svg> root — discard anything outside it.
|
|
1397
|
+
const openMatch = svg.match(/<svg[\s>]/i);
|
|
1398
|
+
const closeMatch = svg.match(/<\/svg\s*>/i);
|
|
1399
|
+
if (!openMatch || !closeMatch) return "";
|
|
1400
|
+
const start = svg.indexOf(openMatch[0]);
|
|
1401
|
+
const end = svg.indexOf(closeMatch[0], start) + closeMatch[0].length;
|
|
1402
|
+
let s = svg.slice(start, end);
|
|
1403
|
+
|
|
1404
|
+
// Strip <script> and <foreignObject> elements (including self-closing).
|
|
1405
|
+
s = s.replace(/<script[\s>][\s\S]*?<\/script\s*>/gi, "");
|
|
1406
|
+
s = s.replace(/<script\b[^>]*\/\s*>/gi, "");
|
|
1407
|
+
s = s.replace(/<foreignObject[\s>][\s\S]*?<\/foreignObject\s*>/gi, "");
|
|
1408
|
+
s = s.replace(/<foreignObject\b[^>]*\/\s*>/gi, "");
|
|
1409
|
+
|
|
1410
|
+
// Strip event-handler attributes (onload, onclick, etc.).
|
|
1411
|
+
s = s.replace(/\s+on[a-z]+\s*=\s*(".*?"|'.*?'|[^\s>]+)/gi, "");
|
|
1412
|
+
|
|
1413
|
+
// Neutralize javascript: URLs in href and xlink:href.
|
|
1414
|
+
s = s.replace(
|
|
1415
|
+
/(\s+(?:xlink:)?href\s*=\s*)(["'])(\s*javascript:)/gi,
|
|
1416
|
+
function (_match, prefix, quote) { return prefix + quote + "#"; }
|
|
1417
|
+
);
|
|
1418
|
+
|
|
1419
|
+
return s;
|
|
1399
1420
|
}
|
|
1400
1421
|
|
|
1401
1422
|
function escapeAttr(value) {
|
|
@@ -1474,6 +1495,8 @@ function renderInlineNodes(nodes) {
|
|
|
1474
1495
|
function renderScope(scope, depth, isTitleScope = false) {
|
|
1475
1496
|
// :comment scopes are not rendered
|
|
1476
1497
|
if (scope.scopeType === "comment") return "";
|
|
1498
|
+
// @about is document metadata, not rendered in output
|
|
1499
|
+
if (scope.id && scope.id.toLowerCase() === "about") return "";
|
|
1477
1500
|
|
|
1478
1501
|
const level = Math.min(6, Math.max(1, depth));
|
|
1479
1502
|
const children = scope.children.map((child) => renderNode(child, depth + 1)).join("\n");
|
package/src/slide-renderer.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// const { nodes, meta } = extractMeta(parsed.nodes);
|
|
8
8
|
// const html = renderSlides(nodes, { meta, themeCss, themeJs });
|
|
9
9
|
|
|
10
|
-
const { parseInline, renderKatex, escapeHtml, escapeAttr } = require("./sdoc");
|
|
10
|
+
const { parseInline, renderKatex, escapeHtml, escapeAttr, sanitizeSvg } = require("./sdoc");
|
|
11
11
|
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
// Inline rendering — produces clean HTML without sdoc-* classes
|
|
@@ -71,6 +71,9 @@ function renderNode(node) {
|
|
|
71
71
|
if (node.lang === "mermaid") {
|
|
72
72
|
return `<pre class="mermaid">${escapeHtml(node.text)}</pre>`;
|
|
73
73
|
}
|
|
74
|
+
if (node.lang === "svg") {
|
|
75
|
+
return `<div class="sdoc-svg-block">${sanitizeSvg(node.text)}</div>`;
|
|
76
|
+
}
|
|
74
77
|
if (node.lang === "math") {
|
|
75
78
|
return `<div class="sdoc-math sdoc-math-block">${renderKatex(node.text, true)}</div>`;
|
|
76
79
|
}
|