@stll/folio-core 0.22.0 → 0.22.1

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.
@@ -68,10 +68,7 @@ declare function parseEndnotes(endnotesXml: string | null, styles?: StyleMap | n
68
68
  /**
69
69
  * Get plain text content of a footnote.
70
70
  *
71
- * Recurses into block-level SDTs so a citation slot inside a note still
72
- * contributes its text; without recursion, the BlockSdt addition from
73
- * the previous commit would silently hide the slot's body from this
74
- * helper.
71
+ * Uses the accepted tracked-change view and recurses through every note block.
75
72
  */
76
73
  declare function getFootnoteText(footnote: document_d_exports.Footnote): string;
77
74
  /**
@@ -1,8 +1,9 @@
1
1
  import { parseEndnoteProperties, parseFootnoteProperties } from "./notePropertiesParser.js";
2
- import { parseParagraph } from "./paragraphParser.js";
2
+ import { getParagraphText, parseParagraph } from "./paragraphParser.js";
3
3
  import { parseSdtProperties } from "./sdtProperties.js";
4
4
  import { parseTable } from "./tableParser.js";
5
5
  import { findChild, findChildren, getAttributes, getChildElements, getLocalName, parseXml } from "./xmlParser.js";
6
+ import { panic } from "better-result";
6
7
  //#region src/docx/footnoteParser.ts
7
8
  /**
8
9
  * Parse note type attribute
@@ -169,10 +170,7 @@ function createEndnoteMap(byId, endnotes) {
169
170
  /**
170
171
  * Get plain text content of a footnote.
171
172
  *
172
- * Recurses into block-level SDTs so a citation slot inside a note still
173
- * contributes its text; without recursion, the BlockSdt addition from
174
- * the previous commit would silently hide the slot's body from this
175
- * helper.
173
+ * Uses the accepted tracked-change view and recurses through every note block.
176
174
  */
177
175
  function getFootnoteText(footnote) {
178
176
  return collectNoteBlockTexts(footnote.content).join("\n");
@@ -185,13 +183,21 @@ function getEndnoteText(endnote) {
185
183
  }
186
184
  function collectNoteBlockTexts(blocks) {
187
185
  const texts = [];
188
- for (const block of blocks) if (block.type === "paragraph") {
189
- const paraTexts = [];
190
- for (const content of block.content) if (content.type === "run") {
191
- for (const runContent of content.content) if (runContent.type === "text") paraTexts.push(runContent.text);
192
- }
193
- texts.push(paraTexts.join(""));
194
- } else if (block.type === "blockSdt") texts.push(...collectNoteBlockTexts(block.content));
186
+ for (const block of blocks) switch (block.type) {
187
+ case "paragraph":
188
+ texts.push(getParagraphText(block));
189
+ break;
190
+ case "table":
191
+ for (const row of block.rows) {
192
+ if (row.formatting?.hidden === true) continue;
193
+ texts.push(row.cells.map((cell) => collectNoteBlockTexts(cell.content).join("\n")).join(" "));
194
+ }
195
+ break;
196
+ case "blockSdt":
197
+ texts.push(...collectNoteBlockTexts(block.content));
198
+ break;
199
+ default: panic(`Unsupported note block in plain-text extraction: ${JSON.stringify(block)}`);
200
+ }
195
201
  return texts;
196
202
  }
197
203
  /**
@@ -8,6 +8,7 @@ import { parseRun, parseRunProperties } from "./runParser.js";
8
8
  import { parseSdtProperties } from "./sdtProperties.js";
9
9
  import { parseSectionProperties } from "./sectionParser.js";
10
10
  import { elementToXml, findChild, findChildren, getAttribute, getChildElements, getLocalName, matchesName, mergeXmlnsDeclarations, parseBooleanElement, parseNumberingLevelAttribute, parseNumericAttribute } from "./xmlParser.js";
11
+ import { panic } from "better-result";
11
12
  import { normalizeRevisionId } from "@stll/docx-core/model";
12
13
  //#region src/docx/paragraphParser.ts
13
14
  /**
@@ -1107,6 +1108,60 @@ function styleChainInd(styleId, styles) {
1107
1108
  }
1108
1109
  return result;
1109
1110
  }
1111
+ const getRunContentText = (content) => {
1112
+ switch (content.type) {
1113
+ case "text": return content.text;
1114
+ case "tab": return " ";
1115
+ case "break": return content.breakType === "page" ? "\f" : "\n";
1116
+ case "noBreakHyphen": return "‑";
1117
+ case "softHyphen": return "­";
1118
+ case "drawing":
1119
+ case "endnoteRef":
1120
+ case "fieldChar":
1121
+ case "footnoteRef":
1122
+ case "instrText":
1123
+ case "renderedPageBreak":
1124
+ case "shape":
1125
+ case "symbol": return "";
1126
+ default: return panic(`Unsupported run content in plain-text extraction: ${JSON.stringify(content)}`);
1127
+ }
1128
+ };
1129
+ const getRunText = (run) => {
1130
+ if (run.formatting?.hidden === true) return "";
1131
+ return run.content.map(getRunContentText).join("");
1132
+ };
1133
+ const getHyperlinkText = (hyperlink) => hyperlink.children.map((child) => {
1134
+ switch (child.type) {
1135
+ case "run": return getRunText(child);
1136
+ case "bookmarkStart":
1137
+ case "bookmarkEnd": return "";
1138
+ default: return panic(`Unsupported hyperlink child in plain-text extraction: ${JSON.stringify(child)}`);
1139
+ }
1140
+ }).join("");
1141
+ const getParagraphContentText = (content) => {
1142
+ switch (content.type) {
1143
+ case "run": return getRunText(content);
1144
+ case "hyperlink": return getHyperlinkText(content);
1145
+ case "simpleField": return content.content.map(getParagraphContentText).join("");
1146
+ case "complexField": return content.fieldResult.map(getRunText).join("");
1147
+ case "inlineSdt": return content.content.map(getParagraphContentText).join("");
1148
+ case "insertion":
1149
+ case "moveTo": return content.content.map(getParagraphContentText).join("");
1150
+ case "deletion":
1151
+ case "moveFrom": return "";
1152
+ case "mathEquation": return content.plainText ?? "";
1153
+ case "bookmarkEnd":
1154
+ case "bookmarkStart":
1155
+ case "commentRangeEnd":
1156
+ case "commentRangeStart":
1157
+ case "commentReference":
1158
+ case "moveFromRangeEnd":
1159
+ case "moveFromRangeStart":
1160
+ case "moveToRangeEnd":
1161
+ case "moveToRangeStart": return "";
1162
+ default: return panic(`Unsupported paragraph content in plain-text extraction: ${JSON.stringify(content)}`);
1163
+ }
1164
+ };
1110
1165
  /**
1111
1166
  * Get plain text from a paragraph
1112
1167
  *
@@ -1114,24 +1169,7 @@ function styleChainInd(styleId, styles) {
1114
1169
  * @returns Concatenated text content
1115
1170
  */
1116
1171
  function getParagraphText(paragraph) {
1117
- let text = "";
1118
- for (const content of paragraph.content) if (content.type === "run") {
1119
- for (const runContent of content.content) if (runContent.type === "text") text += runContent.text;
1120
- else if (runContent.type === "tab") text += " ";
1121
- else if (runContent.type === "break") if (runContent.breakType === "page") text += "\f";
1122
- else text += "\n";
1123
- } else if (content.type === "hyperlink") {
1124
- for (const child of content.children) if (child.type === "run") {
1125
- for (const runContent of child.content) if (runContent.type === "text") text += runContent.text;
1126
- }
1127
- } else if (content.type === "simpleField") {
1128
- for (const child of content.content) if (child.type === "run") {
1129
- for (const runContent of child.content) if (runContent.type === "text") text += runContent.text;
1130
- }
1131
- } else if (content.type === "complexField") {
1132
- for (const run of content.fieldResult) for (const runContent of run.content) if (runContent.type === "text") text += runContent.text;
1133
- }
1134
- return text;
1172
+ return paragraph.content.map(getParagraphContentText).join("");
1135
1173
  }
1136
1174
  /**
1137
1175
  * Check if a paragraph is empty (no visible content)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/folio-core",
3
- "version": "0.22.0",
3
+ "version": "0.22.1",
4
4
  "description": "Headless, framework-neutral core of folio: the OOXML (.docx) parser, document model, ProseMirror integration, and page-layout engine. No React.",
5
5
  "keywords": [
6
6
  "document-model",