feat: add w:pPrChange translator for paragraph property tracked changes (SD-2417)#2705
Conversation
|
Status: PASS The One minor note: See https://ooxml.dev/spec?q=pPrChange for full spec details. |
33e5e5c to
3e946ec
Compare
This issue was fixed. |
There was a problem hiding this comment.
@luccas-harbour clean structure — sharing the base translators between pPr and pPrChange is a nice call.
one issue: when the original <w:pPr/> inside <w:pPrChange> is empty, it gets lost on round-trip. the decode guard you added works, but the encode side never feeds it — the key gets dropped for empty elements. tested with a Word file — the empty <w:pPr/> disappears after export.
also a minor DX thing and a pre-existing ordering note — details in inline comments.
tests look good. left a few comments.
| const changeNode = params.nodes[0]; | ||
| const pPrNode = changeNode?.elements?.find((el) => el.name === 'w:pPr'); | ||
|
|
||
| let paragraphProperties = pPrNode ? pPrTranslator.encode({ ...params, nodes: [pPrNode] }) : undefined; |
There was a problem hiding this comment.
when <w:pPr/> exists but is empty, pPrTranslator.encode() returns undefined here — so the paragraphProperties key never makes it into the result. later, when decoding back to XML, the guard at line 81 (hasParagraphProperties) can't fire because the key is missing. the empty <w:pPr/> is lost.
the spec says <w:pPr> is required inside <w:pPrChange> — even when empty it means "there were no previous properties." tested with a real Word file and confirmed the element disappears after export.
| let paragraphProperties = pPrNode ? pPrTranslator.encode({ ...params, nodes: [pPrNode] }) : undefined; | |
| let paragraphProperties = pPrNode ? (pPrTranslator.encode({ ...params, nodes: [pPrNode] }) ?? {}) : undefined; |
| wWordWrapTranslator, | ||
| wRPrTranslator, | ||
| ]; | ||
| const propertyTranslators = [...basePropertyTranslators, wPPrChangeTranslator]; |
There was a problem hiding this comment.
not blocking, just a heads up: the spec expects sectPr before pPrChange inside <w:pPr>, but the exporter always puts sectPr last. so if a paragraph has both a section break and a tracked property change, they'll be in the wrong order. this predates your PR — the pattern was already there, it just didn't matter until pPrChange existed. rare in practice. maybe a follow-up ticket?
| attributeHandlers = [], | ||
| { emitWhenAttributesOnly = false } = {}, | ||
| ) { | ||
| const propertyTranslatorsByXmlName = {}; |
There was a problem hiding this comment.
emitWhenAttributesOnly isn't used anywhere — the pPrChange translator handles this case with its own logic instead. worth removing so it doesn't sit here unused?
Summary
w:pPrChangetranslator that encodes/decodes tracked changes on paragraph properties (author, date, id) along with the nestedw:pPrcontaining the previous propertiesw:pPrand in the global handler indexpPr↔pPrChange