@docx4j/core-ts 0.5.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.
Files changed (207) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +92 -4
  3. package/dist/html/convert.mjs +2 -1
  4. package/dist/html/elements.mjs +2 -1
  5. package/dist/model/color/ColorMath.d.mts +29 -0
  6. package/dist/model/color/ColorMath.mjs +146 -0
  7. package/dist/model/color/ColorTables.d.mts +6 -0
  8. package/dist/model/color/ColorTables.mjs +83 -0
  9. package/dist/model/color/DrawingMLColors.d.mts +52 -0
  10. package/dist/model/color/DrawingMLColors.mjs +374 -0
  11. package/dist/model/color/ResolvedColor.d.mts +36 -0
  12. package/dist/model/color/ResolvedColor.mjs +65 -0
  13. package/dist/model/color/SpreadsheetColors.d.mts +36 -0
  14. package/dist/model/color/SpreadsheetColors.mjs +84 -0
  15. package/dist/model/color/StyleFill.d.mts +28 -0
  16. package/dist/model/color/StyleFill.mjs +21 -0
  17. package/dist/model/color/ThemeColors.d.mts +86 -0
  18. package/dist/model/color/ThemeColors.mjs +304 -0
  19. package/dist/model/color/WordColors.d.mts +71 -0
  20. package/dist/model/color/WordColors.mjs +121 -0
  21. package/dist/model/color/index.d.mts +6 -0
  22. package/dist/model/color/index.mjs +30 -0
  23. package/dist/model/content/Body.d.mts +145 -23
  24. package/dist/model/content/Body.mjs +507 -150
  25. package/dist/model/content/Comment.d.mts +23 -5
  26. package/dist/model/content/Comment.mjs +207 -26
  27. package/dist/model/content/ContentControl.d.mts +198 -19
  28. package/dist/model/content/ContentControl.mjs +672 -99
  29. package/dist/model/content/Font.d.mts +70 -17
  30. package/dist/model/content/Font.mjs +119 -36
  31. package/dist/model/content/InlinePicture.d.mts +11 -0
  32. package/dist/model/content/InlinePicture.mjs +21 -1
  33. package/dist/model/content/List.d.mts +6 -3
  34. package/dist/model/content/List.mjs +18 -8
  35. package/dist/model/content/Paragraph.d.mts +200 -14
  36. package/dist/model/content/Paragraph.mjs +898 -82
  37. package/dist/model/content/Range.d.mts +227 -12
  38. package/dist/model/content/Range.mjs +785 -59
  39. package/dist/model/content/ResolvedView.d.mts +104 -0
  40. package/dist/model/content/ResolvedView.mjs +596 -0
  41. package/dist/model/content/Table.d.mts +29 -3
  42. package/dist/model/content/Table.mjs +135 -49
  43. package/dist/model/content/TrackedChange.d.mts +174 -15
  44. package/dist/model/content/TrackedChange.mjs +734 -170
  45. package/dist/model/content/comments.d.mts +20 -6
  46. package/dist/model/content/comments.mjs +67 -57
  47. package/dist/model/content/generalException.d.mts +18 -0
  48. package/dist/model/content/generalException.mjs +24 -0
  49. package/dist/model/content/index.d.mts +10 -3
  50. package/dist/model/content/index.mjs +10 -2
  51. package/dist/model/content/mathText.d.mts +21 -0
  52. package/dist/model/content/mathText.mjs +267 -0
  53. package/dist/model/content/officeText.d.mts +27 -0
  54. package/dist/model/content/officeText.mjs +74 -0
  55. package/dist/model/content/ooxml.mjs +12 -1
  56. package/dist/model/content/outline.d.mts +5 -0
  57. package/dist/model/content/outline.mjs +13 -0
  58. package/dist/model/content/paraIds.d.mts +5 -0
  59. package/dist/model/content/paraIds.mjs +54 -0
  60. package/dist/model/content/placeholders.d.mts +110 -0
  61. package/dist/model/content/placeholders.mjs +253 -0
  62. package/dist/model/content/search.d.mts +74 -0
  63. package/dist/model/content/search.mjs +255 -9
  64. package/dist/model/content/spanEdits.d.mts +159 -0
  65. package/dist/model/content/spanEdits.mjs +728 -0
  66. package/dist/model/content/story.d.mts +47 -0
  67. package/dist/model/content/story.mjs +95 -0
  68. package/dist/model/content/tableColumns.d.mts +1 -1
  69. package/dist/model/content/tableColumns.mjs +108 -80
  70. package/dist/model/content/tableRevisions.d.mts +11 -3
  71. package/dist/model/content/tableRevisions.mjs +72 -42
  72. package/dist/model/content/tableRules.d.mts +30 -0
  73. package/dist/model/content/tableRules.mjs +102 -0
  74. package/dist/model/content/textBoxes.d.mts +18 -0
  75. package/dist/model/content/textBoxes.mjs +105 -0
  76. package/dist/model/content/trackedChangeFilter.d.mts +39 -0
  77. package/dist/model/content/trackedChangeFilter.mjs +81 -0
  78. package/dist/model/content/tracking.d.mts +63 -6
  79. package/dist/model/content/tracking.mjs +242 -22
  80. package/dist/model/content/tree.d.mts +172 -24
  81. package/dist/model/content/tree.mjs +328 -54
  82. package/dist/model/content/wordRange.d.mts +48 -0
  83. package/dist/model/content/wordRange.mjs +97 -0
  84. package/dist/model/customxml/CustomXmlPartCollection.d.mts +30 -1
  85. package/dist/model/customxml/CustomXmlPartCollection.mjs +81 -12
  86. package/dist/model/customxml/XmlMapping.d.mts +32 -8
  87. package/dist/model/customxml/XmlMapping.mjs +64 -10
  88. package/dist/model/customxml/bindings.d.mts +33 -4
  89. package/dist/model/customxml/bindings.mjs +171 -45
  90. package/dist/model/customxml/index.d.mts +1 -0
  91. package/dist/model/customxml/index.mjs +1 -0
  92. package/dist/model/customxml/kinds.d.mts +8 -3
  93. package/dist/model/customxml/kinds.mjs +26 -5
  94. package/dist/model/customxml/opendope.d.mts +4 -1
  95. package/dist/model/customxml/opendope.mjs +9 -6
  96. package/dist/model/customxml/picturePlaceholder.d.mts +17 -0
  97. package/dist/model/customxml/picturePlaceholder.mjs +32 -0
  98. package/dist/model/customxml/pictures.d.mts +4 -3
  99. package/dist/model/customxml/pictures.mjs +22 -8
  100. package/dist/model/customxml/storeItems.d.mts +57 -0
  101. package/dist/model/customxml/storeItems.mjs +122 -0
  102. package/dist/model/customxml/xhtml.mjs +23 -22
  103. package/dist/model/dateZone.d.mts +25 -0
  104. package/dist/model/dateZone.mjs +57 -0
  105. package/dist/model/index.d.mts +3 -0
  106. package/dist/model/index.mjs +5 -0
  107. package/dist/model/listnumbering/Emulator.d.mts +37 -5
  108. package/dist/model/listnumbering/Emulator.mjs +63 -9
  109. package/dist/model/properties/PropertyResolver.d.mts +74 -2
  110. package/dist/model/properties/PropertyResolver.mjs +133 -5
  111. package/dist/model/properties/catalogue.d.mts +19 -5
  112. package/dist/model/properties/catalogue.mjs +41 -15
  113. package/dist/model/properties/index.d.mts +1 -1
  114. package/dist/model/properties/log.d.mts +1 -1
  115. package/dist/model/properties/log.mjs +5 -5
  116. package/dist/model/properties/styleUtil.d.mts +3 -1
  117. package/dist/model/properties/styleUtil.mjs +20 -24
  118. package/dist/model/properties/table.mjs +4 -2
  119. package/dist/model/text/CaseMapping.d.mts +38 -0
  120. package/dist/model/text/CaseMapping.mjs +86 -0
  121. package/dist/model/text/Extractor.d.mts +349 -0
  122. package/dist/model/text/Extractor.mjs +2406 -0
  123. package/dist/model/text/LinkTargets.d.mts +45 -0
  124. package/dist/model/text/LinkTargets.mjs +170 -0
  125. package/dist/model/text/MarkdownExporter.d.mts +140 -0
  126. package/dist/model/text/MarkdownExporter.mjs +255 -0
  127. package/dist/model/text/PlainText.d.mts +29 -0
  128. package/dist/model/text/PlainText.mjs +542 -0
  129. package/dist/model/text/TextContext.d.mts +256 -0
  130. package/dist/model/text/TextContext.mjs +600 -0
  131. package/dist/model/text/TextOptions.d.mts +233 -0
  132. package/dist/model/text/TextOptions.mjs +419 -0
  133. package/dist/model/text/TextResult.d.mts +621 -0
  134. package/dist/model/text/TextResult.mjs +629 -0
  135. package/dist/model/text/Texts.d.mts +99 -0
  136. package/dist/model/text/Texts.mjs +187 -0
  137. package/dist/model/text/WmlToMarkdown.d.mts +120 -0
  138. package/dist/model/text/WmlToMarkdown.mjs +936 -0
  139. package/dist/model/text/caseMapping.generated.d.mts +7 -0
  140. package/dist/model/text/caseMapping.generated.mjs +214 -0
  141. package/dist/model/text/commonmark.d.mts +121 -0
  142. package/dist/model/text/commonmark.mjs +655 -0
  143. package/dist/model/text/index.d.mts +8 -0
  144. package/dist/model/text/index.mjs +9 -0
  145. package/dist/model/text/normalize.d.mts +8 -0
  146. package/dist/model/text/normalize.mjs +13 -0
  147. package/dist/model/text/outline.d.mts +4 -0
  148. package/dist/model/text/outline.mjs +71 -0
  149. package/dist/model/wordIntegers.d.mts +29 -0
  150. package/dist/model/wordIntegers.mjs +78 -0
  151. package/dist/office-js/document.mjs +15 -1
  152. package/dist/office-js/fragment.d.mts +7 -5
  153. package/dist/office-js/fragment.mjs +63 -14
  154. package/dist/office-js/proxy.d.mts +8 -0
  155. package/dist/office-js/proxy.mjs +29 -0
  156. package/dist/office-js/run.mjs +2 -0
  157. package/dist/office-js/supported.generated.mjs +16 -0
  158. package/dist/office-js/toApiScript.mjs +29 -12
  159. package/dist/opc/DirectoryPartStore.d.mts +6 -2
  160. package/dist/opc/DirectoryPartStore.mjs +11 -4
  161. package/dist/opc/FlatOpcPartStore.d.mts +4 -2
  162. package/dist/opc/FlatOpcPartStore.mjs +11 -8
  163. package/dist/opc/Load.d.mts +32 -0
  164. package/dist/opc/Load.mjs +115 -5
  165. package/dist/opc/PartStore.d.mts +34 -1
  166. package/dist/opc/PartStore.mjs +71 -8
  167. package/dist/opc/Save.d.mts +32 -0
  168. package/dist/opc/Save.mjs +110 -4
  169. package/dist/opc/ZipPartStore.d.mts +4 -2
  170. package/dist/opc/ZipPartStore.mjs +12 -7
  171. package/dist/opc/exceptions.d.mts +140 -0
  172. package/dist/opc/exceptions.mjs +108 -0
  173. package/dist/opc/index.d.mts +8 -5
  174. package/dist/opc/index.mjs +5 -3
  175. package/dist/opc/mce/preprocessor.d.mts +141 -5
  176. package/dist/opc/mce/preprocessor.mjs +119 -18
  177. package/dist/opc/mce/understood.d.mts +3 -11
  178. package/dist/opc/mce/understood.mjs +27 -23
  179. package/dist/opc/repair/breaks.d.mts +23 -0
  180. package/dist/opc/repair/breaks.mjs +288 -0
  181. package/dist/opc/repair/hosts.d.mts +12 -0
  182. package/dist/opc/repair/hosts.mjs +33 -0
  183. package/dist/opc/repair/mainRoot.d.mts +19 -0
  184. package/dist/opc/repair/mainRoot.mjs +168 -0
  185. package/dist/opc/repair/unknownElements.d.mts +8 -0
  186. package/dist/opc/repair/unknownElements.mjs +180 -0
  187. package/dist/opc/repair/wmlNames.generated.d.mts +2 -0
  188. package/dist/opc/repair/wmlNames.generated.mjs +80 -0
  189. package/dist/opc/skipped.d.mts +50 -0
  190. package/dist/opc/skipped.mjs +140 -0
  191. package/dist/packages/OpcPackage.d.mts +110 -4
  192. package/dist/packages/OpcPackage.mjs +123 -7
  193. package/dist/packages/WordprocessingMLPackage.d.mts +45 -8
  194. package/dist/packages/WordprocessingMLPackage.mjs +158 -21
  195. package/dist/packages/index.d.mts +1 -1
  196. package/dist/parts/DefaultXmlPart.mjs +2 -2
  197. package/dist/parts/Part.d.mts +14 -2
  198. package/dist/parts/RelationshipsPart.d.mts +15 -0
  199. package/dist/parts/RelationshipsPart.mjs +66 -1
  200. package/dist/parts/XmlPart.d.mts +63 -32
  201. package/dist/parts/XmlPart.mjs +240 -96
  202. package/dist/parts/wml/comments.mjs +30 -0
  203. package/dist/parts/wml/index.d.mts +12 -1
  204. package/dist/parts/wml/index.mjs +37 -1
  205. package/dist/xml/dom.d.mts +7 -0
  206. package/dist/xml/dom.mjs +18 -0
  207. package/package.json +2 -2
