@websolutespa/bom-next 3.0.1 → 3.0.2

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 (306) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/dist/_virtual/_rolldown/runtime.js +24 -0
  3. package/dist/client/client.d.ts +9 -0
  4. package/dist/client/client.d.ts.map +1 -0
  5. package/dist/client/client.js +18 -0
  6. package/dist/client/client.js.map +1 -0
  7. package/dist/client/extra.d.ts +17 -0
  8. package/dist/client/extra.d.ts.map +1 -0
  9. package/dist/client/extra.js +13 -0
  10. package/dist/client/extra.js.map +1 -0
  11. package/dist/client/label.d.ts +15 -0
  12. package/dist/client/label.d.ts.map +1 -0
  13. package/dist/client/label.js +20 -0
  14. package/dist/client/label.js.map +1 -0
  15. package/dist/client/layout.d.ts +18 -0
  16. package/dist/client/layout.d.ts.map +1 -0
  17. package/dist/client/layout.js +13 -0
  18. package/dist/client/layout.js.map +1 -0
  19. package/dist/client/local.collection.d.ts +32 -0
  20. package/dist/client/local.collection.d.ts.map +1 -0
  21. package/dist/client/local.collection.js +49 -0
  22. package/dist/client/local.collection.js.map +1 -0
  23. package/dist/client/metadata.d.ts +43 -0
  24. package/dist/client/metadata.d.ts.map +1 -0
  25. package/dist/client/metadata.js +146 -0
  26. package/dist/client/metadata.js.map +1 -0
  27. package/dist/client/page.d.ts +404 -0
  28. package/dist/client/page.d.ts.map +1 -0
  29. package/dist/client/page.js +13 -0
  30. package/dist/client/page.js.map +1 -0
  31. package/dist/client/useApi.d.ts +21 -0
  32. package/dist/client/useApi.d.ts.map +1 -0
  33. package/dist/client/useApi.js +65 -0
  34. package/dist/client/useApi.js.map +1 -0
  35. package/dist/client/useCollectionApi.d.ts +21 -0
  36. package/dist/client/useCollectionApi.d.ts.map +1 -0
  37. package/dist/client/useCollectionApi.js +65 -0
  38. package/dist/client/useCollectionApi.js.map +1 -0
  39. package/dist/client/useExtra.d.ts +9 -0
  40. package/dist/client/useExtra.d.ts.map +1 -0
  41. package/dist/client/useExtra.js +13 -0
  42. package/dist/client/useExtra.js.map +1 -0
  43. package/dist/client/useHttp.d.ts +15 -0
  44. package/dist/client/useHttp.d.ts.map +1 -0
  45. package/dist/client/useHttp.js +70 -0
  46. package/dist/client/useHttp.js.map +1 -0
  47. package/dist/client/useLabel.d.ts +9 -0
  48. package/dist/client/useLabel.d.ts.map +1 -0
  49. package/dist/client/useLabel.js +13 -0
  50. package/dist/client/useLabel.js.map +1 -0
  51. package/dist/client/useLayout.d.ts +9 -0
  52. package/dist/client/useLayout.d.ts.map +1 -0
  53. package/dist/client/useLayout.js +13 -0
  54. package/dist/client/useLayout.js.map +1 -0
  55. package/dist/client/useLink.d.ts +7 -0
  56. package/dist/client/useLink.d.ts.map +1 -0
  57. package/dist/client/useLink.js +15 -0
  58. package/dist/client/useLink.js.map +1 -0
  59. package/dist/client/useMetaData.d.ts +9 -0
  60. package/dist/client/useMetaData.d.ts.map +1 -0
  61. package/dist/client/useMetaData.js +13 -0
  62. package/dist/client/useMetaData.js.map +1 -0
  63. package/dist/client/usePage.d.ts +394 -0
  64. package/dist/client/usePage.d.ts.map +1 -0
  65. package/dist/client/usePage.js +13 -0
  66. package/dist/client/usePage.js.map +1 -0
  67. package/dist/client/useUser.d.ts +9 -0
  68. package/dist/client/useUser.d.ts.map +1 -0
  69. package/dist/client/useUser.js +13 -0
  70. package/dist/client/useUser.js.map +1 -0
  71. package/dist/client/user.d.ts +20 -0
  72. package/dist/client/user.d.ts.map +1 -0
  73. package/dist/client/user.js +33 -0
  74. package/dist/client/user.js.map +1 -0
  75. package/dist/exports/client.d.ts +20 -979
  76. package/dist/exports/client.js +19 -5734
  77. package/dist/exports/instrumentation.d.ts +2 -13
  78. package/dist/exports/instrumentation.js +1 -24
  79. package/dist/exports/proxy.d.ts +5 -71
  80. package/dist/exports/proxy.js +4 -253
  81. package/dist/exports/server.d.ts +19 -402
  82. package/dist/exports/server.js +18 -1973
  83. package/dist/index.d.ts +18 -499
  84. package/dist/index.js +10 -200
  85. package/dist/instrumentation/client.d.ts +8 -0
  86. package/dist/instrumentation/client.d.ts.map +1 -0
  87. package/dist/instrumentation/client.js +15 -0
  88. package/dist/instrumentation/client.js.map +1 -0
  89. package/dist/instrumentation/sentry/capture.requestError.js +10 -0
  90. package/dist/instrumentation/sentry/capture.requestError.js.map +1 -0
  91. package/dist/instrumentation/sentry/capture.routerTransitionStart.js +7 -0
  92. package/dist/instrumentation/sentry/capture.routerTransitionStart.js.map +1 -0
  93. package/dist/instrumentation/server.d.ts +13 -0
  94. package/dist/instrumentation/server.d.ts.map +1 -0
  95. package/dist/instrumentation/server.js +19 -0
  96. package/dist/instrumentation/server.js.map +1 -0
  97. package/dist/{types2.d.ts → instrumentation/types.d.ts} +2 -2
  98. package/dist/instrumentation/types.d.ts.map +1 -0
  99. package/dist/lib/breadcrumb.d.ts +15 -0
  100. package/dist/lib/breadcrumb.d.ts.map +1 -0
  101. package/dist/lib/breadcrumb.js +20 -0
  102. package/dist/lib/breadcrumb.js.map +1 -0
  103. package/dist/lib/const.d.ts +9 -0
  104. package/dist/lib/const.d.ts.map +1 -0
  105. package/dist/lib/const.js +9 -0
  106. package/dist/lib/const.js.map +1 -0
  107. package/dist/lib/http.d.ts +36 -0
  108. package/dist/lib/http.d.ts.map +1 -0
  109. package/dist/{http.js → lib/http.js} +1 -1
  110. package/dist/lib/http.js.map +1 -0
  111. package/dist/lib/label.d.ts +16 -0
  112. package/dist/lib/label.d.ts.map +1 -0
  113. package/dist/lib/label.js +33 -0
  114. package/dist/lib/label.js.map +1 -0
  115. package/dist/lib/layout.defaults.d.ts +9 -0
  116. package/dist/lib/layout.defaults.d.ts.map +1 -0
  117. package/dist/lib/layout.defaults.js +161 -0
  118. package/dist/lib/layout.defaults.js.map +1 -0
  119. package/dist/lib/link.d.ts +9 -0
  120. package/dist/lib/link.d.ts.map +1 -0
  121. package/dist/lib/link.js +16 -0
  122. package/dist/lib/link.js.map +1 -0
  123. package/dist/lib/meta-data.d.ts +56 -0
  124. package/dist/lib/meta-data.d.ts.map +1 -0
  125. package/dist/lib/open-graph.d.ts +143 -0
  126. package/dist/lib/open-graph.d.ts.map +1 -0
  127. package/dist/lib/pagination.d.ts +27 -0
  128. package/dist/lib/pagination.d.ts.map +1 -0
  129. package/dist/lib/pagination.js +39 -0
  130. package/dist/lib/pagination.js.map +1 -0
  131. package/dist/lib/route.d.ts +17 -0
  132. package/dist/lib/route.d.ts.map +1 -0
  133. package/dist/{route.js → lib/route.js} +1 -1
  134. package/dist/lib/route.js.map +1 -0
  135. package/dist/lib/store.d.ts +27 -0
  136. package/dist/lib/store.d.ts.map +1 -0
  137. package/dist/{store.js → lib/store.js} +1 -24
  138. package/dist/lib/store.js.map +1 -0
  139. package/dist/lib/structured-data.d.ts +9 -0
  140. package/dist/lib/structured-data.d.ts.map +1 -0
  141. package/dist/lib/twitter-card.d.ts +43 -0
  142. package/dist/lib/twitter-card.d.ts.map +1 -0
  143. package/dist/lib/utils.d.ts +13 -0
  144. package/dist/lib/utils.d.ts.map +1 -0
  145. package/dist/lib/utils.js +35 -0
  146. package/dist/lib/utils.js.map +1 -0
  147. package/dist/mock.d.ts +127 -0
  148. package/dist/mock.d.ts.map +1 -0
  149. package/dist/node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.js +75 -0
  150. package/dist/node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.js.map +1 -0
  151. package/dist/node_modules/deepmerge/dist/cjs.js +86 -0
  152. package/dist/node_modules/deepmerge/dist/cjs.js.map +1 -0
  153. package/dist/node_modules/dom-serializer/lib/esm/foreignNames.js +105 -0
  154. package/dist/node_modules/dom-serializer/lib/esm/foreignNames.js.map +1 -0
  155. package/dist/node_modules/dom-serializer/lib/esm/index.js +146 -0
  156. package/dist/node_modules/dom-serializer/lib/esm/index.js.map +1 -0
  157. package/dist/node_modules/domelementtype/lib/esm/index.js +53 -0
  158. package/dist/node_modules/domelementtype/lib/esm/index.js.map +1 -0
  159. package/dist/node_modules/domhandler/lib/esm/index.js +130 -0
  160. package/dist/node_modules/domhandler/lib/esm/index.js.map +1 -0
  161. package/dist/node_modules/domhandler/lib/esm/node.js +307 -0
  162. package/dist/node_modules/domhandler/lib/esm/node.js.map +1 -0
  163. package/dist/node_modules/entities/lib/esm/decode.js +363 -0
  164. package/dist/node_modules/entities/lib/esm/decode.js.map +1 -0
  165. package/dist/node_modules/entities/lib/esm/decode_codepoint.js +59 -0
  166. package/dist/node_modules/entities/lib/esm/decode_codepoint.js.map +1 -0
  167. package/dist/node_modules/entities/lib/esm/escape.js +85 -0
  168. package/dist/node_modules/entities/lib/esm/escape.js.map +1 -0
  169. package/dist/node_modules/entities/lib/esm/generated/decode-data-html.js +6 -0
  170. package/dist/node_modules/entities/lib/esm/generated/decode-data-html.js.map +1 -0
  171. package/dist/node_modules/entities/lib/esm/generated/decode-data-xml.js +6 -0
  172. package/dist/node_modules/entities/lib/esm/generated/decode-data-xml.js.map +1 -0
  173. package/dist/node_modules/html-to-text/lib/html-to-text.js +1816 -0
  174. package/dist/node_modules/html-to-text/lib/html-to-text.js.map +1 -0
  175. package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Parser.js +435 -0
  176. package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Parser.js.map +1 -0
  177. package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Tokenizer.js +736 -0
  178. package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/Tokenizer.js.map +1 -0
  179. package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/index.js +19 -0
  180. package/dist/node_modules/html-to-text/node_modules/htmlparser2/lib/esm/index.js.map +1 -0
  181. package/dist/node_modules/leac/lib/leac.js +101 -0
  182. package/dist/node_modules/leac/lib/leac.js.map +1 -0
  183. package/dist/node_modules/parseley/lib/parseley.js +310 -0
  184. package/dist/node_modules/parseley/lib/parseley.js.map +1 -0
  185. package/dist/node_modules/peberminta/lib/core.js +149 -0
  186. package/dist/node_modules/peberminta/lib/core.js.map +1 -0
  187. package/dist/node_modules/selderee/lib/selderee.js +319 -0
  188. package/dist/node_modules/selderee/lib/selderee.js.map +1 -0
  189. package/dist/proxy/protected-route.d.ts +9 -0
  190. package/dist/proxy/protected-route.d.ts.map +1 -0
  191. package/dist/proxy/protected-route.js +40 -0
  192. package/dist/proxy/protected-route.js.map +1 -0
  193. package/dist/proxy/proxy.d.ts +31 -0
  194. package/dist/proxy/proxy.d.ts.map +1 -0
  195. package/dist/proxy/proxy.js +49 -0
  196. package/dist/proxy/proxy.js.map +1 -0
  197. package/dist/proxy/route-auto-detection.d.ts +12 -0
  198. package/dist/proxy/route-auto-detection.d.ts.map +1 -0
  199. package/dist/proxy/route-auto-detection.js +82 -0
  200. package/dist/proxy/route-auto-detection.js.map +1 -0
  201. package/dist/proxy/route-proxy.d.ts +36 -0
  202. package/dist/proxy/route-proxy.d.ts.map +1 -0
  203. package/dist/proxy/route-proxy.js +103 -0
  204. package/dist/proxy/route-proxy.js.map +1 -0
  205. package/dist/server/context.d.ts +30 -0
  206. package/dist/server/context.d.ts.map +1 -0
  207. package/dist/server/context.js +106 -0
  208. package/dist/server/context.js.map +1 -0
  209. package/dist/server/handlers/auth.handler.d.ts +10 -0
  210. package/dist/server/handlers/auth.handler.d.ts.map +1 -0
  211. package/dist/server/handlers/auth.handler.js +29 -0
  212. package/dist/server/handlers/auth.handler.js.map +1 -0
  213. package/dist/server/handlers/captions.handler.d.ts +10 -0
  214. package/dist/server/handlers/captions.handler.d.ts.map +1 -0
  215. package/dist/server/handlers/captions.handler.js +33 -0
  216. package/dist/server/handlers/captions.handler.js.map +1 -0
  217. package/dist/server/handlers/collection.handler.d.ts +36 -0
  218. package/dist/server/handlers/collection.handler.d.ts.map +1 -0
  219. package/dist/server/handlers/collection.handler.js +166 -0
  220. package/dist/server/handlers/collection.handler.js.map +1 -0
  221. package/dist/server/handlers/error-response.js +24 -0
  222. package/dist/server/handlers/error-response.js.map +1 -0
  223. package/dist/server/handlers/index.handler.d.ts +9 -0
  224. package/dist/server/handlers/index.handler.d.ts.map +1 -0
  225. package/dist/server/handlers/index.handler.js +145 -0
  226. package/dist/server/handlers/index.handler.js.map +1 -0
  227. package/dist/server/handlers/preview.handler.d.ts +9 -0
  228. package/dist/server/handlers/preview.handler.d.ts.map +1 -0
  229. package/dist/server/handlers/preview.handler.js +15 -0
  230. package/dist/server/handlers/preview.handler.js.map +1 -0
  231. package/dist/server/handlers/registry.handler.d.ts +16 -0
  232. package/dist/server/handlers/registry.handler.d.ts.map +1 -0
  233. package/dist/server/handlers/registry.handler.js +260 -0
  234. package/dist/server/handlers/registry.handler.js.map +1 -0
  235. package/dist/server/handlers/route.handler.d.ts +20 -0
  236. package/dist/server/handlers/route.handler.d.ts.map +1 -0
  237. package/dist/server/handlers/route.handler.js +122 -0
  238. package/dist/server/handlers/route.handler.js.map +1 -0
  239. package/dist/server/handlers/sitemap.handler.d.ts +30 -0
  240. package/dist/server/handlers/sitemap.handler.d.ts.map +1 -0
  241. package/dist/server/handlers/sitemap.handler.js +338 -0
  242. package/dist/server/handlers/sitemap.handler.js.map +1 -0
  243. package/dist/server/handlers/static-params.handler.d.ts +24 -0
  244. package/dist/server/handlers/static-params.handler.d.ts.map +1 -0
  245. package/dist/server/handlers/static-params.handler.js +56 -0
  246. package/dist/server/handlers/static-params.handler.js.map +1 -0
  247. package/dist/server/handlers/vars.handler.d.ts +10 -0
  248. package/dist/server/handlers/vars.handler.d.ts.map +1 -0
  249. package/dist/server/handlers/vars.handler.js +159 -0
  250. package/dist/server/handlers/vars.handler.js.map +1 -0
  251. package/dist/server/layout.js +88 -0
  252. package/dist/server/layout.js.map +1 -0
  253. package/dist/server/lazy.d.ts +11 -0
  254. package/dist/server/lazy.d.ts.map +1 -0
  255. package/dist/server/lazy.js +33 -0
  256. package/dist/server/lazy.js.map +1 -0
  257. package/dist/server/local-api.d.ts +9 -0
  258. package/dist/server/local-api.d.ts.map +1 -0
  259. package/dist/server/local-api.js +60 -0
  260. package/dist/server/local-api.js.map +1 -0
  261. package/dist/server/metadata.d.ts +21 -0
  262. package/dist/server/metadata.d.ts.map +1 -0
  263. package/dist/server/metadata.js +20 -0
  264. package/dist/server/metadata.js.map +1 -0
  265. package/dist/server/mixer-payload.d.ts +63 -0
  266. package/dist/server/mixer-payload.d.ts.map +1 -0
  267. package/dist/server/mixer.d.ts +214 -0
  268. package/dist/server/mixer.d.ts.map +1 -0
  269. package/dist/server/mixer.js +355 -0
  270. package/dist/server/mixer.js.map +1 -0
  271. package/dist/server/page.d.ts +22 -0
  272. package/dist/server/page.d.ts.map +1 -0
  273. package/dist/server/page.js +57 -0
  274. package/dist/server/page.js.map +1 -0
  275. package/dist/server/utils.d.ts +12 -0
  276. package/dist/server/utils.d.ts.map +1 -0
  277. package/dist/{utils2.js → server/utils.js} +3 -3
  278. package/dist/server/utils.js.map +1 -0
  279. package/dist/server/utmz.d.ts +9 -0
  280. package/dist/server/utmz.d.ts.map +1 -0
  281. package/dist/server/utmz.js +14 -0
  282. package/dist/server/utmz.js.map +1 -0
  283. package/dist/types.d.ts +6 -61
  284. package/dist/types.d.ts.map +1 -1
  285. package/package.json +1 -1
  286. package/dist/exports/client.d.ts.map +0 -1
  287. package/dist/exports/client.js.map +0 -1
  288. package/dist/exports/instrumentation.d.ts.map +0 -1
  289. package/dist/exports/instrumentation.js.map +0 -1
  290. package/dist/exports/proxy.d.ts.map +0 -1
  291. package/dist/exports/proxy.js.map +0 -1
  292. package/dist/exports/server.d.ts.map +0 -1
  293. package/dist/exports/server.js.map +0 -1
  294. package/dist/http.js.map +0 -1
  295. package/dist/index.d.ts.map +0 -1
  296. package/dist/index.js.map +0 -1
  297. package/dist/index2.d.ts +0 -4
  298. package/dist/route.js.map +0 -1
  299. package/dist/store.js.map +0 -1
  300. package/dist/types2.d.ts.map +0 -1
  301. package/dist/utils.js +0 -78
  302. package/dist/utils.js.map +0 -1
  303. package/dist/utils2.js.map +0 -1
  304. /package/dist/{config.client.js → instrumentation/sentry/config.client.js} +0 -0
  305. /package/dist/{config.edge.js → instrumentation/sentry/config.edge.js} +0 -0
  306. /package/dist/{config.server.js → instrumentation/sentry/config.server.js} +0 -0
