extract-webpage 1.2.5

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 (117) hide show
  1. package/README.md +212 -0
  2. package/dist/config/env.d.ts +6 -0
  3. package/dist/config/index.d.ts +23 -0
  4. package/dist/config/serverRegistry.d.ts +7 -0
  5. package/dist/config/types.d.ts +4 -0
  6. package/dist/extract-webpage.cjs.js +2 -0
  7. package/dist/extract-webpage.cjs.js.map +1 -0
  8. package/dist/extract-webpage.es.js +5 -0
  9. package/dist/extract-webpage.es.js.map +1 -0
  10. package/dist/html-to-cite/extract-author.d.ts +11 -0
  11. package/dist/html-to-cite/extract-cite.d.ts +33 -0
  12. package/dist/html-to-cite/extract-date/date-extractors.d.ts +40 -0
  13. package/dist/html-to-cite/extract-date/date-validators.d.ts +15 -0
  14. package/dist/html-to-cite/extract-date/extract-date-quick.d.ts +8 -0
  15. package/dist/html-to-cite/extract-date/extract-date.d.ts +26 -0
  16. package/dist/html-to-cite/extract-source.d.ts +7 -0
  17. package/dist/html-to-cite/extract-title.d.ts +11 -0
  18. package/dist/html-to-cite/human-names-recognize.d.ts +16 -0
  19. package/dist/html-to-cite/metadata-to-cite.d.ts +12 -0
  20. package/dist/html-to-cite/url-to-domain.d.ts +20 -0
  21. package/dist/html-to-content/extract-content/extract-content-mercury-utils.d.ts +27 -0
  22. package/dist/html-to-content/extract-content/extract-content-mercury.d.ts +61 -0
  23. package/dist/html-to-content/extract-content/extract-content-readability.d.ts +101 -0
  24. package/dist/html-to-content/html-to-basic-html.d.ts +36 -0
  25. package/dist/html-to-content/html-to-content.d.ts +51 -0
  26. package/dist/html-to-content/html-utils.d.ts +76 -0
  27. package/dist/index.d.ts +26 -0
  28. package/dist/search/index.d.ts +14 -0
  29. package/dist/search/meta-search-agent-reexport.d.ts +8 -0
  30. package/dist/search/public-searxng.d.ts +47 -0
  31. package/dist/search/search-web.d.ts +33 -0
  32. package/dist/search/tavily.d.ts +20 -0
  33. package/dist/search/url-to-html.d.ts +62 -0
  34. package/dist/seektopic/fold-keyphrases.d.ts +28 -0
  35. package/dist/seektopic/ngrams.d.ts +27 -0
  36. package/dist/seektopic/rank-sentences-keyphrases.d.ts +28 -0
  37. package/dist/seektopic/seektopic-keyphrases.d.ts +53 -0
  38. package/dist/seektopic/types.d.ts +86 -0
  39. package/dist/seektopic/vector-search.d.ts +89 -0
  40. package/dist/seektopic/weight-keyphrases.d.ts +22 -0
  41. package/dist/suggest-next-words/autocomplete-ai.d.ts +0 -0
  42. package/dist/suggest-next-words/autocomplete-search-engines.d.ts +64 -0
  43. package/dist/tokenize/suggest-complete-word.d.ts +48 -0
  44. package/dist/tokenize/text-to-chunks.d.ts +48 -0
  45. package/dist/tokenize/text-to-sentences.d.ts +35 -0
  46. package/dist/tokenize/text-to-topic-tokens.d.ts +51 -0
  47. package/dist/tokenize/word-is-ignored.d.ts +12 -0
  48. package/dist/tokenize/word-to-root-stem.d.ts +16 -0
  49. package/dist/url-to-content/docx-to-content.d.ts +22 -0
  50. package/dist/url-to-content/is-url-adult.d.ts +26 -0
  51. package/dist/url-to-content/url-to-content.d.ts +127 -0
  52. package/dist/url-to-content/url-to-html.d.ts +60 -0
  53. package/dist/url-to-content/youtube-helpers.d.ts +23 -0
  54. package/dist/url-to-content/youtube-to-text.d.ts +70 -0
  55. package/dist/utils/documents.d.ts +4 -0
  56. package/dist/utils/grab.d.ts +18 -0
  57. package/package.json +109 -0
  58. package/src/config/env.ts +8 -0
  59. package/src/config/index.ts +233 -0
  60. package/src/config/serverRegistry.ts +24 -0
  61. package/src/config/types.ts +17 -0
  62. package/src/fs-mock.js +22 -0
  63. package/src/global.d.ts +8 -0
  64. package/src/html-to-cite/extract-author.ts +125 -0
  65. package/src/html-to-cite/extract-cite.ts +97 -0
  66. package/src/html-to-cite/extract-date/date-extractors.ts +484 -0
  67. package/src/html-to-cite/extract-date/date-validators.ts +191 -0
  68. package/src/html-to-cite/extract-date/extract-date-quick.ts +184 -0
  69. package/src/html-to-cite/extract-date/extract-date.ts +1049 -0
  70. package/src/html-to-cite/extract-source.ts +30 -0
  71. package/src/html-to-cite/extract-title.ts +78 -0
  72. package/src/html-to-cite/human-names-92k.json +1 -0
  73. package/src/html-to-cite/human-names-recognize.ts +396 -0
  74. package/src/html-to-cite/metadata-to-cite.ts +73 -0
  75. package/src/html-to-cite/url-to-domain.ts +50 -0
  76. package/src/html-to-content/extract-content/extract-content-mercury-utils.ts +696 -0
  77. package/src/html-to-content/extract-content/extract-content-mercury.ts +830 -0
  78. package/src/html-to-content/extract-content/extract-content-readability.ts +432 -0
  79. package/src/html-to-content/extract-content/extract-selectors-per-domain.json +3453 -0
  80. package/src/html-to-content/html-to-basic-html.ts +282 -0
  81. package/src/html-to-content/html-to-content.ts +97 -0
  82. package/src/html-to-content/html-utils.ts +398 -0
  83. package/src/index.ts +29 -0
  84. package/src/search/__tests__/public-searxng.test.ts +529 -0
  85. package/src/search/index.ts +43 -0
  86. package/src/search/meta-search-agent-reexport.ts +38 -0
  87. package/src/search/public-searxng.ts +470 -0
  88. package/src/search/search-web.ts +668 -0
  89. package/src/search/tavily.ts +106 -0
  90. package/src/search/url-to-html.ts +278 -0
  91. package/src/seektopic/fold-keyphrases.ts +87 -0
  92. package/src/seektopic/ngrams.ts +64 -0
  93. package/src/seektopic/rank-sentences-keyphrases.ts +132 -0
  94. package/src/seektopic/seektopic-keyphrases.ts +279 -0
  95. package/src/seektopic/types.ts +92 -0
  96. package/src/seektopic/vector-search.ts +232 -0
  97. package/src/seektopic/weight-keyphrases.ts +59 -0
  98. package/src/suggest-next-words/autocomplete-ai.ts +38 -0
  99. package/src/suggest-next-words/autocomplete-search-engines.ts +435 -0
  100. package/src/tokenize/suggest-complete-word.ts +137 -0
  101. package/src/tokenize/text-to-chunks.ts +150 -0
  102. package/src/tokenize/text-to-sentences.ts +614 -0
  103. package/src/tokenize/text-to-topic-tokens.ts +175 -0
  104. package/src/tokenize/word-is-ignored.ts +53 -0
  105. package/src/tokenize/word-to-root-stem.ts +151 -0
  106. package/src/types.d.ts +130 -0
  107. package/src/url-to-content/.fuse_hidden003bd28a0000000d +332 -0
  108. package/src/url-to-content/__tests__/url-to-content.test.ts +368 -0
  109. package/src/url-to-content/__tests__/url-to-html.test.ts +301 -0
  110. package/src/url-to-content/docx-to-content.ts +702 -0
  111. package/src/url-to-content/is-url-adult.ts +318 -0
  112. package/src/url-to-content/url-to-content.ts +367 -0
  113. package/src/url-to-content/url-to-html.ts +436 -0
  114. package/src/url-to-content/youtube-helpers.ts +64 -0
  115. package/src/url-to-content/youtube-to-text.ts +468 -0
  116. package/src/utils/documents.ts +71 -0
  117. package/src/utils/grab.ts +51 -0
