@hyperlex/mammoth 1.4.9-beta

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.
Files changed (112) hide show
  1. package/.eslintrc.json +77 -0
  2. package/.github/ISSUE_TEMPLATE.md +12 -0
  3. package/.idea/mammoth.js.iml +12 -0
  4. package/.idea/modules.xml +8 -0
  5. package/.idea/vcs.xml +6 -0
  6. package/.travis.yml +10 -0
  7. package/LICENSE +22 -0
  8. package/NEWS +373 -0
  9. package/README.md +883 -0
  10. package/bin/mammoth +38 -0
  11. package/browser/docx/files.js +14 -0
  12. package/browser/unzip.js +12 -0
  13. package/lib/document-to-html.js +453 -0
  14. package/lib/documents.js +238 -0
  15. package/lib/docx/body-reader.js +636 -0
  16. package/lib/docx/comments-reader.js +31 -0
  17. package/lib/docx/content-types-reader.js +58 -0
  18. package/lib/docx/document-xml-reader.js +26 -0
  19. package/lib/docx/docx-reader.js +222 -0
  20. package/lib/docx/files.js +67 -0
  21. package/lib/docx/notes-reader.js +28 -0
  22. package/lib/docx/numbering-xml.js +69 -0
  23. package/lib/docx/office-xml-reader.js +58 -0
  24. package/lib/docx/relationships-reader.js +43 -0
  25. package/lib/docx/style-map.js +75 -0
  26. package/lib/docx/styles-reader.js +70 -0
  27. package/lib/docx/uris.js +21 -0
  28. package/lib/html/ast.js +50 -0
  29. package/lib/html/index.js +41 -0
  30. package/lib/html/simplify.js +88 -0
  31. package/lib/images.js +29 -0
  32. package/lib/index.js +115 -0
  33. package/lib/main.js +63 -0
  34. package/lib/options-reader.js +98 -0
  35. package/lib/promises.js +42 -0
  36. package/lib/results.js +72 -0
  37. package/lib/style-reader.js +321 -0
  38. package/lib/styles/document-matchers.js +74 -0
  39. package/lib/styles/html-paths.js +81 -0
  40. package/lib/styles/parser/tokeniser.js +30 -0
  41. package/lib/transforms.js +61 -0
  42. package/lib/underline.js +11 -0
  43. package/lib/unzip.js +22 -0
  44. package/lib/writers/html-writer.js +160 -0
  45. package/lib/writers/index.js +14 -0
  46. package/lib/writers/markdown-writer.js +163 -0
  47. package/lib/xml/index.js +7 -0
  48. package/lib/xml/nodes.js +69 -0
  49. package/lib/xml/reader.js +83 -0
  50. package/lib/xml/writer.js +61 -0
  51. package/lib/zipfile.js +77 -0
  52. package/mammoth.browser.js +32950 -0
  53. package/mammoth.browser.min.js +18 -0
  54. package/package.json +65 -0
  55. package/test/.eslintrc.json +7 -0
  56. package/test/document-to-html.tests.js +834 -0
  57. package/test/docx/body-reader.tests.js +1342 -0
  58. package/test/docx/comments-reader.tests.js +52 -0
  59. package/test/docx/content-types-reader.tests.js +45 -0
  60. package/test/docx/document-matchers.js +37 -0
  61. package/test/docx/docx-reader.tests.js +179 -0
  62. package/test/docx/files.tests.js +94 -0
  63. package/test/docx/notes-reader.tests.js +35 -0
  64. package/test/docx/numbering-xml.tests.js +65 -0
  65. package/test/docx/office-xml-reader.tests.js +24 -0
  66. package/test/docx/relationships-reader.tests.js +65 -0
  67. package/test/docx/style-map.tests.js +112 -0
  68. package/test/docx/styles-reader.tests.js +133 -0
  69. package/test/docx/uris.tests.js +22 -0
  70. package/test/html/simplify.tests.js +134 -0
  71. package/test/html/write.tests.js +42 -0
  72. package/test/images.tests.js +34 -0
  73. package/test/main.tests.js +89 -0
  74. package/test/mammoth.tests.js +429 -0
  75. package/test/mocha.opts +1 -0
  76. package/test/options-reader.tests.js +63 -0
  77. package/test/results.tests.js +15 -0
  78. package/test/style-reader.tests.js +256 -0
  79. package/test/styles/document-matchers.tests.js +71 -0
  80. package/test/styles/html-paths.tests.js +20 -0
  81. package/test/styles/parser/tokeniser.tests.js +104 -0
  82. package/test/test-data/comments.docx +0 -0
  83. package/test/test-data/embedded-style-map.docx +0 -0
  84. package/test/test-data/empty.docx +0 -0
  85. package/test/test-data/empty.zip +0 -0
  86. package/test/test-data/endnotes.docx +0 -0
  87. package/test/test-data/external-picture.docx +0 -0
  88. package/test/test-data/footnote-hyperlink.docx +0 -0
  89. package/test/test-data/footnotes.docx +0 -0
  90. package/test/test-data/hello.zip +0 -0
  91. package/test/test-data/hyperlinks/word/_rels/document.xml.rels +10 -0
  92. package/test/test-data/hyperlinks/word/document.xml +18 -0
  93. package/test/test-data/simple/word/document.xml +18 -0
  94. package/test/test-data/simple-list.docx +0 -0
  95. package/test/test-data/single-paragraph.docx +0 -0
  96. package/test/test-data/strikethrough.docx +0 -0
  97. package/test/test-data/tables.docx +0 -0
  98. package/test/test-data/text-box.docx +0 -0
  99. package/test/test-data/tiny-picture-target-base-relative.docx +0 -0
  100. package/test/test-data/tiny-picture.docx +0 -0
  101. package/test/test-data/tiny-picture.png +0 -0
  102. package/test/test-data/underline.docx +0 -0
  103. package/test/test-data/utf8-bom.docx +0 -0
  104. package/test/test.js +11 -0
  105. package/test/testing.js +55 -0
  106. package/test/transforms.tests.js +125 -0
  107. package/test/unzip.tests.js +38 -0
  108. package/test/writers/html-writer.tests.js +133 -0
  109. package/test/writers/markdown-writer.tests.js +304 -0
  110. package/test/xml/reader.tests.js +85 -0
  111. package/test/xml/writer.tests.js +81 -0
  112. package/test/zipfile.tests.js +59 -0
