@entropicwarrior/sdoc 0.2.1 → 0.2.3
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/docs/reference/sdoc-authoring.sdoc +28 -1
- package/lexica/specification.sdoc +2 -0
- package/package.json +1 -1
- package/src/sdoc.js +54 -2
|
@@ -307,7 +307,7 @@ Content of Section B.
|
|
|
307
307
|
|
|
308
308
|
# References @references
|
|
309
309
|
{
|
|
310
|
-
Assign a slug with \`@slug\` on a heading, then reference it
|
|
310
|
+
Assign a slug with \`@slug\` on a heading, then reference it elsewhere in the same document with \`@slug\`:
|
|
311
311
|
|
|
312
312
|
```
|
|
313
313
|
# Setup @setup {
|
|
@@ -318,6 +318,14 @@ Content of Section B.
|
|
|
318
318
|
Make sure you complete @setup first.
|
|
319
319
|
}
|
|
320
320
|
```
|
|
321
|
+
|
|
322
|
+
References are **document-local only** — \`@slug\` resolves within the current file. To point a reader to a section in another file, use a link with a fragment:
|
|
323
|
+
|
|
324
|
+
```
|
|
325
|
+
See [Setup](./other-file.sdoc#setup) for details.
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Do not write \`@setup\` when the target scope is in a different file — it will be flagged as a broken reference.
|
|
321
329
|
}
|
|
322
330
|
|
|
323
331
|
# Code Blocks @code-blocks
|
|
@@ -672,6 +680,25 @@ Content of Section B.
|
|
|
672
680
|
```
|
|
673
681
|
}
|
|
674
682
|
|
|
683
|
+
# Cross-Document @slug References @cross-doc-refs
|
|
684
|
+
{
|
|
685
|
+
\`@slug\` references are document-local. Using \`@slug\` to refer to a section in another file produces a broken reference error:
|
|
686
|
+
|
|
687
|
+
**Wrong** — \`@setup\` does not exist in this file:
|
|
688
|
+
|
|
689
|
+
```
|
|
690
|
+
See `getting-started.sdoc` @setup for installation steps.
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
**Right** — use a link with a fragment:
|
|
694
|
+
|
|
695
|
+
```
|
|
696
|
+
See [Setup](./getting-started.sdoc#setup) for installation steps.
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
The fragment (\`#setup\`) matches the target scope's \`@id\`. Use \`\\@\` if you need a literal \`@\` in text without triggering reference resolution.
|
|
700
|
+
}
|
|
701
|
+
|
|
675
702
|
# @References Inside Link Labels @refs-in-link-labels
|
|
676
703
|
{
|
|
677
704
|
Inline \`@references\` are parsed everywhere, including inside link labels. If you mention a scope ID in a link label, escape the \`@\` to prevent it being treated as a reference to the current document:
|
|
@@ -393,6 +393,8 @@ Content of Section B.
|
|
|
393
393
|
{
|
|
394
394
|
{[.]
|
|
395
395
|
- A reference is `@id` in text (unescaped)
|
|
396
|
+
- References are document-local: `@id` resolves to a scope within the same file only. Cross-document reference syntax may be introduced in a future version but is not part of v0.2
|
|
397
|
+
- To link to a section in another file, use a standard link with a fragment: `[Label](./other-file.sdoc#section-id)`
|
|
396
398
|
- References link to the scope with that ID
|
|
397
399
|
- ID uniqueness is strongly recommended; tooling may warn on duplicates
|
|
398
400
|
- References are parsed inside link labels — use `\@` to include a literal `@` in a link label without triggering a reference
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@entropicwarrior/sdoc",
|
|
3
3
|
"displayName": "SDOC",
|
|
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.3",
|
|
6
6
|
"publisher": "entropicwarrior",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
package/src/sdoc.js
CHANGED
|
@@ -2122,6 +2122,36 @@ const PRINT_STYLE = `
|
|
|
2122
2122
|
|
|
2123
2123
|
const MERMAID_CDN = "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js";
|
|
2124
2124
|
const KATEX_CDN_CSS = "https://cdn.jsdelivr.net/npm/katex@0.16/dist/katex.min.css";
|
|
2125
|
+
const HLJS_CDN = "https://cdn.jsdelivr.net/npm/@highlightjs/cdn-assets@11.11.1/highlight.min.js";
|
|
2126
|
+
|
|
2127
|
+
// Custom highlight.js grammar for SDOC language – registered before highlightElement calls
|
|
2128
|
+
const HLJS_SDOC_GRAMMAR = `hljs.registerLanguage('sdoc',function(hljs){return{name:'SDOC',aliases:['sdoc'],contains:[
|
|
2129
|
+
hljs.COMMENT('^\\\\s*//','$'),
|
|
2130
|
+
{className:'section',begin:'^\\\\s*#+\\\\s+',end:'$',contains:[
|
|
2131
|
+
{className:'symbol',begin:'@[A-Za-z_][A-Za-z0-9_-]*'}
|
|
2132
|
+
]},
|
|
2133
|
+
{className:'meta',begin:'^\\\\s*@[A-Za-z_][A-Za-z0-9_-]*',end:'(?=\\\\s*\\\\{|$)'},
|
|
2134
|
+
{className:'code',begin:'\`\`\`',end:'\`\`\`',contains:[hljs.BACKSLASH_ESCAPE]},
|
|
2135
|
+
{className:'code',begin:'\`[^\`]+\`'},
|
|
2136
|
+
{className:'string',begin:'\\\\[',end:'\\\\]\\\\([^)]*\\\\)',contains:[
|
|
2137
|
+
{className:'link',begin:'\\\\(',end:'\\\\)'}
|
|
2138
|
+
]},
|
|
2139
|
+
{className:'keyword',begin:'\\\\{[!?+\\\\-=~^]',end:'[!?+\\\\-=~^]\\\\}'},
|
|
2140
|
+
{className:'keyword',begin:'\\\\{\\\\[(?:\\\\.|#|\\\\d+|table)\\\\]'},
|
|
2141
|
+
{className:'strong',begin:'\\\\*\\\\*',end:'\\\\*\\\\*'},
|
|
2142
|
+
{className:'emphasis',begin:'(?<!\\\\*)\\\\*(?!\\\\*)',end:'\\\\*(?!\\\\*)'},
|
|
2143
|
+
{className:'deletion',begin:'~~',end:'~~'},
|
|
2144
|
+
{className:'bullet',begin:'^\\\\s*[-]\\\\s'},
|
|
2145
|
+
{className:'bullet',begin:'^\\\\s*\\\\d+[.)]\\\\ '},
|
|
2146
|
+
{className:'quote',begin:'^\\\\s*>',end:'$'},
|
|
2147
|
+
{className:'symbol',begin:'(?<!\\\\\\\\)@[A-Za-z_][A-Za-z0-9_-]*'},
|
|
2148
|
+
{className:'attr',begin:'[A-Za-z_][A-Za-z0-9_-]*(?=\\\\s*:)',end:':',excludeEnd:true}
|
|
2149
|
+
]}});`;
|
|
2150
|
+
|
|
2151
|
+
// Highlight.js GitHub light theme (inline so it works inside shadow DOM in the web viewer)
|
|
2152
|
+
const HLJS_LIGHT_CSS = "pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}";
|
|
2153
|
+
// Highlight.js GitHub dark theme color overrides (used in @media and VS Code dark-mode CSS)
|
|
2154
|
+
const HLJS_DARK_COLORS_CSS = ".hljs{color:#c9d1d9;background:transparent}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}";
|
|
2125
2155
|
|
|
2126
2156
|
function hasMermaidBlocks(nodes) {
|
|
2127
2157
|
for (const node of nodes) {
|
|
@@ -2136,6 +2166,19 @@ function hasMermaidBlocks(nodes) {
|
|
|
2136
2166
|
return false;
|
|
2137
2167
|
}
|
|
2138
2168
|
|
|
2169
|
+
function hasHighlightableCodeBlocks(nodes) {
|
|
2170
|
+
for (const node of nodes) {
|
|
2171
|
+
if (node.type === "code" && node.lang && node.lang !== "mermaid" && node.lang !== "math") return true;
|
|
2172
|
+
if (node.children && hasHighlightableCodeBlocks(node.children)) return true;
|
|
2173
|
+
if (node.items) {
|
|
2174
|
+
for (const item of node.items) {
|
|
2175
|
+
if (item.children && hasHighlightableCodeBlocks(item.children)) return true;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
return false;
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2139
2182
|
function renderBodyNodes(nodes) {
|
|
2140
2183
|
return nodes
|
|
2141
2184
|
.map((node, index) => {
|
|
@@ -2186,6 +2229,15 @@ function renderHtmlDocumentFromParsed(parsed, title, options = {}) {
|
|
|
2186
2229
|
const katexCssTag = body.includes('class="katex"')
|
|
2187
2230
|
? `\n<link rel="stylesheet" href="${KATEX_CDN_CSS}" />`
|
|
2188
2231
|
: "";
|
|
2232
|
+
const hasHljs = hasHighlightableCodeBlocks(parsed.nodes);
|
|
2233
|
+
// Highlight.js CSS is inlined (not a <link>) so it is extracted by parseDocHtml in the web viewer
|
|
2234
|
+
// and applied inside shadow DOM. The @media query handles dark mode in browsers.
|
|
2235
|
+
const hljsCssInline = hasHljs
|
|
2236
|
+
? `\n${HLJS_LIGHT_CSS}\n.sdoc-code code.hljs{padding:0;background:transparent}\n@media (prefers-color-scheme:dark){${HLJS_DARK_COLORS_CSS}}`
|
|
2237
|
+
: "";
|
|
2238
|
+
const hljsScript = hasHljs
|
|
2239
|
+
? `\n<script src="${HLJS_CDN}"></script>\n<script>${HLJS_SDOC_GRAMMAR}\ndocument.querySelectorAll('pre.sdoc-code code[class*="language-"]').forEach(function(b){hljs.highlightElement(b);});</script>`
|
|
2240
|
+
: "";
|
|
2189
2241
|
|
|
2190
2242
|
return `<!DOCTYPE html>
|
|
2191
2243
|
<html lang="en">
|
|
@@ -2194,7 +2246,7 @@ function renderHtmlDocumentFromParsed(parsed, title, options = {}) {
|
|
|
2194
2246
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
2195
2247
|
<title>${escapeHtml(title)}</title>
|
|
2196
2248
|
<style>
|
|
2197
|
-
${cssBase}${cssAppend}
|
|
2249
|
+
${cssBase}${cssAppend}${hljsCssInline}
|
|
2198
2250
|
</style>${katexCssTag}
|
|
2199
2251
|
</head>
|
|
2200
2252
|
<body>
|
|
@@ -2208,7 +2260,7 @@ ${cssBase}${cssAppend}
|
|
|
2208
2260
|
</main>
|
|
2209
2261
|
</div>
|
|
2210
2262
|
${footerContent ? `<footer class="sdoc-page-footer">${footerContent}</footer>` : ""}
|
|
2211
|
-
</div>${scriptTag}${mermaidScript}
|
|
2263
|
+
</div>${scriptTag}${mermaidScript}${hljsScript}
|
|
2212
2264
|
</body>
|
|
2213
2265
|
</html>`;
|
|
2214
2266
|
}
|