@@ -0,0 +1,45 @@
1
+ /**
2
+ * docx4j `LinkTargets`. A target is written as a link when it has no scheme (a relative path, a fragment, a UNC
3
+ * path), is a Windows drive path (`C:\...`, `C:/...`), or its scheme is `http`, `https`, `ftp`, `mailto`, `file`,
4
+ * `news` or `tel`, or one the caller adds. docx4j adds them through its JVM-wide property
5
+ * `docx4j.convert.out.linkSchemes`; this package has no properties file, so they are an argument here and
6
+ * `MarkdownExportOptions.linkSchemes` on the export, for a deployment whose documents carry `onenote:`, `ms-word:` or
7
+ * `notes:` links. Added, never removed: a default stays.
8
+ *
9
+ * The scheme is read as a browser reads one (WHATWG URL parsing): leading control characters and spaces are ignored,
10
+ * and tabs and line breaks are dropped anywhere, so ` \u0001java\tscri\npt:` is `javascript:`; the comparison ignores
11
+ * case. Anything up to the first `:` (where that comes before any `/`, `?` or `#`) is the scheme, so a target whose
12
+ * scheme a browser would reject as malformed (`java script:`) is refused too, rather than second-guessed.
13
+ */
14
+ export declare const LinkTargets: {
15
+ /** The default schemes, frozen. */
16
+ defaultSchemes(): readonly string[];
17
+ /**
18
+ * The schemes a link may use: the defaults plus `extra`, each trimmed and lower-cased, a trailing `:` dropped
19
+ * and an empty one ignored (docx4j reads its property's comma-separated list so).
20
+ */
21
+ schemes(extra?: readonly string[]): readonly string[];
22
+ /**
23
+ * Whether an output may write this target as a link: it has no scheme, is a drive path, or its scheme (read as
24
+ * a browser reads it) is a default one or in `extra`. An undefined or empty target is safe (there is nothing to
25
+ * write).
26
+ */
27
+ isSafe(target: string | undefined, extra?: readonly string[]): boolean;
28
+ /**
29
+ * The target with its character references decoded as CommonMark decodes a link destination: a decimal (`:`) or
30
+ * hex (`:`) reference to its character, U+FFFD for zero, out of range or a surrogate; a named reference that
31
+ * stands for one ASCII character (`:`, `/`, `	`, ...) to that character. Other named references, and an
32
+ * `&` that begins no reference, stay as written. Decoded once, as a renderer decodes once. docx4j
33
+ * `decodeCharacterReferences`.
34
+ */
35
+ decodeCharacterReferences(target: string | undefined): string | undefined;
36
+ /**
37
+ * The target's scheme, read as a browser reads it, lower-cased; undefined where it has none (a relative path, a
38
+ * fragment, a UNC path, or nothing at all).
39
+ */
40
+ scheme(target: string | undefined): string | undefined;
41
+ /** A target for a log line: at most 80 characters (UTF-16 units, as docx4j's), control characters shown as spaces. */
42
+ excerpt(target: string | undefined): string;
43
+ /** The message the export logs, once per document, when it refuses a target. */
44
+ refusedMessage(target: string | undefined): string;
45
+ };
@@ -0,0 +1,170 @@
1
+ // Which link targets the Markdown export writes as a link (CR-012 section 21, the port of docx4j CR-056 phase 1:
2
+ // `org.docx4j.convert.out.common.writer.LinkTargets`, docx4j 84ee9741c). A document's `w:hyperlink` relationship
3
+ // target or HYPERLINK field target was written as the link's destination as it is, so a crafted
4
+ // `javascript:alert(1)` target ran script in a page that rendered the Markdown as HTML (CWE-79, the defect
5
+ // apache/poi#1455 fixed in POI). The rule is docx4j's allowlist of schemes, read as written and with its character
6
+ // references decoded (docx4j's CR-056 section 14, CR-012 section 21.2 here); a refused target gives the link's text with
7
+ // no link.
8
+ /** docx4j's default schemes (POI's set). */
9
+ const DEFAULT_SCHEMES = Object.freeze(['http', 'https', 'ftp', 'mailto', 'file', 'news', 'tel']);
10
+ /**
11
+ * The HTML5 named character references that decode to an ASCII character. A scheme is ASCII, so these are the ones that
12
+ * can build one or end one (`:`, `/`, `#`, `?`, `	`, `
`); any other decodes to a
13
+ * character no scheme holds, or stays as written, and either way leaves a scheme malformed, which is refused.
14
+ */
15
+ const ASCII_REFERENCES = Object.freeze({
16
+ Tab: '\t', NewLine: '\n', excl: '!', quot: '"', QUOT: '"', num: '#', dollar: '$', percnt: '%', amp: '&', AMP: '&',
17
+ apos: "'", lpar: '(', rpar: ')', ast: '*', midast: '*', plus: '+', comma: ',', period: '.', sol: '/', colon: ':',
18
+ semi: ';', lt: '<', LT: '<', equals: '=', gt: '>', GT: '>', quest: '?', commat: '@', lsqb: '[', lbrack: '[',
19
+ bsol: '\\', rsqb: ']', rbrack: ']', Hat: '^', lowbar: '_', UnderBar: '_', grave: '`', DiacriticalGrave: '`',
20
+ lcub: '{', lbrace: '{', verbar: '|', vert: '|', VerticalLine: '|', rcub: '}', rbrace: '}',
21
+ });
22
+ /** docx4j `isSafeAsWritten`, `isSafe` for one reading of the target: no scheme, a drive path, or an allowed scheme. */
23
+ function safeAsWritten(target, extra) {
24
+ const scheme = LinkTargets.scheme(target);
25
+ if (scheme === undefined)
26
+ return true;
27
+ if (scheme.length === 1 && /\p{L}/u.test(scheme)) {
28
+ // a Windows drive path, C:\ or C:/
29
+ const next = normalise(target).charAt(2);
30
+ return next === '\\' || next === '/';
31
+ }
32
+ return LinkTargets.schemes(extra).includes(scheme);
33
+ }
34
+ /** Leading controls and spaces removed; tabs and line breaks removed anywhere. */
35
+ function normalise(target) {
36
+ let out = '';
37
+ for (const c of target) {
38
+ if (c === '\t' || c === '\n' || c === '\r')
39
+ continue;
40
+ if (c <= ' ' && out.length === 0)
41
+ continue;
42
+ out += c;
43
+ }
44
+ return out;
45
+ }
46
+ /**
47
+ * docx4j `LinkTargets`. A target is written as a link when it has no scheme (a relative path, a fragment, a UNC
48
+ * path), is a Windows drive path (`C:\...`, `C:/...`), or its scheme is `http`, `https`, `ftp`, `mailto`, `file`,
49
+ * `news` or `tel`, or one the caller adds. docx4j adds them through its JVM-wide property
50
+ * `docx4j.convert.out.linkSchemes`; this package has no properties file, so they are an argument here and
51
+ * `MarkdownExportOptions.linkSchemes` on the export, for a deployment whose documents carry `onenote:`, `ms-word:` or
52
+ * `notes:` links. Added, never removed: a default stays.
53
+ *
54
+ * The scheme is read as a browser reads one (WHATWG URL parsing): leading control characters and spaces are ignored,
55
+ * and tabs and line breaks are dropped anywhere, so ` \u0001java\tscri\npt:` is `javascript:`; the comparison ignores
56
+ * case. Anything up to the first `:` (where that comes before any `/`, `?` or `#`) is the scheme, so a target whose
57
+ * scheme a browser would reject as malformed (`java script:`) is refused too, rather than second-guessed.
58
+ */
59
+ export const LinkTargets = {
60
+ /** The default schemes, frozen. */
61
+ defaultSchemes() {
62
+ return DEFAULT_SCHEMES;
63
+ },
64
+ /**
65
+ * The schemes a link may use: the defaults plus `extra`, each trimmed and lower-cased, a trailing `:` dropped
66
+ * and an empty one ignored (docx4j reads its property's comma-separated list so).
67
+ */
68
+ schemes(extra = []) {
69
+ const set = new Set(DEFAULT_SCHEMES);
70
+ for (const raw of extra) {
71
+ let s = raw.trim().toLowerCase();
72
+ if (s.endsWith(':'))
73
+ s = s.slice(0, -1);
74
+ if (s !== '')
75
+ set.add(s);
76
+ }
77
+ return [...set];
78
+ },
79
+ /**
80
+ * Whether an output may write this target as a link: it has no scheme, is a drive path, or its scheme (read as
81
+ * a browser reads it) is a default one or in `extra`. An undefined or empty target is safe (there is nothing to
82
+ * write).
83
+ */
84
+ isSafe(target, extra = []) {
85
+ if (target === undefined || target === '')
86
+ return true;
87
+ if (!safeAsWritten(target, extra))
88
+ return false;
89
+ // as a CommonMark renderer reads a destination, its character references decoded (docx4j CR-056 section 14)
90
+ const decoded = LinkTargets.decodeCharacterReferences(target);
91
+ return decoded === target || safeAsWritten(decoded, extra);
92
+ },
93
+ /**
94
+ * The target with its character references decoded as CommonMark decodes a link destination: a decimal (`&#58;`) or
95
+ * hex (`&#x3A;`) reference to its character, U+FFFD for zero, out of range or a surrogate; a named reference that
96
+ * stands for one ASCII character (`&colon;`, `&sol;`, `&Tab;`, ...) to that character. Other named references, and an
97
+ * `&` that begins no reference, stay as written. Decoded once, as a renderer decodes once. docx4j
98
+ * `decodeCharacterReferences`.
99
+ */
100
+ decodeCharacterReferences(target) {
101
+ if (target === undefined || !target.includes('&'))
102
+ return target;
103
+ let out = '';
104
+ let i = 0;
105
+ while (i < target.length) {
106
+ const c = target.charAt(i);
107
+ if (c !== '&') {
108
+ out += c;
109
+ i++;
110
+ continue;
111
+ }
112
+ const semi = target.indexOf(';', i);
113
+ if (semi < 0 || semi - i > 40) {
114
+ out += c;
115
+ i++;
116
+ continue;
117
+ }
118
+ const ref = target.substring(i + 1, semi);
119
+ let decoded;
120
+ if (ref.length > 1 && ref.charAt(0) === '#') {
121
+ const hex = ref.charAt(1) === 'x' || ref.charAt(1) === 'X';
122
+ const digits = ref.substring(hex ? 2 : 1);
123
+ if (digits !== '' && digits.length <= (hex ? 6 : 7) && (hex ? /^[0-9A-Fa-f]+$/ : /^[0-9]+$/).test(digits)) {
124
+ const cp = parseInt(digits, hex ? 16 : 10);
125
+ decoded = cp === 0 || cp > 0x10ffff || (cp >= 0xd800 && cp <= 0xdfff) ? '\ufffd' : String.fromCodePoint(cp);
126
+ }
127
+ }
128
+ else {
129
+ decoded = Object.prototype.hasOwnProperty.call(ASCII_REFERENCES, ref) ? ASCII_REFERENCES[ref] : undefined;
130
+ }
131
+ if (decoded === undefined) {
132
+ out += c;
133
+ i++;
134
+ continue;
135
+ }
136
+ out += decoded;
137
+ i = semi + 1;
138
+ }
139
+ return out;
140
+ },
141
+ /**
142
+ * The target's scheme, read as a browser reads it, lower-cased; undefined where it has none (a relative path, a
143
+ * fragment, a UNC path, or nothing at all).
144
+ */
145
+ scheme(target) {
146
+ if (target === undefined)
147
+ return undefined;
148
+ const s = normalise(target);
149
+ for (let i = 0; i < s.length; i++) {
150
+ const c = s.charAt(i);
151
+ if (c === ':')
152
+ return i === 0 ? undefined : s.slice(0, i).toLowerCase();
153
+ if (c === '/' || c === '?' || c === '#')
154
+ return undefined;
155
+ }
156
+ return undefined;
157
+ },
158
+ /** A target for a log line: at most 80 characters (UTF-16 units, as docx4j's), control characters shown as spaces. */
159
+ excerpt(target) {
160
+ if (target === undefined)
161
+ return 'undefined';
162
+ const s = target.length > 80 ? target.slice(0, 80) + '...' : target;
163
+ return s.replace(/[\u0000-\u001f]/g, ' ');
164
+ },
165
+ /** The message the export logs, once per document, when it refuses a target. */
166
+ refusedMessage(target) {
167
+ return 'Link target refused (scheme not in MarkdownExportOptions.linkSchemes): the text is written without a link: '
168
+ + LinkTargets.excerpt(target);
169
+ },
170
+ };
@@ -0,0 +1,140 @@
1
+ import type { Part } from '../../parts/Part.mjs';
2
+ import { TextOptions, type TextOptionsInit, type TextModelView } from './TextOptions.mjs';
3
+ import { TextResult, type TextBlock, type TextRun } from './TextResult.mjs';
4
+ import type { TextPackage } from './TextContext.mjs';
5
+ /** A picture's image, for a `MarkdownExportOptions.imageDestination`. */
6
+ export interface MarkdownImage {
7
+ /** The picture's run in the block model. */
8
+ readonly run: TextRun;
9
+ /** The image part. */
10
+ readonly part: Part;
11
+ readonly bytes: Uint8Array;
12
+ readonly contentType: string;
13
+ /** The picture's number among the export's images with an image part, from 1. */
14
+ readonly index: number;
15
+ /** docx4j's file name for it, `image1.png`: `image`, the index, and the extension of its content type. */
16
+ readonly fileName: string;
17
+ }
18
+ /** Where a picture's Markdown image points: a data URI by default, or what a host makes of the image. */
19
+ export type MarkdownImageDestination = (image: MarkdownImage) => string | Promise<string>;
20
+ /** `MarkdownExportOptions.of`'s argument. */
21
+ export interface MarkdownExportOptionsInit {
22
+ /** The text model's options the export reads a package with; the default is the text model's. */
23
+ textOptions?: TextOptions | TextOptionsInit;
24
+ /** The view, which sets `textOptions.view`. */
25
+ view?: TextModelView;
26
+ /** Where each picture points; a data URI where unset. */
27
+ imageDestination?: MarkdownImageDestination;
28
+ /** Schemes a link may use beyond `LinkTargets`' defaults. */
29
+ linkSchemes?: readonly string[];
30
+ }
31
+ /**
32
+ * Options for `MarkdownExporter`. What text is written is the text model's, under its `TextOptions`
33
+ * (`textOptions`): the view, the stories, hidden text, field codes, metadata as YAML front matter, under the
34
+ * names of the WD's section 10. The options here are how it is written. docx4j `MarkdownExportOptions`.
35
+ *
36
+ * docx4j's `imageDirPath` and `imageTargetUri`, which write each image to a directory, are `imageDestination`
37
+ * here: nothing outside `./node` writes a file (CR-012 section 16.4). A host that wants the files writes
38
+ * them in the function, which is given docx4j's file name, and returns the link.
39
+ */
40
+ export declare class MarkdownExportOptions {
41
+ /**
42
+ * The text model's options a package is read with (`MarkdownExporter.export(pkg)`): the default is the
43
+ * text model's, the `accepted` view, the main story with its text boxes and notes, hidden text left out.
44
+ * A result is written under the options it was read with.
45
+ */
46
+ textOptions: TextOptions;
47
+ /** Where each picture points; a data URI (`data:image/png;base64,...`) where unset. */
48
+ imageDestination: MarkdownImageDestination | undefined;
49
+ /**
50
+ * Schemes a link may use beyond `LinkTargets`' defaults (`http`, `https`, `ftp`, `mailto`, `file`, `news`, `tel`),
51
+ * for documents that carry `onenote:` or `ms-word:` links. A link whose target has any other scheme is written as
52
+ * its text, with no link (docx4j CR-056, CR-012 section 21). docx4j's JVM-wide property
53
+ * `docx4j.convert.out.linkSchemes`; added to the defaults, never removing one.
54
+ */
55
+ linkSchemes: readonly string[];
56
+ static of(init?: MarkdownExportOptionsInit | MarkdownExportOptions): MarkdownExportOptions;
57
+ /** The revision view: `accepted` (the default), `original` or `markup`. */
58
+ get view(): TextModelView;
59
+ set view(view: TextModelView);
60
+ }
61
+ /** A block's Markdown (`MarkdownExporter.blocks`). */
62
+ export interface MarkdownBlock {
63
+ readonly block: TextBlock;
64
+ /**
65
+ * Its Markdown: the lines from the start of the line its first character is on to the next block's, the
66
+ * blank line after it included. Empty for a block that writes nothing: an empty paragraph, or a code
67
+ * paragraph merged into the fence before it.
68
+ */
69
+ readonly markdown: string;
70
+ }
71
+ /** A result's Markdown block by block (`MarkdownExporter.blocks`). */
72
+ export interface MarkdownBlocks {
73
+ /** The YAML front matter, under `metadata: true` (REQ-704); empty otherwise. */
74
+ readonly frontMatter: string;
75
+ /** Each block of the result, in its order, with its Markdown. */
76
+ readonly blocks: readonly MarkdownBlock[];
77
+ /** The whole: the front matter and the blocks' Markdown joined, what `export` gives. */
78
+ readonly markdown: string;
79
+ }
80
+ /**
81
+ * Exports WordprocessingML to Markdown, CommonMark with GFM's tables and strikethrough, footnotes and math
82
+ * (WD section 7.2). The text is the text model's (`Texts.of`, WD REQ-202): its block model is written as a
83
+ * Markdown tree, which a port of commonmark-java's Markdown renderer serializes, so the escaping and the list
84
+ * markers are commonmark-java's, and the Markdown docx4j's byte for byte.
85
+ *
86
+ * - a heading from its outline level, not its style's name; a list from its numbering, kept apart from an
87
+ * adjacent list and going on at Word's count after a paragraph that interrupts it (REQ-703);
88
+ * - bold, italic, struck-through and code text where a run adds them to its paragraph's style; a code-styled
89
+ * paragraph, or one in a mono paragraph style, a fenced code block;
90
+ * - links from a `w:hyperlink` or a HYPERLINK field, a target whose scheme isn't allowed (`javascript:`) written
91
+ * as its text with no link (`LinkTargets`, `linkSchemes`); pictures with the describer's text, their image a
92
+ * data URI unless `imageDestination` says otherwise;
93
+ * - notes `[^1]` and `[^e1]`, their definitions after the body; GFM tables, the header the `w:tblHeader` rows
94
+ * or the first row, a cell's paragraphs `<br>` apart; block quotes from the Quote styles;
95
+ * - in the `markup` view, CriticMarkup: `{++inserted++}`, `{--deleted--}` and `{>>comment<<}`;
96
+ * - under `metadata: true`, the document properties as YAML front matter (REQ-704).
97
+ *
98
+ * Async because a picture's bytes are read from its part. The package is not changed (REQ-204).
99
+ * docx4j `MarkdownExporter`.
100
+ *
101
+ * ```ts
102
+ * const md = await new MarkdownExporter().export(pkg);
103
+ * const result = await Texts.of(pkg, { view: 'markup' });
104
+ * PlainText.of(result); // the plain text and the Markdown of one reading
105
+ * await MarkdownExporter.export(result, pkg);
106
+ * ```
107
+ */
108
+ export declare class MarkdownExporter {
109
+ readonly options: MarkdownExportOptions;
110
+ constructor(options?: MarkdownExportOptions | MarkdownExportOptionsInit);
111
+ /**
112
+ * The Markdown of a package (the text model's reading of it under `options.textOptions`), or of a result
113
+ * the text model has made, under the options it was read with: its view, and its metadata as front matter
114
+ * where it was read with `metadata: true`. A result's block quotes are nested by their indent beyond the
115
+ * quote style's own where the package it was read from is given, by their indent alone where it isn't.
116
+ */
117
+ export(source: TextPackage | TextResult, pkg?: TextPackage): Promise<string>;
118
+ /**
119
+ * The Markdown of each block (CR-012 section 4.4, the editor's ask), the front matter apart: a host that
120
+ * writes something before each block, or stops after some, has the pieces `export` joins.
121
+ */
122
+ blocks(source: TextPackage | TextResult, pkg?: TextPackage): Promise<MarkdownBlocks>;
123
+ /** `new MarkdownExporter().export(...)`. */
124
+ static export(source: TextPackage | TextResult, pkg?: TextPackage): Promise<string>;
125
+ /** `new MarkdownExporter().blocks(...)`. */
126
+ static blocks(source: TextPackage | TextResult, pkg?: TextPackage): Promise<MarkdownBlocks>;
127
+ /**
128
+ * The document properties as a YAML front-matter block (WD REQ-704, REQ-515): a mapping for each kind of
129
+ * property the package has, `core`, `app` and `custom`, in that order, each property by its element's
130
+ * local name (core, application) or its name (custom), its value a double-quoted string. Empty where the
131
+ * result's metadata has none.
132
+ */
133
+ static frontMatter(result: TextResult): string;
134
+ /**
135
+ * A picture's destination: its image part's bytes (an SVG picture's SVG where it has no PNG copy, docx4j
136
+ * #699) as a data URI or as `imageDestination` says; empty where its image can't be had, so that its alt
137
+ * text is kept.
138
+ */
139
+ private destination;
140
+ }
@@ -0,0 +1,255 @@
1
+ import { BinaryPart } from '../../parts/BinaryPart.mjs';
2
+ import { DefaultXmlPart } from '../../parts/DefaultXmlPart.mjs';
3
+ import { TextOptions } from './TextOptions.mjs';
4
+ import { TextResult } from './TextResult.mjs';
5
+ import { Texts } from './Texts.mjs';
6
+ import { WmlToMarkdown } from './WmlToMarkdown.mjs';
7
+ import { renderMarkdown } from './commonmark.mjs';
8
+ import { base64Encode } from '../../xml/dom.mjs';
9
+ const SVG = 'image/svg+xml';
10
+ /**
11
+ * Options for `MarkdownExporter`. What text is written is the text model's, under its `TextOptions`
12
+ * (`textOptions`): the view, the stories, hidden text, field codes, metadata as YAML front matter, under the
13
+ * names of the WD's section 10. The options here are how it is written. docx4j `MarkdownExportOptions`.
14
+ *
15
+ * docx4j's `imageDirPath` and `imageTargetUri`, which write each image to a directory, are `imageDestination`
16
+ * here: nothing outside `./node` writes a file (CR-012 section 16.4). A host that wants the files writes
17
+ * them in the function, which is given docx4j's file name, and returns the link.
18
+ */
19
+ export class MarkdownExportOptions {
20
+ constructor() {
21
+ /**
22
+ * The text model's options a package is read with (`MarkdownExporter.export(pkg)`): the default is the
23
+ * text model's, the `accepted` view, the main story with its text boxes and notes, hidden text left out.
24
+ * A result is written under the options it was read with.
25
+ */
26
+ this.textOptions = new TextOptions();
27
+ /**
28
+ * Schemes a link may use beyond `LinkTargets`' defaults (`http`, `https`, `ftp`, `mailto`, `file`, `news`, `tel`),
29
+ * for documents that carry `onenote:` or `ms-word:` links. A link whose target has any other scheme is written as
30
+ * its text, with no link (docx4j CR-056, CR-012 section 21). docx4j's JVM-wide property
31
+ * `docx4j.convert.out.linkSchemes`; added to the defaults, never removing one.
32
+ */
33
+ this.linkSchemes = [];
34
+ }
35
+ static of(init) {
36
+ if (init instanceof MarkdownExportOptions)
37
+ return init;
38
+ const o = new MarkdownExportOptions();
39
+ if ((init === null || init === void 0 ? void 0 : init.textOptions) !== undefined)
40
+ o.textOptions = TextOptions.of(init.textOptions);
41
+ if ((init === null || init === void 0 ? void 0 : init.view) !== undefined)
42
+ o.view = init.view;
43
+ o.imageDestination = init === null || init === void 0 ? void 0 : init.imageDestination;
44
+ if ((init === null || init === void 0 ? void 0 : init.linkSchemes) !== undefined)
45
+ o.linkSchemes = [...init.linkSchemes];
46
+ return o;
47
+ }
48
+ /** The revision view: `accepted` (the default), `original` or `markup`. */
49
+ get view() {
50
+ return this.textOptions.view;
51
+ }
52
+ set view(view) {
53
+ this.textOptions.view = view;
54
+ }
55
+ }
56
+ /**
57
+ * Exports WordprocessingML to Markdown, CommonMark with GFM's tables and strikethrough, footnotes and math
58
+ * (WD section 7.2). The text is the text model's (`Texts.of`, WD REQ-202): its block model is written as a
59
+ * Markdown tree, which a port of commonmark-java's Markdown renderer serializes, so the escaping and the list
60
+ * markers are commonmark-java's, and the Markdown docx4j's byte for byte.
61
+ *
62
+ * - a heading from its outline level, not its style's name; a list from its numbering, kept apart from an
63
+ * adjacent list and going on at Word's count after a paragraph that interrupts it (REQ-703);
64
+ * - bold, italic, struck-through and code text where a run adds them to its paragraph's style; a code-styled
65
+ * paragraph, or one in a mono paragraph style, a fenced code block;
66
+ * - links from a `w:hyperlink` or a HYPERLINK field, a target whose scheme isn't allowed (`javascript:`) written
67
+ * as its text with no link (`LinkTargets`, `linkSchemes`); pictures with the describer's text, their image a
68
+ * data URI unless `imageDestination` says otherwise;
69
+ * - notes `[^1]` and `[^e1]`, their definitions after the body; GFM tables, the header the `w:tblHeader` rows
70
+ * or the first row, a cell's paragraphs `<br>` apart; block quotes from the Quote styles;
71
+ * - in the `markup` view, CriticMarkup: `{++inserted++}`, `{--deleted--}` and `{>>comment<<}`;
72
+ * - under `metadata: true`, the document properties as YAML front matter (REQ-704).
73
+ *
74
+ * Async because a picture's bytes are read from its part. The package is not changed (REQ-204).
75
+ * docx4j `MarkdownExporter`.
76
+ *
77
+ * ```ts
78
+ * const md = await new MarkdownExporter().export(pkg);
79
+ * const result = await Texts.of(pkg, { view: 'markup' });
80
+ * PlainText.of(result); // the plain text and the Markdown of one reading
81
+ * await MarkdownExporter.export(result, pkg);
82
+ * ```
83
+ */
84
+ export class MarkdownExporter {
85
+ constructor(options) {
86
+ this.options = MarkdownExportOptions.of(options);
87
+ }
88
+ /**
89
+ * The Markdown of a package (the text model's reading of it under `options.textOptions`), or of a result
90
+ * the text model has made, under the options it was read with: its view, and its metadata as front matter
91
+ * where it was read with `metadata: true`. A result's block quotes are nested by their indent beyond the
92
+ * quote style's own where the package it was read from is given, by their indent alone where it isn't.
93
+ */
94
+ async export(source, pkg) {
95
+ return (await this.blocks(source, pkg)).markdown;
96
+ }
97
+ /**
98
+ * The Markdown of each block (CR-012 section 4.4, the editor's ask), the front matter apart: a host that
99
+ * writes something before each block, or stops after some, has the pieces `export` joins.
100
+ */
101
+ async blocks(source, pkg) {
102
+ let result;
103
+ let styles;
104
+ if (source instanceof TextResult) {
105
+ result = source;
106
+ styles = pkg;
107
+ }
108
+ else {
109
+ result = await Texts.of(source, this.options.textOptions);
110
+ styles = source;
111
+ }
112
+ const writer = new WmlToMarkdown(result, await resolverOf(styles), this.options.linkSchemes);
113
+ const document = writer.convert();
114
+ let index = 0;
115
+ for (const { node, run } of writer.images) {
116
+ node.destination = await this.destination(run, () => ++index);
117
+ }
118
+ const starts = new Map();
119
+ const body = renderMarkdown(document, starts);
120
+ const frontMatter = result.options.metadata ? MarkdownExporter.frontMatter(result) : '';
121
+ return { frontMatter, blocks: sliced(result.blocks, starts, body), markdown: frontMatter + body };
122
+ }
123
+ /** `new MarkdownExporter().export(...)`. */
124
+ static async export(source, pkg) {
125
+ return new MarkdownExporter().export(source, pkg);
126
+ }
127
+ /** `new MarkdownExporter().blocks(...)`. */
128
+ static async blocks(source, pkg) {
129
+ return new MarkdownExporter().blocks(source, pkg);
130
+ }
131
+ /**
132
+ * The document properties as a YAML front-matter block (WD REQ-704, REQ-515): a mapping for each kind of
133
+ * property the package has, `core`, `app` and `custom`, in that order, each property by its element's
134
+ * local name (core, application) or its name (custom), its value a double-quoted string. Empty where the
135
+ * result's metadata has none.
136
+ */
137
+ static frontMatter(result) {
138
+ let sb = '';
139
+ for (const kind of [TextResult.CORE, TextResult.APP, TextResult.CUSTOM]) {
140
+ const properties = result.metadata[kind];
141
+ if (properties === null || typeof properties !== 'object')
142
+ continue;
143
+ const entries = properties instanceof Map ? [...properties.entries()] : Object.entries(properties);
144
+ if (entries.length === 0)
145
+ continue;
146
+ sb += `${kind}:\n`;
147
+ for (const [k, v] of entries)
148
+ sb += ` ${yamlKey(String(k))}: ${yamlString(String(v))}\n`;
149
+ }
150
+ return sb === '' ? '' : `---\n${sb}---\n\n`;
151
+ }
152
+ /**
153
+ * A picture's destination: its image part's bytes (an SVG picture's SVG where it has no PNG copy, docx4j
154
+ * #699) as a data URI or as `imageDestination` says; empty where its image can't be had, so that its alt
155
+ * text is kept.
156
+ */
157
+ async destination(run, next) {
158
+ var _a;
159
+ const part = (_a = run.image) === null || _a === void 0 ? void 0 : _a.part;
160
+ let bytes;
161
+ try {
162
+ if (part instanceof BinaryPart || (part instanceof DefaultXmlPart && part.contentType === SVG))
163
+ bytes = await part.getBytes();
164
+ }
165
+ catch {
166
+ bytes = undefined; // its alt text, with no destination
167
+ }
168
+ if (part === undefined || bytes === undefined)
169
+ return '';
170
+ const contentType = part.contentType;
171
+ if (this.options.imageDestination === undefined)
172
+ return `data:${contentType};base64,${base64Encode(bytes)}`;
173
+ const index = next();
174
+ return this.options.imageDestination({ run, part, bytes, contentType, index, fileName: `image${index}.${extensionFor(contentType, part)}` });
175
+ }
176
+ }
177
+ /** The resolver a block quote's style indent is asked of: the package's, where it has a styles part. */
178
+ async function resolverOf(pkg) {
179
+ if (pkg === undefined)
180
+ return undefined;
181
+ try {
182
+ // asking a package with no styles part for a resolver would add one to it
183
+ if (!pkg.getMainDocumentPart().styleDefinitionsPart)
184
+ return undefined;
185
+ return await pkg.getPropertyResolver();
186
+ }
187
+ catch {
188
+ return undefined;
189
+ }
190
+ }
191
+ /** Each block's Markdown: from its start to the next start, the last to the end; a start is one block's. */
192
+ function sliced(blocks, starts, body) {
193
+ const ordered = [...new Set(starts.values())].sort((a, b) => a - b);
194
+ const end = new Map();
195
+ ordered.forEach((s, i) => { var _a; return end.set(s, (_a = ordered[i + 1]) !== null && _a !== void 0 ? _a : body.length); });
196
+ const taken = new Set();
197
+ return blocks.map((block) => {
198
+ const start = starts.get(block);
199
+ if (start === undefined || taken.has(start))
200
+ return { block, markdown: '' };
201
+ taken.add(start);
202
+ return { block, markdown: body.slice(start, end.get(start)) };
203
+ });
204
+ }
205
+ function yamlKey(key) {
206
+ return /^[A-Za-z_][A-Za-z0-9_.-]*$/.test(key) ? key : yamlString(key);
207
+ }
208
+ /** A YAML double-quoted scalar: `\`, `"` and the control characters escaped. */
209
+ function yamlString(value) {
210
+ let sb = '"';
211
+ for (let i = 0; i < value.length; i++) {
212
+ const c = value.charAt(i);
213
+ const code = value.charCodeAt(i);
214
+ switch (c) {
215
+ case '"':
216
+ sb += '\\"';
217
+ break;
218
+ case '\\':
219
+ sb += '\\\\';
220
+ break;
221
+ case '\n':
222
+ sb += '\\n';
223
+ break;
224
+ case '\r':
225
+ sb += '\\r';
226
+ break;
227
+ case '\t':
228
+ sb += '\\t';
229
+ break;
230
+ default:
231
+ if (code < 0x20 || code === 0x7f || code === 0x85 || code === 0x2028 || code === 0x2029)
232
+ sb += `\\u${code.toString(16).padStart(4, '0')}`;
233
+ else
234
+ sb += c;
235
+ }
236
+ }
237
+ return `${sb}"`;
238
+ }
239
+ function extensionFor(contentType, part) {
240
+ switch (contentType) {
241
+ case 'image/png': return 'png';
242
+ case 'image/jpeg': return 'jpg';
243
+ case 'image/gif': return 'gif';
244
+ case 'image/bmp': return 'bmp';
245
+ case 'image/tiff': return 'tif';
246
+ case 'image/svg+xml': return 'svg';
247
+ case 'image/x-emf': return 'emf';
248
+ case 'image/x-wmf': return 'wmf';
249
+ default: {
250
+ const name = part.partName.name;
251
+ const dot = name.lastIndexOf('.');
252
+ return dot >= 0 ? name.substring(dot + 1) : 'bin';
253
+ }
254
+ }
255
+ }
@@ -0,0 +1,29 @@
1
+ import type { TextResult, TextBlock } from './TextResult.mjs';
2
+ /** The spaces for each 720-twip tab stop of indent under `layout: indent` (REQ-709). */
3
+ export declare const INDENT_SPACES = 4;
4
+ /** The note line before a table in the listed format (REQ-605, REQ-707). */
5
+ export declare const LISTED_FORMAT_NOTE = "[table: listed format]";
6
+ /**
7
+ * Plain text from the block model (WD section 7.1): each paragraph one line, a break one line more
8
+ * (REQ-603); the text exactly as the document holds it (REQ-602), U+000A between lines and after the last.
9
+ *
10
+ * Tables (REQ-605): a simple table a row a line, its cells a tab apart; any other in the listed format,
11
+ * after the note line `[table: listed format]`, a row a line as `Header: value; Header: value`. `tables:
12
+ * tsv` writes every table in the simple form, `tables: grid` as a pandoc grid table, its spans drawn.
13
+ *
14
+ * What the extractor adds follows the WD's bracket convention (REQ-707): `[n]` at a note's reference and
15
+ * at the start of the note; `[image: ...]` (or `[image, generated: ...]`) under `alt_text: true`; `[page
16
+ * n]` under `page_markers: true`; and under `metadata: true`, before the body, one line per kind of
17
+ * property that has any (REQ-515). In the markup view, insertions are `{++text++}`, deletions `{--text--}`
18
+ * and comments `{>>text<<}`, at their references with their replies after them (REQ-702, REQ-504); under
19
+ * `markup_detail` the marker's opening is followed by `author:` or `author, date:`.
20
+ *
21
+ * Under `layout: indent` (REQ-709) a paragraph outside a table begins with four spaces for each tab stop
22
+ * (720 twips) of its first line's indent, rounded to the nearest stop. docx4j `PlainText`.
23
+ */
24
+ export declare const PlainText: {
25
+ /** The plain text of a result. */
26
+ of(result: TextResult): string;
27
+ /** Whether a table is written in REQ-605's simple form under `tables: auto`. */
28
+ isSimple(table: TextBlock): boolean;
29
+ };