@@ -0,0 +1,636 @@
1
+ exports.createBodyReader = createBodyReader;
2
+ exports._readNumberingProperties = readNumberingProperties;
3
+
4
+ var _ = require("underscore");
5
+
6
+ var documents = require("../documents");
7
+ var Result = require("../results").Result;
8
+ var warning = require("../results").warning;
9
+ var uris = require("./uris");
10
+
11
+ function createBodyReader(options) {
12
+ return {
13
+ readXmlElement: function(element) {
14
+ return new BodyReader(options).readXmlElement(element);
15
+ },
16
+ readXmlElements: function(elements) {
17
+ return new BodyReader(options).readXmlElements(elements);
18
+ }
19
+ };
20
+ }
21
+
22
+ function BodyReader(options) {
23
+ var complexFieldStack = [];
24
+ var currentInstrText = [];
25
+ var relationships = options.relationships;
26
+ var contentTypes = options.contentTypes;
27
+ var docxFile = options.docxFile;
28
+ var files = options.files;
29
+ var numbering = options.numbering;
30
+ var styles = options.styles;
31
+
32
+ function readXmlElements(elements) {
33
+ var results = elements.map(readXmlElement);
34
+ return combineResults(results);
35
+ }
36
+
37
+ function readXmlElement(element) {
38
+ if (element.type === "element") {
39
+ var handler = xmlElementReaders[element.name];
40
+ if (handler) {
41
+ return handler(element);
42
+ } else if (!Object.prototype.hasOwnProperty.call(ignoreElements, element.name)) {
43
+ var message = warning("An unrecognised element was ignored: " + element.name);
44
+ return emptyResultWithMessages([message]);
45
+ }
46
+ }
47
+ return emptyResult();
48
+ }
49
+
50
+ function readParagraphIndent(element) {
51
+ return {
52
+ start: element.attributes["w:start"] || element.attributes["w:left"],
53
+ end: element.attributes["w:end"] || element.attributes["w:right"],
54
+ firstLine: element.attributes["w:firstLine"],
55
+ hanging: element.attributes["w:hanging"]
56
+ };
57
+ }
58
+
59
+ function readParagraphSpacing(element) {
60
+ return {
61
+ lineRule: element.attributes["w:lineRule"],
62
+ line: element.attributes["w:line"],
63
+ before: element.attributes["w:before"],
64
+ after: element.attributes["w:after"]
65
+ };
66
+ }
67
+
68
+ function readParagraphBorders(element) {
69
+ return {
70
+ top: readParagraphBorder(element.firstOrEmpty("w:top")),
71
+ left: readParagraphBorder(element.firstOrEmpty("w:left")),
72
+ bottom: readParagraphBorder(element.firstOrEmpty("w:bottom")),
73
+ right: readParagraphBorder(element.firstOrEmpty("w:right"))
74
+ };
75
+ }
76
+
77
+ function readParagraphBorder(element) {
78
+ return {
79
+ style: element.attributes["w:val"],
80
+ width: element.attributes["w:sz"],
81
+ offset: element.attributes["w:space"],
82
+ color: element.attributes["w:color"]
83
+ };
84
+ }
85
+
86
+ function readRunProperties(element) {
87
+ return readRunStyle(element).map(function(style) {
88
+ return {
89
+ type: "runProperties",
90
+ styleId: style.styleId,
91
+ styleName: style.name,
92
+ verticalAlignment: element.firstOrEmpty("w:vertAlign").attributes["w:val"],
93
+ font: element.firstOrEmpty("w:rFonts").attributes["w:ascii"],
94
+ size: element.firstOrEmpty("w:sz").attributes["w:val"],
95
+ isBold: readBooleanElement(element.first("w:b")),
96
+ isUnderline: readBooleanElement(element.first("w:u")),
97
+ isItalic: readBooleanElement(element.first("w:i")),
98
+ isStrikethrough: readBooleanElement(element.first("w:strike")),
99
+ isSmallCaps: readBooleanElement(element.first("w:smallCaps")),
100
+ color: element.firstOrEmpty("w:color").attributes["w:val"],
101
+ highlight: element.firstOrEmpty("w:highlight").attributes["w:val"]
102
+ };
103
+ });
104
+ }
105
+
106
+ function readBooleanElement(element) {
107
+ if (element) {
108
+ var value = element.attributes["w:val"];
109
+ return value !== "false" && value !== "0";
110
+ } else {
111
+ return false;
112
+ }
113
+ }
114
+
115
+ function readParagraphStyle(element) {
116
+ return readStyle(element, "w:pStyle", "Paragraph", styles.findParagraphStyleById);
117
+ }
118
+
119
+ function readRunStyle(element) {
120
+ return readStyle(element, "w:rStyle", "Run", styles.findCharacterStyleById);
121
+ }
122
+
123
+ function readTableStyle(element) {
124
+ return readStyle(element, "w:tblStyle", "Table", styles.findTableStyleById);
125
+ }
126
+
127
+ function readStyle(element, styleTagName, styleType, findStyleById) {
128
+ var messages = [];
129
+ var styleElement = element.first(styleTagName);
130
+ var styleId = null;
131
+ var name = null;
132
+ if (styleElement) {
133
+ styleId = styleElement.attributes["w:val"];
134
+ if (styleId) {
135
+ var style = findStyleById(styleId);
136
+ if (style) {
137
+ name = style.name;
138
+ } else {
139
+ messages.push(undefinedStyleWarning(styleType, styleId));
140
+ }
141
+ }
142
+ }
143
+ return elementResultWithMessages({styleId: styleId, name: name}, messages);
144
+ }
145
+
146
+ var unknownComplexField = {type: "unknown"};
147
+
148
+ function readFldChar(element) {
149
+ var type = element.attributes["w:fldCharType"];
150
+ if (type === "begin") {
151
+ complexFieldStack.push(unknownComplexField);
152
+ currentInstrText = [];
153
+ } else if (type === "end") {
154
+ complexFieldStack.pop();
155
+ } else if (type === "separate") {
156
+ var href = parseHyperlinkFieldCode(currentInstrText.join(''));
157
+ var complexField = href === null ? unknownComplexField : {type: "hyperlink", href: href};
158
+ complexFieldStack.pop();
159
+ complexFieldStack.push(complexField);
160
+ }
161
+ return emptyResult();
162
+ }
163
+
164
+ function currentHyperlinkHref() {
165
+ var topHyperlink = _.last(complexFieldStack.filter(function(complexField) {
166
+ return complexField.type === "hyperlink";
167
+ }));
168
+ return topHyperlink ? topHyperlink.href : null;
169
+ }
170
+
171
+ function parseHyperlinkFieldCode(code) {
172
+ var result = /\s*HYPERLINK "(.*)"/.exec(code);
173
+ if (result) {
174
+ return result[1];
175
+ } else {
176
+ return null;
177
+ }
178
+ }
179
+
180
+ function readInstrText(element) {
181
+ currentInstrText.push(element.text());
182
+ return emptyResult();
183
+ }
184
+
185
+ function noteReferenceReader(noteType) {
186
+ return function(element) {
187
+ var noteId = element.attributes["w:id"];
188
+ return elementResult(new documents.NoteReference({
189
+ noteType: noteType,
190
+ noteId: noteId
191
+ }));
192
+ };
193
+ }
194
+
195
+ function readCommentReference(element) {
196
+ return elementResult(documents.commentReference({
197
+ commentId: element.attributes["w:id"]
198
+ }));
199
+ }
200
+
201
+ function readChildElements(element) {
202
+ return readXmlElements(element.children);
203
+ }
204
+
205
+ var xmlElementReaders = {
206
+ "w:p": function(element) {
207
+ return readXmlElements(element.children)
208
+ .map(function(children) {
209
+ var properties = _.find(children, isParagraphProperties);
210
+ return new documents.Paragraph(
211
+ children.filter(negate(isParagraphProperties)),
212
+ properties
213
+ );
214
+ })
215
+ .insertExtra();
216
+ },
217
+ "w:pPr": function(element) {
218
+ return readParagraphStyle(element).map(function(style) {
219
+ return {
220
+ type: "paragraphProperties",
221
+ styleId: style.styleId,
222
+ styleName: style.name,
223
+ alignment: element.firstOrEmpty("w:jc").attributes["w:val"],
224
+ numbering: readNumberingProperties(element.firstOrEmpty("w:numPr"), numbering),
225
+ indent: readParagraphIndent(element.firstOrEmpty("w:ind")),
226
+ spacing: readParagraphSpacing(element.firstOrEmpty("w:spacing")),
227
+ border: readParagraphBorders(element.firstOrEmpty("w:pBdr"))
228
+ };
229
+ });
230
+ },
231
+ "w:r": function(element) {
232
+ return readXmlElements(element.children)
233
+ .map(function(children) {
234
+ var properties = _.find(children, isRunProperties);
235
+ children = children.filter(negate(isRunProperties));
236
+
237
+ var hyperlinkHref = currentHyperlinkHref();
238
+ if (hyperlinkHref !== null) {
239
+ children = [new documents.Hyperlink(children, {href: hyperlinkHref})];
240
+ }
241
+
242
+ return new documents.Run(children, properties);
243
+ });
244
+ },
245
+ "w:rPr": readRunProperties,
246
+ "w:fldChar": readFldChar,
247
+ "w:instrText": readInstrText,
248
+ "w:t": function(element) {
249
+ return elementResult(new documents.Text(element.text()));
250
+ },
251
+ "w:tab": function(element) {
252
+ return elementResult(new documents.Tab());
253
+ },
254
+ "w:noBreakHyphen": function() {
255
+ return elementResult(new documents.Text("\u2011"));
256
+ },
257
+ "w:hyperlink": function(element) {
258
+ var relationshipId = element.attributes["r:id"];
259
+ var anchor = element.attributes["w:anchor"];
260
+ return readXmlElements(element.children).map(function(children) {
261
+ function create(options) {
262
+ var targetFrame = element.attributes["w:tgtFrame"] || null;
263
+
264
+ return new documents.Hyperlink(
265
+ children,
266
+ _.extend({targetFrame: targetFrame}, options)
267
+ );
268
+ }
269
+
270
+ if (relationshipId) {
271
+ var href = relationships.findTargetByRelationshipId(relationshipId);
272
+ if (anchor) {
273
+ href = uris.replaceFragment(href, anchor);
274
+ }
275
+ return create({href: href});
276
+ } else if (anchor) {
277
+ return create({anchor: anchor});
278
+ } else {
279
+ return children;
280
+ }
281
+ });
282
+ },
283
+ "w:tbl": readTable,
284
+ "w:tr": readTableRow,
285
+ "w:tc": readTableCell,
286
+ "w:footnoteReference": noteReferenceReader("footnote"),
287
+ "w:endnoteReference": noteReferenceReader("endnote"),
288
+ "w:commentReference": readCommentReference,
289
+ "w:br": function(element) {
290
+ var breakType = element.attributes["w:type"];
291
+ if (breakType == null || breakType === "textWrapping") {
292
+ return elementResult(documents.lineBreak);
293
+ } else if (breakType === "page") {
294
+ return elementResult(documents.pageBreak);
295
+ } else if (breakType === "column") {
296
+ return elementResult(documents.columnBreak);
297
+ } else {
298
+ return emptyResultWithMessages([warning("Unsupported break type: " + breakType)]);
299
+ }
300
+ },
301
+ "w:bookmarkStart": function(element){
302
+ var name = element.attributes["w:name"];
303
+ if (name === "_GoBack") {
304
+ return emptyResult();
305
+ } else {
306
+ return elementResult(new documents.BookmarkStart({name: name}));
307
+ }
308
+ },
309
+
310
+ "mc:AlternateContent": function(element) {
311
+ return readChildElements(element.first("mc:Fallback"));
312
+ },
313
+
314
+ "w:sdt": function(element) {
315
+ return readXmlElements(element.firstOrEmpty("w:sdtContent").children);
316
+ },
317
+
318
+ "w:ins": readChildElements,
319
+ "w:object": readChildElements,
320
+ "w:smartTag": readChildElements,
321
+ "w:drawing": readChildElements,
322
+ "w:pict": function(element) {
323
+ return readChildElements(element).toExtra();
324
+ },
325
+ "v:roundrect": readChildElements,
326
+ "v:shape": readChildElements,
327
+ "v:textbox": readChildElements,
328
+ "w:txbxContent": readChildElements,
329
+ "wp:inline": readDrawingElement,
330
+ "wp:anchor": readDrawingElement,
331
+ "v:imagedata": readImageData,
332
+ "v:group": readChildElements,
333
+ "v:rect": readChildElements
334
+ };
335
+
336
+ return {
337
+ readXmlElement: readXmlElement,
338
+ readXmlElements: readXmlElements
339
+ };
340
+
341
+
342
+ function readTable(element) {
343
+ var propertiesResult = readTableProperties(element.firstOrEmpty("w:tblPr"));
344
+ return readXmlElements(element.children)
345
+ .flatMap(calculateRowSpans)
346
+ .flatMap(function(children) {
347
+ return propertiesResult.map(function(properties) {
348
+ return documents.Table(children, properties);
349
+ });
350
+ });
351
+ }
352
+
353
+ function readTableProperties(element) {
354
+ return readTableStyle(element).map(function(style) {
355
+ return {
356
+ styleId: style.styleId,
357
+ styleName: style.name
358
+ };
359
+ });
360
+ }
361
+
362
+ function readTableRow(element) {
363
+ var properties = element.firstOrEmpty("w:trPr");
364
+ var isHeader = !!properties.first("w:tblHeader");
365
+ return readXmlElements(element.children).map(function(children) {
366
+ return documents.TableRow(children, {isHeader: isHeader});
367
+ });
368
+ }
369
+
370
+ function readTableCell(element) {
371
+ return readXmlElements(element.children).map(function(children) {
372
+ var properties = element.firstOrEmpty("w:tcPr");
373
+
374
+ var gridSpan = properties.firstOrEmpty("w:gridSpan").attributes["w:val"];
375
+ var colSpan = gridSpan ? parseInt(gridSpan, 10) : 1;
376
+
377
+ var cell = documents.TableCell(children, {colSpan: colSpan});
378
+ cell._vMerge = readVMerge(properties);
379
+ return cell;
380
+ });
381
+ }
382
+
383
+ function readVMerge(properties) {
384
+ var element = properties.first("w:vMerge");
385
+ if (element) {
386
+ var val = element.attributes["w:val"];
387
+ return val === "continue" || !val;
388
+ } else {
389
+ return null;
390
+ }
391
+ }
392
+
393
+ function calculateRowSpans(rows) {
394
+ var unexpectedNonRows = _.any(rows, function(row) {
395
+ return row.type !== documents.types.tableRow;
396
+ });
397
+ if (unexpectedNonRows) {
398
+ return elementResultWithMessages(rows, [warning(
399
+ "unexpected non-row element in table, cell merging may be incorrect"
400
+ )]);
401
+ }
402
+ var unexpectedNonCells = _.any(rows, function(row) {
403
+ return _.any(row.children, function(cell) {
404
+ return cell.type !== documents.types.tableCell;
405
+ });
406
+ });
407
+ if (unexpectedNonCells) {
408
+ return elementResultWithMessages(rows, [warning(
409
+ "unexpected non-cell element in table row, cell merging may be incorrect"
410
+ )]);
411
+ }
412
+
413
+ var columns = {};
414
+
415
+ rows.forEach(function(row) {
416
+ var cellIndex = 0;
417
+ row.children.forEach(function(cell) {
418
+ if (cell._vMerge && columns[cellIndex]) {
419
+ columns[cellIndex].rowSpan++;
420
+ } else {
421
+ columns[cellIndex] = cell;
422
+ cell._vMerge = false;
423
+ }
424
+ cellIndex += cell.colSpan;
425
+ });
426
+ });
427
+
428
+ rows.forEach(function(row) {
429
+ row.children = row.children.filter(function(cell) {
430
+ return !cell._vMerge;
431
+ });
432
+ row.children.forEach(function(cell) {
433
+ delete cell._vMerge;
434
+ });
435
+ });
436
+
437
+ return elementResult(rows);
438
+ }
439
+
440
+ function readDrawingElement(element) {
441
+ var blips = element
442
+ .getElementsByTagName("a:graphic")
443
+ .getElementsByTagName("a:graphicData")
444
+ .getElementsByTagName("pic:pic")
445
+ .getElementsByTagName("pic:blipFill")
446
+ .getElementsByTagName("a:blip");
447
+
448
+ return combineResults(blips.map(readBlip.bind(null, element)));
449
+ }
450
+
451
+ function readBlip(element, blip) {
452
+ var properties = element.first("wp:docPr").attributes;
453
+ var altText = isBlank(properties.descr) ? properties.title : properties.descr;
454
+ return readImage(findBlipImageFile(blip), altText);
455
+ }
456
+
457
+ function isBlank(value) {
458
+ return value == null || /^\s*$/.test(value);
459
+ }
460
+
461
+ function findBlipImageFile(blip) {
462
+ var embedRelationshipId = blip.attributes["r:embed"];
463
+ var linkRelationshipId = blip.attributes["r:link"];
464
+ if (embedRelationshipId) {
465
+ return findEmbeddedImageFile(embedRelationshipId);
466
+ } else {
467
+ var imagePath = relationships.findTargetByRelationshipId(linkRelationshipId);
468
+ return {
469
+ path: imagePath,
470
+ read: files.read.bind(files, imagePath)
471
+ };
472
+ }
473
+ }
474
+
475
+ function readImageData(element) {
476
+ var relationshipId = element.attributes['r:id'];
477
+
478
+ if (relationshipId) {
479
+ return readImage(
480
+ findEmbeddedImageFile(relationshipId),
481
+ element.attributes["o:title"]);
482
+ } else {
483
+ return emptyResultWithMessages([warning("A v:imagedata element without a relationship ID was ignored")]);
484
+ }
485
+ }
486
+
487
+ function findEmbeddedImageFile(relationshipId) {
488
+ var path = uris.uriToZipEntryName("word", relationships.findTargetByRelationshipId(relationshipId));
489
+ return {
490
+ path: path,
491
+ read: docxFile.read.bind(docxFile, path)
492
+ };
493
+ }
494
+
495
+ function readImage(imageFile, altText) {
496
+ var contentType = contentTypes.findContentType(imageFile.path);
497
+
498
+ var image = documents.Image({
499
+ readImage: imageFile.read,
500
+ altText: altText,
501
+ contentType: contentType
502
+ });
503
+ var warnings = supportedImageTypes[contentType] ?
504
+ [] : warning("Image of type " + contentType + " is unlikely to display in web browsers");
505
+ return elementResultWithMessages(image, warnings);
506
+ }
507
+
508
+ function undefinedStyleWarning(type, styleId) {
509
+ return warning(
510
+ type + " style with ID " + styleId + " was referenced but not defined in the document");
511
+ }
512
+ }
513
+
514
+
515
+ function readNumberingProperties(element, numbering) {
516
+ var level = element.firstOrEmpty("w:ilvl").attributes["w:val"];
517
+ var numId = element.firstOrEmpty("w:numId").attributes["w:val"];
518
+ if (level === undefined || numId === undefined) {
519
+ return null;
520
+ } else {
521
+ return numbering.findLevel(numId, level);
522
+ }
523
+ }
524
+
525
+ var supportedImageTypes = {
526
+ "image/png": true,
527
+ "image/gif": true,
528
+ "image/jpeg": true,
529
+ "image/svg+xml": true,
530
+ "image/tiff": true
531
+ };
532
+
533
+ var ignoreElements = {
534
+ "office-word:wrap": true,
535
+ "v:shadow": true,
536
+ "v:shapetype": true,
537
+ "w:annotationRef": true,
538
+ "w:bookmarkEnd": true,
539
+ "w:sectPr": true,
540
+ "w:proofErr": true,
541
+ "w:lastRenderedPageBreak": true,
542
+ "w:commentRangeStart": true,
543
+ "w:commentRangeEnd": true,
544
+ "w:del": true,
545
+ "w:footnoteRef": true,
546
+ "w:endnoteRef": true,
547
+ "w:tblPr": true,
548
+ "w:tblGrid": true,
549
+ "w:trPr": true,
550
+ "w:tcPr": true
551
+ };
552
+
553
+ function isParagraphProperties(element) {
554
+ return element.type === "paragraphProperties";
555
+ }
556
+
557
+ function isRunProperties(element) {
558
+ return element.type === "runProperties";
559
+ }
560
+
561
+ function negate(predicate) {
562
+ return function(value) {
563
+ return !predicate(value);
564
+ };
565
+ }
566
+
567
+
568
+ function emptyResultWithMessages(messages) {
569
+ return new ReadResult(null, null, messages);
570
+ }
571
+
572
+ function emptyResult() {
573
+ return new ReadResult(null);
574
+ }
575
+
576
+ function elementResult(element) {
577
+ return new ReadResult(element);
578
+ }
579
+
580
+ function elementResultWithMessages(element, messages) {
581
+ return new ReadResult(element, null, messages);
582
+ }
583
+
584
+ function ReadResult(element, extra, messages) {
585
+ this.value = element || [];
586
+ this.extra = extra;
587
+ this._result = new Result({
588
+ element: this.value,
589
+ extra: extra
590
+ }, messages);
591
+ this.messages = this._result.messages;
592
+ }
593
+
594
+ ReadResult.prototype.toExtra = function() {
595
+ return new ReadResult(null, joinElements(this.extra, this.value), this.messages);
596
+ };
597
+
598
+ ReadResult.prototype.insertExtra = function() {
599
+ var extra = this.extra;
600
+ if (extra && extra.length) {
601
+ return new ReadResult(joinElements(this.value, extra), null, this.messages);
602
+ } else {
603
+ return this;
604
+ }
605
+ };
606
+
607
+ ReadResult.prototype.map = function(func) {
608
+ var result = this._result.map(function(value) {
609
+ return func(value.element);
610
+ });
611
+ return new ReadResult(result.value, this.extra, result.messages);
612
+ };
613
+
614
+ ReadResult.prototype.flatMap = function(func) {
615
+ var result = this._result.flatMap(function(value) {
616
+ return func(value.element)._result;
617
+ });
618
+ return new ReadResult(result.value.element, joinElements(this.extra, result.value.extra), result.messages);
619
+ };
620
+
621
+ function combineResults(results) {
622
+ var result = Result.combine(_.pluck(results, "_result"));
623
+ return new ReadResult(
624
+ _.flatten(_.pluck(result.value, "element")),
625
+ _.filter(_.flatten(_.pluck(result.value, "extra")), identity),
626
+ result.messages
627
+ );
628
+ }
629
+
630
+ function joinElements(first, second) {
631
+ return _.flatten([first, second]);
632
+ }
633
+
634
+ function identity(value) {
635
+ return value;
636
+ }
@@ -0,0 +1,31 @@
1
+ var documents = require("../documents");
2
+ var Result = require("../results").Result;
3
+
4
+ function createCommentsReader(bodyReader) {
5
+ function readCommentsXml(element) {
6
+ return Result.combine(element.getElementsByTagName("w:comment")
7
+ .map(readCommentElement));
8
+ }
9
+
10
+ function readCommentElement(element) {
11
+ var id = element.attributes["w:id"];
12
+
13
+ function readOptionalAttribute(name) {
14
+ return (element.attributes[name] || "").trim() || null;
15
+ }
16
+
17
+ return bodyReader.readXmlElements(element.children)
18
+ .map(function(body) {
19
+ return documents.comment({
20
+ commentId: id,
21
+ body: body,
22
+ authorName: readOptionalAttribute("w:author"),
23
+ authorInitials: readOptionalAttribute("w:initials")
24
+ });
25
+ });
26
+ }
27
+
28
+ return readCommentsXml;
29
+ }
30
+
31
+ exports.createCommentsReader = createCommentsReader;