feat(content-controls): support richText type and regenerate NDA demo fixture (SD-3131)#3275
Conversation
…Ts per ECMA-376 (SD-3131)
Adds 'richText' to ContentControlType so SuperDoc resolves typeless w:sdt
SDTs to 'richText' per ECMA-376 §17.5.2.26 ("If no type element is
specified, then the nearest ancestor structured document tag shall be
of type richText"). Before, typeless SDTs - which Word emits for
ContentControls.Add(0, range) and the default Add($null, range) - fell
through to 'unknown', blocking customers from inspecting Word-authored
controls by type.
- Detection: typeless sdtPr and explicit <w:richText/> both resolve to
'richText'. Unmodeled type children (w:equation, w:picture, w:citation,
w:bibliography, w:docPartList) still return null so resolveControlType
yields 'unknown' - keeping 'unknown' as "unsupported or unrecognized",
not "typeless rich-text control".
- Export/create maps: richText: 'w:richText' in both CONTROL_TYPE_SDT_PR_ELEMENTS
(wrappers) and CONTROL_TYPE_ELEMENT_MAP (converter), plus a 'richText'
case in buildDefaultTypeSdtPrElement so create.contentControl and setType
produce valid OOXML.
- text.setValue stays restricted to actual w:text controls.
Tests: 22 in handle-structured-content-node.test.js (10 new), 39 in
content-controls-wrappers, 1189 in conformance - all pass.
…-3131) The contract-templates demo fixture had inline smart fields authored as default rich-text controls (typeless sdtPr), which is why none of them detected as 'text' - they fell through to 'unknown' before SD-3131 and resolve as 'richText' after. Regenerated nda-template.docx with ContentControls.Add(1, range) for the 7 inline smart fields (now <w:text/> in sdtPr, controlType: 'text') while leaving the 6 block clauses as typeless (controlType: 'richText'). Verified unzip: 13 SDTs total, 7 <w:text/>, 0 explicit <w:richText/>. Switched per-occurrence field update from replaceContent to text.setValue to exercise the typed API. Clause replacement stays on replaceContent because rich-text controls don't have a typed setter. README/JSDoc updated: "seven inline plain-text + six block rich-text" (was "thirteen plain-text"). Honest limits section updated to reflect the API split. Browser smoke verified: receivingParty fan-out updates 2/2 occurrences (header + nested), clause replacement decrements "updates available" correctly, summary line accurate.
|
Good — Status: PASS The schema-level changes look spec-correct:
Caveat: I could not load the ecma-spec MCP tools (permission not granted in this session), so the spec-text verification above is from prior OOXML knowledge rather than live lookup. If you want me to re-verify the §17.5.2.26 citation precisely, allow the |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 530fc63275
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…t unknown (SD-3139) (#3281) Follow-up to SD-3131 (#3275). After that PR, imported typeless w:sdtPr correctly resolves to controlType: 'richText' per ECMA-376 §17.5.2.26, but newly created controls via create.contentControl (no controlType) and contentControls.wrap still defaulted to 'unknown'. Customers filtering contentControls.list() by type saw different results before vs after save/reopen — the same typeless OOXML round-tripped from 'unknown' to 'richText'. - createWrapper: collapse three `?? 'unknown'` into a single `?? 'richText'` local. - wrapWrapper: explicitly seed controlType, type, and a default sdtPr with <w:richText/> on the wrapper attrs (previously controlType was unset entirely, leaving resolveControlType to fall back to 'unknown'). Newly created controls now emit explicit <w:richText/> in sdtPr for unambiguous engine state and exported markup. Imported typeless Word-authored SDTs preserve their original raw sdtPr (import path unchanged). Per the SD-3131 design, 'unknown' keeps its meaning of "unsupported or unrecognized type" — it's no longer the default for new controls. Tests: 3 new (default-create → richText, explicit-richText-create seeds <w:richText/>, wrap → richText + seeds <w:richText/>). 42 wrappers + 1189 conformance + 1398 document-api pass.
|
🎉 This PR is included in @superdoc-dev/mcp v0.3.0-next.90 The release is available on GitHub release |
|
🎉 This PR is included in vscode-ext v2.3.0-next.135 |
|
🎉 This PR is included in @superdoc-dev/react v1.2.0-next.133 The release is available on GitHub release |
|
🎉 This PR is included in superdoc-cli v0.8.0-next.105 The release is available on GitHub release |
|
🎉 This PR is included in superdoc-sdk v1.8.0-next.89 |
|
🎉 This PR is included in superdoc v1.30.0-next.87 The release is available on GitHub release |
… fixture (SD-3131) (superdoc-dev#3275) * feat(content-controls): support richText type and resolve typeless SDTs per ECMA-376 (SD-3131) Adds 'richText' to ContentControlType so SuperDoc resolves typeless w:sdt SDTs to 'richText' per ECMA-376 §17.5.2.26 ("If no type element is specified, then the nearest ancestor structured document tag shall be of type richText"). Before, typeless SDTs - which Word emits for ContentControls.Add(0, range) and the default Add($null, range) - fell through to 'unknown', blocking customers from inspecting Word-authored controls by type. - Detection: typeless sdtPr and explicit <w:richText/> both resolve to 'richText'. Unmodeled type children (w:equation, w:picture, w:citation, w:bibliography, w:docPartList) still return null so resolveControlType yields 'unknown' - keeping 'unknown' as "unsupported or unrecognized", not "typeless rich-text control". - Export/create maps: richText: 'w:richText' in both CONTROL_TYPE_SDT_PR_ELEMENTS (wrappers) and CONTROL_TYPE_ELEMENT_MAP (converter), plus a 'richText' case in buildDefaultTypeSdtPrElement so create.contentControl and setType produce valid OOXML. - text.setValue stays restricted to actual w:text controls. Tests: 22 in handle-structured-content-node.test.js (10 new), 39 in content-controls-wrappers, 1189 in conformance - all pass. * feat(demos): regenerate NDA fixture with plain-text inline fields (SD-3131) The contract-templates demo fixture had inline smart fields authored as default rich-text controls (typeless sdtPr), which is why none of them detected as 'text' - they fell through to 'unknown' before SD-3131 and resolve as 'richText' after. Regenerated nda-template.docx with ContentControls.Add(1, range) for the 7 inline smart fields (now <w:text/> in sdtPr, controlType: 'text') while leaving the 6 block clauses as typeless (controlType: 'richText'). Verified unzip: 13 SDTs total, 7 <w:text/>, 0 explicit <w:richText/>. Switched per-occurrence field update from replaceContent to text.setValue to exercise the typed API. Clause replacement stays on replaceContent because rich-text controls don't have a typed setter. README/JSDoc updated: "seven inline plain-text + six block rich-text" (was "thirteen plain-text"). Honest limits section updated to reflect the API split. Browser smoke verified: receivingParty fan-out updates 2/2 occurrences (header + nested), clause replacement decrements "updates available" correctly, summary line accurate.
…t unknown (SD-3139) (superdoc-dev#3281) Follow-up to SD-3131 (superdoc-dev#3275). After that PR, imported typeless w:sdtPr correctly resolves to controlType: 'richText' per ECMA-376 §17.5.2.26, but newly created controls via create.contentControl (no controlType) and contentControls.wrap still defaulted to 'unknown'. Customers filtering contentControls.list() by type saw different results before vs after save/reopen — the same typeless OOXML round-tripped from 'unknown' to 'richText'. - createWrapper: collapse three `?? 'unknown'` into a single `?? 'richText'` local. - wrapWrapper: explicitly seed controlType, type, and a default sdtPr with <w:richText/> on the wrapper attrs (previously controlType was unset entirely, leaving resolveControlType to fall back to 'unknown'). Newly created controls now emit explicit <w:richText/> in sdtPr for unambiguous engine state and exported markup. Imported typeless Word-authored SDTs preserve their original raw sdtPr (import path unchanged). Per the SD-3131 design, 'unknown' keeps its meaning of "unsupported or unrecognized type" — it's no longer the default for new controls. Tests: 3 new (default-create → richText, explicit-richText-create seeds <w:richText/>, wrap → richText + seeds <w:richText/>). 42 wrappers + 1189 conformance + 1398 document-api pass.
Adds
'richText'toContentControlTypeso SuperDoc resolves typelessw:sdtSDTs to'richText'per ECMA-376 §17.5.2.26 ("If no type element is specified, then the nearest ancestor structured document tag shall be of type richText"). Before this change, typeless SDTs — which is what Word emits forContentControls.Add(0, range)and the defaultAdd($null, range)— fell through to'unknown', blocking customers from inspecting their Word-authored controls by type.handle-structured-content-node.js): typeless sdtPr and explicit<w:richText/>both resolve to'richText'. Unmodeled type children (w:equation,w:picture,w:citation,w:bibliography,w:docPartList) still return null soresolveControlTypeyields'unknown'.unknownkeeps its meaning of "unsupported or unrecognized type", not "typeless rich-text control".richText: 'w:richText'added to bothCONTROL_TYPE_SDT_PR_ELEMENTS(wrappers) andCONTROL_TYPE_ELEMENT_MAP(converter), plus a'richText'case inbuildDefaultTypeSdtPrElementsocreate.contentControl({ controlType: 'richText' })andsetType(..., 'richText')produce valid OOXML.text.setValuestays restricted to actualw:textcontrols. UsereplaceContentfor richText.The contract-templates demo fixture had inline smart fields authored as default rich-text controls (typeless), which is why none of them detected as
'text'. Regeneratednda-template.docxwithContentControls.Add(1, range)for the 7 inline fields (now<w:text/>→controlType: 'text') while leaving the 6 block clauses as typeless (controlType: 'richText'). Switched the demo's per-occurrence field update totext.setValueto exercise the typed API; clause replacement stays onreplaceContent.Verified:
handle-structured-content-node.test.js(10 new), 39 incontent-controls-wrappers, 1189 in conformance, 1398 in@superdoc/document-api— all pass.<w:text/>, 0 explicit<w:richText/>.receivingPartyfan-out updates 2/2 occurrences (header + nested), clause replacement decrements "updates available" correctly.Related: SD-3130, IT-1046.
Scope note: this PR fixes the
richTextcontent-control type classification and OOXML export/create maps. Rendering of substantive rich content inside richText SDTs uses the existing content-driven pipeline and will be covered by a follow-up fixture.