Problem
safe-docx currently represents inline formatting in several overlapping forms:
formatting_tags.ts emits an HTML-shaped tagged_text string.
serialize_markdown.ts and serialize_html.ts independently translate that representation.
tag_parser.ts parses an allowlisted tag syntax into ReplacementPart[] for edits.
AddRunProps and ReplacementPart are the typed structures that ultimately drive OOXML changes.
The string representations duplicate tokenization and formatting rules. They also make it easy for read, edit, Markdown export, and HTML export behavior to drift.
Proposed direction
Introduce a shared typed inline representation, for example:
type InlineSpan = {
text: string;
bold?: boolean;
italic?: boolean;
underline?: boolean | string;
highlight?: string;
color?: string;
fontName?: string;
fontSize?: number;
link?: { href: string };
};
The exact schema should follow the formatting semantics already supported by AddRunProps and the serializers.
Markdown and sanitized HTML should be input/output formats around this typed model, not the canonical model itself:
DOCX/OOXML -> InlineSpan[] -> tagged text / Markdown / HTML
Markdown or allowlisted HTML -> InlineSpan[] -> ReplacementPart[] -> OOXML
Markdown can represent common emphasis. A small allowlisted HTML subset can represent semantics Markdown lacks, such as <u>, <mark>, and foreground color.
Scope boundary
Do not use Markdown or HTML as the canonical representation for tracked changes or document structure. Revision IDs, authors, dates, prior formatting snapshots, comments, fields, relationships, paragraph changes, style inheritance, and other OOXML semantics must remain typed.
The first implementation should normalize ordinary inline run formatting only. It should not encode tracked changes as <ins> or <del> except in a one-way display serializer.
Relevant code
packages/docx-core/src/primitives/formatting_tags.ts
packages/docx-core/src/primitives/serialize_markdown.ts
packages/docx-core/src/primitives/serialize_html.ts
packages/docx-core/src/primitives/text.ts
packages/docx-mcp/src/tools/tag_parser.ts
packages/docx-mcp/src/tools/replace_text.ts
packages/docx-mcp/src/tools/insert_paragraph.ts
Security requirements
- Parse a fixed allowlist rather than retaining arbitrary HTML.
- Reject event attributes and unsupported elements or attributes.
- Restrict link URL schemes.
- Restrict CSS to explicitly supported properties and validated values.
- Escape unknown markup as text.
- Keep the existing lossy-export warning where Markdown cannot preserve Word semantics.
Acceptance criteria
Problem
safe-docxcurrently represents inline formatting in several overlapping forms:formatting_tags.tsemits an HTML-shapedtagged_textstring.serialize_markdown.tsandserialize_html.tsindependently translate that representation.tag_parser.tsparses an allowlisted tag syntax intoReplacementPart[]for edits.AddRunPropsandReplacementPartare the typed structures that ultimately drive OOXML changes.The string representations duplicate tokenization and formatting rules. They also make it easy for read, edit, Markdown export, and HTML export behavior to drift.
Proposed direction
Introduce a shared typed inline representation, for example:
The exact schema should follow the formatting semantics already supported by
AddRunPropsand the serializers.Markdown and sanitized HTML should be input/output formats around this typed model, not the canonical model itself:
Markdown can represent common emphasis. A small allowlisted HTML subset can represent semantics Markdown lacks, such as
<u>,<mark>, and foreground color.Scope boundary
Do not use Markdown or HTML as the canonical representation for tracked changes or document structure. Revision IDs, authors, dates, prior formatting snapshots, comments, fields, relationships, paragraph changes, style inheritance, and other OOXML semantics must remain typed.
The first implementation should normalize ordinary inline run formatting only. It should not encode tracked changes as
<ins>or<del>except in a one-way display serializer.Relevant code
packages/docx-core/src/primitives/formatting_tags.tspackages/docx-core/src/primitives/serialize_markdown.tspackages/docx-core/src/primitives/serialize_html.tspackages/docx-core/src/primitives/text.tspackages/docx-mcp/src/tools/tag_parser.tspackages/docx-mcp/src/tools/replace_text.tspackages/docx-mcp/src/tools/insert_paragraph.tsSecurity requirements
Acceptance criteria