fix: escape docs map heading markup

This commit is contained in:
Mason Huang 2026-07-02 21:58:11 +08:00
parent e3f46d0926
commit 261466a2a8
No known key found for this signature in database
3 changed files with 44 additions and 21 deletions

View file

@ -289,7 +289,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- Route: /channels/channel-routing
- Headings:
- H1: Channels & routing
- H1: Channels & routing
- H2: Key terms
- H2: Outbound target prefixes
- H2: Session key shapes (examples)
@ -1226,7 +1226,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H3: agents bindings
- H3: agents bind
- H3: agents unbind
- H3: agents delete
- H3: agents delete <id>
- H2: Identity files
- H2: Set identity
- H2: Related
@ -1418,13 +1418,13 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H1: openclaw devices
- H2: Commands
- H3: openclaw devices list
- H3: openclaw devices remove
- H3: openclaw devices remove <deviceId>
- H3: openclaw devices clear --yes [--pending]
- H3: openclaw devices approve [requestId] [--latest]
- H2: Paperclip / openclawgateway first-run approval
- H3: openclaw devices reject
- H3: openclaw devices rotate --device --role [--scope ]
- H3: openclaw devices revoke --device --role
- H3: openclaw devices reject <requestId>
- H3: openclaw devices rotate --device <id> --role <role> [--scope <scope...>]
- H3: openclaw devices revoke --device <id> --role <role>
- H2: Common options
- H2: Notes
- H2: Token drift recovery checklist
@ -1506,7 +1506,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H3: gateway status
- H3: gateway probe
- H4: Remote over SSH (Mac app parity)
- H3: gateway call
- H3: gateway call <method>
- H2: Manage the Gateway service
- H3: Install with a wrapper
- H2: Discover gateways (Bonjour)
@ -1747,11 +1747,11 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H3: JSONL
- H3: YAML
- H2: Subcommand reference
- H3: resolve
- H3: find
- H3: set
- H3: validate
- H3: emit
- H3: resolve <oc-path>
- H3: find <pattern>
- H3: set <oc-path> <value>
- H3: validate <oc-path>
- H3: emit <file>
- H2: Exit codes
- H2: Output mode
- H2: Notes
@ -2039,12 +2039,12 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H3: wiki status
- H3: wiki doctor
- H3: wiki init
- H3: wiki ingest
- H3: wiki okf import
- H3: wiki ingest <path-or-url>
- H3: wiki okf import <path>
- H3: wiki compile
- H3: wiki lint
- H3: wiki search
- H3: wiki get
- H3: wiki search <query>
- H3: wiki get <lookup>
- H3: wiki apply
- H3: wiki bridge import
- H3: wiki unsafe-local import
@ -4492,7 +4492,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H3: Volume (required)
- H3: Variables
- H2: Connect a channel
- H2: Backups & migration
- H2: Backups & migration
- H2: Next steps
## install/raspberry-pi.md
@ -5129,7 +5129,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- Route: /platforms/mac/voicewake
- Headings:
- H1: Voice Wake & Push-to-Talk
- H1: Voice Wake & Push-to-Talk
- H2: Requirements
- H2: Modes
- H2: Runtime behavior (wake-word)
@ -8544,7 +8544,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H3: 3.6 Discovery (AML.TA0008)
- H4: T-DISC-001: Tool Enumeration
- H4: T-DISC-002: Session Data Extraction
- H3: 3.7 Collection & Exfiltration (AML.TA0009, AML.TA0010)
- H3: 3.7 Collection & Exfiltration (AML.TA0009, AML.TA0010)
- H4: T-EXFIL-001: Data Theft via webfetch
- H4: T-EXFIL-002: Unauthorized Message Sending
- H4: T-EXFIL-003: Credential Harvesting

View file

@ -84,14 +84,20 @@ function stripFrontmatter(raw) {
return raw;
}
function escapeMarkdownHtmlText(value) {
return value.replace(/&/gu, "&amp;").replace(/</gu, "&lt;").replace(/>/gu, "&gt;");
}
function cleanHeadingText(value) {
return value
const normalized = value
.replace(/\s+#+\s*$/u, "")
.replace(/<[^>]+>/gu, "")
.replace(/\[([^\]]+)\]\([^)]*\)/gu, "$1")
.replace(/[*_~`]/gu, "")
.replace(/\s+/gu, " ")
.trim();
// Docs map is Markdown consumed by humans and agents. Escape HTML instead of
// trying to strip tags so malformed source headings cannot reintroduce markup.
return escapeMarkdownHtmlText(normalized);
}
function extractHeadings(raw) {
@ -198,3 +204,7 @@ const isMain = process.argv[1] ? fileURLToPath(import.meta.url) === process.argv
if (isMain) {
main();
}
export const testing = {
cleanHeadingText,
};

View file

@ -0,0 +1,13 @@
import { describe, expect, it } from "vitest";
import { testing } from "../../scripts/generate-docs-map.mjs";
describe("generate docs map", () => {
it("renders heading HTML as text", () => {
expect(testing.cleanHeadingText("`API` <script>alert(1)</script>")).toBe(
"API &lt;script&gt;alert(1)&lt;/script&gt;",
);
expect(testing.cleanHeadingText("<scr<script>ipt>alert(1)</script>")).toBe(
"&lt;scr&lt;script&gt;ipt&gt;alert(1)&lt;/script&gt;",
);
});
});