@entropicwarrior/sdoc 0.2.8 → 0.2.10
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 +5 -1
- package/docs/reference/sdoc-authoring.sdoc +16 -0
- package/docs/reference/slide-authoring.sdoc +1 -0
- package/lexica/specification.sdoc +24 -11
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/src/sdoc.js +45 -2
- package/src/slide-renderer.js +4 -1
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ Markdown has no formal structure — section boundaries are ambiguous, extractio
|
|
|
25
25
|
|
|
26
26
|
**PDF and HTML export** — export any document to A4 PDF via headless Chrome, or to standalone HTML. Available as both a CLI tool and a VS Code command.
|
|
27
27
|
|
|
28
|
-
**A VS Code extension** — live preview, sticky scroll, code folding, document symbols, mermaid rendering, and commands for all the above.
|
|
28
|
+
**A VS Code extension** — live preview, sticky scroll, code folding, document symbols, mermaid/SVG rendering, and commands for all the above.
|
|
29
29
|
|
|
30
30
|
## Quick Start
|
|
31
31
|
|
|
@@ -170,6 +170,10 @@ Fenced with triple backticks, optional language tag for syntax highlighting. The
|
|
|
170
170
|
|
|
171
171
|
Code blocks tagged `mermaid` render as SVG diagrams — flowcharts, sequence diagrams, class diagrams, state diagrams, and more.
|
|
172
172
|
|
|
173
|
+
### SVG Diagrams
|
|
174
|
+
|
|
175
|
+
Code blocks tagged `svg` render as inline SVG graphics, giving full control over shapes, layout, and styling. `<script>` and `<foreignObject>` tags are stripped for security.
|
|
176
|
+
|
|
173
177
|
### Images
|
|
174
178
|
|
|
175
179
|
Markdown-style images with optional width and alignment:
|
|
@@ -408,6 +408,22 @@ Content of Section B.
|
|
|
408
408
|
Mermaid supports flowcharts (\`graph\`), sequence diagrams (\`sequenceDiagram\`), class diagrams (\`classDiagram\`), state diagrams (\`stateDiagram-v2\`), and more. The Mermaid library is loaded from CDN only when a document contains mermaid blocks.
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
+
# SVG Diagrams @svg
|
|
412
|
+
{
|
|
413
|
+
Code blocks with the \`svg\` language tag render as inline SVG graphics. This gives full control over shapes, layout, and styling for diagrams that need more precision than Mermaid offers:
|
|
414
|
+
|
|
415
|
+
````
|
|
416
|
+
```svg
|
|
417
|
+
<svg viewBox="0 0 200 60" xmlns="http://www.w3.org/2000/svg">
|
|
418
|
+
<rect x="10" y="10" width="80" height="40" rx="5" fill="#4a90d9" />
|
|
419
|
+
<text x="50" y="35" text-anchor="middle" fill="white" font-family="sans-serif" font-size="13">Hello</text>
|
|
420
|
+
</svg>
|
|
421
|
+
```
|
|
422
|
+
````
|
|
423
|
+
|
|
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
|
+
}
|
|
426
|
+
|
|
411
427
|
# Math Blocks @math-blocks
|
|
412
428
|
{
|
|
413
429
|
Code blocks with the \`math\` language tag are rendered as display equations via KaTeX:
|
|
@@ -165,6 +165,7 @@
|
|
|
165
165
|
\`{[table]}\` | \`<table>\`
|
|
166
166
|
Code fence | \`<pre><code>\`
|
|
167
167
|
Mermaid code fence | \`<pre class="mermaid">\` (rendered as SVG)
|
|
168
|
+
SVG code fence | \`<div class="sdoc-svg-block">\` (inline SVG)
|
|
168
169
|
\`**bold**\` | \`<strong>\`
|
|
169
170
|
\`*italic*\` | \`<em>\`
|
|
170
171
|
\`\\\`code\\\`\` | \`<code>\`
|
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
# About @about
|
|
11
11
|
{
|
|
12
12
|
The formal SDOC v0.2 specification. Defines syntax for scopes,
|
|
13
|
-
lists, tables, code blocks, inline formatting,
|
|
14
|
-
|
|
13
|
+
lists, tables (with formulas), code blocks, inline formatting,
|
|
14
|
+
references, autolinks (including bare email detection), the meta
|
|
15
|
+
scope, scope types, data blocks, comments, and collapsible scopes.
|
|
15
16
|
Includes the formal EBNF grammar. Read for edge cases and
|
|
16
17
|
parser behaviour questions. For a friendlier user-facing
|
|
17
18
|
reference, see \`docs/reference/syntax.sdoc\`.
|
|
@@ -607,6 +608,9 @@ Content of Section B.
|
|
|
607
608
|
- Optional language tag after the opening fence
|
|
608
609
|
- The special language tag `math` renders the block as a display equation via KaTeX (no copy button)
|
|
609
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 tags, foreignObject tags, event-handler attributes, and javascript: URLs are stripped for security.
|
|
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, except for `math`, `mermaid`, and `svg` blocks which render without it
|
|
610
614
|
}
|
|
611
615
|
|
|
612
616
|
# Include by Link @code-includes
|
|
@@ -819,9 +823,14 @@ Content of Section B.
|
|
|
819
823
|
{[.]
|
|
820
824
|
- Key matching is case-insensitive
|
|
821
825
|
- The pattern requires at least one space after the colon (`key: value`, not `key:value`)
|
|
822
|
-
- Well-known keys: `style`, `styleappend`/`style-append`, `header`, `footer`, `sdoc-version`
|
|
826
|
+
- Well-known keys: `style`, `styleappend`/`style-append`, `header`, `footer`, `sdoc-version`, `type`, `tags`, `uuid`, `company`, `confidential`
|
|
823
827
|
- `sdoc-version` identifies the SDOC format version the document targets (current: `0.2`). A parser warning is emitted when this key is missing.
|
|
824
|
-
-
|
|
828
|
+
- `type` classifies the document (e.g. `doc`, `skill`). Promoted to `meta.type`.
|
|
829
|
+
- `tags` is a comma-separated list of keywords. Promoted to `meta.tags` (array).
|
|
830
|
+
- `uuid` provides a stable unique identifier. Promoted to `meta.uuid`.
|
|
831
|
+
- `company` sets the company name for footer display. Promoted to `meta.company`.
|
|
832
|
+
- `confidential` marks the document as confidential. When set (any truthy value), a confidential notice banner is displayed at the top of the rendered output. Promoted to `meta.confidential`.
|
|
833
|
+
- All other keys are stored as custom properties in `meta.properties` (e.g., `author`, `date`, `version`, `status`)
|
|
825
834
|
- Sub-scope syntax takes precedence: if both `# Style { path }` and `style: path` exist, the sub-scope value wins
|
|
826
835
|
- Key:value and sub-scope syntax can be mixed freely in the same meta scope
|
|
827
836
|
- Each key:value pair must be on its own paragraph line (separated by blank lines from other pairs)
|
|
@@ -832,7 +841,7 @@ Content of Section B.
|
|
|
832
841
|
|
|
833
842
|
# Interactive Preview @interactive-preview
|
|
834
843
|
{
|
|
835
|
-
The VSCode extension provides an interactive preview
|
|
844
|
+
The VSCode extension provides an interactive preview. Some features (collapsible scopes, copy-to-clipboard) also work in all rendered HTML output. Click-to-navigate is preview-only.
|
|
836
845
|
|
|
837
846
|
# Theme Support @theme-support
|
|
838
847
|
{
|
|
@@ -843,8 +852,8 @@ Content of Section B.
|
|
|
843
852
|
- Dark mode overrides the \`--sdoc-*\` CSS custom properties and hardcoded \`rgba()\` colours (table headers, code blocks, confidential notices, error blocks)
|
|
844
853
|
- Mermaid diagrams use the \`dark\` theme when in a dark colour theme and \`neutral\` otherwise
|
|
845
854
|
- Theme changes take effect immediately (CSS-driven) and trigger a full preview rebuild (for Mermaid re-initialisation)
|
|
846
|
-
- Exported HTML follows the user's OS colour preference via
|
|
847
|
-
- Custom stylesheets (
|
|
855
|
+
- Exported HTML follows the user's OS colour preference via `\@media (prefers-color-scheme: dark)`. Print output always uses light theme colours
|
|
856
|
+
- Custom stylesheets (`sdoc.config.json` or `\@meta style`) that use `--sdoc-*` variables inherit dark values automatically. Hardcoded colours in custom styles are not overridden
|
|
848
857
|
}
|
|
849
858
|
}
|
|
850
859
|
|
|
@@ -852,11 +861,14 @@ Content of Section B.
|
|
|
852
861
|
{
|
|
853
862
|
Scope headings that have children display a toggle triangle, visible on hover. Clicking the triangle collapses the scope's children (hides the content below the heading). Clicking again expands them.
|
|
854
863
|
|
|
864
|
+
Collapsible scopes work in all HTML output: the VS Code preview, exported HTML, Open in Browser, and the document server viewer. The toggle CSS and click handler are included in the default stylesheet and rendered HTML.
|
|
865
|
+
|
|
855
866
|
{[.]
|
|
856
867
|
- The triangle points right when collapsed, down when expanded
|
|
857
|
-
-
|
|
868
|
+
- In the VS Code preview, collapse state is preserved across refreshes using webview state
|
|
858
869
|
- Scopes are identified by their `@id` if present, otherwise by source line number
|
|
859
870
|
- Only scopes with children show the toggle
|
|
871
|
+
- Toggles are hidden in print output and all sections are expanded
|
|
860
872
|
}
|
|
861
873
|
}
|
|
862
874
|
|
|
@@ -1011,9 +1023,10 @@ Content of Section A.
|
|
|
1011
1023
|
|
|
1012
1024
|
code_block = fence_open raw_text fence_close ;
|
|
1013
1025
|
data_block = data_fence_open raw_text fence_close ;
|
|
1014
|
-
fence_open =
|
|
1015
|
-
data_fence_open =
|
|
1016
|
-
fence_close =
|
|
1026
|
+
fence_open = backticks [lang] [ws "src:" path] [ws "lines:" range] newline ;
|
|
1027
|
+
data_fence_open = backticks lang ws ":data" newline ;
|
|
1028
|
+
fence_close = backticks newline ; (* must match opening fence length *)
|
|
1029
|
+
backticks = "```" { "`" } ; (* 3 or more backticks *)
|
|
1017
1030
|
|
|
1018
1031
|
line_comment = "//" { any_char } newline ; (* discarded, not in AST *)
|
|
1019
1032
|
|
package/llms.txt
CHANGED
|
@@ -8,7 +8,7 @@ The authoring guide (`docs/reference/sdoc-authoring.sdoc`) is written as an AI a
|
|
|
8
8
|
|
|
9
9
|
## Docs
|
|
10
10
|
|
|
11
|
-
- [SDOC Authoring Guide](https://raw.githubusercontent.com/entropicwarrior/sdoc/main/docs/reference/sdoc-authoring.sdoc): Skill document — how to write correct SDOC files. Covers document structure, inline formatting, block types (lists, tables, code, blockquotes), mermaid diagrams, and common mistakes. Start here to learn the format.
|
|
11
|
+
- [SDOC Authoring Guide](https://raw.githubusercontent.com/entropicwarrior/sdoc/main/docs/reference/sdoc-authoring.sdoc): Skill document — how to write correct SDOC files. Covers document structure, inline formatting, block types (lists, tables, code, blockquotes), mermaid/SVG diagrams, and common mistakes. Start here to learn the format.
|
|
12
12
|
- [SDOC Specification](https://raw.githubusercontent.com/entropicwarrior/sdoc/main/lexica/specification.sdoc): Formal v0.1 specification with EBNF grammar. Defines syntax for scopes, lists, tables, code blocks, inline formatting, references, and the meta scope.
|
|
13
13
|
- [Why SDOC Over Markdown](https://raw.githubusercontent.com/entropicwarrior/sdoc/main/docs/guide/why-sdoc.sdoc): The case for SDOC — structural problems with Markdown, why explicit scoping solves them, parsing safety as a security property, and the adoption path forward.
|
|
14
14
|
|
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.10",
|
|
6
6
|
"publisher": "entropicwarrior-msenfin",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
package/src/sdoc.js
CHANGED
|
@@ -1390,6 +1390,35 @@ function escapeHtml(value) {
|
|
|
1390
1390
|
.replace(/"/g, """);
|
|
1391
1391
|
}
|
|
1392
1392
|
|
|
1393
|
+
function sanitizeSvg(svg) {
|
|
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;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1393
1422
|
function escapeAttr(value) {
|
|
1394
1423
|
return escapeHtml(value).replace(/'/g, "'");
|
|
1395
1424
|
}
|
|
@@ -1928,6 +1957,9 @@ function renderNode(node, depth) {
|
|
|
1928
1957
|
if (node.lang === "mermaid") {
|
|
1929
1958
|
return `<pre class="mermaid"${dl}>${escapeHtml(node.text)}</pre>`;
|
|
1930
1959
|
}
|
|
1960
|
+
if (node.lang === "svg") {
|
|
1961
|
+
return `<div class="sdoc-svg-block"${dl}>${sanitizeSvg(node.text)}</div>`;
|
|
1962
|
+
}
|
|
1931
1963
|
if (node.lang === "math") {
|
|
1932
1964
|
return `<div class="sdoc-math sdoc-math-block"${dl}>${renderKatex(node.text, true)}</div>`;
|
|
1933
1965
|
}
|
|
@@ -2371,6 +2403,16 @@ const DEFAULT_STYLE = `
|
|
|
2371
2403
|
margin-left: 0.5%;
|
|
2372
2404
|
}
|
|
2373
2405
|
|
|
2406
|
+
.sdoc-svg-block {
|
|
2407
|
+
margin: 0.6rem 0;
|
|
2408
|
+
text-align: center;
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
.sdoc-svg-block svg {
|
|
2412
|
+
max-width: 100%;
|
|
2413
|
+
height: auto;
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2374
2416
|
.sdoc-code {
|
|
2375
2417
|
background: rgba(22, 21, 19, 0.06);
|
|
2376
2418
|
border: 1px solid var(--sdoc-border);
|
|
@@ -2579,7 +2621,7 @@ function hasMermaidBlocks(nodes) {
|
|
|
2579
2621
|
|
|
2580
2622
|
function hasHighlightableCodeBlocks(nodes) {
|
|
2581
2623
|
for (const node of nodes) {
|
|
2582
|
-
if (node.type === "code" && node.lang && node.lang !== "mermaid" && node.lang !== "math") return true;
|
|
2624
|
+
if (node.type === "code" && node.lang && node.lang !== "mermaid" && node.lang !== "math" && node.lang !== "svg") return true;
|
|
2583
2625
|
if (node.children && hasHighlightableCodeBlocks(node.children)) return true;
|
|
2584
2626
|
if (node.items) {
|
|
2585
2627
|
for (const item of node.items) {
|
|
@@ -3128,5 +3170,6 @@ module.exports = {
|
|
|
3128
3170
|
parseInline,
|
|
3129
3171
|
renderKatex,
|
|
3130
3172
|
escapeHtml,
|
|
3131
|
-
escapeAttr
|
|
3173
|
+
escapeAttr,
|
|
3174
|
+
sanitizeSvg
|
|
3132
3175
|
};
|
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
|
}
|