@docx4j/core-ts 0.6.0 → 0.7.0
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 +60 -0
- package/dist/model/content/Body.mjs +6 -17
- package/dist/model/content/Comment.d.mts +2 -2
- package/dist/model/content/Comment.mjs +12 -7
- package/dist/model/content/ContentControl.d.mts +1 -1
- package/dist/model/content/ContentControl.mjs +8 -4
- package/dist/model/content/Font.d.mts +4 -1
- package/dist/model/content/Font.mjs +6 -2
- package/dist/model/content/List.d.mts +6 -3
- package/dist/model/content/List.mjs +15 -8
- package/dist/model/content/Paragraph.d.mts +12 -2
- package/dist/model/content/Paragraph.mjs +31 -11
- package/dist/model/content/Table.mjs +26 -16
- package/dist/model/content/TrackedChange.d.mts +2 -2
- package/dist/model/content/TrackedChange.mjs +6 -3
- package/dist/model/content/index.d.mts +3 -1
- package/dist/model/content/index.mjs +4 -1
- package/dist/model/content/ooxml.mjs +12 -1
- package/dist/model/content/paraIds.d.mts +5 -0
- package/dist/model/content/paraIds.mjs +54 -0
- package/dist/model/content/search.d.mts +2 -0
- package/dist/model/content/search.mjs +51 -7
- package/dist/model/content/story.d.mts +5 -2
- package/dist/model/content/story.mjs +6 -3
- package/dist/model/content/tableRules.mjs +2 -0
- package/dist/model/content/tracking.d.mts +35 -6
- package/dist/model/content/tracking.mjs +93 -12
- package/dist/model/content/tree.d.mts +7 -8
- package/dist/model/content/tree.mjs +7 -9
- package/dist/model/content/wordRange.d.mts +48 -0
- package/dist/model/content/wordRange.mjs +97 -0
- package/dist/model/customxml/CustomXmlPartCollection.d.mts +22 -1
- package/dist/model/customxml/CustomXmlPartCollection.mjs +48 -2
- package/dist/model/customxml/XmlMapping.d.mts +31 -7
- package/dist/model/customxml/XmlMapping.mjs +53 -10
- package/dist/model/customxml/bindings.d.mts +12 -2
- package/dist/model/customxml/bindings.mjs +98 -16
- package/dist/model/customxml/index.d.mts +1 -0
- package/dist/model/customxml/index.mjs +1 -0
- package/dist/model/customxml/opendope.d.mts +4 -1
- package/dist/model/customxml/opendope.mjs +9 -6
- package/dist/model/customxml/pictures.mjs +5 -3
- package/dist/model/customxml/storeItems.d.mts +57 -0
- package/dist/model/customxml/storeItems.mjs +122 -0
- package/dist/model/customxml/xhtml.mjs +15 -20
- package/dist/model/dateZone.d.mts +25 -0
- package/dist/model/dateZone.mjs +57 -0
- package/dist/model/index.d.mts +1 -0
- package/dist/model/index.mjs +1 -0
- package/dist/model/properties/PropertyResolver.d.mts +14 -1
- package/dist/model/properties/PropertyResolver.mjs +18 -3
- package/dist/model/properties/index.d.mts +1 -1
- package/dist/model/properties/log.mjs +2 -2
- package/dist/model/properties/styleUtil.d.mts +3 -1
- package/dist/model/properties/styleUtil.mjs +20 -24
- package/dist/model/text/CaseMapping.d.mts +38 -0
- package/dist/model/text/CaseMapping.mjs +86 -0
- package/dist/model/text/Extractor.d.mts +66 -6
- package/dist/model/text/Extractor.mjs +300 -56
- package/dist/model/text/PlainText.mjs +7 -4
- package/dist/model/text/TextContext.d.mts +103 -8
- package/dist/model/text/TextContext.mjs +228 -53
- package/dist/model/text/TextOptions.d.mts +88 -5
- package/dist/model/text/TextOptions.mjs +158 -17
- package/dist/model/text/TextResult.d.mts +126 -9
- package/dist/model/text/TextResult.mjs +115 -12
- package/dist/model/text/WmlToMarkdown.mjs +32 -7
- package/dist/model/text/caseMapping.generated.d.mts +7 -0
- package/dist/model/text/caseMapping.generated.mjs +214 -0
- package/dist/model/text/index.d.mts +3 -2
- package/dist/model/text/index.mjs +1 -0
- package/dist/model/wordIntegers.d.mts +29 -0
- package/dist/model/wordIntegers.mjs +78 -0
- package/dist/office-js/document.mjs +15 -1
- package/dist/office-js/toApiScript.mjs +8 -7
- package/dist/opc/DirectoryPartStore.d.mts +6 -2
- package/dist/opc/DirectoryPartStore.mjs +11 -4
- package/dist/opc/FlatOpcPartStore.d.mts +4 -2
- package/dist/opc/FlatOpcPartStore.mjs +11 -8
- package/dist/opc/Load.d.mts +32 -0
- package/dist/opc/Load.mjs +115 -5
- package/dist/opc/PartStore.d.mts +34 -1
- package/dist/opc/PartStore.mjs +71 -8
- package/dist/opc/Save.d.mts +17 -2
- package/dist/opc/Save.mjs +100 -4
- package/dist/opc/ZipPartStore.d.mts +4 -2
- package/dist/opc/ZipPartStore.mjs +12 -7
- package/dist/opc/exceptions.d.mts +140 -0
- package/dist/opc/exceptions.mjs +108 -0
- package/dist/opc/index.d.mts +7 -4
- package/dist/opc/index.mjs +5 -3
- package/dist/opc/mce/preprocessor.d.mts +121 -10
- package/dist/opc/mce/preprocessor.mjs +122 -21
- package/dist/opc/mce/understood.d.mts +3 -35
- package/dist/opc/mce/understood.mjs +27 -53
- package/dist/opc/repair/breaks.d.mts +23 -0
- package/dist/opc/repair/breaks.mjs +288 -0
- package/dist/opc/repair/hosts.d.mts +12 -0
- package/dist/opc/repair/hosts.mjs +33 -0
- package/dist/opc/repair/mainRoot.d.mts +19 -0
- package/dist/opc/repair/mainRoot.mjs +168 -0
- package/dist/opc/repair/unknownElements.d.mts +8 -0
- package/dist/opc/repair/unknownElements.mjs +180 -0
- package/dist/opc/repair/wmlNames.generated.d.mts +2 -0
- package/dist/opc/repair/wmlNames.generated.mjs +80 -0
- package/dist/opc/skipped.d.mts +50 -0
- package/dist/opc/skipped.mjs +140 -0
- package/dist/packages/OpcPackage.d.mts +98 -5
- package/dist/packages/OpcPackage.mjs +122 -7
- package/dist/packages/WordprocessingMLPackage.mjs +3 -1
- package/dist/packages/index.d.mts +1 -1
- package/dist/parts/Part.d.mts +5 -1
- package/dist/parts/RelationshipsPart.d.mts +15 -0
- package/dist/parts/RelationshipsPart.mjs +66 -1
- package/dist/parts/XmlPart.d.mts +54 -5
- package/dist/parts/XmlPart.mjs +203 -10
- package/dist/parts/wml/index.d.mts +12 -1
- package/dist/parts/wml/index.mjs +25 -1
- package/package.json +2 -2
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { AlternativeFormatInputPart } from '../../parts/BinaryPart.mjs';
|
|
2
|
-
import { Emulator } from '../listnumbering/Emulator.mjs';
|
|
3
2
|
import { runItemsOf, selectedBranchOf, segmentsOf, hiddenRunsOf, SDT_TYPES } from '../content/tree.mjs';
|
|
4
3
|
import { TextBlock, TextRun, TextRow, TextCell, TextField, TextNumbering, TextRevision, TextWarning, TextComment, TextImage, TextResult, } from './TextResult.mjs';
|
|
5
|
-
import {
|
|
4
|
+
import { revisionDateText } from '../content/tracking.mjs';
|
|
6
5
|
import { normalize } from './normalize.mjs';
|
|
7
6
|
const W_NS = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
|
|
8
7
|
const R_NS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
|
|
@@ -146,8 +145,9 @@ function asciiFont(rPr) {
|
|
|
146
145
|
var _a;
|
|
147
146
|
return (_a = rPr === null || rPr === void 0 ? void 0 : rPr.rFonts) === null || _a === void 0 ? void 0 : _a.ascii;
|
|
148
147
|
}
|
|
148
|
+
/** A revision with its author and its stamp as REQ-702 writes it: the author's local time, the offset where known (CR-012 section 23.7). */
|
|
149
149
|
function revisionOf(tc, type) {
|
|
150
|
-
return new TextRevision(type, tc.author,
|
|
150
|
+
return new TextRevision(type, tc.author, revisionDateText(tc.date, tc.dateUtc));
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
153
153
|
* Each item's place in `Paragraph.text` (CR-012 D2, section 4.4): the content API's own reader since phase 4
|
|
@@ -172,6 +172,8 @@ class FieldState {
|
|
|
172
172
|
this.locked = false;
|
|
173
173
|
/** A table of contents under `toc: false` (D12): nothing of it is read. */
|
|
174
174
|
this.toc = false;
|
|
175
|
+
/** A SET field: its stored result is never shown (Word hides it; REQ-505, CR-012 section 26). */
|
|
176
|
+
this.hiddenResult = false;
|
|
175
177
|
this.codeStart = 0;
|
|
176
178
|
this.previousFloor = 0;
|
|
177
179
|
}
|
|
@@ -185,6 +187,7 @@ class FieldState {
|
|
|
185
187
|
f.computed = this.computed;
|
|
186
188
|
f.link = this.link;
|
|
187
189
|
f.toc = this.toc;
|
|
190
|
+
f.hiddenResult = this.hiddenResult;
|
|
188
191
|
return f;
|
|
189
192
|
}
|
|
190
193
|
}
|
|
@@ -220,6 +223,8 @@ class Story {
|
|
|
220
223
|
this.pending = [];
|
|
221
224
|
this.tableDepth = 0;
|
|
222
225
|
this.noteNumber = 0;
|
|
226
|
+
if (part)
|
|
227
|
+
x.storyParts.add(part);
|
|
223
228
|
}
|
|
224
229
|
/** The resolver the walk reads styles with, for `officeSpans`' hidden rule. */
|
|
225
230
|
get resolver() {
|
|
@@ -268,6 +273,8 @@ export class Extractor {
|
|
|
268
273
|
this.context = context;
|
|
269
274
|
this.warnings = [];
|
|
270
275
|
this.warned = new Set();
|
|
276
|
+
/** The parts this reading took a story from, for what the walk can't meet (`partWarningsUnmet`). */
|
|
277
|
+
this.storyParts = new Set();
|
|
271
278
|
/** What every address this extraction makes starts with. */
|
|
272
279
|
this.root = '';
|
|
273
280
|
/** The run properties a paragraph style and character style give, by their ids. */
|
|
@@ -283,19 +290,39 @@ export class Extractor {
|
|
|
283
290
|
}
|
|
284
291
|
// --- the package ------------------------------------------------------------------------------
|
|
285
292
|
extract() {
|
|
286
|
-
var _a;
|
|
293
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
287
294
|
const out = [];
|
|
288
295
|
const comments = new Map();
|
|
296
|
+
// a name the container held twice, the first copy read (REQ-206, CR-024): the package's, so every reading of it says so
|
|
297
|
+
for (const d of (_b = (_a = this.trees.pkg) === null || _a === void 0 ? void 0 : _a.duplicateEntries) !== null && _b !== void 0 ? _b : []) {
|
|
298
|
+
this.warn(new TextWarning(TextWarning.PACKAGE_DUPLICATE_ENTRY, undefined, undefined, undefined, d.entry, d.count));
|
|
299
|
+
}
|
|
300
|
+
// more than one officeDocument relationship, the last's target read (REQ-206's statement, CR-024 section 9)
|
|
301
|
+
const mainParts = (_c = this.trees.pkg) === null || _c === void 0 ? void 0 : _c.multipleMainParts;
|
|
302
|
+
if (mainParts)
|
|
303
|
+
this.warn(new TextWarning(TextWarning.PACKAGE_MULTIPLE_MAIN_PARTS, undefined, undefined, undefined, mainParts.partName, mainParts.count));
|
|
304
|
+
// an External main relationship dropped, this package's own repair (REQ-206's NOTE, CR-031), and a relationships part read
|
|
305
|
+
// by local name (CR-031 section 2.3): the load's, so every reading says so
|
|
306
|
+
const external = (_d = this.trees.pkg) === null || _d === void 0 ? void 0 : _d.externalMainPart;
|
|
307
|
+
if (external)
|
|
308
|
+
this.warn(new TextWarning(TextWarning.PACKAGE_EXTERNAL_MAIN_PART, undefined, undefined, undefined, external.partName, external.urls[0]));
|
|
309
|
+
for (const r of (_f = (_e = this.trees.pkg) === null || _e === void 0 ? void 0 : _e.relationshipsNamespaces) !== null && _f !== void 0 ? _f : []) {
|
|
310
|
+
this.warn(new TextWarning(TextWarning.PACKAGE_RELATIONSHIPS_NAMESPACE, undefined, undefined, undefined, r.partName, r.count));
|
|
311
|
+
}
|
|
289
312
|
const metadata = this.metadata();
|
|
290
313
|
const main = this.trees.main;
|
|
291
314
|
const body = main === null || main === void 0 ? void 0 : main.document.body;
|
|
292
|
-
if (!main || !body)
|
|
315
|
+
if (!main || !body) {
|
|
316
|
+
if (main)
|
|
317
|
+
this.storyParts.add(main.part);
|
|
318
|
+
this.partWarningsUnmet();
|
|
293
319
|
return new TextResult(out, comments, this.warnings, metadata, this.options);
|
|
320
|
+
}
|
|
294
321
|
// the main story, each text box after its anchor; sections recorded as they end
|
|
295
322
|
const story = new Story(this, 'MAIN', `${this.root}body`, main.part);
|
|
296
323
|
story.sections = [];
|
|
297
324
|
const mainBlocks = [];
|
|
298
|
-
this.blocks((
|
|
325
|
+
this.blocks((_g = body.content) !== null && _g !== void 0 ? _g : [], `${this.root}body`, story, mainBlocks);
|
|
299
326
|
story.sections.push(body.sectPr);
|
|
300
327
|
this.context.mainRead = true;
|
|
301
328
|
const headers = this.options.includes.has('headers');
|
|
@@ -315,19 +342,35 @@ export class Extractor {
|
|
|
315
342
|
// comments, rendered at their references (REQ-504)
|
|
316
343
|
if (this.commentsIncluded())
|
|
317
344
|
this.comments(comments);
|
|
345
|
+
this.partWarningsUnmet();
|
|
318
346
|
return new TextResult(out, comments, this.warnings, metadata, this.options);
|
|
319
347
|
}
|
|
320
|
-
/** The result's metadata: `fields_update_on_open` and the document properties (REQ-801, REQ-515). */
|
|
348
|
+
/** The result's metadata: `fields_update_on_open`, `repaired` and the document properties (REQ-801, REQ-207, REQ-515). */
|
|
321
349
|
metadata() {
|
|
322
|
-
var _a;
|
|
323
|
-
const metadata = {
|
|
324
|
-
|
|
350
|
+
var _a, _b, _c;
|
|
351
|
+
const metadata = {
|
|
352
|
+
[TextResult.FIELDS_UPDATE_ON_OPEN]: this.fieldsUpdateOnOpen(),
|
|
353
|
+
[TextResult.REPAIRED]: (_b = (_a = this.trees.pkg) === null || _a === void 0 ? void 0 : _a.repaired) !== null && _b !== void 0 ? _b : 'none',
|
|
354
|
+
};
|
|
355
|
+
Object.assign(metadata, (_c = this.trees.properties) !== null && _c !== void 0 ? _c : {});
|
|
356
|
+
// a properties part read for the metadata written (REQ-515), where it could not be read (WD 0.76)
|
|
357
|
+
if (this.options.metadata)
|
|
358
|
+
for (const role of ['core', 'app', 'custom'])
|
|
359
|
+
this.consult(role);
|
|
325
360
|
return metadata;
|
|
326
361
|
}
|
|
362
|
+
/** `w:updateFields`, which every result's metadata carries: so a settings part that cannot be read is needed by every reading. */
|
|
327
363
|
fieldsUpdateOnOpen() {
|
|
328
364
|
var _a;
|
|
365
|
+
this.consult('settings');
|
|
329
366
|
return on((_a = this.trees.settings) === null || _a === void 0 ? void 0 : _a.updateFields);
|
|
330
367
|
}
|
|
368
|
+
/** A part the reading needs here: `part.not_read`, once, where it could not be read (REQ-801; CR-012 section 28). */
|
|
369
|
+
consult(role) {
|
|
370
|
+
const partName = this.trees.notRead.get(role);
|
|
371
|
+
if (partName !== undefined)
|
|
372
|
+
this.warn(new TextWarning(TextWarning.PART_NOT_READ, undefined, undefined, undefined, partName));
|
|
373
|
+
}
|
|
331
374
|
commentsIncluded() {
|
|
332
375
|
return this.view === 'markup' || this.options.comments;
|
|
333
376
|
}
|
|
@@ -346,31 +389,35 @@ export class Extractor {
|
|
|
346
389
|
const metadata = {};
|
|
347
390
|
if (this.trees.pkg !== undefined)
|
|
348
391
|
metadata[TextResult.FIELDS_UPDATE_ON_OPEN] = this.fieldsUpdateOnOpen();
|
|
392
|
+
this.partWarningsUnmet();
|
|
349
393
|
return new TextResult(out, new Map(), this.warnings, metadata, this.options);
|
|
350
394
|
}
|
|
351
395
|
/** The notes of one kind, in the context's reference order (`Texts.of(notesPart)`). */
|
|
352
396
|
extractNotes(type) {
|
|
353
397
|
const out = [];
|
|
354
398
|
this.notes(type, out);
|
|
399
|
+
this.partWarningsUnmet();
|
|
355
400
|
return new TextResult(out, new Map(), this.warnings, { [TextResult.FIELDS_UPDATE_ON_OPEN]: this.fieldsUpdateOnOpen() }, this.options);
|
|
356
401
|
}
|
|
357
402
|
/** The comments (`Texts.of(commentsPart)`): what the view includes, in the comments part's order. */
|
|
358
403
|
extractComments() {
|
|
359
404
|
const comments = new Map();
|
|
360
405
|
this.comments(comments);
|
|
406
|
+
this.partWarningsUnmet();
|
|
361
407
|
return new TextResult([], comments, this.warnings, { [TextResult.FIELDS_UPDATE_ON_OPEN]: this.fieldsUpdateOnOpen() }, this.options);
|
|
362
408
|
}
|
|
363
409
|
// --- the glossary (REQ-516) -------------------------------------------------------------------
|
|
364
410
|
glossary(out) {
|
|
365
|
-
var _a, _b, _c;
|
|
411
|
+
var _a, _b, _c, _d;
|
|
412
|
+
this.storyRead((_a = this.trees.main) === null || _a === void 0 ? void 0 : _a.part.glossaryDocumentPart);
|
|
366
413
|
const g = this.trees.glossary;
|
|
367
|
-
const parts = (
|
|
414
|
+
const parts = (_c = (_b = g === null || g === void 0 ? void 0 : g.tree.docParts) === null || _b === void 0 ? void 0 : _b.docPart) !== null && _c !== void 0 ? _c : [];
|
|
368
415
|
for (let i = 0; i < parts.length; i++) {
|
|
369
416
|
const body = parts[i].docPartBody;
|
|
370
417
|
if (!body)
|
|
371
418
|
continue;
|
|
372
419
|
const prefix = `${this.root}glossary:${i}`;
|
|
373
|
-
this.blocks((
|
|
420
|
+
this.blocks((_d = body.content) !== null && _d !== void 0 ? _d : [], prefix, new Story(this, 'GLOSSARY', prefix, g.part), out);
|
|
374
421
|
}
|
|
375
422
|
}
|
|
376
423
|
// --- block level ------------------------------------------------------------------------------
|
|
@@ -378,11 +425,15 @@ export class Extractor {
|
|
|
378
425
|
blocks(items, prefix, story, sink, state = PLAIN) {
|
|
379
426
|
if (!items)
|
|
380
427
|
return;
|
|
428
|
+
const dropCap = {};
|
|
381
429
|
for (let i = 0; i < items.length; i++)
|
|
382
|
-
i = this.block(items, i, prefix, story, sink, state);
|
|
430
|
+
i = this.block(items, i, prefix, story, sink, state, dropCap);
|
|
383
431
|
}
|
|
384
|
-
/**
|
|
385
|
-
|
|
432
|
+
/**
|
|
433
|
+
* The block at `items[i]` into `sink`, with the paragraphs a view joins to it; the index of the last item it took.
|
|
434
|
+
* `dropCap` is a drop cap's frame paragraph just read in the same container, for the paragraph next to take (REQ-521).
|
|
435
|
+
*/
|
|
436
|
+
block(items, i, prefix, story, sink, state, dropCap = {}) {
|
|
386
437
|
var _a, _b, _c;
|
|
387
438
|
const item = items[i];
|
|
388
439
|
if (this.removes(item))
|
|
@@ -390,6 +441,8 @@ export class Extractor {
|
|
|
390
441
|
const v = unwrap(item);
|
|
391
442
|
const address = `${prefix}/${i}`;
|
|
392
443
|
const tn = typeOf(v);
|
|
444
|
+
if (tn !== P && !isMarker(item))
|
|
445
|
+
dropCap.block = undefined; // a table, a control, the end: left as it is
|
|
393
446
|
if (tn === P) {
|
|
394
447
|
const chain = [v];
|
|
395
448
|
const addresses = [address];
|
|
@@ -411,9 +464,14 @@ export class Extractor {
|
|
|
411
464
|
if ((_a = this.plan) === null || _a === void 0 ? void 0 : _a.joinsIntoTable(chain[chain.length - 1])) {
|
|
412
465
|
// a deleted mark with a table next and text left: into the table's first cell (docx4j CR-043 section 17)
|
|
413
466
|
this.pendingTableJoin = { chain, addresses };
|
|
467
|
+
dropCap.block = undefined;
|
|
414
468
|
return j;
|
|
415
469
|
}
|
|
416
|
-
|
|
470
|
+
const taking = dropCap.block;
|
|
471
|
+
dropCap.block = undefined;
|
|
472
|
+
const block = this.paragraph(chain, addresses, story, sink, state, taking);
|
|
473
|
+
if (taking === undefined && block !== undefined && this.dropCapFrame(chain, block))
|
|
474
|
+
dropCap.block = block;
|
|
417
475
|
return j;
|
|
418
476
|
}
|
|
419
477
|
if (tn === TBL) {
|
|
@@ -424,6 +482,7 @@ export class Extractor {
|
|
|
424
482
|
this.pendingTableJoin = undefined;
|
|
425
483
|
this.paragraph(chain, addresses, story, sink, state);
|
|
426
484
|
}
|
|
485
|
+
dropCap.block = undefined;
|
|
427
486
|
}
|
|
428
487
|
else if (isSdt(v) && this.unwraps(item)) {
|
|
429
488
|
// an inserted control rejected: its content in its place, its properties gone
|
|
@@ -454,7 +513,7 @@ export class Extractor {
|
|
|
454
513
|
}
|
|
455
514
|
else if (tn === AC) {
|
|
456
515
|
const ac = v;
|
|
457
|
-
this.compareBranches(ac, address);
|
|
516
|
+
this.compareBranches(ac, address, story);
|
|
458
517
|
this.blocks(selectedBranchOf(ac), address, story, sink, state);
|
|
459
518
|
}
|
|
460
519
|
else if (revisionHolder(item) !== undefined) {
|
|
@@ -532,15 +591,20 @@ export class Extractor {
|
|
|
532
591
|
}
|
|
533
592
|
return -1;
|
|
534
593
|
}
|
|
535
|
-
|
|
594
|
+
/**
|
|
595
|
+
* A paragraph chain's block into the sink, returned; undefined where it makes none. A drop cap's frame paragraph read
|
|
596
|
+
* just before (`dropCap`; REQ-521) is taken in at its start.
|
|
597
|
+
*/
|
|
598
|
+
paragraph(chain, addresses, story, sink, state, dropCap) {
|
|
536
599
|
var _a, _b, _c, _d;
|
|
537
600
|
const first = chain[0];
|
|
538
601
|
const last = chain[chain.length - 1];
|
|
539
602
|
const block = new TextBlock('PARAGRAPH', story.kind, addresses[0]);
|
|
603
|
+
this.consult('styles'); // every block is resolved through the part's defaults
|
|
540
604
|
if (this.fieldsOnly) {
|
|
541
605
|
for (let c = 0; c < chain.length; c++)
|
|
542
606
|
this.runs(chain[c].content, new ParagraphState(block, chain[c], addresses[c], story), state);
|
|
543
|
-
return;
|
|
607
|
+
return undefined;
|
|
544
608
|
}
|
|
545
609
|
if (chain.length > 1)
|
|
546
610
|
block.joined = addresses.slice(1);
|
|
@@ -577,7 +641,7 @@ export class Extractor {
|
|
|
577
641
|
block.runs.length = 0;
|
|
578
642
|
this.flushIfOutsideTable(story, sink);
|
|
579
643
|
this.endSection(last, story);
|
|
580
|
-
return;
|
|
644
|
+
return undefined;
|
|
581
645
|
}
|
|
582
646
|
block.hidden = hiddenParagraph;
|
|
583
647
|
if (!this.options.hidden) {
|
|
@@ -589,7 +653,7 @@ export class Extractor {
|
|
|
589
653
|
// a table of contents' paragraph, under toc: false (D12): no line at all
|
|
590
654
|
this.flushIfOutsideTable(story, sink);
|
|
591
655
|
this.endSection(last, story);
|
|
592
|
-
return;
|
|
656
|
+
return undefined;
|
|
593
657
|
}
|
|
594
658
|
// one count per paragraph: the label (list_labels) and the numbering's value come from it
|
|
595
659
|
if (this.trees.pkg !== undefined && (this.options.listLabels || block.numbering !== undefined)) {
|
|
@@ -600,9 +664,78 @@ export class Extractor {
|
|
|
600
664
|
block.numbering.value = counted.count;
|
|
601
665
|
}
|
|
602
666
|
block.section = (_d = (_c = story.sections) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0;
|
|
603
|
-
|
|
667
|
+
if (dropCap === undefined || !this.joinDropCap(dropCap, block, story, sink))
|
|
668
|
+
sink.push(block);
|
|
604
669
|
this.flushIfOutsideTable(story, sink);
|
|
605
670
|
this.endSection(last, story);
|
|
671
|
+
return block;
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Whether a paragraph just read is a drop cap's frame, for the paragraph next to take (REQ-521; CR-012 section 24.3):
|
|
675
|
+
* under `drop_caps: join`, one `w:p` whose `w:framePr/@w:dropCap` (its own, or its style's) is `drop` or `margin`, whose
|
|
676
|
+
* text is at most one word (no white space and no space character, U+00A0 included), and which ends no section.
|
|
677
|
+
*/
|
|
678
|
+
dropCapFrame(chain, block) {
|
|
679
|
+
var _a, _b;
|
|
680
|
+
if (this.options.dropCaps !== 'join' || chain.length !== 1)
|
|
681
|
+
return false;
|
|
682
|
+
const p = chain[0];
|
|
683
|
+
if ((_a = p.pPr) === null || _a === void 0 ? void 0 : _a.sectPr)
|
|
684
|
+
return false;
|
|
685
|
+
// Java's Character.isWhitespace or isSpaceChar, docx4j's test
|
|
686
|
+
if (/[\t-\r\x1C-\x1F\p{Z}]/u.test(block.text))
|
|
687
|
+
return false;
|
|
688
|
+
let pPr = this.viewPPr(p);
|
|
689
|
+
if (this.resolver) {
|
|
690
|
+
try {
|
|
691
|
+
pPr = this.resolver.getEffectivePPr(pPr);
|
|
692
|
+
}
|
|
693
|
+
catch {
|
|
694
|
+
// the paragraph's own properties, as read
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
const dropCap = (_b = pPr === null || pPr === void 0 ? void 0 : pPr.framePr) === null || _b === void 0 ? void 0 : _b.dropCap;
|
|
698
|
+
return dropCap === 'drop' || dropCap === 'margin';
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* A drop cap's frame paragraph joined to the block after it (REQ-521): its runs and fields put at the block's start with
|
|
702
|
+
* no separator, the block (its address, its properties) in the frame's place in the sink, so that what the frame
|
|
703
|
+
* anchored still follows it; the warning `paragraph.drop_cap_joined` at the frame's address. The letter's run merges
|
|
704
|
+
* into the word's first run on docx4j's rule (the same kind, hidden and placeholder flags, revision and formatting; D6,
|
|
705
|
+
* Jason 2026-11-02), which replaces section 4.4's `officeOffset` contiguity rule at this one join, the two runs' text
|
|
706
|
+
* coming from two paragraphs' `Paragraph.text`: the merged run keeps the letter's source, and its `officeOffset` is
|
|
707
|
+
* undefined. False, and nothing done, where the frame is not in the sink.
|
|
708
|
+
*/
|
|
709
|
+
joinDropCap(frame, block, story, sink) {
|
|
710
|
+
var _a;
|
|
711
|
+
const at = sink.lastIndexOf(frame);
|
|
712
|
+
if (at < 0)
|
|
713
|
+
return false;
|
|
714
|
+
const runs = [...frame.runs];
|
|
715
|
+
let first = 0;
|
|
716
|
+
if (runs.length > 0 && block.runs.length > 0) {
|
|
717
|
+
const left = runs[runs.length - 1];
|
|
718
|
+
const right = block.runs[0];
|
|
719
|
+
if (left.kind === 'TEXT' && right.kind === 'TEXT' && !left.math && !right.math && left.hidden === right.hidden
|
|
720
|
+
&& left.placeholder === right.placeholder && sameRevision(left.revision, right.revision) && left.sameFormat(right)) {
|
|
721
|
+
const merged = new TextRun('TEXT', left.text + right.text, left.revision);
|
|
722
|
+
merged.hidden = left.hidden;
|
|
723
|
+
merged.placeholder = left.placeholder;
|
|
724
|
+
merged.copyFormat(left);
|
|
725
|
+
merged.source = left.source;
|
|
726
|
+
runs[runs.length - 1] = merged;
|
|
727
|
+
first = 1;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
runs.push(...block.runs.slice(first));
|
|
731
|
+
block.runs.length = 0;
|
|
732
|
+
block.runs.push(...runs);
|
|
733
|
+
block.fields.unshift(...frame.fields);
|
|
734
|
+
block.revisions += frame.revisions;
|
|
735
|
+
block.hidden = block.hidden && frame.hidden;
|
|
736
|
+
sink[at] = block;
|
|
737
|
+
this.warn(new TextWarning(TextWarning.DROP_CAP_JOINED, frame.address, undefined, undefined, (_a = story.part) === null || _a === void 0 ? void 0 : _a.partName.name));
|
|
738
|
+
return true;
|
|
606
739
|
}
|
|
607
740
|
endSection(last, story) {
|
|
608
741
|
var _a;
|
|
@@ -624,7 +757,10 @@ export class Extractor {
|
|
|
624
757
|
}
|
|
625
758
|
}
|
|
626
759
|
// --- altChunk (REQ-513) -----------------------------------------------------------------------
|
|
627
|
-
/**
|
|
760
|
+
/**
|
|
761
|
+
* An `altChunk`: not expanded until CR-012 phase 5e, which raises `altchunk.not_expanded` naming the chunk's part, its
|
|
762
|
+
* selector (WD 0.47, CR-012 section 22.2 (a)), with its content type.
|
|
763
|
+
*/
|
|
628
764
|
altChunk(chunk, address, story) {
|
|
629
765
|
var _a;
|
|
630
766
|
const part = related(story.part, chunk.id);
|
|
@@ -632,7 +768,7 @@ export class Extractor {
|
|
|
632
768
|
return;
|
|
633
769
|
const ct = (_a = part.contentType) !== null && _a !== void 0 ? _a : '';
|
|
634
770
|
const semi = ct.indexOf(';');
|
|
635
|
-
this.warn(new TextWarning(TextWarning.ALTCHUNK_NOT_EXPANDED, address, undefined, (semi >= 0 ? ct.slice(0, semi) : ct).trim()));
|
|
771
|
+
this.warn(new TextWarning(TextWarning.ALTCHUNK_NOT_EXPANDED, address, undefined, (semi >= 0 ? ct.slice(0, semi) : ct).trim(), part.partName.name));
|
|
636
772
|
}
|
|
637
773
|
// --- bound values (REQ-509) -------------------------------------------------------------------
|
|
638
774
|
/**
|
|
@@ -648,6 +784,10 @@ export class Extractor {
|
|
|
648
784
|
const binding = (_a = sdtPrChild(pr, 'dataBinding')) === null || _a === void 0 ? void 0 : _a.value;
|
|
649
785
|
if (!binding)
|
|
650
786
|
return undefined;
|
|
787
|
+
// a store it names that could not be read: read as absent, the binding resolved by REQ-509's repair (CR-012 section 28, D3)
|
|
788
|
+
const unread = this.trees.unreadStoreOf(binding);
|
|
789
|
+
if (unread !== undefined)
|
|
790
|
+
this.warn(new TextWarning(TextWarning.PART_NOT_READ, undefined, undefined, undefined, unread));
|
|
651
791
|
const value = this.trees.boundValue(binding);
|
|
652
792
|
if (value === undefined)
|
|
653
793
|
return undefined;
|
|
@@ -756,16 +896,16 @@ export class Extractor {
|
|
|
756
896
|
const numId = String(numIdValue);
|
|
757
897
|
if (Number(numIdValue) === 0)
|
|
758
898
|
return undefined;
|
|
899
|
+
const emulator = this.numberingEmulator();
|
|
759
900
|
const ilvlValue = (_b = numPr === null || numPr === void 0 ? void 0 : numPr.ilvl) === null || _b === void 0 ? void 0 : _b.val;
|
|
760
901
|
const ilvl = ilvlValue === undefined || ilvlValue === null ? 0 : Number(ilvlValue);
|
|
761
902
|
let format;
|
|
762
903
|
let text;
|
|
763
904
|
let abstractNumId;
|
|
764
905
|
let start = 1;
|
|
765
|
-
const part = this.trees.numberingPart;
|
|
766
906
|
const definitions = this.trees.numbering;
|
|
767
907
|
try {
|
|
768
|
-
if (
|
|
908
|
+
if (emulator && !directNumId && this.linkedElsewhere(emulator, numId, String(ilvl), pStyle))
|
|
769
909
|
return undefined;
|
|
770
910
|
const list = definitions === null || definitions === void 0 ? void 0 : definitions.list(numId);
|
|
771
911
|
abstractNumId = (_c = list === null || list === void 0 ? void 0 : list.abstractDefinition) === null || _c === void 0 ? void 0 : _c.id;
|
|
@@ -784,10 +924,21 @@ export class Extractor {
|
|
|
784
924
|
numbering.abstractNumId = abstractNumId;
|
|
785
925
|
return numbering;
|
|
786
926
|
}
|
|
927
|
+
/**
|
|
928
|
+
* The numbering a numbered paragraph is counted by (`PackageTrees.numberingFor`): where the numbering part is absent or
|
|
929
|
+
* cannot be read, Word's default definition, and `part.absent` or `part.not_read` naming the part, once (WD 0.76).
|
|
930
|
+
*/
|
|
931
|
+
numberingEmulator() {
|
|
932
|
+
const missing = this.trees.numberingMissing;
|
|
933
|
+
if (missing !== undefined && this.trees.pkg !== undefined) {
|
|
934
|
+
this.warn(new TextWarning(missing.kind === 'part.absent' ? TextWarning.PART_ABSENT : TextWarning.PART_NOT_READ, undefined, undefined, undefined, missing.partName));
|
|
935
|
+
}
|
|
936
|
+
return this.trees.numberingFor();
|
|
937
|
+
}
|
|
787
938
|
/** Whether the level belongs to a paragraph style that is neither the paragraph's nor one its style is based on. */
|
|
788
|
-
linkedElsewhere(
|
|
939
|
+
linkedElsewhere(emulator, numId, ilvl, pStyle) {
|
|
789
940
|
var _a, _b, _c, _d;
|
|
790
|
-
const linked =
|
|
941
|
+
const linked = emulator.levelStyleId(numId, ilvl);
|
|
791
942
|
if (linked === undefined || linked === '')
|
|
792
943
|
return false;
|
|
793
944
|
// a paragraph naming no style is in the default paragraph style, which can own a level
|
|
@@ -803,11 +954,11 @@ export class Extractor {
|
|
|
803
954
|
}
|
|
804
955
|
/** The paragraph counted in its story's numbering state; undefined where it is not numbered. */
|
|
805
956
|
count(p, story) {
|
|
806
|
-
const
|
|
807
|
-
if (
|
|
957
|
+
const emulator = this.trees.emulator;
|
|
958
|
+
if (this.trees.pkg === undefined || !emulator)
|
|
808
959
|
return undefined;
|
|
809
960
|
try {
|
|
810
|
-
return
|
|
961
|
+
return emulator.getNumber(p.pPr, story.numbering());
|
|
811
962
|
}
|
|
812
963
|
catch {
|
|
813
964
|
return undefined;
|
|
@@ -817,6 +968,7 @@ export class Extractor {
|
|
|
817
968
|
table(tbl, address, story, sink, state) {
|
|
818
969
|
var _a, _b;
|
|
819
970
|
const block = new TextBlock('TABLE', story.kind, address);
|
|
971
|
+
this.consult('styles');
|
|
820
972
|
block.section = (_b = (_a = story.sections) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
|
821
973
|
block.source = tbl;
|
|
822
974
|
story.tableDepth++;
|
|
@@ -866,7 +1018,7 @@ export class Extractor {
|
|
|
866
1018
|
else if (typeOf(v) === AC) {
|
|
867
1019
|
// a row-level mc:AlternateContent: its selected branch's rows, addressed from the element (CR-013)
|
|
868
1020
|
const ac = v;
|
|
869
|
-
this.compareBranches(ac, address);
|
|
1021
|
+
this.compareBranches(ac, address, story);
|
|
870
1022
|
this.rows(selectedBranchOf(ac), address, story, table, state);
|
|
871
1023
|
}
|
|
872
1024
|
else {
|
|
@@ -917,7 +1069,7 @@ export class Extractor {
|
|
|
917
1069
|
else if (typeOf(v) === AC) {
|
|
918
1070
|
// a cell-level mc:AlternateContent: its selected branch's cells, addressed from the element (CR-013)
|
|
919
1071
|
const ac = v;
|
|
920
|
-
this.compareBranches(ac, address);
|
|
1072
|
+
this.compareBranches(ac, address, story);
|
|
921
1073
|
this.cells(selectedBranchOf(ac), address, story, row, state);
|
|
922
1074
|
}
|
|
923
1075
|
else {
|
|
@@ -945,7 +1097,7 @@ export class Extractor {
|
|
|
945
1097
|
}
|
|
946
1098
|
else if (tn === AC) {
|
|
947
1099
|
const ac = v;
|
|
948
|
-
this.compareBranches(ac, para.block.address);
|
|
1100
|
+
this.compareBranches(ac, para.block.address, para.story);
|
|
949
1101
|
this.runs(selectedBranchOf(ac), para, state);
|
|
950
1102
|
}
|
|
951
1103
|
else if (isSdt(v) && this.unwraps(item)) {
|
|
@@ -1047,6 +1199,7 @@ export class Extractor {
|
|
|
1047
1199
|
const f = fields[0];
|
|
1048
1200
|
if (f) {
|
|
1049
1201
|
f.separated = true;
|
|
1202
|
+
f.hiddenResult = isSetField(f.instr);
|
|
1050
1203
|
f.link = fieldHyperlinkTarget(f.instr);
|
|
1051
1204
|
if (!this.options.toc && !suppressed(para.story) && isTocField(f.instr)) {
|
|
1052
1205
|
f.toc = true;
|
|
@@ -1188,7 +1341,7 @@ export class Extractor {
|
|
|
1188
1341
|
}
|
|
1189
1342
|
case 'AlternateContent': {
|
|
1190
1343
|
const ac = v;
|
|
1191
|
-
this.compareBranches(ac, para.block.address);
|
|
1344
|
+
this.compareBranches(ac, para.block.address, para.story);
|
|
1192
1345
|
for (const o of (_b = selectedBranchOf(ac)) !== null && _b !== void 0 ? _b : [])
|
|
1193
1346
|
this.runItem(o, r, hidden, para, state);
|
|
1194
1347
|
return;
|
|
@@ -1215,6 +1368,8 @@ export class Extractor {
|
|
|
1215
1368
|
}
|
|
1216
1369
|
if (suppressed(para.story))
|
|
1217
1370
|
return;
|
|
1371
|
+
if (para.story.fields.some((f) => f.hiddenResult))
|
|
1372
|
+
return; // a SET's stored value: never shown
|
|
1218
1373
|
if (!(hidden && !this.options.hidden)) {
|
|
1219
1374
|
for (const f of para.story.fields)
|
|
1220
1375
|
f.result += s;
|
|
@@ -1271,7 +1426,7 @@ export class Extractor {
|
|
|
1271
1426
|
this.warn(new TextWarning(TextWarning.FIELD_NO_RESULT, para.block.address));
|
|
1272
1427
|
}
|
|
1273
1428
|
simpleField(field, para, state) {
|
|
1274
|
-
var _a;
|
|
1429
|
+
var _a, _b, _c;
|
|
1275
1430
|
if (suppressed(para.story))
|
|
1276
1431
|
return; // inside a computed field's cached result
|
|
1277
1432
|
const instr = (_a = field.instr) !== null && _a !== void 0 ? _a : '';
|
|
@@ -1281,6 +1436,15 @@ export class Extractor {
|
|
|
1281
1436
|
}
|
|
1282
1437
|
if (this.options.fieldCodes && !inCode(para.story))
|
|
1283
1438
|
this.addText(para, instr, 'FIELD_CODE', false, state);
|
|
1439
|
+
if (isSetField(instr)) {
|
|
1440
|
+
// a SET's stored value is never shown (REQ-505), in this form as in the complex one (FieldState.hiddenResult)
|
|
1441
|
+
this.resultOf(field.content, para, state, undefined, true);
|
|
1442
|
+
const stored = ((_c = (_b = field.content) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 0;
|
|
1443
|
+
para.block.fields.push(new TextField(instr, stored ? '' : undefined));
|
|
1444
|
+
if (!stored)
|
|
1445
|
+
this.warn(new TextWarning(TextWarning.FIELD_NO_RESULT, para.block.address));
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1284
1448
|
const before = para.block.runs.length;
|
|
1285
1449
|
const text = this.resultOf(field.content, para, state, fieldHyperlinkTarget(instr));
|
|
1286
1450
|
const hasResult = text !== '' || para.block.runs.length > before;
|
|
@@ -1288,11 +1452,12 @@ export class Extractor {
|
|
|
1288
1452
|
if (!hasResult)
|
|
1289
1453
|
this.warn(new TextWarning(TextWarning.FIELD_NO_RESULT, para.block.address));
|
|
1290
1454
|
}
|
|
1291
|
-
/** The runs of a simple field's result, added to the paragraph; their text. */
|
|
1292
|
-
resultOf(content, para, state, link) {
|
|
1455
|
+
/** The runs of a simple field's result, added to the paragraph; their text. `hidden`: a result never shown (a SET's). */
|
|
1456
|
+
resultOf(content, para, state, link, hidden = false) {
|
|
1293
1457
|
const capture = new FieldState();
|
|
1294
1458
|
capture.separated = true;
|
|
1295
1459
|
capture.link = link;
|
|
1460
|
+
capture.hiddenResult = hidden;
|
|
1296
1461
|
para.story.fields.push(capture);
|
|
1297
1462
|
try {
|
|
1298
1463
|
this.runs(content, para, state);
|
|
@@ -1377,7 +1542,7 @@ export class Extractor {
|
|
|
1377
1542
|
return false;
|
|
1378
1543
|
case AC: {
|
|
1379
1544
|
const ac = value;
|
|
1380
|
-
this.compareBranches(ac, para.block.address);
|
|
1545
|
+
this.compareBranches(ac, para.block.address, para.story);
|
|
1381
1546
|
for (const o of (_a = selectedBranchOf(ac)) !== null && _a !== void 0 ? _a : [])
|
|
1382
1547
|
walk(unwrap(o), 1, visitor);
|
|
1383
1548
|
return false;
|
|
@@ -1502,13 +1667,13 @@ export class Extractor {
|
|
|
1502
1667
|
* differ after REQ-1201's normalisation. A branch's text is every `w:t`, `m:t` and `a:t` in it, whatever
|
|
1503
1668
|
* the view and hidden or not, as docx4j reads it: a comparison made at load knows no view, and a branch
|
|
1504
1669
|
* that differs only in hidden or deleted text is one an agent should hear of (Jason, 2026-10-21, for WD
|
|
1505
|
-
* 0.29; CR-012 section 15.6).
|
|
1670
|
+
* 0.29; CR-012 section 15.6). `mce.nothing_selected` (REQ-305): where the element has Choices and nothing is selected.
|
|
1506
1671
|
*/
|
|
1507
|
-
compareBranches(ac, address) {
|
|
1672
|
+
compareBranches(ac, address, story) {
|
|
1508
1673
|
var _a, _b, _c, _d;
|
|
1509
1674
|
if (!this.options.warnings || this.fieldsOnly)
|
|
1510
1675
|
return;
|
|
1511
|
-
const selected = selectedBranchOf(ac);
|
|
1676
|
+
const selected = selectedBranchOf(ac, { onNothingSelected: ({ namespaces }) => this.nothingSelected(address, story.part, namespaces) });
|
|
1512
1677
|
if (selected === undefined)
|
|
1513
1678
|
return;
|
|
1514
1679
|
const mine = branchText(selected);
|
|
@@ -1529,6 +1694,44 @@ export class Extractor {
|
|
|
1529
1694
|
}
|
|
1530
1695
|
}
|
|
1531
1696
|
}
|
|
1697
|
+
/** `mce.nothing_selected`, its selector the part and its `detail` the namespaces (REQ-801). */
|
|
1698
|
+
nothingSelected(address, part, namespaces) {
|
|
1699
|
+
this.warn(new TextWarning(TextWarning.MCE_NOTHING_SELECTED, address, undefined, undefined, part === null || part === void 0 ? void 0 : part.partName.name, namespaces.join(' ')));
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* What the walk can't meet, from the warnings the load's passes recorded on each part this reading took, none with an address:
|
|
1703
|
+
* `mce.nothing_selected` for an element a resolving load took out or one at a part's root (CR-029 section 3.5);
|
|
1704
|
+
* `mce.undeclared_prefix` (REQ-323, CR-030), on a story part or the styles, numbering or settings part the reading consults;
|
|
1705
|
+
* and `part.unexpected_root` (REQ-320, CR-028 D11).
|
|
1706
|
+
*/
|
|
1707
|
+
partWarningsUnmet() {
|
|
1708
|
+
var _a, _b;
|
|
1709
|
+
if (!this.options.warnings || this.fieldsOnly)
|
|
1710
|
+
return;
|
|
1711
|
+
const main = (_a = this.trees.main) === null || _a === void 0 ? void 0 : _a.part;
|
|
1712
|
+
const consulted = [main === null || main === void 0 ? void 0 : main.styleDefinitionsPart, main === null || main === void 0 ? void 0 : main.numberingDefinitionsPart, main === null || main === void 0 ? void 0 : main.documentSettingsPart];
|
|
1713
|
+
for (const part of [...this.storyParts, ...consulted]) {
|
|
1714
|
+
if (!part)
|
|
1715
|
+
continue;
|
|
1716
|
+
for (const w of (_b = part.warnings) !== null && _b !== void 0 ? _b : []) {
|
|
1717
|
+
if (w.code === 'mce.nothing_selected' && (w.removed || w.root))
|
|
1718
|
+
this.nothingSelected(undefined, part, w.namespaces);
|
|
1719
|
+
else if (w.code === 'mce.undeclared_prefix')
|
|
1720
|
+
this.warn(new TextWarning(TextWarning.MCE_UNDECLARED_PREFIX, undefined, undefined, undefined, part.partName.name, w.prefixes.join(' ')));
|
|
1721
|
+
else if (w.code === 'part.unexpected_root')
|
|
1722
|
+
this.warn(new TextWarning(TextWarning.PART_UNEXPECTED_ROOT, undefined, undefined, undefined, w.partName, w.root));
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
/**
|
|
1727
|
+
* A story part the reading takes that could not be read: none of its text, and `content.not_read` naming it (REQ-801),
|
|
1728
|
+
* at the story's address prefix for a header or footer; docx4j's `storyContent` (`4fdd80063`).
|
|
1729
|
+
*/
|
|
1730
|
+
storyRead(part, address) {
|
|
1731
|
+
if (part && this.trees.unreadable.has(part)) {
|
|
1732
|
+
this.warn(new TextWarning(TextWarning.CONTENT_NOT_READ, address, undefined, undefined, part.partName.name));
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1532
1735
|
warn(w) {
|
|
1533
1736
|
if (this.warned.has(w.key))
|
|
1534
1737
|
return;
|
|
@@ -1538,6 +1741,7 @@ export class Extractor {
|
|
|
1538
1741
|
// --- headers and footers by section (REQ-502) ---------------------------------------------------
|
|
1539
1742
|
sectionsWithHeaders(sections, mainBlocks, headers, footers, out) {
|
|
1540
1743
|
var _a, _b;
|
|
1744
|
+
this.consult('settings');
|
|
1541
1745
|
const evenAndOdd = on((_a = this.trees.settings) === null || _a === void 0 ? void 0 : _a.evenAndOddHeaders);
|
|
1542
1746
|
const emitted = new Set();
|
|
1543
1747
|
const lastHeader = new Map();
|
|
@@ -1581,15 +1785,19 @@ export class Extractor {
|
|
|
1581
1785
|
emitted.add(rId);
|
|
1582
1786
|
const main = this.trees.main;
|
|
1583
1787
|
const part = main ? related(main.part, rId) : undefined;
|
|
1788
|
+
const prefix = `${this.root}${kind === 'HEADER' ? 'header:' : 'footer:'}${rId}`;
|
|
1789
|
+
this.storyRead(part, prefix);
|
|
1584
1790
|
const content = part ? this.trees.headersAndFooters.get(part) : undefined;
|
|
1585
1791
|
if (!content)
|
|
1586
1792
|
return;
|
|
1587
|
-
const prefix = `${this.root}${kind === 'HEADER' ? 'header:' : 'footer:'}${rId}`;
|
|
1588
1793
|
const story = new Story(this, kind, prefix, part);
|
|
1589
1794
|
this.blocks(blockItems(content), prefix, story, out);
|
|
1590
1795
|
}
|
|
1591
1796
|
/** A header or footer part's content as its own story (`Texts.of(headerPart)`). */
|
|
1592
1797
|
headerOrFooterPart(part, kind, rId) {
|
|
1798
|
+
// read alone, a part that could not be read throws why, as the main part does (CR-012 section 25, D1)
|
|
1799
|
+
if (this.trees.unreadable.has(part))
|
|
1800
|
+
throw this.trees.unreadable.get(part);
|
|
1593
1801
|
const out = [];
|
|
1594
1802
|
const content = this.trees.headersAndFooters.get(part);
|
|
1595
1803
|
const prefix = `${this.root}${kind === 'HEADER' ? 'header:' : 'footer:'}${rId}`;
|
|
@@ -1599,12 +1807,13 @@ export class Extractor {
|
|
|
1599
1807
|
}
|
|
1600
1808
|
// --- notes (REQ-503) ------------------------------------------------------------------------
|
|
1601
1809
|
notes(type, out) {
|
|
1602
|
-
var _a;
|
|
1810
|
+
var _a, _b, _c;
|
|
1811
|
+
this.storyRead(type === 'footnote' ? (_a = this.trees.main) === null || _a === void 0 ? void 0 : _a.part.footnotesPart : (_b = this.trees.main) === null || _b === void 0 ? void 0 : _b.part.endnotesPart);
|
|
1603
1812
|
const holder = type === 'footnote' ? this.trees.footnotes : this.trees.endnotes;
|
|
1604
1813
|
const numbers = type === 'footnote' ? this.context.footnotes : this.context.endnotes;
|
|
1605
1814
|
if (!holder || numbers.size === 0)
|
|
1606
1815
|
return;
|
|
1607
|
-
const notes = ((
|
|
1816
|
+
const notes = ((_c = (type === 'footnote' ? holder.tree.footnote : holder.tree.endnote)) !== null && _c !== void 0 ? _c : []);
|
|
1608
1817
|
const byId = new Map();
|
|
1609
1818
|
for (const note of notes)
|
|
1610
1819
|
if (note.id !== undefined && note.id !== null)
|
|
@@ -1649,19 +1858,20 @@ export class Extractor {
|
|
|
1649
1858
|
}
|
|
1650
1859
|
// --- comments (REQ-504) ---------------------------------------------------------------------
|
|
1651
1860
|
comments(out) {
|
|
1652
|
-
var _a, _b, _c, _d, _e;
|
|
1861
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1862
|
+
this.storyRead((_a = this.trees.main) === null || _a === void 0 ? void 0 : _a.part.commentsPart);
|
|
1653
1863
|
const part = this.trees.comments;
|
|
1654
1864
|
if (!part)
|
|
1655
1865
|
return;
|
|
1656
1866
|
const extended = new Map();
|
|
1657
|
-
for (const ex of ((
|
|
1867
|
+
for (const ex of ((_c = (_b = this.trees.commentsExtended) === null || _b === void 0 ? void 0 : _b.commentEx) !== null && _c !== void 0 ? _c : [])) {
|
|
1658
1868
|
if (ex.paraId)
|
|
1659
1869
|
extended.set(ex.paraId.toUpperCase(), ex);
|
|
1660
1870
|
}
|
|
1661
1871
|
const idByParaId = new Map();
|
|
1662
1872
|
const anchored = this.trees.anchoredComments();
|
|
1663
|
-
for (const c of ((
|
|
1664
|
-
if ((
|
|
1873
|
+
for (const c of ((_d = part.tree.comment) !== null && _d !== void 0 ? _d : [])) {
|
|
1874
|
+
if ((_e = this.plan) === null || _e === void 0 ? void 0 : _e.removesComment(c.id))
|
|
1665
1875
|
continue;
|
|
1666
1876
|
const id = c.id === undefined || c.id === null ? '' : String(c.id);
|
|
1667
1877
|
// a comment with no anchor in the document is none of its text: Word drops it on save (REQ-504)
|
|
@@ -1670,10 +1880,11 @@ export class Extractor {
|
|
|
1670
1880
|
const comment = new TextComment(id);
|
|
1671
1881
|
comment.author = c.author;
|
|
1672
1882
|
comment.initials = c.initials;
|
|
1673
|
-
|
|
1883
|
+
const paraId = lastParaId(c.content);
|
|
1884
|
+
// REQ-702's form: w:date's wall clock, the offset where the comments extensible part's w16cex:dateUtc gives it
|
|
1885
|
+
comment.date = revisionDateText(c.date, paraId === undefined ? undefined : this.trees.commentDatesUtc.get(paraId.toUpperCase()));
|
|
1674
1886
|
const prefix = `${this.root}comment:${id}`;
|
|
1675
1887
|
this.blocks(c.content, prefix, new Story(this, 'COMMENT', prefix, part.part), comment.blocks);
|
|
1676
|
-
const paraId = lastParaId(c.content);
|
|
1677
1888
|
if (paraId !== undefined) {
|
|
1678
1889
|
idByParaId.set(paraId.toUpperCase(), id);
|
|
1679
1890
|
const ex = extended.get(paraId.toUpperCase());
|
|
@@ -1690,7 +1901,7 @@ export class Extractor {
|
|
|
1690
1901
|
const parent = idByParaId.get(comment.parentId.toUpperCase());
|
|
1691
1902
|
comment.parentId = parent;
|
|
1692
1903
|
if (parent !== undefined)
|
|
1693
|
-
(
|
|
1904
|
+
(_f = out.get(parent)) === null || _f === void 0 ? void 0 : _f.replies.push(comment);
|
|
1694
1905
|
}
|
|
1695
1906
|
}
|
|
1696
1907
|
// --- the view -------------------------------------------------------------------------------
|
|
@@ -1727,20 +1938,42 @@ export class Extractor {
|
|
|
1727
1938
|
/**
|
|
1728
1939
|
* A run's formatting beyond its paragraph style's (CR-046 phase 3): bold, italic, struck through,
|
|
1729
1940
|
* monospaced, each as the run's own property gives it, else its styles', where the paragraph style
|
|
1730
|
-
* alone doesn't give it.
|
|
1941
|
+
* alone doesn't give it. And, whatever the paragraph style says, what the text shows (docx4j CR-069;
|
|
1942
|
+
* CR-012 section 24): its case, folded the same way, a run under both caps and small caps being caps
|
|
1943
|
+
* (WD REQ-607); its vertical alignment (REQ-710); and a cased run's language. A run carrying only that.
|
|
1731
1944
|
*/
|
|
1732
1945
|
formatOf(r, p) {
|
|
1733
|
-
var _a;
|
|
1946
|
+
var _a, _b;
|
|
1734
1947
|
const own = r.rPr;
|
|
1735
1948
|
const styles = this.styleRPr((_a = own === null || own === void 0 ? void 0 : own.rStyle) === null || _a === void 0 ? void 0 : _a.val, p);
|
|
1736
1949
|
const paragraph = this.styleRPr(undefined, p);
|
|
1737
1950
|
const f = new TextRun('TEXT', '', undefined);
|
|
1738
1951
|
f.bold = onOf(own === null || own === void 0 ? void 0 : own.b, styles === null || styles === void 0 ? void 0 : styles.b) && !on(paragraph === null || paragraph === void 0 ? void 0 : paragraph.b);
|
|
1739
1952
|
f.italic = onOf(own === null || own === void 0 ? void 0 : own.i, styles === null || styles === void 0 ? void 0 : styles.i) && !on(paragraph === null || paragraph === void 0 ? void 0 : paragraph.i);
|
|
1740
|
-
|
|
1953
|
+
// struck once or twice (w:dstrike: docx4j CR-069 phase 4, CR-012 section 24.5), the paragraph style's either cancelling it
|
|
1954
|
+
f.strike = (onOf(own === null || own === void 0 ? void 0 : own.strike, styles === null || styles === void 0 ? void 0 : styles.strike) || onOf(own === null || own === void 0 ? void 0 : own.dstrike, styles === null || styles === void 0 ? void 0 : styles.dstrike))
|
|
1955
|
+
&& !(on(paragraph === null || paragraph === void 0 ? void 0 : paragraph.strike) || on(paragraph === null || paragraph === void 0 ? void 0 : paragraph.dstrike));
|
|
1741
1956
|
f.monospace = isMonospace(this.runFont(r, p)) && !isMonospace(asciiFont(paragraph));
|
|
1957
|
+
f.caps = onOf(own === null || own === void 0 ? void 0 : own.caps, styles === null || styles === void 0 ? void 0 : styles.caps);
|
|
1958
|
+
f.smallCaps = !f.caps && onOf(own === null || own === void 0 ? void 0 : own.smallCaps, styles === null || styles === void 0 ? void 0 : styles.smallCaps);
|
|
1959
|
+
const vertAlign = (_b = own === null || own === void 0 ? void 0 : own.vertAlign) !== null && _b !== void 0 ? _b : styles === null || styles === void 0 ? void 0 : styles.vertAlign;
|
|
1960
|
+
if ((vertAlign === null || vertAlign === void 0 ? void 0 : vertAlign.val) === 'superscript')
|
|
1961
|
+
f.verticalAlignment = 'SUPERSCRIPT';
|
|
1962
|
+
if ((vertAlign === null || vertAlign === void 0 ? void 0 : vertAlign.val) === 'subscript')
|
|
1963
|
+
f.verticalAlignment = 'SUBSCRIPT';
|
|
1964
|
+
if (f.caps || f.smallCaps)
|
|
1965
|
+
f.language = this.language(own, styles);
|
|
1742
1966
|
return f;
|
|
1743
1967
|
}
|
|
1968
|
+
/**
|
|
1969
|
+
* The language a cased run's capitals are mapped by (WD REQ-607): its own `w:lang/@w:val`, else its styles' (with the
|
|
1970
|
+
* document defaults'), else the `default_language` option. `w:themeFontLang` is no link (WD 0.80, CR-012 section 24.8):
|
|
1971
|
+
* it chooses among the theme's fonts, and Word cases such a run by its editing language, which the option stands in for.
|
|
1972
|
+
*/
|
|
1973
|
+
language(own, styles) {
|
|
1974
|
+
var _a, _b;
|
|
1975
|
+
return (_b = (_a = langOf(own === null || own === void 0 ? void 0 : own.lang)) !== null && _a !== void 0 ? _a : langOf(styles === null || styles === void 0 ? void 0 : styles.lang)) !== null && _b !== void 0 ? _b : this.options.defaultLanguage;
|
|
1976
|
+
}
|
|
1744
1977
|
/** The run's font for `monospace`: its own `w:rFonts/@w:ascii`, else its styles'. */
|
|
1745
1978
|
runFont(r, p) {
|
|
1746
1979
|
var _a, _b, _c;
|
|
@@ -1830,6 +2063,12 @@ function textLength(block) {
|
|
|
1830
2063
|
function sameRevision(a, b) {
|
|
1831
2064
|
return a === undefined ? b === undefined : a.equals(b);
|
|
1832
2065
|
}
|
|
2066
|
+
/** A `w:lang`'s `w:val`, trimmed; undefined for none or an empty one. */
|
|
2067
|
+
function langOf(l) {
|
|
2068
|
+
var _a;
|
|
2069
|
+
const v = (_a = l === null || l === void 0 ? void 0 : l.val) === null || _a === void 0 ? void 0 : _a.trim();
|
|
2070
|
+
return v === undefined || v === '' ? undefined : v;
|
|
2071
|
+
}
|
|
1833
2072
|
/** An on/off property: the run's own where it has one, else its styles'. */
|
|
1834
2073
|
function onOf(own, styles) {
|
|
1835
2074
|
if (own !== undefined)
|
|
@@ -1878,6 +2117,11 @@ export function isTocField(instr) {
|
|
|
1878
2117
|
const tokens = fieldTokens(instr);
|
|
1879
2118
|
return tokens.length > 0 && tokens[0].toUpperCase() === 'TOC';
|
|
1880
2119
|
}
|
|
2120
|
+
/** A SET field's code: Word stores its value as its result, under a bookmark of its name, and shows nothing (REQ-505). */
|
|
2121
|
+
function isSetField(instr) {
|
|
2122
|
+
const tokens = fieldTokens(instr);
|
|
2123
|
+
return tokens.length > 0 && tokens[0].toUpperCase() === 'SET';
|
|
2124
|
+
}
|
|
1881
2125
|
/** A table of contents' code, shown under `field_codes` until it was known to be one, taken out again. */
|
|
1882
2126
|
function removeFieldCode(f, para) {
|
|
1883
2127
|
// what follows the field may merge with what preceded it, as it would with no field codes
|