@@ -0,0 +1,696 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @module research/extractor/html-to-content/extract-content/extract-content-mercury-utils
4
+ * @description Research library module.
5
+ */
6
+ //HTML-to-Content Postlight Utilities
7
+
8
+ const SPACER_RE = new RegExp("transparent|spacer|blank", "i");
9
+ const KEEP_CLASS = "parser-keep";
10
+ const STRIP_OUTPUT_TAGS = [
11
+ "title",
12
+ "script",
13
+ "noscript",
14
+ "link",
15
+ "style",
16
+ "hr",
17
+ "embed",
18
+ "iframe",
19
+ "object",
20
+ ];
21
+ const WHITELIST_ATTRS = [
22
+ "src",
23
+ "srcset",
24
+ "sizes",
25
+ "type",
26
+ "href",
27
+ "class",
28
+ "id",
29
+ "alt",
30
+ "xlink:href",
31
+ "width",
32
+ "height",
33
+ ];
34
+ const WHITELIST_ATTRS_RE = new RegExp(`^(${WHITELIST_ATTRS.join("|")})$`, "i");
35
+ const REMOVE_EMPTY_TAGS = ["p"];
36
+ const REMOVE_EMPTY_SELECTORS = REMOVE_EMPTY_TAGS.map(
37
+ (tag) => `${tag}:empty`
38
+ ).join(",");
39
+ const UNLIKELY_CANDIDATES_BLACKLIST = [
40
+ "ad-break",
41
+ "adbox",
42
+ "advert",
43
+ "addthis",
44
+ "agegate",
45
+ "aux",
46
+ "blogger-labels",
47
+ "combx",
48
+ "comment",
49
+ "conversation",
50
+ "disqus",
51
+ "entry-unrelated",
52
+ "extra",
53
+ "foot",
54
+ "header",
55
+ "hidden",
56
+ "loader",
57
+ "login",
58
+ "menu",
59
+ "meta",
60
+ "nav",
61
+ "outbrain",
62
+ "pager",
63
+ "pagination",
64
+ "predicta",
65
+ "presence_control_external",
66
+ "popup",
67
+ "printfriendly",
68
+ "related",
69
+ "remove",
70
+ "remark",
71
+ "rss",
72
+ "share",
73
+ "shoutbox",
74
+ "sidebar",
75
+ "sociable",
76
+ "sponsor",
77
+ "taboola",
78
+ "tools",
79
+ ];
80
+ const UNLIKELY_CANDIDATES_WHITELIST = [
81
+ "and",
82
+ "article",
83
+ "body",
84
+ "blogindex",
85
+ "column",
86
+ "content",
87
+ "entry-content-asset",
88
+ "format",
89
+ "hfeed",
90
+ "hentry",
91
+ "hatom",
92
+ "main",
93
+ "page",
94
+ "posts",
95
+ "shadow",
96
+ ];
97
+ const DIV_TO_P_BLOCK_TAGS = [
98
+ "a",
99
+ "blockquote",
100
+ "dl",
101
+ "div",
102
+ "img",
103
+ "p",
104
+ "pre",
105
+ "table",
106
+ ].join(",");
107
+ const NON_TOP_CANDIDATE_TAGS = [
108
+ "br",
109
+ "b",
110
+ "i",
111
+ "label",
112
+ "hr",
113
+ "area",
114
+ "base",
115
+ "basefont",
116
+ "input",
117
+ "img",
118
+ "link",
119
+ "meta",
120
+ ];
121
+ const NON_TOP_CANDIDATE_TAGS_RE = new RegExp(
122
+ `^(${NON_TOP_CANDIDATE_TAGS.join("|")})$`,
123
+ "i"
124
+ );
125
+ const HNEWS_CONTENT_SELECTORS = [
126
+ [".hentry", ".entry-content"],
127
+ ["entry", ".entry-content"],
128
+ [".entry", ".entry_content"],
129
+ [".post", ".postbody"],
130
+ [".post", ".post_body"],
131
+ [".post", ".post-body"],
132
+ ];
133
+ const PHOTO_HINTS = ["figure", "photo", "image", "caption"];
134
+ const PHOTO_HINTS_RE = new RegExp(PHOTO_HINTS.join("|"), "i");
135
+ const POSITIVE_SCORE_HINTS = [
136
+ "article",
137
+ "articlecontent",
138
+ "instapaper_body",
139
+ "blog",
140
+ "body",
141
+ "content",
142
+ "entry-content-asset",
143
+ "entry",
144
+ "hentry",
145
+ "main",
146
+ "Normal",
147
+ "page",
148
+ "pagination",
149
+ "permalink",
150
+ "post",
151
+ "story",
152
+ "text",
153
+ "[-_]copy",
154
+ "\\Bcopy",
155
+ ];
156
+ const POSITIVE_SCORE_RE = new RegExp(POSITIVE_SCORE_HINTS.join("|"), "i");
157
+ const READABILITY_ASSET = new RegExp("entry-content-asset", "i");
158
+ const NEGATIVE_SCORE_HINTS = [
159
+ "adbox",
160
+ "advert",
161
+ "author",
162
+ "bio",
163
+ "bookmark",
164
+ "bottom",
165
+ "byline",
166
+ "clear",
167
+ "com-",
168
+ "combx",
169
+ "comment",
170
+ "comment\\B",
171
+ "contact",
172
+ "copy",
173
+ "credit",
174
+ "crumb",
175
+ "date",
176
+ "deck",
177
+ "excerpt",
178
+ "featured",
179
+ "foot",
180
+ "footer",
181
+ "footnote",
182
+ "graf",
183
+ "head",
184
+ "info",
185
+ "infotext",
186
+ "instapaper_ignore",
187
+ "jump",
188
+ "linebreak",
189
+ "link",
190
+ "masthead",
191
+ "media",
192
+ "meta",
193
+ "modal",
194
+ "outbrain",
195
+ "promo",
196
+ "pr_",
197
+ "related",
198
+ "respond",
199
+ "roundcontent",
200
+ "scroll",
201
+ "secondary",
202
+ "share",
203
+ "shopping",
204
+ "shoutbox",
205
+ "side",
206
+ "sidebar",
207
+ "sponsor",
208
+ "stamp",
209
+ "sub",
210
+ "summary",
211
+ "tags",
212
+ "tools",
213
+ "widget",
214
+ ];
215
+ const NEGATIVE_SCORE_RE = new RegExp(NEGATIVE_SCORE_HINTS.join("|"), "i");
216
+ const IS_WP_SELECTOR = "meta[name=generator][value^=WordPress]";
217
+ const DIGIT_RE = new RegExp("[0-9]");
218
+ const EXTRANEOUS_LINK_HINTS = [
219
+ "print",
220
+ "archive",
221
+ "comment",
222
+ "discuss",
223
+ "e-mail",
224
+ "email",
225
+ "share",
226
+ "reply",
227
+ "all",
228
+ "login",
229
+ "sign",
230
+ "single",
231
+ "adx",
232
+ "entry-unrelated",
233
+ ];
234
+ const BLOCK_LEVEL_TAGS = [
235
+ "article",
236
+ "aside",
237
+ "blockquote",
238
+ "body",
239
+ "br",
240
+ "button",
241
+ "canvas",
242
+ "caption",
243
+ "col",
244
+ "colgroup",
245
+ "dd",
246
+ "div",
247
+ "dl",
248
+ "dt",
249
+ "embed",
250
+ "fieldset",
251
+ "figcaption",
252
+ "figure",
253
+ "footer",
254
+ "form",
255
+ "h1",
256
+ "h2",
257
+ "h3",
258
+ "h4",
259
+ "h5",
260
+ "h6",
261
+ "header",
262
+ "hgroup",
263
+ "hr",
264
+ "li",
265
+ "map",
266
+ "object",
267
+ "ol",
268
+ "output",
269
+ "p",
270
+ "pre",
271
+ "progress",
272
+ "section",
273
+ "table",
274
+ "tbody",
275
+ "textarea",
276
+ "tfoot",
277
+ "th",
278
+ "thead",
279
+ "tr",
280
+ "ul",
281
+ "video",
282
+ ];
283
+ const BLOCK_LEVEL_TAGS_RE = new RegExp(
284
+ `^(${BLOCK_LEVEL_TAGS.join("|")})$`,
285
+ "i"
286
+ );
287
+ const candidatesBlacklist = UNLIKELY_CANDIDATES_BLACKLIST.join("|");
288
+ const CANDIDATES_BLACKLIST = new RegExp(candidatesBlacklist, "i");
289
+ const candidatesWhitelist = UNLIKELY_CANDIDATES_WHITELIST.join("|");
290
+ const CANDIDATES_WHITELIST = new RegExp(candidatesWhitelist, "i");
291
+
292
+
293
+ function normalizeSpaces(text) {
294
+ return text.replace(/\s{2,}(?![^<>]*<\/(pre|code|textarea)>)/g, " ").trim();
295
+ }
296
+
297
+
298
+ function paragraphize(node, document, br = false) {
299
+ if (br) {
300
+ let sibling = node.nextSibling;
301
+ const p = document.createElement("p");
302
+
303
+ while (
304
+ sibling &&
305
+ !(sibling.tagName && BLOCK_LEVEL_TAGS_RE.test(sibling.tagName))
306
+ ) {
307
+ const { nextSibling } = sibling;
308
+ p.appendChild(sibling);
309
+ sibling = nextSibling;
310
+ }
311
+
312
+ node.parentNode?.replaceChild(p, node);
313
+ node.remove();
314
+ return document;
315
+ }
316
+
317
+ return document;
318
+ }
319
+
320
+
321
+ function getAttrs(node) {
322
+ return node.attributes
323
+ ? Array.from(node.attributes).reduce((acc, attr) => {
324
+ acc[attr.name] = attr.value;
325
+ return acc;
326
+ }, {})
327
+ : {};
328
+ }
329
+
330
+
331
+ function convertNodeTo(node, document, tag = "p") {
332
+ if (!node) {
333
+ return document;
334
+ }
335
+ const attrs = getAttrs(node);
336
+
337
+ const attribString = Object.keys(attrs)
338
+ .map((key) => `${key}="${attrs[key]}"`)
339
+ .join(" ");
340
+ const html =
341
+ node.tagName.toLowerCase() === "noscript"
342
+ ? node.textContent
343
+ : node.innerHTML;
344
+
345
+ const newElement = document.createElement(tag);
346
+ newElement.innerHTML = html;
347
+ Object.keys(attrs).forEach((key) => newElement.setAttribute(key, attrs[key]));
348
+
349
+ node.parentNode?.replaceChild(newElement, node);
350
+ return document;
351
+ }
352
+
353
+
354
+ function brsToPs(document) {
355
+ let collapsing = false;
356
+ document.querySelectorAll("br").forEach((element) => {
357
+ const nextElement = element.nextElementSibling;
358
+
359
+ if (nextElement && nextElement.tagName.toLowerCase() === "br") {
360
+ collapsing = true;
361
+ element.remove();
362
+ } else if (collapsing) {
363
+ collapsing = false;
364
+ paragraphize(element, document, true);
365
+ }
366
+ });
367
+
368
+ return document;
369
+ }
370
+
371
+
372
+ function convertDivs(document) {
373
+ document.querySelectorAll("div").forEach((div) => {
374
+ const convertible = div.querySelectorAll(DIV_TO_P_BLOCK_TAGS).length === 0;
375
+
376
+ if (convertible) {
377
+ convertNodeTo(div, document, "p");
378
+ }
379
+ });
380
+
381
+ return document;
382
+ }
383
+
384
+
385
+ function convertSpans(document) {
386
+ document.querySelectorAll("span").forEach((span) => {
387
+ const convertible = !span.closest("p, div, li, figcaption");
388
+ if (convertible) {
389
+ convertNodeTo(span, document, "p");
390
+ }
391
+ });
392
+
393
+ return document;
394
+ }
395
+
396
+
397
+ function convertToParagraphs(document) {
398
+ document = brsToPs(document);
399
+ document = convertDivs(document);
400
+ document = convertSpans(document);
401
+
402
+ return document;
403
+ }
404
+
405
+
406
+ function cleanForHeight(img, document) {
407
+ const height = parseInt(img.getAttribute("height"), 10);
408
+ const width = parseInt(img.getAttribute("width"), 10) || 20;
409
+
410
+ if ((height || 20) < 10 || width < 10) {
411
+ img.remove();
412
+ } else if (height) {
413
+ img.removeAttribute("height");
414
+ }
415
+
416
+ return document;
417
+ }
418
+
419
+
420
+ function removeSpacers(img, document) {
421
+ if (SPACER_RE.test(img.getAttribute("src"))) {
422
+ img.remove();
423
+ }
424
+
425
+ return document;
426
+ }
427
+
428
+
429
+ function cleanImages(article, document) {
430
+ article.querySelectorAll("img").forEach((img) => {
431
+ cleanForHeight(img, document);
432
+ removeSpacers(img, document);
433
+ });
434
+
435
+ return document;
436
+ }
437
+
438
+
439
+ function stripJunkTags(article, document, tags = []) {
440
+ if (tags.length === 0) {
441
+ tags = STRIP_OUTPUT_TAGS;
442
+ }
443
+
444
+ article.querySelectorAll(tags.join(",")).forEach((element) => {
445
+ if (!element.classList.contains(KEEP_CLASS)) {
446
+ element.remove();
447
+ }
448
+ });
449
+
450
+ return document;
451
+ }
452
+
453
+
454
+ function cleanHOnes(article, document) {
455
+ const hOnes = article.querySelectorAll("h1");
456
+
457
+ if (hOnes.length < 3) {
458
+ hOnes.forEach((node) => node.remove());
459
+ } else {
460
+ hOnes.forEach((node) => {
461
+ convertNodeTo(node, document, "h2");
462
+ });
463
+ }
464
+
465
+ return document;
466
+ }
467
+
468
+
469
+ function cleanAttributes(article, document) {
470
+ return removeAllButWhitelist(
471
+ article.parentNode ? article.parentNode : article,
472
+ document
473
+ );
474
+ }
475
+
476
+ function removeAllButWhitelist(article) {
477
+ article.querySelectorAll("*").forEach((node) => {
478
+ const attrs = getAttrs(node);
479
+
480
+ setAttrs(
481
+ node,
482
+ Object.keys(attrs).reduce((acc, attr) => {
483
+ if (WHITELIST_ATTRS_RE.test(attr)) {
484
+ return { ...acc, [attr]: attrs[attr] };
485
+ }
486
+
487
+ return acc;
488
+ }, {})
489
+ );
490
+ });
491
+
492
+ article.querySelectorAll(`.${KEEP_CLASS}`).forEach((node) => {
493
+ node.classList.remove(KEEP_CLASS);
494
+ });
495
+
496
+ return article;
497
+ }
498
+
499
+
500
+ function removeEmpty(article) {
501
+ article.querySelectorAll("p").forEach((p) => {
502
+ if (
503
+ p.querySelectorAll("iframe, img").length === 0 &&
504
+ p.textContent.trim() === ""
505
+ )
506
+ p.remove();
507
+ });
508
+
509
+ return article;
510
+ }
511
+
512
+
513
+ function removeUnlessContent(node, weight) {
514
+ if (node.classList.contains("entry-content-asset")) {
515
+ return;
516
+ }
517
+
518
+ const content = normalizeSpaces(node.textContent);
519
+
520
+ if (content.match(/,/g)?.length < 10) {
521
+ const pCount = node.querySelectorAll("p").length;
522
+ const inputCount = node.querySelectorAll("input").length;
523
+
524
+ if (inputCount > pCount / 3) {
525
+ node.remove();
526
+ return;
527
+ }
528
+
529
+ const contentLength = content.length;
530
+ const imgCount = node.querySelectorAll("img").length;
531
+
532
+ if (contentLength < 25 && imgCount === 0) {
533
+ node.remove();
534
+ return;
535
+ }
536
+
537
+ const density = linkDensity(node);
538
+
539
+ if (weight < 25 && density > 0.2 && contentLength > 75) {
540
+ node.remove();
541
+ return;
542
+ }
543
+
544
+ if (weight >= 25 && density > 0.5) {
545
+ const tagName = node.tagName.toLowerCase();
546
+ const nodeIsList = tagName === "ol" || tagName === "ul";
547
+ if (nodeIsList) {
548
+ const previousNode = node.previousElementSibling;
549
+ if (
550
+ previousNode &&
551
+ normalizeSpaces(previousNode.textContent).slice(-1) === ":"
552
+ ) {
553
+ return;
554
+ }
555
+ }
556
+
557
+ node.remove();
558
+ return;
559
+ }
560
+
561
+ const scriptCount = node.querySelectorAll("script").length;
562
+
563
+ if (scriptCount > 0 && contentLength < 150) {
564
+ node.remove();
565
+ }
566
+ }
567
+ }
568
+
569
+
570
+ function rewriteTopLevel(article, document) {
571
+ // document.documentElement.outerHTML = `<div>${document.documentElement.innerHTML}</div>`;
572
+ document.body.outerHTML = `<div>${document.body.innerHTML}</div>`;
573
+
574
+ return document;
575
+ }
576
+
577
+
578
+ function textLength(text) {
579
+ return text.trim().replace(/\s+/g, " ").length;
580
+ }
581
+
582
+
583
+ function linkDensity(node) {
584
+ const totalTextLength = textLength(node.textContent);
585
+
586
+ const linkText = Array.from(node.querySelectorAll("a"))
587
+ .map((a) => a.textContent)
588
+ .join(" ");
589
+ const linkLength = textLength(linkText);
590
+
591
+ if (totalTextLength > 0) {
592
+ return linkLength / totalTextLength;
593
+ }
594
+ if (totalTextLength === 0 && linkLength > 0) {
595
+ return 1;
596
+ }
597
+
598
+ return 0;
599
+ }
600
+
601
+
602
+ function stripTags(text, document) {
603
+ const span = document.createElement("span");
604
+ span.innerHTML = text;
605
+ const cleanText = span.textContent;
606
+ return cleanText === "" ? text : cleanText;
607
+ }
608
+
609
+
610
+ function stripUnlikelyCandidates(document) {
611
+ document.querySelectorAll("*:not(a)").forEach((node) => {
612
+ const classes = node.getAttribute("class");
613
+ const id = node.getAttribute("id");
614
+ if (!id && !classes) return;
615
+
616
+ const classAndId = `${classes || ""} ${id || ""}`;
617
+ if (CANDIDATES_WHITELIST.test(classAndId)) {
618
+ return;
619
+ }
620
+ if (CANDIDATES_BLACKLIST.test(classAndId)) {
621
+ node.remove();
622
+ }
623
+ });
624
+
625
+ return document;
626
+ }
627
+
628
+
629
+ function withinComment(node) {
630
+ let parent = node.parentNode;
631
+ while (parent) {
632
+ const attrs = getAttrs(parent);
633
+ const { class: nodeClass, id } = attrs;
634
+ const classAndId = `${nodeClass} ${id}`;
635
+ if (classAndId.includes("comment")) {
636
+ return true;
637
+ }
638
+ parent = parent.parentNode;
639
+ }
640
+
641
+ return false;
642
+ }
643
+
644
+
645
+ function nodeIsSufficient(node) {
646
+ return node.textContent.trim().length >= 100;
647
+ }
648
+
649
+
650
+ function isWordpress(document) {
651
+ return document.querySelectorAll(IS_WP_SELECTOR).length > 0;
652
+ }
653
+
654
+
655
+ function setAttr(node, attr, val) {
656
+ node.setAttribute(attr, val);
657
+ return node;
658
+ }
659
+
660
+
661
+ function setAttrs(node, attrs) {
662
+ while (node.attributes.length > 0) {
663
+ node.removeAttribute(node.attributes[0].name);
664
+ }
665
+
666
+ Object.keys(attrs).forEach((key) => {
667
+ node.setAttribute(key, attrs[key]);
668
+ });
669
+
670
+ return node;
671
+ }
672
+
673
+ export {
674
+ normalizeSpaces,
675
+ paragraphize,
676
+ getAttrs,
677
+ convertNodeTo,
678
+ brsToPs,
679
+ convertToParagraphs,
680
+ cleanImages,
681
+ stripJunkTags,
682
+ cleanHOnes,
683
+ cleanAttributes,
684
+ removeEmpty,
685
+ rewriteTopLevel,
686
+ textLength,
687
+ linkDensity,
688
+ stripTags,
689
+ stripUnlikelyCandidates,
690
+ withinComment,
691
+ nodeIsSufficient,
692
+ isWordpress,
693
+ setAttr,
694
+ removeUnlessContent,
695
+ setAttrs,
696
+ };