@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,70 @@
1
+ exports.readStylesXml = readStylesXml;
2
+ exports.Styles = Styles;
3
+ exports.defaultStyles = new Styles({}, {});
4
+
5
+ function Styles(paragraphStyles, characterStyles, tableStyles, numberingStyles) {
6
+ return {
7
+ findParagraphStyleById: function(styleId) {
8
+ return paragraphStyles[styleId];
9
+ },
10
+ findCharacterStyleById: function(styleId) {
11
+ return characterStyles[styleId];
12
+ },
13
+ findTableStyleById: function(styleId) {
14
+ return tableStyles[styleId];
15
+ },
16
+ findNumberingStyleById: function(styleId) {
17
+ return numberingStyles[styleId];
18
+ }
19
+ };
20
+ }
21
+
22
+ Styles.EMPTY = new Styles({}, {}, {}, {});
23
+
24
+ function readStylesXml(root) {
25
+ var paragraphStyles = {};
26
+ var characterStyles = {};
27
+ var tableStyles = {};
28
+ var numberingStyles = {};
29
+
30
+ var styles = {
31
+ "paragraph": paragraphStyles,
32
+ "character": characterStyles,
33
+ "table": tableStyles
34
+ };
35
+
36
+ root.getElementsByTagName("w:style").forEach(function(styleElement) {
37
+ var style = readStyleElement(styleElement);
38
+ if (style.type === "numbering") {
39
+ numberingStyles[style.styleId] = readNumberingStyleElement(styleElement);
40
+ } else {
41
+ var styleSet = styles[style.type];
42
+ if (styleSet) {
43
+ styleSet[style.styleId] = style;
44
+ }
45
+ }
46
+ });
47
+
48
+ return new Styles(paragraphStyles, characterStyles, tableStyles, numberingStyles);
49
+ }
50
+
51
+ function readStyleElement(styleElement) {
52
+ var type = styleElement.attributes["w:type"];
53
+ var styleId = styleElement.attributes["w:styleId"];
54
+ var name = styleName(styleElement);
55
+ return {type: type, styleId: styleId, name: name};
56
+ }
57
+
58
+ function styleName(styleElement) {
59
+ var nameElement = styleElement.first("w:name");
60
+ return nameElement ? nameElement.attributes["w:val"] : null;
61
+ }
62
+
63
+ function readNumberingStyleElement(styleElement) {
64
+ var numId = styleElement
65
+ .firstOrEmpty("w:pPr")
66
+ .firstOrEmpty("w:numPr")
67
+ .firstOrEmpty("w:numId")
68
+ .attributes["w:val"];
69
+ return {numId: numId};
70
+ }
@@ -0,0 +1,21 @@
1
+ exports.uriToZipEntryName = uriToZipEntryName;
2
+ exports.replaceFragment = replaceFragment;
3
+
4
+ function uriToZipEntryName(base, uri) {
5
+ if (uri.charAt(0) === "/") {
6
+ return uri.substr(1);
7
+ } else {
8
+ // In general, we should check first and second for trailing and leading slashes,
9
+ // but in our specific case this seems to be sufficient
10
+ return base + "/" + uri;
11
+ }
12
+ }
13
+
14
+
15
+ function replaceFragment(uri, fragment) {
16
+ var hashIndex = uri.indexOf("#");
17
+ if (hashIndex !== -1) {
18
+ uri = uri.substring(0, hashIndex);
19
+ }
20
+ return uri + "#" + fragment;
21
+ }
@@ -0,0 +1,50 @@
1
+ var htmlPaths = require("../styles/html-paths");
2
+
3
+
4
+ function nonFreshElement(tagName, attributes, children) {
5
+ return elementWithTag(
6
+ htmlPaths.element(tagName, attributes, {fresh: false}),
7
+ children);
8
+ }
9
+
10
+ function freshElement(tagName, attributes, children) {
11
+ var tag = htmlPaths.element(tagName, attributes, {fresh: true});
12
+ return elementWithTag(tag, children);
13
+ }
14
+
15
+ function elementWithTag(tag, children) {
16
+ return {
17
+ type: "element",
18
+ tag: tag,
19
+ children: children || []
20
+ };
21
+ }
22
+
23
+ function text(value) {
24
+ return {
25
+ type: "text",
26
+ value: value
27
+ };
28
+ }
29
+
30
+ var forceWrite = {
31
+ type: "forceWrite"
32
+ };
33
+
34
+ exports.freshElement = freshElement;
35
+ exports.nonFreshElement = nonFreshElement;
36
+ exports.elementWithTag = elementWithTag;
37
+ exports.text = text;
38
+ exports.forceWrite = forceWrite;
39
+
40
+ var voidTagNames = {
41
+ "br": true,
42
+ "hr": true,
43
+ "img": true
44
+ };
45
+
46
+ function isVoidElement(node) {
47
+ return (node.children.length === 0) && voidTagNames[node.tag.tagName];
48
+ }
49
+
50
+ exports.isVoidElement = isVoidElement;
@@ -0,0 +1,41 @@
1
+ var ast = require("./ast");
2
+
3
+ exports.freshElement = ast.freshElement;
4
+ exports.nonFreshElement = ast.nonFreshElement;
5
+ exports.elementWithTag = ast.elementWithTag;
6
+ exports.text = ast.text;
7
+ exports.forceWrite = ast.forceWrite;
8
+
9
+ exports.simplify = require("./simplify");
10
+
11
+ function write(writer, nodes) {
12
+ nodes.forEach(function(node) {
13
+ writeNode(writer, node);
14
+ });
15
+ }
16
+
17
+ function writeNode(writer, node) {
18
+ toStrings[node.type](writer, node);
19
+ }
20
+
21
+ var toStrings = {
22
+ element: generateElementString,
23
+ text: generateTextString,
24
+ forceWrite: function() { }
25
+ };
26
+
27
+ function generateElementString(writer, node) {
28
+ if (ast.isVoidElement(node)) {
29
+ writer.selfClosing(node.tag.tagName, node.tag.attributes);
30
+ } else {
31
+ writer.open(node.tag.tagName, node.tag.attributes);
32
+ write(writer, node.children);
33
+ writer.close(node.tag.tagName);
34
+ }
35
+ }
36
+
37
+ function generateTextString(writer, node) {
38
+ writer.text(node.value);
39
+ }
40
+
41
+ exports.write = write;
@@ -0,0 +1,88 @@
1
+ var _ = require("underscore");
2
+
3
+ var ast = require("./ast");
4
+
5
+ function simplify(nodes) {
6
+ return collapse(removeEmpty(nodes));
7
+ }
8
+
9
+ function collapse(nodes) {
10
+ var children = [];
11
+
12
+ nodes.map(collapseNode).forEach(function(child) {
13
+ appendChild(children, child);
14
+ });
15
+ return children;
16
+ }
17
+
18
+ function collapseNode(node) {
19
+ return collapsers[node.type](node);
20
+ }
21
+
22
+ var collapsers = {
23
+ element: collapseElement,
24
+ text: identity,
25
+ forceWrite: identity
26
+ };
27
+
28
+ function collapseElement(node) {
29
+ return ast.elementWithTag(node.tag, collapse(node.children));
30
+ }
31
+
32
+ function identity(value) {
33
+ return value;
34
+ }
35
+
36
+ function appendChild(children, child) {
37
+ var lastChild = children[children.length - 1];
38
+ if (child.type === "element" && !child.tag.fresh && lastChild && lastChild.type === "element" && child.tag.matchesElement(lastChild.tag)) {
39
+ if (child.tag.separator) {
40
+ appendChild(lastChild.children, ast.text(child.tag.separator));
41
+ }
42
+ child.children.forEach(function(grandChild) {
43
+ // Mutation is fine since simplifying elements create a copy of the children.
44
+ appendChild(lastChild.children, grandChild);
45
+ });
46
+ } else {
47
+ children.push(child);
48
+ }
49
+ }
50
+
51
+ function removeEmpty(nodes) {
52
+ return flatMap(nodes, function(node) {
53
+ return emptiers[node.type](node);
54
+ });
55
+ }
56
+
57
+ function flatMap(values, func) {
58
+ return _.flatten(_.map(values, func), true);
59
+ }
60
+
61
+ var emptiers = {
62
+ element: elementEmptier,
63
+ text: textEmptier,
64
+ forceWrite: neverEmpty
65
+ };
66
+
67
+ function neverEmpty(node) {
68
+ return [node];
69
+ }
70
+
71
+ function elementEmptier(element) {
72
+ var children = removeEmpty(element.children);
73
+ if (children.length === 0 && !ast.isVoidElement(element)) {
74
+ return [];
75
+ } else {
76
+ return [ast.elementWithTag(element.tag, children)];
77
+ }
78
+ }
79
+
80
+ function textEmptier(node) {
81
+ if (node.value.length === 0) {
82
+ return [];
83
+ } else {
84
+ return [node];
85
+ }
86
+ }
87
+
88
+ module.exports = simplify;
package/lib/images.js ADDED
@@ -0,0 +1,29 @@
1
+ var _ = require("underscore");
2
+
3
+ var promises = require("./promises");
4
+ var Html = require("./html");
5
+
6
+ exports.imgElement = imgElement;
7
+
8
+ function imgElement(func) {
9
+ return function(element, messages) {
10
+ return promises.when(func(element)).then(function(result) {
11
+ var attributes = _.clone(result);
12
+ if (element.altText) {
13
+ attributes.alt = element.altText;
14
+ }
15
+ return [Html.freshElement("img", attributes)];
16
+ });
17
+ };
18
+ }
19
+
20
+ // Undocumented, but retained for backwards-compatibility with 0.3.x
21
+ exports.inline = exports.imgElement;
22
+
23
+ exports.dataUri = imgElement(function(element) {
24
+ return element.read("base64").then(function(imageBuffer) {
25
+ return {
26
+ src: "data:" + element.contentType + ";base64," + imageBuffer
27
+ };
28
+ });
29
+ });
package/lib/index.js ADDED
@@ -0,0 +1,115 @@
1
+ var _ = require("underscore");
2
+
3
+ var docxReader = require("./docx/docx-reader");
4
+ var docxStyleMap = require("./docx/style-map");
5
+ var DocumentConverter = require("./document-to-html").DocumentConverter;
6
+ var readStyle = require("./style-reader").readStyle;
7
+ var readOptions = require("./options-reader").readOptions;
8
+ var unzip = require("./unzip");
9
+ var Result = require("./results").Result;
10
+ var results = require("./results");
11
+
12
+ exports.convertToHtml = convertToHtml;
13
+ exports.convertToMarkdown = convertToMarkdown;
14
+ exports.convert = convert;
15
+ exports.extractRawText = extractRawText;
16
+ exports.images = require("./images");
17
+ exports.transforms = require("./transforms");
18
+ exports.underline = require("./underline");
19
+ exports.embedStyleMap = embedStyleMap;
20
+ exports.readEmbeddedStyleMap = readEmbeddedStyleMap;
21
+
22
+ function convertToHtml(input, options) {
23
+ return convert(input, options);
24
+ }
25
+
26
+ function convertToMarkdown(input, options) {
27
+ var markdownOptions = Object.create(options || {});
28
+ markdownOptions.outputFormat = "markdown";
29
+ return convert(input, markdownOptions);
30
+ }
31
+
32
+ function convert(input, options) {
33
+ options = readOptions(options);
34
+
35
+ return unzip.openZip(input)
36
+ .tap(function(docxFile) {
37
+ return docxStyleMap.readStyleMap(docxFile).then(function(styleMap) {
38
+ options.embeddedStyleMap = styleMap;
39
+ });
40
+ })
41
+ .then(function(docxFile) {
42
+ return docxReader.read(docxFile, input)
43
+ .then(function(documentResult) {
44
+ return documentResult.map(options.transformDocument);
45
+ })
46
+ .then(function(documentResult) {
47
+ return convertDocumentToHtml(documentResult, options);
48
+ });
49
+ });
50
+ }
51
+
52
+ function readEmbeddedStyleMap(input) {
53
+ return unzip.openZip(input)
54
+ .then(docxStyleMap.readStyleMap);
55
+ }
56
+
57
+ function convertDocumentToHtml(documentResult, options) {
58
+ var styleMapResult = parseStyleMap(options.readStyleMap());
59
+ var parsedOptions = _.extend({}, options, {
60
+ styleMap: styleMapResult.value
61
+ });
62
+ var documentConverter = new DocumentConverter(parsedOptions);
63
+
64
+ return documentResult.flatMapThen(function(document) {
65
+ return styleMapResult.flatMapThen(function(styleMap) {
66
+ return documentConverter.convertToHtml(document);
67
+ });
68
+ });
69
+ }
70
+
71
+ function parseStyleMap(styleMap) {
72
+ return Result.combine((styleMap || [])
73
+ .map(function(arg) {
74
+ return _.isObject(arg) ? results.success(arg) : readStyle(arg);
75
+ }))
76
+ .map(function(styleMap) {
77
+ return styleMap.filter(function(styleMapping) {
78
+ return !!styleMapping;
79
+ });
80
+ });
81
+ }
82
+
83
+
84
+ function extractRawText(input) {
85
+ return unzip.openZip(input)
86
+ .then(docxReader.read)
87
+ .then(function(documentResult) {
88
+ return documentResult.map(convertElementToRawText);
89
+ });
90
+ }
91
+
92
+ function convertElementToRawText(element) {
93
+ if (element.type === "text") {
94
+ return element.value;
95
+ } else {
96
+ var tail = element.type === "paragraph" ? "\n\n" : "";
97
+ return (element.children || []).map(convertElementToRawText).join("") + tail;
98
+ }
99
+ }
100
+
101
+ function embedStyleMap(input, styleMap) {
102
+ return unzip.openZip(input)
103
+ .tap(function(docxFile) {
104
+ return docxStyleMap.writeStyleMap(docxFile, styleMap);
105
+ })
106
+ .then(function(docxFile) {
107
+ return {
108
+ toBuffer: docxFile.toBuffer
109
+ };
110
+ });
111
+ }
112
+
113
+ exports.styleMapping = function() {
114
+ throw new Error('Use a raw string instead of mammoth.styleMapping e.g. "p[style-name=\'Title\'] => h1" instead of mammoth.styleMapping("p[style-name=\'Title\'] => h1")');
115
+ };
package/lib/main.js ADDED
@@ -0,0 +1,63 @@
1
+ /* global process */
2
+
3
+ var fs = require("fs");
4
+ var path = require("path");
5
+
6
+ var mammoth = require("./");
7
+ var promises = require("./promises");
8
+ var images = require("./images");
9
+
10
+ function main(argv) {
11
+ var docxPath = argv["docx-path"];
12
+ var outputPath = argv["output-path"];
13
+ var outputDir = argv.output_dir;
14
+ var outputFormat = argv.output_format;
15
+ var styleMapPath = argv.style_map;
16
+
17
+ readStyleMap(styleMapPath).then(function(styleMap) {
18
+ var options = {
19
+ styleMap: styleMap,
20
+ outputFormat: outputFormat
21
+ };
22
+
23
+ if (outputDir) {
24
+ var basename = path.basename(docxPath, ".docx");
25
+ outputPath = path.join(outputDir, basename + ".html");
26
+ var imageIndex = 0;
27
+ options.convertImage = images.imgElement(function(element) {
28
+ imageIndex++;
29
+ var extension = element.contentType.split("/")[1];
30
+ var filename = imageIndex + "." + extension;
31
+
32
+ return element.read().then(function(imageBuffer) {
33
+ var imagePath = path.join(outputDir, filename);
34
+ return promises.nfcall(fs.writeFile, imagePath, imageBuffer);
35
+ }).then(function() {
36
+ return {src: filename};
37
+ });
38
+ });
39
+ }
40
+
41
+ return mammoth.convert({path: docxPath}, options)
42
+ .then(function(result) {
43
+ result.messages.forEach(function(message) {
44
+ process.stderr.write(message.message);
45
+ process.stderr.write("\n");
46
+ });
47
+
48
+ var outputStream = outputPath ? fs.createWriteStream(outputPath) : process.stdout;
49
+
50
+ outputStream.write(result.value);
51
+ });
52
+ }).done();
53
+ }
54
+
55
+ function readStyleMap(styleMapPath) {
56
+ if (styleMapPath) {
57
+ return promises.nfcall(fs.readFile, styleMapPath, "utf8");
58
+ } else {
59
+ return promises.resolve(null);
60
+ }
61
+ }
62
+
63
+ module.exports = main;
@@ -0,0 +1,98 @@
1
+ exports.readOptions = readOptions;
2
+
3
+
4
+ var _ = require("underscore");
5
+
6
+ var defaultStyleMap = exports._defaultStyleMap = [
7
+ "p.Heading1 => h1:fresh",
8
+ "p.Heading2 => h2:fresh",
9
+ "p.Heading3 => h3:fresh",
10
+ "p.Heading4 => h4:fresh",
11
+ "p.Heading5 => h5:fresh",
12
+ "p.Heading6 => h6:fresh",
13
+ "p[style-name='Heading 1'] => h1:fresh",
14
+ "p[style-name='Heading 2'] => h2:fresh",
15
+ "p[style-name='Heading 3'] => h3:fresh",
16
+ "p[style-name='Heading 4'] => h4:fresh",
17
+ "p[style-name='Heading 5'] => h5:fresh",
18
+ "p[style-name='Heading 6'] => h6:fresh",
19
+ "p[style-name='heading 1'] => h1:fresh",
20
+ "p[style-name='heading 2'] => h2:fresh",
21
+ "p[style-name='heading 3'] => h3:fresh",
22
+ "p[style-name='heading 4'] => h4:fresh",
23
+ "p[style-name='heading 5'] => h5:fresh",
24
+ "p[style-name='heading 6'] => h6:fresh",
25
+
26
+ "r[style-name='Strong'] => strong",
27
+
28
+ "p[style-name='footnote text'] => p:fresh",
29
+ "r[style-name='footnote reference'] =>",
30
+ "p[style-name='endnote text'] => p:fresh",
31
+ "r[style-name='endnote reference'] =>",
32
+ "p[style-name='annotation text'] => p:fresh",
33
+ "r[style-name='annotation reference'] =>",
34
+
35
+ // LibreOffice
36
+ "p[style-name='Footnote'] => p:fresh",
37
+ "r[style-name='Footnote anchor'] =>",
38
+ "p[style-name='Endnote'] => p:fresh",
39
+ "r[style-name='Endnote anchor'] =>",
40
+
41
+ "p:unordered-list(1) => ul > li:fresh",
42
+ "p:unordered-list(2) => ul|ol > li > ul > li:fresh",
43
+ "p:unordered-list(3) => ul|ol > li > ul|ol > li > ul > li:fresh",
44
+ "p:unordered-list(4) => ul|ol > li > ul|ol > li > ul|ol > li > ul > li:fresh",
45
+ "p:unordered-list(5) => ul|ol > li > ul|ol > li > ul|ol > li > ul|ol > li > ul > li:fresh",
46
+ "p:ordered-list(1) => ol > li:fresh",
47
+ "p:ordered-list(2) => ul|ol > li > ol > li:fresh",
48
+ "p:ordered-list(3) => ul|ol > li > ul|ol > li > ol > li:fresh",
49
+ "p:ordered-list(4) => ul|ol > li > ul|ol > li > ul|ol > li > ol > li:fresh",
50
+ "p:ordered-list(5) => ul|ol > li > ul|ol > li > ul|ol > li > ul|ol > li > ol > li:fresh",
51
+
52
+ "r[style-name='Hyperlink'] =>",
53
+
54
+ "p[style-name='Normal'] => p:fresh"
55
+ ];
56
+
57
+ var standardOptions = exports._standardOptions = {
58
+ transformDocument: identity,
59
+ includeDefaultStyleMap: true,
60
+ includeEmbeddedStyleMap: true
61
+ };
62
+
63
+ function readOptions(options) {
64
+ options = options || {};
65
+ return _.extend({}, standardOptions, options, {
66
+ customStyleMap: readStyleMap(options.styleMap),
67
+ readStyleMap: function() {
68
+ var styleMap = this.customStyleMap;
69
+ if (this.includeEmbeddedStyleMap) {
70
+ styleMap = styleMap.concat(readStyleMap(this.embeddedStyleMap));
71
+ }
72
+ if (this.includeDefaultStyleMap) {
73
+ styleMap = styleMap.concat(defaultStyleMap);
74
+ }
75
+ return styleMap;
76
+ }
77
+ });
78
+ }
79
+
80
+ function readStyleMap(styleMap) {
81
+ if (!styleMap) {
82
+ return [];
83
+ } else if (_.isString(styleMap)) {
84
+ return styleMap.split("\n")
85
+ .map(function(line) {
86
+ return line.trim();
87
+ })
88
+ .filter(function(line) {
89
+ return line !== "" && line.charAt(0) !== "#";
90
+ });
91
+ } else {
92
+ return styleMap;
93
+ }
94
+ }
95
+
96
+ function identity(value) {
97
+ return value;
98
+ }
@@ -0,0 +1,42 @@
1
+ var _ = require("underscore");
2
+ var bluebird = require("bluebird/js/release/promise")();
3
+
4
+ exports.defer = defer;
5
+ exports.when = bluebird.resolve;
6
+ exports.resolve = bluebird.resolve;
7
+ exports.all = bluebird.all;
8
+ exports.props = bluebird.props;
9
+ exports.reject = bluebird.reject;
10
+ exports.promisify = bluebird.promisify;
11
+ exports.mapSeries = bluebird.mapSeries;
12
+ exports.attempt = bluebird.attempt;
13
+
14
+ exports.nfcall = function(func) {
15
+ var args = Array.prototype.slice.call(arguments, 1);
16
+ var promisedFunc = bluebird.promisify(func);
17
+ return promisedFunc.apply(null, args);
18
+ };
19
+
20
+ bluebird.prototype.fail = bluebird.prototype.caught;
21
+
22
+ bluebird.prototype.also = function(func) {
23
+ return this.then(function(value) {
24
+ var returnValue = _.extend({}, value, func(value));
25
+ return bluebird.props(returnValue);
26
+ });
27
+ };
28
+
29
+ function defer() {
30
+ var resolve;
31
+ var reject;
32
+ var promise = new bluebird.Promise(function(resolveArg, rejectArg) {
33
+ resolve = resolveArg;
34
+ reject = rejectArg;
35
+ });
36
+
37
+ return {
38
+ resolve: resolve,
39
+ reject: reject,
40
+ promise: promise
41
+ };
42
+ }
package/lib/results.js ADDED
@@ -0,0 +1,72 @@
1
+ var _ = require("underscore");
2
+
3
+
4
+ exports.Result = Result;
5
+ exports.success = success;
6
+ exports.warning = warning;
7
+ exports.error = error;
8
+
9
+
10
+ function Result(value, messages) {
11
+ this.value = value;
12
+ this.messages = messages || [];
13
+ }
14
+
15
+ Result.prototype.map = function(func) {
16
+ return new Result(func(this.value), this.messages);
17
+ };
18
+
19
+ Result.prototype.flatMap = function(func) {
20
+ var funcResult = func(this.value);
21
+ return new Result(funcResult.value, combineMessages([this, funcResult]));
22
+ };
23
+
24
+ Result.prototype.flatMapThen = function(func) {
25
+ var that = this;
26
+ return func(this.value).then(function(otherResult) {
27
+ return new Result(otherResult.value, combineMessages([that, otherResult]));
28
+ });
29
+ };
30
+
31
+ Result.combine = function(results) {
32
+ var values = _.flatten(_.pluck(results, "value"));
33
+ var messages = combineMessages(results);
34
+ return new Result(values, messages);
35
+ };
36
+
37
+ function success(value) {
38
+ return new Result(value, []);
39
+ }
40
+
41
+ function warning(message) {
42
+ return {
43
+ type: "warning",
44
+ message: message
45
+ };
46
+ }
47
+
48
+ function error(exception) {
49
+ return {
50
+ type: "error",
51
+ message: exception.message,
52
+ error: exception
53
+ };
54
+ }
55
+
56
+ function combineMessages(results) {
57
+ var messages = [];
58
+ _.flatten(_.pluck(results, "messages"), true).forEach(function(message) {
59
+ if (!containsMessage(messages, message)) {
60
+ messages.push(message);
61
+ }
62
+ });
63
+ return messages;
64
+ }
65
+
66
+ function containsMessage(messages, message) {
67
+ return _.find(messages, isSameMessage.bind(null, message)) !== undefined;
68
+ }
69
+
70
+ function isSameMessage(first, second) {
71
+ return first.type === second.type && first.message === second.message;
72
+ }