rtf-codec 3.0.1 → 3.0.2
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/README.md +18 -17
- package/dist/codepage.d.cts +1 -1
- package/dist/codepage.d.ts +1 -1
- package/dist/{diagnostics-CjMoO7x1.d.cts → diagnostics-DWEjJXeQ.d.cts} +1 -0
- package/dist/{diagnostics-CjMoO7x1.d.ts → diagnostics-DWEjJXeQ.d.ts} +1 -0
- package/dist/diagnostics.cjs +1 -0
- package/dist/diagnostics.d.cts +1 -1
- package/dist/diagnostics.d.ts +1 -1
- package/dist/diagnostics.js +1 -0
- package/dist/header.d.cts +1 -1
- package/dist/header.d.ts +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/options.d.cts +1 -1
- package/dist/options.d.ts +1 -1
- package/dist/read.cjs +19 -4
- package/dist/read.d.cts +1 -1
- package/dist/read.d.ts +1 -1
- package/dist/read.js +19 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -148,23 +148,24 @@ A `contentControl` construct mints a real `\*\formfield` only for the three cont
|
|
|
148
148
|
|
|
149
149
|
Each of these is reported through a diagnostic rather than dropped silently — see [Diagnostics](#diagnostics).
|
|
150
150
|
|
|
151
|
-
| Construct
|
|
152
|
-
|
|
|
153
|
-
| Headers, footers, footnotes, endnotes, annotations
|
|
154
|
-
| Content controls beyond RTF's own form-field vocabulary (richText, comboBox, date, picture, repeatingSection, button, index, group)
|
|
155
|
-
| East Asian DBCS code pages (932, 936, 949, 950, 1361)
|
|
156
|
-
| Code page 42 (`SYMBOL_CHARSET`)
|
|
157
|
-
| Metafile and bitmap pictures (`\wmetafileN`, `\emfblip`, `\dibitmapN`, `\wbitmapN`, `\macpict`)
|
|
158
|
-
| A picture with no stated size
|
|
159
|
-
| Nested tables (`\nestcell`/`\nestrow`)
|
|
160
|
-
| Drawing objects (`\do`, `\shp`)
|
|
161
|
-
| A real, foreign `\object`'s OLE data
|
|
162
|
-
| Superscript/subscript (`\super`, `\sub`, `\upN`, `\dnN`), character scaling, kerning, background colour
|
|
163
|
-
| Right-to-left text (`\rtlch`, `\ltrch`, `\rtlpar`, `\rtlrow`, `\rtldoc`)
|
|
164
|
-
| Cell vertical alignment (`\clvertalt`/`\clvertalc`/`\clvertalb`), diagonal cell borders (`\cldglu`/`\cldgll`), `\clshdngN`
|
|
165
|
-
| A bookmark whose two halves straddle a table cell wall
|
|
166
|
-
| A contentControl extent that crosses another contentControl extent in the same paragraph
|
|
167
|
-
|
|
|
151
|
+
| Construct | Why |
|
|
152
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
153
|
+
| Headers, footers, footnotes, endnotes, annotations | `ContentDocument`'s flat form has no page-furniture or note position for them. A footnote's real home is `document-schema.js`'s tree-only `definitions` table, which a codec producing the flat form cannot reach. |
|
|
154
|
+
| Content controls beyond RTF's own form-field vocabulary (richText, comboBox, date, picture, repeatingSection, button, index, group) | **RTF 1.9.1 specifies nothing for these.** It predates OOXML's `w:sdt`: its "Custom XML Tags" (`\xmlopen`/`\xmlclose`) are a bare namespace/name tag with no type, lock, alias or value, and `\*\datastore` is an opaque blob whose "format ... is unknown to RTF" by the spec's own words. `\*\formfield` (see the Scope table above) is the one real analogue RTF has, and covers plainText/checkbox/dropDown only. |
|
|
155
|
+
| East Asian DBCS code pages (932, 936, 949, 950, 1361) | Each needs a ~20k-entry table and its own lead-byte state machine. A document declaring one decodes through cp1252 and says so. |
|
|
156
|
+
| Code page 42 (`SYMBOL_CHARSET`) | Not an encoding: its bytes are glyph indices into whichever symbol font the run names, so there is no correct Unicode for them without that font's own cmap. |
|
|
157
|
+
| Metafile and bitmap pictures (`\wmetafileN`, `\emfblip`, `\dibitmapN`, `\wbitmapN`, `\macpict`) | `ContentImageBlock` carries PNG and JPEG only. |
|
|
158
|
+
| A picture with no stated size | `ContentImageBlock` requires a positive width and height, and deriving them from the payload would need an image decoder this package deliberately does not carry. |
|
|
159
|
+
| Nested tables (`\nestcell`/`\nestrow`) | Read as ordinary cell content; the inner table's own structure is not reconstructed. |
|
|
160
|
+
| Drawing objects (`\do`, `\shp`) | **A schema gap, not a container one.** These are Word's own native in-document vector-drawing layer, not an OLE embed -- there is no raw drawing-shape `ContentBlock` for a wordprocessing section's block flow to land in (only `ContentEmbeddedObjectBlock`, which names a whole embedded document, not a shape), so a `\do`/`\shp` construct is dropped regardless of the container work [Embedded objects](#embedded-objects) below did for `\object`. |
|
|
161
|
+
| A real, foreign `\object`'s OLE data | This package's own `\objdata` payload round-trips fully (see [Embedded objects](#embedded-objects)); a real Word-authored OLESaveToStream structure (an actual embedded `.xls`/`.doc`/OLE-control payload) has no decoder here and degrades with a diagnostic, recovering `\result`'s own fallback paragraphs when present instead of the real object. |
|
|
162
|
+
| Superscript/subscript (`\super`, `\sub`, `\upN`, `\dnN`), character scaling, kerning, background colour | **A schema gap, not an RTF one.** `ContentRun` carries no vertical-alignment field at all -- `epub-codec` reports the identical gap for its own `<sub>`/`<sup>`, and `ooxml.js`'s docx reader has no `w:vertAlign` handling either. Closing it is a change to `document-schema.js` and every codec that would then carry it, not to this one. |
|
|
163
|
+
| Right-to-left text (`\rtlch`, `\ltrch`, `\rtlpar`, `\rtlrow`, `\rtldoc`) | The same shape of gap: no `ContentDocument` field carries text direction, at any of the four scopes RTF states it at. |
|
|
164
|
+
| Cell vertical alignment (`\clvertalt`/`\clvertalc`/`\clvertalb`), diagonal cell borders (`\cldglu`/`\cldgll`), `\clshdngN` | `ContentTableCell.borders` has no diagonal member, so a diagonal rule is not a side; `\clshdngN`'s own shading percentage names a genuine two-colour pattern fill, which `document-schema.js`'s `ContentCellFill` can now express (ExaDev/documents.js#951) but this package does not yet resolve either `\clcbpatN`'s own foreground colour or `\clshdngN`'s percentage into one -- `\clcbpatN`'s background colour alone still reads and writes as a `'solid'` fill. |
|
|
165
|
+
| A bookmark whose two halves straddle a table cell wall | `document-schema.js` ratifies this as a drop rather than a shape to repair: each block list is its own bracket scope, and pairing across two of them would need the marker ids its contract deliberately refuses. |
|
|
166
|
+
| A contentControl extent that crosses another contentControl extent in the same paragraph | RTF's `\*\formfield` destination can only nest, never cross: a `{\field...}` group nests cleanly inside another one's own `\fldrslt`, but two extents that start-before/end-after each other have no valid brace sequence, since whichever closes second would close the other's own braces instead of its own. |
|
|
167
|
+
| Two block-scoped bookmarks whose real ranges are disjoint but whose halves both land in the same paragraph (one's `\bkmkend`, the other's `\bkmkstart`) | A paragraph is this reader's finest addressable block-extent unit, so the shared paragraph's own block index gets claimed by both bookmarks' extents even though their real text never overlapped -- a genuine crossing pair, not a nesting one, and `document-schema.js`'s own construct group has no shape for that (a tree would need two subtrees crossing, which no tree holds). The later-starting bookmark is dropped with a diagnostic; the earlier one keeps its extent intact. |
|
|
168
|
+
| A `table` or `pageBreak` block placed directly inside a table cell | `writeCellBlocks` writes a cell's own content as a run of `\intbl` `<pict>`/`<obj>`/paragraph groups, plus any bracketing `constructStart`/`constructEnd` markers spliced in inline exactly as `writeBlock` does at the top level; an `image`/`embeddedObject` block borrows the identical `\intbl` shell a paragraph gets (a `\pict`/`\object` group inside an ordinary `\intbl` paragraph is a real, already-round-trippable shape -- see the tests around it), but a nested `table` needs its own `\itapN` row grammar this writer does not build, and a mid-row `\page` would `\pard`-reset the row's own `\intbl` state, so those two kinds are still dropped. |
|
|
168
169
|
|
|
169
170
|
## Embedded objects
|
|
170
171
|
|
package/dist/codepage.d.cts
CHANGED
package/dist/codepage.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ declare const RtfDiagnosticCodes: {
|
|
|
21
21
|
readonly NESTED_TABLE_FLATTENED: "rtf/nested-table-flattened";
|
|
22
22
|
readonly SECTION_BREAK_UNREPRESENTED: "rtf/section-break-unrepresented";
|
|
23
23
|
readonly BOOKMARK_UNPAIRED: "rtf/bookmark-unpaired";
|
|
24
|
+
readonly BLOCK_CONSTRUCT_EXTENTS_CROSSED: "rtf/block-construct-extents-crossed";
|
|
24
25
|
readonly FORM_FIELD_SPAN_DROPPED: "rtf/form-field-span-dropped";
|
|
25
26
|
readonly FORM_FIELD_KEYWORD_LOST: "rtf/form-field-keyword-lost";
|
|
26
27
|
readonly CONSTRUCT_UNREPRESENTED: "rtf/construct-unrepresented";
|
|
@@ -21,6 +21,7 @@ declare const RtfDiagnosticCodes: {
|
|
|
21
21
|
readonly NESTED_TABLE_FLATTENED: "rtf/nested-table-flattened";
|
|
22
22
|
readonly SECTION_BREAK_UNREPRESENTED: "rtf/section-break-unrepresented";
|
|
23
23
|
readonly BOOKMARK_UNPAIRED: "rtf/bookmark-unpaired";
|
|
24
|
+
readonly BLOCK_CONSTRUCT_EXTENTS_CROSSED: "rtf/block-construct-extents-crossed";
|
|
24
25
|
readonly FORM_FIELD_SPAN_DROPPED: "rtf/form-field-span-dropped";
|
|
25
26
|
readonly FORM_FIELD_KEYWORD_LOST: "rtf/form-field-keyword-lost";
|
|
26
27
|
readonly CONSTRUCT_UNREPRESENTED: "rtf/construct-unrepresented";
|
package/dist/diagnostics.cjs
CHANGED
|
@@ -14,6 +14,7 @@ const RtfDiagnosticCodes = {
|
|
|
14
14
|
NESTED_TABLE_FLATTENED: "rtf/nested-table-flattened",
|
|
15
15
|
SECTION_BREAK_UNREPRESENTED: "rtf/section-break-unrepresented",
|
|
16
16
|
BOOKMARK_UNPAIRED: "rtf/bookmark-unpaired",
|
|
17
|
+
BLOCK_CONSTRUCT_EXTENTS_CROSSED: "rtf/block-construct-extents-crossed",
|
|
17
18
|
FORM_FIELD_SPAN_DROPPED: "rtf/form-field-span-dropped",
|
|
18
19
|
FORM_FIELD_KEYWORD_LOST: "rtf/form-field-keyword-lost",
|
|
19
20
|
CONSTRUCT_UNREPRESENTED: "rtf/construct-unrepresented",
|
package/dist/diagnostics.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-
|
|
1
|
+
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-DWEjJXeQ.cjs";
|
|
2
2
|
export { NOOP_RTF_DIAGNOSTIC_SINK, RtfDiagnostic, RtfDiagnosticCodes, RtfDiagnosticSeverity, RtfDiagnosticSink, RtfInputTooLargeError, RtfNestingLimitExceededError, RtfNotAnRtfDocumentError, RtfParseError, RtfUnsupportedDocumentKindError, RtfWriteError };
|
package/dist/diagnostics.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-
|
|
1
|
+
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-DWEjJXeQ.js";
|
|
2
2
|
export { NOOP_RTF_DIAGNOSTIC_SINK, RtfDiagnostic, RtfDiagnosticCodes, RtfDiagnosticSeverity, RtfDiagnosticSink, RtfInputTooLargeError, RtfNestingLimitExceededError, RtfNotAnRtfDocumentError, RtfParseError, RtfUnsupportedDocumentKindError, RtfWriteError };
|
package/dist/diagnostics.js
CHANGED
|
@@ -13,6 +13,7 @@ const RtfDiagnosticCodes = {
|
|
|
13
13
|
NESTED_TABLE_FLATTENED: "rtf/nested-table-flattened",
|
|
14
14
|
SECTION_BREAK_UNREPRESENTED: "rtf/section-break-unrepresented",
|
|
15
15
|
BOOKMARK_UNPAIRED: "rtf/bookmark-unpaired",
|
|
16
|
+
BLOCK_CONSTRUCT_EXTENTS_CROSSED: "rtf/block-construct-extents-crossed",
|
|
16
17
|
FORM_FIELD_SPAN_DROPPED: "rtf/form-field-span-dropped",
|
|
17
18
|
FORM_FIELD_KEYWORD_LOST: "rtf/form-field-keyword-lost",
|
|
18
19
|
CONSTRUCT_UNREPRESENTED: "rtf/construct-unrepresented",
|
package/dist/header.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as RtfDiagnosticSink } from "./diagnostics-
|
|
1
|
+
import { a as RtfDiagnosticSink } from "./diagnostics-DWEjJXeQ.cjs";
|
|
2
2
|
import { RtfToken } from "./tokenize.cjs";
|
|
3
3
|
import { Color, LayoutMetadata } from "document-schema.js";
|
|
4
4
|
//#region src/header.d.ts
|
package/dist/header.d.ts
CHANGED
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { rtfBytesFromLatin1 } from "./bytes.cjs";
|
|
2
2
|
import { RtfBytesSchema, rtfCodec, rtfContentCodec } from "./codec.cjs";
|
|
3
|
-
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-
|
|
3
|
+
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-DWEjJXeQ.cjs";
|
|
4
4
|
import { DEFAULT_MAX_GROUP_DEPTH, DEFAULT_MAX_INPUT_BYTES, ReadRtfOptions, RtfLineEnding, WriteRtfOptions } from "./options.cjs";
|
|
5
5
|
import { ReadRtfContentResult, ReadRtfResult, readRtf, readRtfContent } from "./read.cjs";
|
|
6
6
|
import { writeRtf, writeRtfContent } from "./write.cjs";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { rtfBytesFromLatin1 } from "./bytes.js";
|
|
2
2
|
import { RtfBytesSchema, rtfCodec, rtfContentCodec } from "./codec.js";
|
|
3
|
-
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-
|
|
3
|
+
import { a as RtfDiagnosticSink, c as RtfNotAnRtfDocumentError, d as RtfWriteError, i as RtfDiagnosticSeverity, l as RtfParseError, n as RtfDiagnostic, o as RtfInputTooLargeError, r as RtfDiagnosticCodes, s as RtfNestingLimitExceededError, t as NOOP_RTF_DIAGNOSTIC_SINK, u as RtfUnsupportedDocumentKindError } from "./diagnostics-DWEjJXeQ.js";
|
|
4
4
|
import { DEFAULT_MAX_GROUP_DEPTH, DEFAULT_MAX_INPUT_BYTES, ReadRtfOptions, RtfLineEnding, WriteRtfOptions } from "./options.js";
|
|
5
5
|
import { ReadRtfContentResult, ReadRtfResult, readRtf, readRtfContent } from "./read.js";
|
|
6
6
|
import { writeRtf, writeRtfContent } from "./write.js";
|
package/dist/options.d.cts
CHANGED
package/dist/options.d.ts
CHANGED
package/dist/read.cjs
CHANGED
|
@@ -275,9 +275,24 @@ function skipUnicodeFallback(tokens, from, count) {
|
|
|
275
275
|
textOffset
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
|
-
function
|
|
278
|
+
function dropCrossingExtents(ordered, sink) {
|
|
279
|
+
const kept = [];
|
|
280
|
+
for (const candidate of ordered) {
|
|
281
|
+
if (kept.some((extent) => candidate.startIndex < extent.endIndex && candidate.endIndex > extent.endIndex)) {
|
|
282
|
+
sink({
|
|
283
|
+
code: require_diagnostics.RtfDiagnosticCodes.BLOCK_CONSTRUCT_EXTENTS_CROSSED,
|
|
284
|
+
severity: "warning",
|
|
285
|
+
message: `a '${candidate.descriptor.kind}' construct's own block extent crosses an already-open one instead of nesting inside or sitting disjoint from it -- both bookmarks likely closed and opened within the same paragraph, which this reader cannot express as two separate extents, so this one is dropped`
|
|
286
|
+
});
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
kept.push(candidate);
|
|
290
|
+
}
|
|
291
|
+
return kept;
|
|
292
|
+
}
|
|
293
|
+
function insertConstructMarkers(blocks, extents, sink) {
|
|
279
294
|
if (extents.length === 0) return [...blocks];
|
|
280
|
-
const ordered = [...extents].sort((left, right) => left.startIndex - right.startIndex || right.endIndex - left.endIndex);
|
|
295
|
+
const ordered = dropCrossingExtents([...extents].sort((left, right) => left.startIndex - right.startIndex || right.endIndex - left.endIndex), sink);
|
|
281
296
|
const closing = [...ordered].reverse();
|
|
282
297
|
const out = [];
|
|
283
298
|
for (let index = 0; index <= blocks.length; index += 1) {
|
|
@@ -560,7 +575,7 @@ var ContentBuilder = class {
|
|
|
560
575
|
endCell(para) {
|
|
561
576
|
this.endParagraph(para, false);
|
|
562
577
|
this.flushClosingBookmarks(true, this.cellBlocks.length);
|
|
563
|
-
this.rowCells.push({ blocks: insertConstructMarkers(this.cellBlocks, this.cellBlockExtents) });
|
|
578
|
+
this.rowCells.push({ blocks: insertConstructMarkers(this.cellBlocks, this.cellBlockExtents, this.sink) });
|
|
564
579
|
this.cellBlocks = [];
|
|
565
580
|
this.cellBlockExtents = [];
|
|
566
581
|
}
|
|
@@ -742,7 +757,7 @@ var ContentBuilder = class {
|
|
|
742
757
|
this.closeTable();
|
|
743
758
|
this.flushClosingBookmarks(false, this.blocks.length);
|
|
744
759
|
this.reportUnclosedBookmarks();
|
|
745
|
-
const blocks = insertConstructMarkers(this.blocks, this.sectionBlockExtents);
|
|
760
|
+
const blocks = insertConstructMarkers(this.blocks, this.sectionBlockExtents, this.sink);
|
|
746
761
|
this.sectionBlockExtents = [];
|
|
747
762
|
if (blocks.length === 0 && this.sections.length > 0) {
|
|
748
763
|
this.blocks = [];
|
package/dist/read.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as RtfDiagnostic } from "./diagnostics-
|
|
1
|
+
import { n as RtfDiagnostic } from "./diagnostics-DWEjJXeQ.cjs";
|
|
2
2
|
import { ReadRtfOptions } from "./options.cjs";
|
|
3
3
|
import { ContentDocument, DocumentTree } from "document-schema.js";
|
|
4
4
|
//#region src/read.d.ts
|
package/dist/read.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as RtfDiagnostic } from "./diagnostics-
|
|
1
|
+
import { n as RtfDiagnostic } from "./diagnostics-DWEjJXeQ.js";
|
|
2
2
|
import { ReadRtfOptions } from "./options.js";
|
|
3
3
|
import { ContentDocument, DocumentTree } from "document-schema.js";
|
|
4
4
|
//#region src/read.d.ts
|
package/dist/read.js
CHANGED
|
@@ -274,9 +274,24 @@ function skipUnicodeFallback(tokens, from, count) {
|
|
|
274
274
|
textOffset
|
|
275
275
|
};
|
|
276
276
|
}
|
|
277
|
-
function
|
|
277
|
+
function dropCrossingExtents(ordered, sink) {
|
|
278
|
+
const kept = [];
|
|
279
|
+
for (const candidate of ordered) {
|
|
280
|
+
if (kept.some((extent) => candidate.startIndex < extent.endIndex && candidate.endIndex > extent.endIndex)) {
|
|
281
|
+
sink({
|
|
282
|
+
code: RtfDiagnosticCodes.BLOCK_CONSTRUCT_EXTENTS_CROSSED,
|
|
283
|
+
severity: "warning",
|
|
284
|
+
message: `a '${candidate.descriptor.kind}' construct's own block extent crosses an already-open one instead of nesting inside or sitting disjoint from it -- both bookmarks likely closed and opened within the same paragraph, which this reader cannot express as two separate extents, so this one is dropped`
|
|
285
|
+
});
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
kept.push(candidate);
|
|
289
|
+
}
|
|
290
|
+
return kept;
|
|
291
|
+
}
|
|
292
|
+
function insertConstructMarkers(blocks, extents, sink) {
|
|
278
293
|
if (extents.length === 0) return [...blocks];
|
|
279
|
-
const ordered = [...extents].sort((left, right) => left.startIndex - right.startIndex || right.endIndex - left.endIndex);
|
|
294
|
+
const ordered = dropCrossingExtents([...extents].sort((left, right) => left.startIndex - right.startIndex || right.endIndex - left.endIndex), sink);
|
|
280
295
|
const closing = [...ordered].reverse();
|
|
281
296
|
const out = [];
|
|
282
297
|
for (let index = 0; index <= blocks.length; index += 1) {
|
|
@@ -559,7 +574,7 @@ var ContentBuilder = class {
|
|
|
559
574
|
endCell(para) {
|
|
560
575
|
this.endParagraph(para, false);
|
|
561
576
|
this.flushClosingBookmarks(true, this.cellBlocks.length);
|
|
562
|
-
this.rowCells.push({ blocks: insertConstructMarkers(this.cellBlocks, this.cellBlockExtents) });
|
|
577
|
+
this.rowCells.push({ blocks: insertConstructMarkers(this.cellBlocks, this.cellBlockExtents, this.sink) });
|
|
563
578
|
this.cellBlocks = [];
|
|
564
579
|
this.cellBlockExtents = [];
|
|
565
580
|
}
|
|
@@ -741,7 +756,7 @@ var ContentBuilder = class {
|
|
|
741
756
|
this.closeTable();
|
|
742
757
|
this.flushClosingBookmarks(false, this.blocks.length);
|
|
743
758
|
this.reportUnclosedBookmarks();
|
|
744
|
-
const blocks = insertConstructMarkers(this.blocks, this.sectionBlockExtents);
|
|
759
|
+
const blocks = insertConstructMarkers(this.blocks, this.sectionBlockExtents, this.sink);
|
|
745
760
|
this.sectionBlockExtents = [];
|
|
746
761
|
if (blocks.length === 0 && this.sections.length > 0) {
|
|
747
762
|
this.blocks = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rtf-codec",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Hand-written Rich Text Format (RTF 1.9.1) reader and writer against the shared document-schema.js content pivot.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"license": "MIT",
|
|
81
81
|
"packageManager": "pnpm@11.6.0",
|
|
82
82
|
"dependencies": {
|
|
83
|
-
"archive-codec": "^1.6.
|
|
84
|
-
"document-schema.js": "^6.2.
|
|
83
|
+
"archive-codec": "^1.6.2",
|
|
84
|
+
"document-schema.js": "^6.2.1",
|
|
85
85
|
"zod": "^4.4.3"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|