@@ -0,0 +1,1816 @@
1
+ import { __toESM } from "../../../_virtual/_rolldown/runtime.js";
2
+ import { DecisionTree } from "../../selderee/lib/selderee.js";
3
+ import { hp2Builder } from "../../@selderee/plugin-htmlparser2/lib/hp2-builder.js";
4
+ import render from "../../dom-serializer/lib/esm/index.js";
5
+ import { parseDocument } from "../node_modules/htmlparser2/lib/esm/index.js";
6
+ import { require_cjs } from "../../deepmerge/dist/cjs.js";
7
+ //#region ../../node_modules/html-to-text/lib/html-to-text.mjs
8
+ var import_cjs = /* @__PURE__ */ __toESM(require_cjs(), 1);
9
+ /**
10
+ * Make a recursive function that will only run to a given depth
11
+ * and switches to an alternative function at that depth. \
12
+ * No limitation if `n` is `undefined` (Just wraps `f` in that case).
13
+ *
14
+ * @param { number | undefined } n Allowed depth of recursion. `undefined` for no limitation.
15
+ * @param { Function } f Function that accepts recursive callback as the first argument.
16
+ * @param { Function } [g] Function to run instead, when maximum depth was reached. Do nothing by default.
17
+ * @returns { Function }
18
+ */
19
+ function limitedDepthRecursive(n, f, g = () => void 0) {
20
+ if (n === void 0) {
21
+ const f1 = function(...args) {
22
+ return f(f1, ...args);
23
+ };
24
+ return f1;
25
+ }
26
+ if (n >= 0) return function(...args) {
27
+ return f(limitedDepthRecursive(n - 1, f, g), ...args);
28
+ };
29
+ return g;
30
+ }
31
+ /**
32
+ * Return the same string or a substring with
33
+ * the given character occurrences removed from each side.
34
+ *
35
+ * @param { string } str A string to trim.
36
+ * @param { string } char A character to be trimmed.
37
+ * @returns { string }
38
+ */
39
+ function trimCharacter(str, char) {
40
+ let start = 0;
41
+ let end = str.length;
42
+ while (start < end && str[start] === char) ++start;
43
+ while (end > start && str[end - 1] === char) --end;
44
+ return start > 0 || end < str.length ? str.substring(start, end) : str;
45
+ }
46
+ /**
47
+ * Return the same string or a substring with
48
+ * the given character occurrences removed from the end only.
49
+ *
50
+ * @param { string } str A string to trim.
51
+ * @param { string } char A character to be trimmed.
52
+ * @returns { string }
53
+ */
54
+ function trimCharacterEnd(str, char) {
55
+ let end = str.length;
56
+ while (end > 0 && str[end - 1] === char) --end;
57
+ return end < str.length ? str.substring(0, end) : str;
58
+ }
59
+ /**
60
+ * Return a new string will all characters replaced with unicode escape sequences.
61
+ * This extreme kind of escaping can used to be safely compose regular expressions.
62
+ *
63
+ * @param { string } str A string to escape.
64
+ * @returns { string } A string of unicode escape sequences.
65
+ */
66
+ function unicodeEscape(str) {
67
+ return str.replace(/[\s\S]/g, (c) => "\\u" + c.charCodeAt().toString(16).padStart(4, "0"));
68
+ }
69
+ /**
70
+ * Deduplicate an array by a given key callback.
71
+ * Item properties are merged recursively and with the preference for last defined values.
72
+ * Of items with the same key, merged item takes the place of the last item,
73
+ * others are omitted.
74
+ *
75
+ * @param { any[] } items An array to deduplicate.
76
+ * @param { (x: any) => string } getKey Callback to get a value that distinguishes unique items.
77
+ * @returns { any[] }
78
+ */
79
+ function mergeDuplicatesPreferLast(items, getKey) {
80
+ const map = /* @__PURE__ */ new Map();
81
+ for (let i = items.length; i-- > 0;) {
82
+ const item = items[i];
83
+ const key = getKey(item);
84
+ map.set(key, map.has(key) ? (0, import_cjs.default)(item, map.get(key), { arrayMerge: overwriteMerge$1 }) : item);
85
+ }
86
+ return [...map.values()].reverse();
87
+ }
88
+ const overwriteMerge$1 = (acc, src, options) => [...src];
89
+ /**
90
+ * Get a nested property from an object.
91
+ *
92
+ * @param { object } obj The object to query for the value.
93
+ * @param { string[] } path The path to the property.
94
+ * @returns { any }
95
+ */
96
+ function get(obj, path) {
97
+ for (const key of path) {
98
+ if (!obj) return;
99
+ obj = obj[key];
100
+ }
101
+ return obj;
102
+ }
103
+ /**
104
+ * Convert a number into alphabetic sequence representation (Sequence without zeroes).
105
+ *
106
+ * For example: `a, ..., z, aa, ..., zz, aaa, ...`.
107
+ *
108
+ * @param { number } num Number to convert. Must be >= 1.
109
+ * @param { string } [baseChar = 'a'] Character for 1 in the sequence.
110
+ * @param { number } [base = 26] Number of characters in the sequence.
111
+ * @returns { string }
112
+ */
113
+ function numberToLetterSequence(num, baseChar = "a", base = 26) {
114
+ const digits = [];
115
+ do {
116
+ num -= 1;
117
+ digits.push(num % base);
118
+ num = num / base >> 0;
119
+ } while (num > 0);
120
+ const baseCode = baseChar.charCodeAt(0);
121
+ return digits.reverse().map((n) => String.fromCharCode(baseCode + n)).join("");
122
+ }
123
+ const I = [
124
+ "I",
125
+ "X",
126
+ "C",
127
+ "M"
128
+ ];
129
+ const V = [
130
+ "V",
131
+ "L",
132
+ "D"
133
+ ];
134
+ /**
135
+ * Convert a number to it's Roman representation. No large numbers extension.
136
+ *
137
+ * @param { number } num Number to convert. `0 < num <= 3999`.
138
+ * @returns { string }
139
+ */
140
+ function numberToRoman(num) {
141
+ return [...num + ""].map((n) => +n).reverse().map((v, i) => v % 5 < 4 ? (v < 5 ? "" : V[i]) + I[i].repeat(v % 5) : I[i] + (v < 5 ? V[i] : I[i + 1])).reverse().join("");
142
+ }
143
+ /**
144
+ * Helps to build text from words.
145
+ */
146
+ var InlineTextBuilder = class {
147
+ /**
148
+ * Creates an instance of InlineTextBuilder.
149
+ *
150
+ * If `maxLineLength` is not provided then it is either `options.wordwrap` or unlimited.
151
+ *
152
+ * @param { Options } options HtmlToText options.
153
+ * @param { number } [ maxLineLength ] This builder will try to wrap text to fit this line length.
154
+ */
155
+ constructor(options, maxLineLength = void 0) {
156
+ /** @type { string[][] } */
157
+ this.lines = [];
158
+ /** @type { string[] } */
159
+ this.nextLineWords = [];
160
+ this.maxLineLength = maxLineLength || options.wordwrap || Number.MAX_VALUE;
161
+ this.nextLineAvailableChars = this.maxLineLength;
162
+ this.wrapCharacters = get(options, ["longWordSplit", "wrapCharacters"]) || [];
163
+ this.forceWrapOnLimit = get(options, ["longWordSplit", "forceWrapOnLimit"]) || false;
164
+ this.stashedSpace = false;
165
+ this.wordBreakOpportunity = false;
166
+ }
167
+ /**
168
+ * Add a new word.
169
+ *
170
+ * @param { string } word A word to add.
171
+ * @param { boolean } [noWrap] Don't wrap text even if the line is too long.
172
+ */
173
+ pushWord(word, noWrap = false) {
174
+ if (this.nextLineAvailableChars <= 0 && !noWrap) this.startNewLine();
175
+ const isLineStart = this.nextLineWords.length === 0;
176
+ const cost = word.length + (isLineStart ? 0 : 1);
177
+ if (cost <= this.nextLineAvailableChars || noWrap) {
178
+ this.nextLineWords.push(word);
179
+ this.nextLineAvailableChars -= cost;
180
+ } else {
181
+ const [first, ...rest] = this.splitLongWord(word);
182
+ if (!isLineStart) this.startNewLine();
183
+ this.nextLineWords.push(first);
184
+ this.nextLineAvailableChars -= first.length;
185
+ for (const part of rest) {
186
+ this.startNewLine();
187
+ this.nextLineWords.push(part);
188
+ this.nextLineAvailableChars -= part.length;
189
+ }
190
+ }
191
+ }
192
+ /**
193
+ * Pop a word from the currently built line.
194
+ * This doesn't affect completed lines.
195
+ *
196
+ * @returns { string }
197
+ */
198
+ popWord() {
199
+ const lastWord = this.nextLineWords.pop();
200
+ if (lastWord !== void 0) {
201
+ const isLineStart = this.nextLineWords.length === 0;
202
+ const cost = lastWord.length + (isLineStart ? 0 : 1);
203
+ this.nextLineAvailableChars += cost;
204
+ }
205
+ return lastWord;
206
+ }
207
+ /**
208
+ * Concat a word to the last word already in the builder.
209
+ * Adds a new word in case there are no words yet in the last line.
210
+ *
211
+ * @param { string } word A word to be concatenated.
212
+ * @param { boolean } [noWrap] Don't wrap text even if the line is too long.
213
+ */
214
+ concatWord(word, noWrap = false) {
215
+ if (this.wordBreakOpportunity && word.length > this.nextLineAvailableChars) {
216
+ this.pushWord(word, noWrap);
217
+ this.wordBreakOpportunity = false;
218
+ } else {
219
+ const lastWord = this.popWord();
220
+ this.pushWord(lastWord ? lastWord.concat(word) : word, noWrap);
221
+ }
222
+ }
223
+ /**
224
+ * Add current line (and more empty lines if provided argument > 1) to the list of complete lines and start a new one.
225
+ *
226
+ * @param { number } n Number of line breaks that will be added to the resulting string.
227
+ */
228
+ startNewLine(n = 1) {
229
+ this.lines.push(this.nextLineWords);
230
+ if (n > 1) this.lines.push(...Array.from({ length: n - 1 }, () => []));
231
+ this.nextLineWords = [];
232
+ this.nextLineAvailableChars = this.maxLineLength;
233
+ }
234
+ /**
235
+ * No words in this builder.
236
+ *
237
+ * @returns { boolean }
238
+ */
239
+ isEmpty() {
240
+ return this.lines.length === 0 && this.nextLineWords.length === 0;
241
+ }
242
+ clear() {
243
+ this.lines.length = 0;
244
+ this.nextLineWords.length = 0;
245
+ this.nextLineAvailableChars = this.maxLineLength;
246
+ }
247
+ /**
248
+ * Join all lines of words inside the InlineTextBuilder into a complete string.
249
+ *
250
+ * @returns { string }
251
+ */
252
+ toString() {
253
+ return [...this.lines, this.nextLineWords].map((words) => words.join(" ")).join("\n");
254
+ }
255
+ /**
256
+ * Split a long word up to fit within the word wrap limit.
257
+ * Use either a character to split looking back from the word wrap limit,
258
+ * or truncate to the word wrap limit.
259
+ *
260
+ * @param { string } word Input word.
261
+ * @returns { string[] } Parts of the word.
262
+ */
263
+ splitLongWord(word) {
264
+ const parts = [];
265
+ let idx = 0;
266
+ while (word.length > this.maxLineLength) {
267
+ const firstLine = word.substring(0, this.maxLineLength);
268
+ const remainingChars = word.substring(this.maxLineLength);
269
+ const splitIndex = firstLine.lastIndexOf(this.wrapCharacters[idx]);
270
+ if (splitIndex > -1) {
271
+ word = firstLine.substring(splitIndex + 1) + remainingChars;
272
+ parts.push(firstLine.substring(0, splitIndex + 1));
273
+ } else {
274
+ idx++;
275
+ if (idx < this.wrapCharacters.length) word = firstLine + remainingChars;
276
+ else {
277
+ if (this.forceWrapOnLimit) {
278
+ parts.push(firstLine);
279
+ word = remainingChars;
280
+ if (word.length > this.maxLineLength) continue;
281
+ } else word = firstLine + remainingChars;
282
+ break;
283
+ }
284
+ }
285
+ }
286
+ parts.push(word);
287
+ return parts;
288
+ }
289
+ };
290
+ var StackItem = class {
291
+ constructor(next = null) {
292
+ this.next = next;
293
+ }
294
+ getRoot() {
295
+ return this.next ? this.next : this;
296
+ }
297
+ };
298
+ var BlockStackItem = class extends StackItem {
299
+ constructor(options, next = null, leadingLineBreaks = 1, maxLineLength = void 0) {
300
+ super(next);
301
+ this.leadingLineBreaks = leadingLineBreaks;
302
+ this.inlineTextBuilder = new InlineTextBuilder(options, maxLineLength);
303
+ this.rawText = "";
304
+ this.stashedLineBreaks = 0;
305
+ this.isPre = next && next.isPre;
306
+ this.isNoWrap = next && next.isNoWrap;
307
+ }
308
+ };
309
+ var ListStackItem = class extends BlockStackItem {
310
+ constructor(options, next = null, { interRowLineBreaks = 1, leadingLineBreaks = 2, maxLineLength = void 0, maxPrefixLength = 0, prefixAlign = "left" } = {}) {
311
+ super(options, next, leadingLineBreaks, maxLineLength);
312
+ this.maxPrefixLength = maxPrefixLength;
313
+ this.prefixAlign = prefixAlign;
314
+ this.interRowLineBreaks = interRowLineBreaks;
315
+ }
316
+ };
317
+ var ListItemStackItem = class extends BlockStackItem {
318
+ constructor(options, next = null, { leadingLineBreaks = 1, maxLineLength = void 0, prefix = "" } = {}) {
319
+ super(options, next, leadingLineBreaks, maxLineLength);
320
+ this.prefix = prefix;
321
+ }
322
+ };
323
+ var TableStackItem = class extends StackItem {
324
+ constructor(next = null) {
325
+ super(next);
326
+ this.rows = [];
327
+ this.isPre = next && next.isPre;
328
+ this.isNoWrap = next && next.isNoWrap;
329
+ }
330
+ };
331
+ var TableRowStackItem = class extends StackItem {
332
+ constructor(next = null) {
333
+ super(next);
334
+ this.cells = [];
335
+ this.isPre = next && next.isPre;
336
+ this.isNoWrap = next && next.isNoWrap;
337
+ }
338
+ };
339
+ var TableCellStackItem = class extends StackItem {
340
+ constructor(options, next = null, maxColumnWidth = void 0) {
341
+ super(next);
342
+ this.inlineTextBuilder = new InlineTextBuilder(options, maxColumnWidth);
343
+ this.rawText = "";
344
+ this.stashedLineBreaks = 0;
345
+ this.isPre = next && next.isPre;
346
+ this.isNoWrap = next && next.isNoWrap;
347
+ }
348
+ };
349
+ var TransformerStackItem = class extends StackItem {
350
+ constructor(next = null, transform) {
351
+ super(next);
352
+ this.transform = transform;
353
+ }
354
+ };
355
+ function charactersToCodes(str) {
356
+ return [...str].map((c) => "\\u" + c.charCodeAt(0).toString(16).padStart(4, "0")).join("");
357
+ }
358
+ /**
359
+ * Helps to handle HTML whitespaces.
360
+ *
361
+ * @class WhitespaceProcessor
362
+ */
363
+ var WhitespaceProcessor = class {
364
+ /**
365
+ * Creates an instance of WhitespaceProcessor.
366
+ *
367
+ * @param { Options } options HtmlToText options.
368
+ * @memberof WhitespaceProcessor
369
+ */
370
+ constructor(options) {
371
+ this.whitespaceChars = options.preserveNewlines ? options.whitespaceCharacters.replace(/\n/g, "") : options.whitespaceCharacters;
372
+ const whitespaceCodes = charactersToCodes(this.whitespaceChars);
373
+ this.leadingWhitespaceRe = new RegExp(`^[${whitespaceCodes}]`);
374
+ this.trailingWhitespaceRe = new RegExp(`[${whitespaceCodes}]$`);
375
+ this.allWhitespaceOrEmptyRe = new RegExp(`^[${whitespaceCodes}]*$`);
376
+ this.newlineOrNonWhitespaceRe = new RegExp(`(\\n|[^\\n${whitespaceCodes}])`, "g");
377
+ this.newlineOrNonNewlineStringRe = new RegExp(`(\\n|[^\\n]+)`, "g");
378
+ if (options.preserveNewlines) {
379
+ const wordOrNewlineRe = new RegExp(`\\n|[^\\n${whitespaceCodes}]+`, "gm");
380
+ /**
381
+ * Shrink whitespaces and wrap text, add to the builder.
382
+ *
383
+ * @param { string } text Input text.
384
+ * @param { InlineTextBuilder } inlineTextBuilder A builder to receive processed text.
385
+ * @param { (str: string) => string } [ transform ] A transform to be applied to words.
386
+ * @param { boolean } [noWrap] Don't wrap text even if the line is too long.
387
+ */
388
+ this.shrinkWrapAdd = function(text, inlineTextBuilder, transform = ((str) => str), noWrap = false) {
389
+ if (!text) return;
390
+ const previouslyStashedSpace = inlineTextBuilder.stashedSpace;
391
+ let anyMatch = false;
392
+ let m = wordOrNewlineRe.exec(text);
393
+ if (m) {
394
+ anyMatch = true;
395
+ if (m[0] === "\n") inlineTextBuilder.startNewLine();
396
+ else if (previouslyStashedSpace || this.testLeadingWhitespace(text)) inlineTextBuilder.pushWord(transform(m[0]), noWrap);
397
+ else inlineTextBuilder.concatWord(transform(m[0]), noWrap);
398
+ while ((m = wordOrNewlineRe.exec(text)) !== null) if (m[0] === "\n") inlineTextBuilder.startNewLine();
399
+ else inlineTextBuilder.pushWord(transform(m[0]), noWrap);
400
+ }
401
+ inlineTextBuilder.stashedSpace = previouslyStashedSpace && !anyMatch || this.testTrailingWhitespace(text);
402
+ };
403
+ } else {
404
+ const wordRe = new RegExp(`[^${whitespaceCodes}]+`, "g");
405
+ this.shrinkWrapAdd = function(text, inlineTextBuilder, transform = ((str) => str), noWrap = false) {
406
+ if (!text) return;
407
+ const previouslyStashedSpace = inlineTextBuilder.stashedSpace;
408
+ let anyMatch = false;
409
+ let m = wordRe.exec(text);
410
+ if (m) {
411
+ anyMatch = true;
412
+ if (previouslyStashedSpace || this.testLeadingWhitespace(text)) inlineTextBuilder.pushWord(transform(m[0]), noWrap);
413
+ else inlineTextBuilder.concatWord(transform(m[0]), noWrap);
414
+ while ((m = wordRe.exec(text)) !== null) inlineTextBuilder.pushWord(transform(m[0]), noWrap);
415
+ }
416
+ inlineTextBuilder.stashedSpace = previouslyStashedSpace && !anyMatch || this.testTrailingWhitespace(text);
417
+ };
418
+ }
419
+ }
420
+ /**
421
+ * Add text with only minimal processing.
422
+ * Everything between newlines considered a single word.
423
+ * No whitespace is trimmed.
424
+ * Not affected by preserveNewlines option - `\n` always starts a new line.
425
+ *
426
+ * `noWrap` argument is `true` by default - this won't start a new line
427
+ * even if there is not enough space left in the current line.
428
+ *
429
+ * @param { string } text Input text.
430
+ * @param { InlineTextBuilder } inlineTextBuilder A builder to receive processed text.
431
+ * @param { boolean } [noWrap] Don't wrap text even if the line is too long.
432
+ */
433
+ addLiteral(text, inlineTextBuilder, noWrap = true) {
434
+ if (!text) return;
435
+ const previouslyStashedSpace = inlineTextBuilder.stashedSpace;
436
+ let anyMatch = false;
437
+ let m = this.newlineOrNonNewlineStringRe.exec(text);
438
+ if (m) {
439
+ anyMatch = true;
440
+ if (m[0] === "\n") inlineTextBuilder.startNewLine();
441
+ else if (previouslyStashedSpace) inlineTextBuilder.pushWord(m[0], noWrap);
442
+ else inlineTextBuilder.concatWord(m[0], noWrap);
443
+ while ((m = this.newlineOrNonNewlineStringRe.exec(text)) !== null) if (m[0] === "\n") inlineTextBuilder.startNewLine();
444
+ else inlineTextBuilder.pushWord(m[0], noWrap);
445
+ }
446
+ inlineTextBuilder.stashedSpace = previouslyStashedSpace && !anyMatch;
447
+ }
448
+ /**
449
+ * Test whether the given text starts with HTML whitespace character.
450
+ *
451
+ * @param { string } text The string to test.
452
+ * @returns { boolean }
453
+ */
454
+ testLeadingWhitespace(text) {
455
+ return this.leadingWhitespaceRe.test(text);
456
+ }
457
+ /**
458
+ * Test whether the given text ends with HTML whitespace character.
459
+ *
460
+ * @param { string } text The string to test.
461
+ * @returns { boolean }
462
+ */
463
+ testTrailingWhitespace(text) {
464
+ return this.trailingWhitespaceRe.test(text);
465
+ }
466
+ /**
467
+ * Test whether the given text contains any non-whitespace characters.
468
+ *
469
+ * @param { string } text The string to test.
470
+ * @returns { boolean }
471
+ */
472
+ testContainsWords(text) {
473
+ return !this.allWhitespaceOrEmptyRe.test(text);
474
+ }
475
+ /**
476
+ * Return the number of newlines if there are no words.
477
+ *
478
+ * If any word is found then return zero regardless of the actual number of newlines.
479
+ *
480
+ * @param { string } text Input string.
481
+ * @returns { number }
482
+ */
483
+ countNewlinesNoWords(text) {
484
+ this.newlineOrNonWhitespaceRe.lastIndex = 0;
485
+ let counter = 0;
486
+ let match;
487
+ while ((match = this.newlineOrNonWhitespaceRe.exec(text)) !== null) if (match[0] === "\n") counter++;
488
+ else return 0;
489
+ return counter;
490
+ }
491
+ };
492
+ /**
493
+ * Helps to build text from inline and block elements.
494
+ *
495
+ * @class BlockTextBuilder
496
+ */
497
+ var BlockTextBuilder = class {
498
+ /**
499
+ * Creates an instance of BlockTextBuilder.
500
+ *
501
+ * @param { Options } options HtmlToText options.
502
+ * @param { import('selderee').Picker<DomNode, TagDefinition> } picker Selectors decision tree picker.
503
+ * @param { any} [metadata] Optional metadata for HTML document, for use in formatters.
504
+ */
505
+ constructor(options, picker, metadata = void 0) {
506
+ this.options = options;
507
+ this.picker = picker;
508
+ this.metadata = metadata;
509
+ this.whitespaceProcessor = new WhitespaceProcessor(options);
510
+ /** @type { StackItem } */
511
+ this._stackItem = new BlockStackItem(options);
512
+ /** @type { TransformerStackItem } */
513
+ this._wordTransformer = void 0;
514
+ }
515
+ /**
516
+ * Put a word-by-word transform function onto the transformations stack.
517
+ *
518
+ * Mainly used for uppercasing. Can be bypassed to add unformatted text such as URLs.
519
+ *
520
+ * Word transformations applied before wrapping.
521
+ *
522
+ * @param { (str: string) => string } wordTransform Word transformation function.
523
+ */
524
+ pushWordTransform(wordTransform) {
525
+ this._wordTransformer = new TransformerStackItem(this._wordTransformer, wordTransform);
526
+ }
527
+ /**
528
+ * Remove a function from the word transformations stack.
529
+ *
530
+ * @returns { (str: string) => string } A function that was removed.
531
+ */
532
+ popWordTransform() {
533
+ if (!this._wordTransformer) return;
534
+ const transform = this._wordTransformer.transform;
535
+ this._wordTransformer = this._wordTransformer.next;
536
+ return transform;
537
+ }
538
+ /**
539
+ * Ignore wordwrap option in followup inline additions and disable automatic wrapping.
540
+ */
541
+ startNoWrap() {
542
+ this._stackItem.isNoWrap = true;
543
+ }
544
+ /**
545
+ * Return automatic wrapping to behavior defined by options.
546
+ */
547
+ stopNoWrap() {
548
+ this._stackItem.isNoWrap = false;
549
+ }
550
+ /** @returns { (str: string) => string } */
551
+ _getCombinedWordTransformer() {
552
+ const wt = this._wordTransformer ? ((str) => applyTransformer(str, this._wordTransformer)) : void 0;
553
+ const ce = this.options.encodeCharacters;
554
+ return wt ? ce ? (str) => ce(wt(str)) : wt : ce;
555
+ }
556
+ _popStackItem() {
557
+ const item = this._stackItem;
558
+ this._stackItem = item.next;
559
+ return item;
560
+ }
561
+ /**
562
+ * Add a line break into currently built block.
563
+ */
564
+ addLineBreak() {
565
+ if (!(this._stackItem instanceof BlockStackItem || this._stackItem instanceof ListItemStackItem || this._stackItem instanceof TableCellStackItem)) return;
566
+ if (this._stackItem.isPre) this._stackItem.rawText += "\n";
567
+ else this._stackItem.inlineTextBuilder.startNewLine();
568
+ }
569
+ /**
570
+ * Allow to break line in case directly following text will not fit.
571
+ */
572
+ addWordBreakOpportunity() {
573
+ if (this._stackItem instanceof BlockStackItem || this._stackItem instanceof ListItemStackItem || this._stackItem instanceof TableCellStackItem) this._stackItem.inlineTextBuilder.wordBreakOpportunity = true;
574
+ }
575
+ /**
576
+ * Add a node inline into the currently built block.
577
+ *
578
+ * @param { string } str
579
+ * Text content of a node to add.
580
+ *
581
+ * @param { object } [param1]
582
+ * Object holding the parameters of the operation.
583
+ *
584
+ * @param { boolean } [param1.noWordTransform]
585
+ * Ignore word transformers if there are any.
586
+ * Don't encode characters as well.
587
+ * (Use this for things like URL addresses).
588
+ */
589
+ addInline(str, { noWordTransform = false } = {}) {
590
+ if (!(this._stackItem instanceof BlockStackItem || this._stackItem instanceof ListItemStackItem || this._stackItem instanceof TableCellStackItem)) return;
591
+ if (this._stackItem.isPre) {
592
+ this._stackItem.rawText += str;
593
+ return;
594
+ }
595
+ if (str.length === 0 || this._stackItem.stashedLineBreaks && !this.whitespaceProcessor.testContainsWords(str)) return;
596
+ if (this.options.preserveNewlines) {
597
+ const newlinesNumber = this.whitespaceProcessor.countNewlinesNoWords(str);
598
+ if (newlinesNumber > 0) {
599
+ this._stackItem.inlineTextBuilder.startNewLine(newlinesNumber);
600
+ return;
601
+ }
602
+ }
603
+ if (this._stackItem.stashedLineBreaks) this._stackItem.inlineTextBuilder.startNewLine(this._stackItem.stashedLineBreaks);
604
+ this.whitespaceProcessor.shrinkWrapAdd(str, this._stackItem.inlineTextBuilder, noWordTransform ? void 0 : this._getCombinedWordTransformer(), this._stackItem.isNoWrap);
605
+ this._stackItem.stashedLineBreaks = 0;
606
+ }
607
+ /**
608
+ * Add a string inline into the currently built block.
609
+ *
610
+ * Use this for markup elements that don't have to adhere
611
+ * to text layout rules.
612
+ *
613
+ * @param { string } str Text to add.
614
+ */
615
+ addLiteral(str) {
616
+ if (!(this._stackItem instanceof BlockStackItem || this._stackItem instanceof ListItemStackItem || this._stackItem instanceof TableCellStackItem)) return;
617
+ if (str.length === 0) return;
618
+ if (this._stackItem.isPre) {
619
+ this._stackItem.rawText += str;
620
+ return;
621
+ }
622
+ if (this._stackItem.stashedLineBreaks) this._stackItem.inlineTextBuilder.startNewLine(this._stackItem.stashedLineBreaks);
623
+ this.whitespaceProcessor.addLiteral(str, this._stackItem.inlineTextBuilder, this._stackItem.isNoWrap);
624
+ this._stackItem.stashedLineBreaks = 0;
625
+ }
626
+ /**
627
+ * Start building a new block.
628
+ *
629
+ * @param { object } [param0]
630
+ * Object holding the parameters of the block.
631
+ *
632
+ * @param { number } [param0.leadingLineBreaks]
633
+ * This block should have at least this number of line breaks to separate it from any preceding block.
634
+ *
635
+ * @param { number } [param0.reservedLineLength]
636
+ * Reserve this number of characters on each line for block markup.
637
+ *
638
+ * @param { boolean } [param0.isPre]
639
+ * Should HTML whitespace be preserved inside this block.
640
+ */
641
+ openBlock({ leadingLineBreaks = 1, reservedLineLength = 0, isPre = false } = {}) {
642
+ const maxLineLength = Math.max(20, this._stackItem.inlineTextBuilder.maxLineLength - reservedLineLength);
643
+ this._stackItem = new BlockStackItem(this.options, this._stackItem, leadingLineBreaks, maxLineLength);
644
+ if (isPre) this._stackItem.isPre = true;
645
+ }
646
+ /**
647
+ * Finalize currently built block, add it's content to the parent block.
648
+ *
649
+ * @param { object } [param0]
650
+ * Object holding the parameters of the block.
651
+ *
652
+ * @param { number } [param0.trailingLineBreaks]
653
+ * This block should have at least this number of line breaks to separate it from any following block.
654
+ *
655
+ * @param { (str: string) => string } [param0.blockTransform]
656
+ * A function to transform the block text before adding to the parent block.
657
+ * This happens after word wrap and should be used in combination with reserved line length
658
+ * in order to keep line lengths correct.
659
+ * Used for whole block markup.
660
+ */
661
+ closeBlock({ trailingLineBreaks = 1, blockTransform = void 0 } = {}) {
662
+ const block = this._popStackItem();
663
+ const blockText = blockTransform ? blockTransform(getText(block)) : getText(block);
664
+ addText(this._stackItem, blockText, block.leadingLineBreaks, Math.max(block.stashedLineBreaks, trailingLineBreaks));
665
+ }
666
+ /**
667
+ * Start building a new list.
668
+ *
669
+ * @param { object } [param0]
670
+ * Object holding the parameters of the list.
671
+ *
672
+ * @param { number } [param0.maxPrefixLength]
673
+ * Length of the longest list item prefix.
674
+ * If not supplied or too small then list items won't be aligned properly.
675
+ *
676
+ * @param { 'left' | 'right' } [param0.prefixAlign]
677
+ * Specify how prefixes of different lengths have to be aligned
678
+ * within a column.
679
+ *
680
+ * @param { number } [param0.interRowLineBreaks]
681
+ * Minimum number of line breaks between list items.
682
+ *
683
+ * @param { number } [param0.leadingLineBreaks]
684
+ * This list should have at least this number of line breaks to separate it from any preceding block.
685
+ */
686
+ openList({ maxPrefixLength = 0, prefixAlign = "left", interRowLineBreaks = 1, leadingLineBreaks = 2 } = {}) {
687
+ this._stackItem = new ListStackItem(this.options, this._stackItem, {
688
+ interRowLineBreaks,
689
+ leadingLineBreaks,
690
+ maxLineLength: this._stackItem.inlineTextBuilder.maxLineLength,
691
+ maxPrefixLength,
692
+ prefixAlign
693
+ });
694
+ }
695
+ /**
696
+ * Start building a new list item.
697
+ *
698
+ * @param {object} param0
699
+ * Object holding the parameters of the list item.
700
+ *
701
+ * @param { string } [param0.prefix]
702
+ * Prefix for this list item (item number, bullet point, etc).
703
+ */
704
+ openListItem({ prefix = "" } = {}) {
705
+ if (!(this._stackItem instanceof ListStackItem)) throw new Error("Can't add a list item to something that is not a list! Check the formatter.");
706
+ const list = this._stackItem;
707
+ const prefixLength = Math.max(prefix.length, list.maxPrefixLength);
708
+ const maxLineLength = Math.max(20, list.inlineTextBuilder.maxLineLength - prefixLength);
709
+ this._stackItem = new ListItemStackItem(this.options, list, {
710
+ prefix,
711
+ maxLineLength,
712
+ leadingLineBreaks: list.interRowLineBreaks
713
+ });
714
+ }
715
+ /**
716
+ * Finalize currently built list item, add it's content to the parent list.
717
+ */
718
+ closeListItem() {
719
+ const listItem = this._popStackItem();
720
+ const list = listItem.next;
721
+ const prefixLength = Math.max(listItem.prefix.length, list.maxPrefixLength);
722
+ const spacing = "\n" + " ".repeat(prefixLength);
723
+ addText(list, (list.prefixAlign === "right" ? listItem.prefix.padStart(prefixLength) : listItem.prefix.padEnd(prefixLength)) + getText(listItem).replace(/\n/g, spacing), listItem.leadingLineBreaks, Math.max(listItem.stashedLineBreaks, list.interRowLineBreaks));
724
+ }
725
+ /**
726
+ * Finalize currently built list, add it's content to the parent block.
727
+ *
728
+ * @param { object } param0
729
+ * Object holding the parameters of the list.
730
+ *
731
+ * @param { number } [param0.trailingLineBreaks]
732
+ * This list should have at least this number of line breaks to separate it from any following block.
733
+ */
734
+ closeList({ trailingLineBreaks = 2 } = {}) {
735
+ const list = this._popStackItem();
736
+ const text = getText(list);
737
+ if (text) addText(this._stackItem, text, list.leadingLineBreaks, trailingLineBreaks);
738
+ }
739
+ /**
740
+ * Start building a table.
741
+ */
742
+ openTable() {
743
+ this._stackItem = new TableStackItem(this._stackItem);
744
+ }
745
+ /**
746
+ * Start building a table row.
747
+ */
748
+ openTableRow() {
749
+ if (!(this._stackItem instanceof TableStackItem)) throw new Error("Can't add a table row to something that is not a table! Check the formatter.");
750
+ this._stackItem = new TableRowStackItem(this._stackItem);
751
+ }
752
+ /**
753
+ * Start building a table cell.
754
+ *
755
+ * @param { object } [param0]
756
+ * Object holding the parameters of the cell.
757
+ *
758
+ * @param { number } [param0.maxColumnWidth]
759
+ * Wrap cell content to this width. Fall back to global wordwrap value if undefined.
760
+ */
761
+ openTableCell({ maxColumnWidth = void 0 } = {}) {
762
+ if (!(this._stackItem instanceof TableRowStackItem)) throw new Error("Can't add a table cell to something that is not a table row! Check the formatter.");
763
+ this._stackItem = new TableCellStackItem(this.options, this._stackItem, maxColumnWidth);
764
+ }
765
+ /**
766
+ * Finalize currently built table cell and add it to parent table row's cells.
767
+ *
768
+ * @param { object } [param0]
769
+ * Object holding the parameters of the cell.
770
+ *
771
+ * @param { number } [param0.colspan] How many columns this cell should occupy.
772
+ * @param { number } [param0.rowspan] How many rows this cell should occupy.
773
+ */
774
+ closeTableCell({ colspan = 1, rowspan = 1 } = {}) {
775
+ const cell = this._popStackItem();
776
+ const text = trimCharacter(getText(cell), "\n");
777
+ cell.next.cells.push({
778
+ colspan,
779
+ rowspan,
780
+ text
781
+ });
782
+ }
783
+ /**
784
+ * Finalize currently built table row and add it to parent table's rows.
785
+ */
786
+ closeTableRow() {
787
+ const row = this._popStackItem();
788
+ row.next.rows.push(row.cells);
789
+ }
790
+ /**
791
+ * Finalize currently built table and add the rendered text to the parent block.
792
+ *
793
+ * @param { object } param0
794
+ * Object holding the parameters of the table.
795
+ *
796
+ * @param { TablePrinter } param0.tableToString
797
+ * A function to convert a table of stringified cells into a complete table.
798
+ *
799
+ * @param { number } [param0.leadingLineBreaks]
800
+ * This table should have at least this number of line breaks to separate if from any preceding block.
801
+ *
802
+ * @param { number } [param0.trailingLineBreaks]
803
+ * This table should have at least this number of line breaks to separate it from any following block.
804
+ */
805
+ closeTable({ tableToString, leadingLineBreaks = 2, trailingLineBreaks = 2 }) {
806
+ const output = tableToString(this._popStackItem().rows);
807
+ if (output) addText(this._stackItem, output, leadingLineBreaks, trailingLineBreaks);
808
+ }
809
+ /**
810
+ * Return the rendered text content of this builder.
811
+ *
812
+ * @returns { string }
813
+ */
814
+ toString() {
815
+ return getText(this._stackItem.getRoot());
816
+ }
817
+ };
818
+ function getText(stackItem) {
819
+ if (!(stackItem instanceof BlockStackItem || stackItem instanceof ListItemStackItem || stackItem instanceof TableCellStackItem)) throw new Error("Only blocks, list items and table cells can be requested for text contents.");
820
+ return stackItem.inlineTextBuilder.isEmpty() ? stackItem.rawText : stackItem.rawText + stackItem.inlineTextBuilder.toString();
821
+ }
822
+ function addText(stackItem, text, leadingLineBreaks, trailingLineBreaks) {
823
+ if (!(stackItem instanceof BlockStackItem || stackItem instanceof ListItemStackItem || stackItem instanceof TableCellStackItem)) throw new Error("Only blocks, list items and table cells can contain text.");
824
+ const parentText = getText(stackItem);
825
+ const lineBreaks = Math.max(stackItem.stashedLineBreaks, leadingLineBreaks);
826
+ stackItem.inlineTextBuilder.clear();
827
+ if (parentText) stackItem.rawText = parentText + "\n".repeat(lineBreaks) + text;
828
+ else {
829
+ stackItem.rawText = text;
830
+ stackItem.leadingLineBreaks = lineBreaks;
831
+ }
832
+ stackItem.stashedLineBreaks = trailingLineBreaks;
833
+ }
834
+ /**
835
+ * @param { string } str A string to transform.
836
+ * @param { TransformerStackItem } transformer A transformer item (with possible continuation).
837
+ * @returns { string }
838
+ */
839
+ function applyTransformer(str, transformer) {
840
+ return transformer ? applyTransformer(transformer.transform(str), transformer.next) : str;
841
+ }
842
+ /**
843
+ * Compile selectors into a decision tree,
844
+ * return a function intended for batch processing.
845
+ *
846
+ * @param { Options } [options = {}] HtmlToText options (defaults, formatters, user options merged, deduplicated).
847
+ * @returns { (html: string, metadata?: any) => string } Pre-configured converter function.
848
+ * @static
849
+ */
850
+ function compile$1(options = {}) {
851
+ const selectorsWithoutFormat = options.selectors.filter((s) => !s.format);
852
+ if (selectorsWithoutFormat.length) throw new Error("Following selectors have no specified format: " + selectorsWithoutFormat.map((s) => `\`${s.selector}\``).join(", "));
853
+ const picker = new DecisionTree(options.selectors.map((s) => [s.selector, s])).build(hp2Builder);
854
+ if (typeof options.encodeCharacters !== "function") options.encodeCharacters = makeReplacerFromDict(options.encodeCharacters);
855
+ const baseSelectorsPicker = new DecisionTree(options.baseElements.selectors.map((s, i) => [s, i + 1])).build(hp2Builder);
856
+ function findBaseElements(dom) {
857
+ return findBases(dom, options, baseSelectorsPicker);
858
+ }
859
+ const limitedWalk = limitedDepthRecursive(options.limits.maxDepth, recursiveWalk, function(dom, builder) {
860
+ builder.addInline(options.limits.ellipsis || "");
861
+ });
862
+ return function(html, metadata = void 0) {
863
+ return process(html, metadata, options, picker, findBaseElements, limitedWalk);
864
+ };
865
+ }
866
+ /**
867
+ * Convert given HTML according to preprocessed options.
868
+ *
869
+ * @param { string } html HTML content to convert.
870
+ * @param { any } metadata Optional metadata for HTML document, for use in formatters.
871
+ * @param { Options } options HtmlToText options (preprocessed).
872
+ * @param { import('selderee').Picker<DomNode, TagDefinition> } picker
873
+ * Tag definition picker for DOM nodes processing.
874
+ * @param { (dom: DomNode[]) => DomNode[] } findBaseElements
875
+ * Function to extract elements from HTML DOM
876
+ * that will only be present in the output text.
877
+ * @param { RecursiveCallback } walk Recursive callback.
878
+ * @returns { string }
879
+ */
880
+ function process(html, metadata, options, picker, findBaseElements, walk) {
881
+ const maxInputLength = options.limits.maxInputLength;
882
+ if (maxInputLength && html && html.length > maxInputLength) {
883
+ console.warn(`Input length ${html.length} is above allowed limit of ${maxInputLength}. Truncating without ellipsis.`);
884
+ html = html.substring(0, maxInputLength);
885
+ }
886
+ const bases = findBaseElements(parseDocument(html, { decodeEntities: options.decodeEntities }).children);
887
+ const builder = new BlockTextBuilder(options, picker, metadata);
888
+ walk(bases, builder);
889
+ return builder.toString();
890
+ }
891
+ function findBases(dom, options, baseSelectorsPicker) {
892
+ const results = [];
893
+ function recursiveWalk(walk, dom) {
894
+ dom = dom.slice(0, options.limits.maxChildNodes);
895
+ for (const elem of dom) {
896
+ if (elem.type !== "tag") continue;
897
+ const pickedSelectorIndex = baseSelectorsPicker.pick1(elem);
898
+ if (pickedSelectorIndex > 0) results.push({
899
+ selectorIndex: pickedSelectorIndex,
900
+ element: elem
901
+ });
902
+ else if (elem.children) walk(elem.children);
903
+ if (results.length >= options.limits.maxBaseElements) return;
904
+ }
905
+ }
906
+ limitedDepthRecursive(options.limits.maxDepth, recursiveWalk)(dom);
907
+ if (options.baseElements.orderBy !== "occurrence") results.sort((a, b) => a.selectorIndex - b.selectorIndex);
908
+ return options.baseElements.returnDomByDefault && results.length === 0 ? dom : results.map((x) => x.element);
909
+ }
910
+ /**
911
+ * Function to walk through DOM nodes and accumulate their string representations.
912
+ *
913
+ * @param { RecursiveCallback } walk Recursive callback.
914
+ * @param { DomNode[] } [dom] Nodes array to process.
915
+ * @param { BlockTextBuilder } builder Passed around to accumulate output text.
916
+ * @private
917
+ */
918
+ function recursiveWalk(walk, dom, builder) {
919
+ if (!dom) return;
920
+ const options = builder.options;
921
+ if (dom.length > options.limits.maxChildNodes) {
922
+ dom = dom.slice(0, options.limits.maxChildNodes);
923
+ dom.push({
924
+ data: options.limits.ellipsis,
925
+ type: "text"
926
+ });
927
+ }
928
+ for (const elem of dom) switch (elem.type) {
929
+ case "text":
930
+ builder.addInline(elem.data);
931
+ break;
932
+ case "tag": {
933
+ const tagDefinition = builder.picker.pick1(elem);
934
+ const format = options.formatters[tagDefinition.format];
935
+ format(elem, walk, builder, tagDefinition.options || {});
936
+ break;
937
+ }
938
+ }
939
+ }
940
+ /**
941
+ * @param { Object<string,string | false> } dict
942
+ * A dictionary where keys are characters to replace
943
+ * and values are replacement strings.
944
+ *
945
+ * First code point from dict keys is used.
946
+ * Compound emojis with ZWJ are not supported (not until Node 16).
947
+ *
948
+ * @returns { ((str: string) => string) | undefined }
949
+ */
950
+ function makeReplacerFromDict(dict) {
951
+ if (!dict || Object.keys(dict).length === 0) return;
952
+ /** @type { [string, string][] } */
953
+ const entries = Object.entries(dict).filter(([, v]) => v !== false);
954
+ const regex = new RegExp(entries.map(([c]) => `(${unicodeEscape([...c][0])})`).join("|"), "g");
955
+ const values = entries.map(([, v]) => v);
956
+ const replacer = (m, ...cgs) => values[cgs.findIndex((cg) => cg)];
957
+ return (str) => str.replace(regex, replacer);
958
+ }
959
+ /**
960
+ * Dummy formatter that discards the input and does nothing.
961
+ *
962
+ * @type { FormatCallback }
963
+ */
964
+ function formatSkip(elem, walk, builder, formatOptions) {}
965
+ /**
966
+ * Insert the given string literal inline instead of a tag.
967
+ *
968
+ * @type { FormatCallback }
969
+ */
970
+ function formatInlineString(elem, walk, builder, formatOptions) {
971
+ builder.addLiteral(formatOptions.string || "");
972
+ }
973
+ /**
974
+ * Insert a block with the given string literal instead of a tag.
975
+ *
976
+ * @type { FormatCallback }
977
+ */
978
+ function formatBlockString(elem, walk, builder, formatOptions) {
979
+ builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });
980
+ builder.addLiteral(formatOptions.string || "");
981
+ builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });
982
+ }
983
+ /**
984
+ * Process an inline-level element.
985
+ *
986
+ * @type { FormatCallback }
987
+ */
988
+ function formatInline(elem, walk, builder, formatOptions) {
989
+ walk(elem.children, builder);
990
+ }
991
+ /**
992
+ * Process a block-level container.
993
+ *
994
+ * @type { FormatCallback }
995
+ */
996
+ function formatBlock$1(elem, walk, builder, formatOptions) {
997
+ builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });
998
+ walk(elem.children, builder);
999
+ builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });
1000
+ }
1001
+ function renderOpenTag(elem) {
1002
+ const attrs = elem.attribs && elem.attribs.length ? " " + Object.entries(elem.attribs).map(([k, v]) => v === "" ? k : `${k}=${v.replace(/"/g, "&quot;")}`).join(" ") : "";
1003
+ return `<${elem.name}${attrs}>`;
1004
+ }
1005
+ function renderCloseTag(elem) {
1006
+ return `</${elem.name}>`;
1007
+ }
1008
+ /**
1009
+ * Render an element as inline HTML tag, walk through it's children.
1010
+ *
1011
+ * @type { FormatCallback }
1012
+ */
1013
+ function formatInlineTag(elem, walk, builder, formatOptions) {
1014
+ builder.startNoWrap();
1015
+ builder.addLiteral(renderOpenTag(elem));
1016
+ builder.stopNoWrap();
1017
+ walk(elem.children, builder);
1018
+ builder.startNoWrap();
1019
+ builder.addLiteral(renderCloseTag(elem));
1020
+ builder.stopNoWrap();
1021
+ }
1022
+ /**
1023
+ * Render an element as HTML block bag, walk through it's children.
1024
+ *
1025
+ * @type { FormatCallback }
1026
+ */
1027
+ function formatBlockTag(elem, walk, builder, formatOptions) {
1028
+ builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });
1029
+ builder.startNoWrap();
1030
+ builder.addLiteral(renderOpenTag(elem));
1031
+ builder.stopNoWrap();
1032
+ walk(elem.children, builder);
1033
+ builder.startNoWrap();
1034
+ builder.addLiteral(renderCloseTag(elem));
1035
+ builder.stopNoWrap();
1036
+ builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });
1037
+ }
1038
+ /**
1039
+ * Render an element with all it's children as inline HTML.
1040
+ *
1041
+ * @type { FormatCallback }
1042
+ */
1043
+ function formatInlineHtml(elem, walk, builder, formatOptions) {
1044
+ builder.startNoWrap();
1045
+ builder.addLiteral(render(elem, { decodeEntities: builder.options.decodeEntities }));
1046
+ builder.stopNoWrap();
1047
+ }
1048
+ /**
1049
+ * Render an element with all it's children as HTML block.
1050
+ *
1051
+ * @type { FormatCallback }
1052
+ */
1053
+ function formatBlockHtml(elem, walk, builder, formatOptions) {
1054
+ builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });
1055
+ builder.startNoWrap();
1056
+ builder.addLiteral(render(elem, { decodeEntities: builder.options.decodeEntities }));
1057
+ builder.stopNoWrap();
1058
+ builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });
1059
+ }
1060
+ /**
1061
+ * Render inline element wrapped with given strings.
1062
+ *
1063
+ * @type { FormatCallback }
1064
+ */
1065
+ function formatInlineSurround(elem, walk, builder, formatOptions) {
1066
+ builder.addLiteral(formatOptions.prefix || "");
1067
+ walk(elem.children, builder);
1068
+ builder.addLiteral(formatOptions.suffix || "");
1069
+ }
1070
+ var genericFormatters = /*#__PURE__*/ Object.freeze({
1071
+ __proto__: null,
1072
+ block: formatBlock$1,
1073
+ blockHtml: formatBlockHtml,
1074
+ blockString: formatBlockString,
1075
+ blockTag: formatBlockTag,
1076
+ inline: formatInline,
1077
+ inlineHtml: formatInlineHtml,
1078
+ inlineString: formatInlineString,
1079
+ inlineSurround: formatInlineSurround,
1080
+ inlineTag: formatInlineTag,
1081
+ skip: formatSkip
1082
+ });
1083
+ function getRow(matrix, j) {
1084
+ if (!matrix[j]) matrix[j] = [];
1085
+ return matrix[j];
1086
+ }
1087
+ function findFirstVacantIndex(row, x = 0) {
1088
+ while (row[x]) x++;
1089
+ return x;
1090
+ }
1091
+ function transposeInPlace(matrix, maxSize) {
1092
+ for (let i = 0; i < maxSize; i++) {
1093
+ const rowI = getRow(matrix, i);
1094
+ for (let j = 0; j < i; j++) {
1095
+ const rowJ = getRow(matrix, j);
1096
+ if (rowI[j] || rowJ[i]) {
1097
+ const temp = rowI[j];
1098
+ rowI[j] = rowJ[i];
1099
+ rowJ[i] = temp;
1100
+ }
1101
+ }
1102
+ }
1103
+ }
1104
+ function putCellIntoLayout(cell, layout, baseRow, baseCol) {
1105
+ for (let r = 0; r < cell.rowspan; r++) {
1106
+ const layoutRow = getRow(layout, baseRow + r);
1107
+ for (let c = 0; c < cell.colspan; c++) layoutRow[baseCol + c] = cell;
1108
+ }
1109
+ }
1110
+ function getOrInitOffset(offsets, index) {
1111
+ if (offsets[index] === void 0) offsets[index] = index === 0 ? 0 : 1 + getOrInitOffset(offsets, index - 1);
1112
+ return offsets[index];
1113
+ }
1114
+ function updateOffset(offsets, base, span, value) {
1115
+ offsets[base + span] = Math.max(getOrInitOffset(offsets, base + span), getOrInitOffset(offsets, base) + value);
1116
+ }
1117
+ /**
1118
+ * Render a table into a string.
1119
+ * Cells can contain multiline text and span across multiple rows and columns.
1120
+ *
1121
+ * Modifies cells to add lines array.
1122
+ *
1123
+ * @param { TablePrinterCell[][] } tableRows Table to render.
1124
+ * @param { number } rowSpacing Number of spaces between columns.
1125
+ * @param { number } colSpacing Number of empty lines between rows.
1126
+ * @returns { string }
1127
+ */
1128
+ function tableToString(tableRows, rowSpacing, colSpacing) {
1129
+ const layout = [];
1130
+ let colNumber = 0;
1131
+ const rowNumber = tableRows.length;
1132
+ const rowOffsets = [0];
1133
+ for (let j = 0; j < rowNumber; j++) {
1134
+ const layoutRow = getRow(layout, j);
1135
+ const cells = tableRows[j];
1136
+ let x = 0;
1137
+ for (let i = 0; i < cells.length; i++) {
1138
+ const cell = cells[i];
1139
+ x = findFirstVacantIndex(layoutRow, x);
1140
+ putCellIntoLayout(cell, layout, j, x);
1141
+ x += cell.colspan;
1142
+ cell.lines = cell.text.split("\n");
1143
+ const cellHeight = cell.lines.length;
1144
+ updateOffset(rowOffsets, j, cell.rowspan, cellHeight + rowSpacing);
1145
+ }
1146
+ colNumber = layoutRow.length > colNumber ? layoutRow.length : colNumber;
1147
+ }
1148
+ transposeInPlace(layout, rowNumber > colNumber ? rowNumber : colNumber);
1149
+ const outputLines = [];
1150
+ const colOffsets = [0];
1151
+ for (let x = 0; x < colNumber; x++) {
1152
+ let y = 0;
1153
+ let cell;
1154
+ const rowsInThisColumn = Math.min(rowNumber, layout[x].length);
1155
+ while (y < rowsInThisColumn) {
1156
+ cell = layout[x][y];
1157
+ if (cell) {
1158
+ if (!cell.rendered) {
1159
+ let cellWidth = 0;
1160
+ for (let j = 0; j < cell.lines.length; j++) {
1161
+ const line = cell.lines[j];
1162
+ const lineOffset = rowOffsets[y] + j;
1163
+ outputLines[lineOffset] = (outputLines[lineOffset] || "").padEnd(colOffsets[x]) + line;
1164
+ cellWidth = line.length > cellWidth ? line.length : cellWidth;
1165
+ }
1166
+ updateOffset(colOffsets, x, cell.colspan, cellWidth + colSpacing);
1167
+ cell.rendered = true;
1168
+ }
1169
+ y += cell.rowspan;
1170
+ } else {
1171
+ const lineOffset = rowOffsets[y];
1172
+ outputLines[lineOffset] = outputLines[lineOffset] || "";
1173
+ y++;
1174
+ }
1175
+ }
1176
+ }
1177
+ return outputLines.join("\n");
1178
+ }
1179
+ /**
1180
+ * Process a line-break.
1181
+ *
1182
+ * @type { FormatCallback }
1183
+ */
1184
+ function formatLineBreak(elem, walk, builder, formatOptions) {
1185
+ builder.addLineBreak();
1186
+ }
1187
+ /**
1188
+ * Process a `wbr` tag (word break opportunity).
1189
+ *
1190
+ * @type { FormatCallback }
1191
+ */
1192
+ function formatWbr(elem, walk, builder, formatOptions) {
1193
+ builder.addWordBreakOpportunity();
1194
+ }
1195
+ /**
1196
+ * Process a horizontal line.
1197
+ *
1198
+ * @type { FormatCallback }
1199
+ */
1200
+ function formatHorizontalLine(elem, walk, builder, formatOptions) {
1201
+ builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });
1202
+ builder.addInline("-".repeat(formatOptions.length || builder.options.wordwrap || 40));
1203
+ builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });
1204
+ }
1205
+ /**
1206
+ * Process a paragraph.
1207
+ *
1208
+ * @type { FormatCallback }
1209
+ */
1210
+ function formatParagraph(elem, walk, builder, formatOptions) {
1211
+ builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });
1212
+ walk(elem.children, builder);
1213
+ builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });
1214
+ }
1215
+ /**
1216
+ * Process a preformatted content.
1217
+ *
1218
+ * @type { FormatCallback }
1219
+ */
1220
+ function formatPre(elem, walk, builder, formatOptions) {
1221
+ builder.openBlock({
1222
+ isPre: true,
1223
+ leadingLineBreaks: formatOptions.leadingLineBreaks || 2
1224
+ });
1225
+ walk(elem.children, builder);
1226
+ builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });
1227
+ }
1228
+ /**
1229
+ * Process a heading.
1230
+ *
1231
+ * @type { FormatCallback }
1232
+ */
1233
+ function formatHeading(elem, walk, builder, formatOptions) {
1234
+ builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });
1235
+ if (formatOptions.uppercase !== false) {
1236
+ builder.pushWordTransform((str) => str.toUpperCase());
1237
+ walk(elem.children, builder);
1238
+ builder.popWordTransform();
1239
+ } else walk(elem.children, builder);
1240
+ builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });
1241
+ }
1242
+ /**
1243
+ * Process a blockquote.
1244
+ *
1245
+ * @type { FormatCallback }
1246
+ */
1247
+ function formatBlockquote(elem, walk, builder, formatOptions) {
1248
+ builder.openBlock({
1249
+ leadingLineBreaks: formatOptions.leadingLineBreaks || 2,
1250
+ reservedLineLength: 2
1251
+ });
1252
+ walk(elem.children, builder);
1253
+ builder.closeBlock({
1254
+ trailingLineBreaks: formatOptions.trailingLineBreaks || 2,
1255
+ blockTransform: (str) => (formatOptions.trimEmptyLines !== false ? trimCharacter(str, "\n") : str).split("\n").map((line) => "> " + line).join("\n")
1256
+ });
1257
+ }
1258
+ function withBrackets(str, brackets) {
1259
+ if (!brackets) return str;
1260
+ const lbr = typeof brackets[0] === "string" ? brackets[0] : "[";
1261
+ const rbr = typeof brackets[1] === "string" ? brackets[1] : "]";
1262
+ return lbr + str + rbr;
1263
+ }
1264
+ function pathRewrite(path, rewriter, baseUrl, metadata, elem) {
1265
+ const modifiedPath = typeof rewriter === "function" ? rewriter(path, metadata, elem) : path;
1266
+ return modifiedPath[0] === "/" && baseUrl ? trimCharacterEnd(baseUrl, "/") + modifiedPath : modifiedPath;
1267
+ }
1268
+ /**
1269
+ * Process an image.
1270
+ *
1271
+ * @type { FormatCallback }
1272
+ */
1273
+ function formatImage(elem, walk, builder, formatOptions) {
1274
+ const attribs = elem.attribs || {};
1275
+ const alt = attribs.alt ? attribs.alt : "";
1276
+ const src = !attribs.src ? "" : pathRewrite(attribs.src, formatOptions.pathRewrite, formatOptions.baseUrl, builder.metadata, elem);
1277
+ const text = !src ? alt : !alt ? withBrackets(src, formatOptions.linkBrackets) : alt + " " + withBrackets(src, formatOptions.linkBrackets);
1278
+ builder.addInline(text, { noWordTransform: true });
1279
+ }
1280
+ /**
1281
+ * Process an anchor.
1282
+ *
1283
+ * @type { FormatCallback }
1284
+ */
1285
+ function formatAnchor(elem, walk, builder, formatOptions) {
1286
+ function getHref() {
1287
+ if (formatOptions.ignoreHref) return "";
1288
+ if (!elem.attribs || !elem.attribs.href) return "";
1289
+ let href = elem.attribs.href.replace(/^mailto:/, "");
1290
+ if (formatOptions.noAnchorUrl && href[0] === "#") return "";
1291
+ href = pathRewrite(href, formatOptions.pathRewrite, formatOptions.baseUrl, builder.metadata, elem);
1292
+ return href;
1293
+ }
1294
+ const href = getHref();
1295
+ if (!href) walk(elem.children, builder);
1296
+ else {
1297
+ let text = "";
1298
+ builder.pushWordTransform((str) => {
1299
+ if (str) text += str;
1300
+ return str;
1301
+ });
1302
+ walk(elem.children, builder);
1303
+ builder.popWordTransform();
1304
+ if (!(formatOptions.hideLinkHrefIfSameAsText && href === text)) builder.addInline(!text ? href : " " + withBrackets(href, formatOptions.linkBrackets), { noWordTransform: true });
1305
+ }
1306
+ }
1307
+ /**
1308
+ * @param { DomNode } elem List items with their prefixes.
1309
+ * @param { RecursiveCallback } walk Recursive callback to process child nodes.
1310
+ * @param { BlockTextBuilder } builder Passed around to accumulate output text.
1311
+ * @param { FormatOptions } formatOptions Options specific to a formatter.
1312
+ * @param { () => string } nextPrefixCallback Function that returns increasing index each time it is called.
1313
+ */
1314
+ function formatList(elem, walk, builder, formatOptions, nextPrefixCallback) {
1315
+ const isNestedList = get(elem, ["parent", "name"]) === "li";
1316
+ let maxPrefixLength = 0;
1317
+ const listItems = (elem.children || []).filter((child) => child.type !== "text" || !/^\s*$/.test(child.data)).map(function(child) {
1318
+ if (child.name !== "li") return {
1319
+ node: child,
1320
+ prefix: ""
1321
+ };
1322
+ const prefix = isNestedList ? nextPrefixCallback().trimStart() : nextPrefixCallback();
1323
+ if (prefix.length > maxPrefixLength) maxPrefixLength = prefix.length;
1324
+ return {
1325
+ node: child,
1326
+ prefix
1327
+ };
1328
+ });
1329
+ if (!listItems.length) return;
1330
+ builder.openList({
1331
+ interRowLineBreaks: 1,
1332
+ leadingLineBreaks: isNestedList ? 1 : formatOptions.leadingLineBreaks || 2,
1333
+ maxPrefixLength,
1334
+ prefixAlign: "left"
1335
+ });
1336
+ for (const { node, prefix } of listItems) {
1337
+ builder.openListItem({ prefix });
1338
+ walk([node], builder);
1339
+ builder.closeListItem();
1340
+ }
1341
+ builder.closeList({ trailingLineBreaks: isNestedList ? 1 : formatOptions.trailingLineBreaks || 2 });
1342
+ }
1343
+ /**
1344
+ * Process an unordered list.
1345
+ *
1346
+ * @type { FormatCallback }
1347
+ */
1348
+ function formatUnorderedList(elem, walk, builder, formatOptions) {
1349
+ const prefix = formatOptions.itemPrefix || " * ";
1350
+ return formatList(elem, walk, builder, formatOptions, () => prefix);
1351
+ }
1352
+ /**
1353
+ * Process an ordered list.
1354
+ *
1355
+ * @type { FormatCallback }
1356
+ */
1357
+ function formatOrderedList(elem, walk, builder, formatOptions) {
1358
+ let nextIndex = Number(elem.attribs.start || "1");
1359
+ const indexFunction = getOrderedListIndexFunction(elem.attribs.type);
1360
+ const nextPrefixCallback = () => " " + indexFunction(nextIndex++) + ". ";
1361
+ return formatList(elem, walk, builder, formatOptions, nextPrefixCallback);
1362
+ }
1363
+ /**
1364
+ * Return a function that can be used to generate index markers of a specified format.
1365
+ *
1366
+ * @param { string } [olType='1'] Marker type.
1367
+ * @returns { (i: number) => string }
1368
+ */
1369
+ function getOrderedListIndexFunction(olType = "1") {
1370
+ switch (olType) {
1371
+ case "a": return (i) => numberToLetterSequence(i, "a");
1372
+ case "A": return (i) => numberToLetterSequence(i, "A");
1373
+ case "i": return (i) => numberToRoman(i).toLowerCase();
1374
+ case "I": return (i) => numberToRoman(i);
1375
+ default: return (i) => i.toString();
1376
+ }
1377
+ }
1378
+ /**
1379
+ * Given a list of class and ID selectors (prefixed with '.' and '#'),
1380
+ * return them as separate lists of names without prefixes.
1381
+ *
1382
+ * @param { string[] } selectors Class and ID selectors (`[".class", "#id"]` etc).
1383
+ * @returns { { classes: string[], ids: string[] } }
1384
+ */
1385
+ function splitClassesAndIds(selectors) {
1386
+ const classes = [];
1387
+ const ids = [];
1388
+ for (const selector of selectors) if (selector.startsWith(".")) classes.push(selector.substring(1));
1389
+ else if (selector.startsWith("#")) ids.push(selector.substring(1));
1390
+ return {
1391
+ classes,
1392
+ ids
1393
+ };
1394
+ }
1395
+ function isDataTable(attr, tables) {
1396
+ if (tables === true) return true;
1397
+ if (!attr) return false;
1398
+ const { classes, ids } = splitClassesAndIds(tables);
1399
+ const attrClasses = (attr["class"] || "").split(" ");
1400
+ const attrIds = (attr["id"] || "").split(" ");
1401
+ return attrClasses.some((x) => classes.includes(x)) || attrIds.some((x) => ids.includes(x));
1402
+ }
1403
+ /**
1404
+ * Process a table (either as a container or as a data table, depending on options).
1405
+ *
1406
+ * @type { FormatCallback }
1407
+ */
1408
+ function formatTable(elem, walk, builder, formatOptions) {
1409
+ return isDataTable(elem.attribs, builder.options.tables) ? formatDataTable(elem, walk, builder, formatOptions) : formatBlock(elem, walk, builder, formatOptions);
1410
+ }
1411
+ function formatBlock(elem, walk, builder, formatOptions) {
1412
+ builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks });
1413
+ walk(elem.children, builder);
1414
+ builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks });
1415
+ }
1416
+ /**
1417
+ * Process a data table.
1418
+ *
1419
+ * @type { FormatCallback }
1420
+ */
1421
+ function formatDataTable(elem, walk, builder, formatOptions) {
1422
+ builder.openTable();
1423
+ elem.children.forEach(walkTable);
1424
+ builder.closeTable({
1425
+ tableToString: (rows) => tableToString(rows, formatOptions.rowSpacing ?? 0, formatOptions.colSpacing ?? 3),
1426
+ leadingLineBreaks: formatOptions.leadingLineBreaks,
1427
+ trailingLineBreaks: formatOptions.trailingLineBreaks
1428
+ });
1429
+ function formatCell(cellNode) {
1430
+ const colspan = +get(cellNode, ["attribs", "colspan"]) || 1;
1431
+ const rowspan = +get(cellNode, ["attribs", "rowspan"]) || 1;
1432
+ builder.openTableCell({ maxColumnWidth: formatOptions.maxColumnWidth });
1433
+ walk(cellNode.children, builder);
1434
+ builder.closeTableCell({
1435
+ colspan,
1436
+ rowspan
1437
+ });
1438
+ }
1439
+ function walkTable(elem) {
1440
+ if (elem.type !== "tag") return;
1441
+ const formatHeaderCell = formatOptions.uppercaseHeaderCells !== false ? (cellNode) => {
1442
+ builder.pushWordTransform((str) => str.toUpperCase());
1443
+ formatCell(cellNode);
1444
+ builder.popWordTransform();
1445
+ } : formatCell;
1446
+ switch (elem.name) {
1447
+ case "thead":
1448
+ case "tbody":
1449
+ case "tfoot":
1450
+ case "center":
1451
+ elem.children.forEach(walkTable);
1452
+ return;
1453
+ case "tr":
1454
+ builder.openTableRow();
1455
+ for (const childOfTr of elem.children) {
1456
+ if (childOfTr.type !== "tag") continue;
1457
+ switch (childOfTr.name) {
1458
+ case "th":
1459
+ formatHeaderCell(childOfTr);
1460
+ break;
1461
+ case "td": formatCell(childOfTr);
1462
+ }
1463
+ }
1464
+ builder.closeTableRow();
1465
+ }
1466
+ }
1467
+ }
1468
+ var textFormatters = /*#__PURE__*/ Object.freeze({
1469
+ __proto__: null,
1470
+ anchor: formatAnchor,
1471
+ blockquote: formatBlockquote,
1472
+ dataTable: formatDataTable,
1473
+ heading: formatHeading,
1474
+ horizontalLine: formatHorizontalLine,
1475
+ image: formatImage,
1476
+ lineBreak: formatLineBreak,
1477
+ orderedList: formatOrderedList,
1478
+ paragraph: formatParagraph,
1479
+ pre: formatPre,
1480
+ table: formatTable,
1481
+ unorderedList: formatUnorderedList,
1482
+ wbr: formatWbr
1483
+ });
1484
+ /**
1485
+ * Default options.
1486
+ *
1487
+ * @constant
1488
+ * @type { Options }
1489
+ * @default
1490
+ * @private
1491
+ */
1492
+ const DEFAULT_OPTIONS = {
1493
+ baseElements: {
1494
+ selectors: ["body"],
1495
+ orderBy: "selectors",
1496
+ returnDomByDefault: true
1497
+ },
1498
+ decodeEntities: true,
1499
+ encodeCharacters: {},
1500
+ formatters: {},
1501
+ limits: {
1502
+ ellipsis: "...",
1503
+ maxBaseElements: void 0,
1504
+ maxChildNodes: void 0,
1505
+ maxDepth: void 0,
1506
+ maxInputLength: 1 << 24
1507
+ },
1508
+ longWordSplit: {
1509
+ forceWrapOnLimit: false,
1510
+ wrapCharacters: []
1511
+ },
1512
+ preserveNewlines: false,
1513
+ selectors: [
1514
+ {
1515
+ selector: "*",
1516
+ format: "inline"
1517
+ },
1518
+ {
1519
+ selector: "a",
1520
+ format: "anchor",
1521
+ options: {
1522
+ baseUrl: null,
1523
+ hideLinkHrefIfSameAsText: false,
1524
+ ignoreHref: false,
1525
+ linkBrackets: ["[", "]"],
1526
+ noAnchorUrl: true
1527
+ }
1528
+ },
1529
+ {
1530
+ selector: "article",
1531
+ format: "block",
1532
+ options: {
1533
+ leadingLineBreaks: 1,
1534
+ trailingLineBreaks: 1
1535
+ }
1536
+ },
1537
+ {
1538
+ selector: "aside",
1539
+ format: "block",
1540
+ options: {
1541
+ leadingLineBreaks: 1,
1542
+ trailingLineBreaks: 1
1543
+ }
1544
+ },
1545
+ {
1546
+ selector: "blockquote",
1547
+ format: "blockquote",
1548
+ options: {
1549
+ leadingLineBreaks: 2,
1550
+ trailingLineBreaks: 2,
1551
+ trimEmptyLines: true
1552
+ }
1553
+ },
1554
+ {
1555
+ selector: "br",
1556
+ format: "lineBreak"
1557
+ },
1558
+ {
1559
+ selector: "div",
1560
+ format: "block",
1561
+ options: {
1562
+ leadingLineBreaks: 1,
1563
+ trailingLineBreaks: 1
1564
+ }
1565
+ },
1566
+ {
1567
+ selector: "footer",
1568
+ format: "block",
1569
+ options: {
1570
+ leadingLineBreaks: 1,
1571
+ trailingLineBreaks: 1
1572
+ }
1573
+ },
1574
+ {
1575
+ selector: "form",
1576
+ format: "block",
1577
+ options: {
1578
+ leadingLineBreaks: 1,
1579
+ trailingLineBreaks: 1
1580
+ }
1581
+ },
1582
+ {
1583
+ selector: "h1",
1584
+ format: "heading",
1585
+ options: {
1586
+ leadingLineBreaks: 3,
1587
+ trailingLineBreaks: 2,
1588
+ uppercase: true
1589
+ }
1590
+ },
1591
+ {
1592
+ selector: "h2",
1593
+ format: "heading",
1594
+ options: {
1595
+ leadingLineBreaks: 3,
1596
+ trailingLineBreaks: 2,
1597
+ uppercase: true
1598
+ }
1599
+ },
1600
+ {
1601
+ selector: "h3",
1602
+ format: "heading",
1603
+ options: {
1604
+ leadingLineBreaks: 3,
1605
+ trailingLineBreaks: 2,
1606
+ uppercase: true
1607
+ }
1608
+ },
1609
+ {
1610
+ selector: "h4",
1611
+ format: "heading",
1612
+ options: {
1613
+ leadingLineBreaks: 2,
1614
+ trailingLineBreaks: 2,
1615
+ uppercase: true
1616
+ }
1617
+ },
1618
+ {
1619
+ selector: "h5",
1620
+ format: "heading",
1621
+ options: {
1622
+ leadingLineBreaks: 2,
1623
+ trailingLineBreaks: 2,
1624
+ uppercase: true
1625
+ }
1626
+ },
1627
+ {
1628
+ selector: "h6",
1629
+ format: "heading",
1630
+ options: {
1631
+ leadingLineBreaks: 2,
1632
+ trailingLineBreaks: 2,
1633
+ uppercase: true
1634
+ }
1635
+ },
1636
+ {
1637
+ selector: "header",
1638
+ format: "block",
1639
+ options: {
1640
+ leadingLineBreaks: 1,
1641
+ trailingLineBreaks: 1
1642
+ }
1643
+ },
1644
+ {
1645
+ selector: "hr",
1646
+ format: "horizontalLine",
1647
+ options: {
1648
+ leadingLineBreaks: 2,
1649
+ length: void 0,
1650
+ trailingLineBreaks: 2
1651
+ }
1652
+ },
1653
+ {
1654
+ selector: "img",
1655
+ format: "image",
1656
+ options: {
1657
+ baseUrl: null,
1658
+ linkBrackets: ["[", "]"]
1659
+ }
1660
+ },
1661
+ {
1662
+ selector: "main",
1663
+ format: "block",
1664
+ options: {
1665
+ leadingLineBreaks: 1,
1666
+ trailingLineBreaks: 1
1667
+ }
1668
+ },
1669
+ {
1670
+ selector: "nav",
1671
+ format: "block",
1672
+ options: {
1673
+ leadingLineBreaks: 1,
1674
+ trailingLineBreaks: 1
1675
+ }
1676
+ },
1677
+ {
1678
+ selector: "ol",
1679
+ format: "orderedList",
1680
+ options: {
1681
+ leadingLineBreaks: 2,
1682
+ trailingLineBreaks: 2
1683
+ }
1684
+ },
1685
+ {
1686
+ selector: "p",
1687
+ format: "paragraph",
1688
+ options: {
1689
+ leadingLineBreaks: 2,
1690
+ trailingLineBreaks: 2
1691
+ }
1692
+ },
1693
+ {
1694
+ selector: "pre",
1695
+ format: "pre",
1696
+ options: {
1697
+ leadingLineBreaks: 2,
1698
+ trailingLineBreaks: 2
1699
+ }
1700
+ },
1701
+ {
1702
+ selector: "section",
1703
+ format: "block",
1704
+ options: {
1705
+ leadingLineBreaks: 1,
1706
+ trailingLineBreaks: 1
1707
+ }
1708
+ },
1709
+ {
1710
+ selector: "table",
1711
+ format: "table",
1712
+ options: {
1713
+ colSpacing: 3,
1714
+ leadingLineBreaks: 2,
1715
+ maxColumnWidth: 60,
1716
+ rowSpacing: 0,
1717
+ trailingLineBreaks: 2,
1718
+ uppercaseHeaderCells: true
1719
+ }
1720
+ },
1721
+ {
1722
+ selector: "ul",
1723
+ format: "unorderedList",
1724
+ options: {
1725
+ itemPrefix: " * ",
1726
+ leadingLineBreaks: 2,
1727
+ trailingLineBreaks: 2
1728
+ }
1729
+ },
1730
+ {
1731
+ selector: "wbr",
1732
+ format: "wbr"
1733
+ }
1734
+ ],
1735
+ tables: [],
1736
+ whitespaceCharacters: " \r\n\f​",
1737
+ wordwrap: 80
1738
+ };
1739
+ const concatMerge = (acc, src, options) => [...acc, ...src];
1740
+ const overwriteMerge = (acc, src, options) => [...src];
1741
+ const selectorsMerge = (acc, src, options) => acc.some((s) => typeof s === "object") ? concatMerge(acc, src) : overwriteMerge(acc, src);
1742
+ /**
1743
+ * Preprocess options, compile selectors into a decision tree,
1744
+ * return a function intended for batch processing.
1745
+ *
1746
+ * @param { Options } [options = {}] HtmlToText options.
1747
+ * @returns { (html: string, metadata?: any) => string } Pre-configured converter function.
1748
+ * @static
1749
+ */
1750
+ function compile(options = {}) {
1751
+ options = (0, import_cjs.default)(DEFAULT_OPTIONS, options, {
1752
+ arrayMerge: overwriteMerge,
1753
+ customMerge: (key) => key === "selectors" ? selectorsMerge : void 0
1754
+ });
1755
+ options.formatters = Object.assign({}, genericFormatters, textFormatters, options.formatters);
1756
+ options.selectors = mergeDuplicatesPreferLast(options.selectors, ((s) => s.selector));
1757
+ handleDeprecatedOptions(options);
1758
+ return compile$1(options);
1759
+ }
1760
+ /**
1761
+ * Convert given HTML content to plain text string.
1762
+ *
1763
+ * @param { string } html HTML content to convert.
1764
+ * @param { Options } [options = {}] HtmlToText options.
1765
+ * @param { any } [metadata] Optional metadata for HTML document, for use in formatters.
1766
+ * @returns { string } Plain text string.
1767
+ * @static
1768
+ *
1769
+ * @example
1770
+ * const { convert } = require('html-to-text');
1771
+ * const text = convert('<h1>Hello World</h1>', {
1772
+ * wordwrap: 130
1773
+ * });
1774
+ * console.log(text); // HELLO WORLD
1775
+ */
1776
+ function convert(html, options = {}, metadata = void 0) {
1777
+ return compile(options)(html, metadata);
1778
+ }
1779
+ /**
1780
+ * Map previously existing and now deprecated options to the new options layout.
1781
+ * This is a subject for cleanup in major releases.
1782
+ *
1783
+ * @param { Options } options HtmlToText options.
1784
+ */
1785
+ function handleDeprecatedOptions(options) {
1786
+ if (options.tags) {
1787
+ const tagDefinitions = Object.entries(options.tags).map(([selector, definition]) => ({
1788
+ ...definition,
1789
+ selector: selector || "*"
1790
+ }));
1791
+ options.selectors.push(...tagDefinitions);
1792
+ options.selectors = mergeDuplicatesPreferLast(options.selectors, ((s) => s.selector));
1793
+ }
1794
+ function set(obj, path, value) {
1795
+ const valueKey = path.pop();
1796
+ for (const key of path) {
1797
+ let nested = obj[key];
1798
+ if (!nested) {
1799
+ nested = {};
1800
+ obj[key] = nested;
1801
+ }
1802
+ obj = nested;
1803
+ }
1804
+ obj[valueKey] = value;
1805
+ }
1806
+ if (options["baseElement"]) {
1807
+ const baseElement = options["baseElement"];
1808
+ set(options, ["baseElements", "selectors"], Array.isArray(baseElement) ? baseElement : [baseElement]);
1809
+ }
1810
+ if (options["returnDomByDefault"] !== void 0) set(options, ["baseElements", "returnDomByDefault"], options["returnDomByDefault"]);
1811
+ for (const definition of options.selectors) if (definition.format === "anchor" && get(definition, ["options", "noLinkBrackets"])) set(definition, ["options", "linkBrackets"], false);
1812
+ }
1813
+ //#endregion
1814
+ export { compile, convert, convert as htmlToText };
1815
+
1816
+ //# sourceMappingURL=html-to-text.js.map