webforai 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -1
- package/dist/adapters/index.js +58 -0
- package/dist/adapters/registry.js +149 -0
- package/dist/adapters/sites/declarative.js +178 -0
- package/dist/adapters/sites/hackernews.js +94 -0
- package/dist/adapters/sites/youtube.js +165 -0
- package/dist/adapters/types.js +0 -0
- package/dist/bin.js +3199 -399
- package/dist/cjs/adapters/index.js +86 -0
- package/dist/cjs/adapters/registry.js +178 -0
- package/dist/cjs/adapters/sites/declarative.js +202 -0
- package/dist/cjs/adapters/sites/hackernews.js +117 -0
- package/dist/cjs/adapters/sites/youtube.js +191 -0
- package/dist/cjs/adapters/types.js +16 -0
- package/dist/cjs/constants.js +2 -2
- package/dist/cjs/extractors/index.js +8 -0
- package/dist/cjs/extractors/lib/constants.js +186 -0
- package/dist/cjs/extractors/lib/sanitize.js +425 -0
- package/dist/cjs/extractors/lib/score.js +264 -0
- package/dist/cjs/extractors/lib/terminators.js +131 -0
- package/dist/cjs/extractors/lib/ui-chrome.js +119 -0
- package/dist/cjs/extractors/pipeExtractors.js +12 -9
- package/dist/cjs/extractors/presets/auto.js +44 -0
- package/dist/cjs/extractors/presets/minimal-filter.js +27 -48
- package/dist/cjs/extractors/presets/takumi.js +84 -122
- package/dist/cjs/html-to-markdown.js +44 -7
- package/dist/cjs/html-to-mdast.js +9 -1
- package/dist/cjs/index.js +33 -2
- package/dist/cjs/mdast-handlers/custom-a-handler.js +25 -9
- package/dist/cjs/mdast-handlers/custom-img-handler.js +23 -1
- package/dist/cjs/mdast-handlers/custom-table-handler.js +16 -0
- package/dist/cjs/mdast-handlers/definition-list-handler.js +99 -0
- package/dist/cjs/mdast-handlers/math-handler.js +12 -3
- package/dist/cjs/mdast-handlers/sup-sub-handler.js +39 -0
- package/dist/cjs/metadata/index.js +223 -0
- package/dist/cjs/normalize/index.js +168 -0
- package/dist/cjs/platform/client.js +147 -0
- package/dist/cjs/platform/error.js +36 -0
- package/dist/cjs/platform/fetch.js +37 -0
- package/dist/cjs/platform/index.js +40 -0
- package/dist/cjs/platform/types.js +34 -0
- package/dist/cjs/utils/hast-fast.js +284 -0
- package/dist/constants.js +2 -2
- package/dist/extractors/index.js +5 -0
- package/dist/extractors/lib/constants.js +150 -0
- package/dist/extractors/lib/sanitize.js +415 -0
- package/dist/extractors/lib/score.js +242 -0
- package/dist/extractors/lib/terminators.js +107 -0
- package/dist/extractors/lib/ui-chrome.js +96 -0
- package/dist/extractors/pipeExtractors.js +12 -9
- package/dist/extractors/presets/auto.js +20 -0
- package/dist/extractors/presets/minimal-filter.js +35 -47
- package/dist/extractors/presets/takumi.js +91 -122
- package/dist/html-to-markdown.js +42 -6
- package/dist/html-to-mdast.js +9 -1
- package/dist/index.js +34 -3
- package/dist/mdast-handlers/custom-a-handler.js +25 -9
- package/dist/mdast-handlers/custom-img-handler.js +23 -1
- package/dist/mdast-handlers/custom-table-handler.js +16 -0
- package/dist/mdast-handlers/definition-list-handler.js +76 -0
- package/dist/mdast-handlers/math-handler.js +12 -3
- package/dist/mdast-handlers/sup-sub-handler.js +16 -0
- package/dist/metadata/index.js +198 -0
- package/dist/normalize/index.js +149 -0
- package/dist/platform/client.js +125 -0
- package/dist/platform/error.js +13 -0
- package/dist/platform/fetch.js +14 -0
- package/dist/platform/index.js +19 -0
- package/dist/platform/types.js +9 -0
- package/dist/types/adapters/index.d.ts +24 -0
- package/dist/types/adapters/index.js.map +1 -0
- package/dist/types/adapters/registry.d.ts +35 -0
- package/dist/types/adapters/registry.js.map +1 -0
- package/dist/types/adapters/sites/declarative.d.ts +13 -0
- package/dist/types/adapters/sites/declarative.js.map +1 -0
- package/dist/types/adapters/sites/hackernews.d.ts +13 -0
- package/dist/types/adapters/sites/hackernews.js.map +1 -0
- package/dist/types/adapters/sites/youtube.d.ts +31 -0
- package/dist/types/adapters/sites/youtube.js.map +1 -0
- package/dist/types/adapters/types.d.ts +99 -0
- package/dist/types/adapters/types.js.map +1 -0
- package/dist/types/cli/bin.js.map +1 -1
- package/dist/types/cli/commands/skill/content.d.ts +9 -0
- package/dist/types/cli/commands/skill/content.js.map +1 -0
- package/dist/types/cli/commands/skill/index.d.ts +19 -0
- package/dist/types/cli/commands/skill/index.js.map +1 -0
- package/dist/types/cli/commands/webforai/interactive.d.ts +7 -0
- package/dist/types/cli/commands/webforai/interactive.js.map +1 -0
- package/dist/types/cli/commands/webforai/loadHtml.js.map +1 -1
- package/dist/types/cli/commands/webforai/options.d.ts +55 -0
- package/dist/types/cli/commands/webforai/options.js.map +1 -0
- package/dist/types/cli/commands/webforai/run.d.ts +10 -0
- package/dist/types/cli/commands/webforai/run.js.map +1 -0
- package/dist/types/cli/constants.d.ts +14 -4
- package/dist/types/cli/constants.js.map +1 -1
- package/dist/types/cli/helpers/selectExtractMode.js.map +1 -1
- package/dist/types/cli/helpers/selectLoader.js.map +1 -1
- package/dist/types/constants.d.ts +7 -1
- package/dist/types/constants.js.map +1 -1
- package/dist/types/extractors/index.d.ts +2 -0
- package/dist/types/extractors/index.js.map +1 -1
- package/dist/types/extractors/lib/constants.d.ts +81 -0
- package/dist/types/extractors/lib/constants.js.map +1 -0
- package/dist/types/extractors/lib/sanitize.d.ts +66 -0
- package/dist/types/extractors/lib/sanitize.js.map +1 -0
- package/dist/types/extractors/lib/score.d.ts +85 -0
- package/dist/types/extractors/lib/score.js.map +1 -0
- package/dist/types/extractors/lib/terminators.d.ts +26 -0
- package/dist/types/extractors/lib/terminators.js.map +1 -0
- package/dist/types/extractors/lib/ui-chrome.d.ts +18 -0
- package/dist/types/extractors/lib/ui-chrome.js.map +1 -0
- package/dist/types/extractors/pipeExtractors.d.ts +5 -0
- package/dist/types/extractors/pipeExtractors.js.map +1 -1
- package/dist/types/extractors/presets/auto.d.ts +30 -0
- package/dist/types/extractors/presets/auto.js.map +1 -0
- package/dist/types/extractors/presets/minimal-filter.d.ts +10 -2
- package/dist/types/extractors/presets/minimal-filter.js.map +1 -1
- package/dist/types/extractors/presets/takumi.d.ts +19 -3
- package/dist/types/extractors/presets/takumi.js.map +1 -1
- package/dist/types/extractors/types.d.ts +8 -0
- package/dist/types/html-to-markdown.d.ts +38 -0
- package/dist/types/html-to-markdown.js.map +1 -1
- package/dist/types/html-to-mdast.d.ts +11 -0
- package/dist/types/html-to-mdast.js.map +1 -1
- package/dist/types/index.d.ts +6 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/mdast-handlers/custom-a-handler.js.map +1 -1
- package/dist/types/mdast-handlers/custom-img-handler.js.map +1 -1
- package/dist/types/mdast-handlers/custom-table-handler.js.map +1 -1
- package/dist/types/mdast-handlers/definition-list-handler.d.ts +13 -0
- package/dist/types/mdast-handlers/definition-list-handler.js.map +1 -0
- package/dist/types/mdast-handlers/math-handler.js.map +1 -1
- package/dist/types/mdast-handlers/sup-sub-handler.d.ts +10 -0
- package/dist/types/mdast-handlers/sup-sub-handler.js.map +1 -0
- package/dist/types/metadata/index.d.ts +47 -0
- package/dist/types/metadata/index.js.map +1 -0
- package/dist/types/normalize/index.d.ts +53 -0
- package/dist/types/normalize/index.js.map +1 -0
- package/dist/types/platform/client.d.ts +54 -0
- package/dist/types/platform/client.js.map +1 -0
- package/dist/types/platform/error.d.ts +20 -0
- package/dist/types/platform/error.js.map +1 -0
- package/dist/types/platform/fetch.d.ts +34 -0
- package/dist/types/platform/fetch.js.map +1 -0
- package/dist/types/platform/index.d.ts +4 -0
- package/dist/types/platform/index.js.map +1 -0
- package/dist/types/platform/types.d.ts +135 -0
- package/dist/types/platform/types.js.map +1 -0
- package/dist/types/utils/hast-fast.d.ts +101 -0
- package/dist/types/utils/hast-fast.js.map +1 -0
- package/dist/utils/hast-fast.js +246 -0
- package/package.json +10 -3
- package/dist/types/cli/commands/webforai/index.d.ts +0 -6
- package/dist/types/cli/commands/webforai/index.js.map +0 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var terminators_exports = {};
|
|
20
|
+
__export(terminators_exports, {
|
|
21
|
+
TERMINATOR_TAIL_FRACTION: () => TERMINATOR_TAIL_FRACTION,
|
|
22
|
+
truncateTrailingBoilerplate: () => truncateTrailingBoilerplate
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(terminators_exports);
|
|
25
|
+
var import_hast_fast = require("../../utils/hast-fast");
|
|
26
|
+
const TERMINATOR_PATTERNS = [
|
|
27
|
+
/^was this (page|article|document) helpful/i,
|
|
28
|
+
/^thanks for the feedback/i,
|
|
29
|
+
/^(this page was )?last (modified|updated) (on|at|:)?\s/i,
|
|
30
|
+
/^learn how to contribute/i,
|
|
31
|
+
/^help (us )?improve\b/i,
|
|
32
|
+
// The stranded Yes/No pair of a feedback widget whose question was removed separately.
|
|
33
|
+
/^yes ?no$/i,
|
|
34
|
+
/^(related (articles?|posts?|stories|content)|you might also like|recommended for you|more from|read next)$/i,
|
|
35
|
+
/^(comments?|leave a (comment|reply)|join the (conversation|discussion))$/i,
|
|
36
|
+
/^(この(ページ|記事)は(参考|役に立ち)ました?か)/,
|
|
37
|
+
/^(関連記事|あわせて読みたい|こちらもおすすめ|おすすめ記事)$/,
|
|
38
|
+
/^(コメントを(残す|書く)|コメント一覧)$/,
|
|
39
|
+
/^最終更新日?[::\s]/
|
|
40
|
+
];
|
|
41
|
+
const TAIL_START_FRACTION = 0.8;
|
|
42
|
+
const MAX_TERMINATOR_BLOCK_LENGTH = 500;
|
|
43
|
+
const BLOCK_TAGS = /* @__PURE__ */ new Set(["p", "div", "section", "footer", "aside", "h1", "h2", "h3", "h4", "h5", "h6", "ul", "ol"]);
|
|
44
|
+
const isTerminatorBlock = (element, start, tailStart) => {
|
|
45
|
+
if (!BLOCK_TAGS.has(element.tagName) || start < tailStart) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const text = textOf(element).replace(/\s+/g, " ").trim();
|
|
49
|
+
if (text.length === 0 || text.length > MAX_TERMINATOR_BLOCK_LENGTH) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return TERMINATOR_PATTERNS.some((pattern) => pattern.test(text));
|
|
53
|
+
};
|
|
54
|
+
const textOf = (node) => {
|
|
55
|
+
if (node.type === "text") {
|
|
56
|
+
return node.value;
|
|
57
|
+
}
|
|
58
|
+
if (!(0, import_hast_fast.isParent)(node)) {
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
let text = "";
|
|
62
|
+
for (const child of node.children) {
|
|
63
|
+
text += textOf(child);
|
|
64
|
+
}
|
|
65
|
+
return text;
|
|
66
|
+
};
|
|
67
|
+
const truncateTrailingBoilerplate = (tree) => {
|
|
68
|
+
const starts = /* @__PURE__ */ new Map();
|
|
69
|
+
let total = 0;
|
|
70
|
+
const measure = (node) => {
|
|
71
|
+
starts.set(node, total);
|
|
72
|
+
if (node.type === "text") {
|
|
73
|
+
total += node.value.trim().length;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if ((0, import_hast_fast.isParent)(node)) {
|
|
77
|
+
for (const child of node.children) {
|
|
78
|
+
measure(child);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
measure(tree);
|
|
83
|
+
if (total === 0) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const tailStart = total * TAIL_START_FRACTION;
|
|
87
|
+
let cutoff = -1;
|
|
88
|
+
const find = (node) => {
|
|
89
|
+
if (cutoff !== -1 || !(0, import_hast_fast.isParent)(node)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
for (const child of node.children) {
|
|
93
|
+
if (cutoff !== -1) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!(0, import_hast_fast.isElement)(child)) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const start = starts.get(child) ?? 0;
|
|
100
|
+
if (isTerminatorBlock(child, start, tailStart)) {
|
|
101
|
+
cutoff = start;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
find(child);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
find(tree);
|
|
108
|
+
if (cutoff === -1) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
(0, import_hast_fast.pruneInPlace)(tree, (node) => {
|
|
112
|
+
if (node === tree) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
const start = starts.get(node);
|
|
116
|
+
if (start === void 0) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
if (start >= cutoff) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
});
|
|
124
|
+
return true;
|
|
125
|
+
};
|
|
126
|
+
const TERMINATOR_TAIL_FRACTION = TAIL_START_FRACTION;
|
|
127
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
128
|
+
0 && (module.exports = {
|
|
129
|
+
TERMINATOR_TAIL_FRACTION,
|
|
130
|
+
truncateTrailingBoilerplate
|
|
131
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var ui_chrome_exports = {};
|
|
20
|
+
__export(ui_chrome_exports, {
|
|
21
|
+
isUiChromeText: () => isUiChromeText
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(ui_chrome_exports);
|
|
24
|
+
const UI_PHRASES = /* @__PURE__ */ new Set([
|
|
25
|
+
// Documentation and article controls
|
|
26
|
+
"copy",
|
|
27
|
+
"copy page",
|
|
28
|
+
"copy link",
|
|
29
|
+
"copy code",
|
|
30
|
+
"copied",
|
|
31
|
+
"edit this page",
|
|
32
|
+
"edit on github",
|
|
33
|
+
"on this page",
|
|
34
|
+
"in this article",
|
|
35
|
+
"table of contents",
|
|
36
|
+
"contents",
|
|
37
|
+
"print",
|
|
38
|
+
"print this page",
|
|
39
|
+
"back to top",
|
|
40
|
+
"scroll to top",
|
|
41
|
+
"skip to content",
|
|
42
|
+
"skip to main content",
|
|
43
|
+
"permalink",
|
|
44
|
+
"anchor",
|
|
45
|
+
// Feedback widgets
|
|
46
|
+
"was this page helpful",
|
|
47
|
+
"was this helpful",
|
|
48
|
+
"was this article helpful",
|
|
49
|
+
"yes no",
|
|
50
|
+
"feedback",
|
|
51
|
+
"send feedback",
|
|
52
|
+
"report an issue",
|
|
53
|
+
"rate this page",
|
|
54
|
+
// Sharing and subscription
|
|
55
|
+
"share",
|
|
56
|
+
"share this",
|
|
57
|
+
"share this article",
|
|
58
|
+
"share on twitter",
|
|
59
|
+
"share on facebook",
|
|
60
|
+
"subscribe",
|
|
61
|
+
"sign up",
|
|
62
|
+
"sign in",
|
|
63
|
+
"log in",
|
|
64
|
+
"login",
|
|
65
|
+
"newsletter",
|
|
66
|
+
// Advertising and promotion
|
|
67
|
+
"advertisement",
|
|
68
|
+
"advertisements",
|
|
69
|
+
"sponsored",
|
|
70
|
+
"sponsored content",
|
|
71
|
+
"promoted",
|
|
72
|
+
// Navigation affordances
|
|
73
|
+
"read more",
|
|
74
|
+
"show more",
|
|
75
|
+
"show less",
|
|
76
|
+
"see more",
|
|
77
|
+
"load more",
|
|
78
|
+
"previous",
|
|
79
|
+
"next",
|
|
80
|
+
"previous page",
|
|
81
|
+
"next page",
|
|
82
|
+
"menu",
|
|
83
|
+
"close",
|
|
84
|
+
"search",
|
|
85
|
+
// Japanese equivalents
|
|
86
|
+
"\u76EE\u6B21",
|
|
87
|
+
"\u5E83\u544A",
|
|
88
|
+
"\u30B7\u30A7\u30A2",
|
|
89
|
+
"\u5171\u6709",
|
|
90
|
+
"\u3053\u306E\u8A18\u4E8B\u3092\u30B7\u30A7\u30A2",
|
|
91
|
+
"\u7D9A\u304D\u3092\u8AAD\u3080",
|
|
92
|
+
"\u3082\u3063\u3068\u898B\u308B",
|
|
93
|
+
"\u95A2\u9023\u8A18\u4E8B",
|
|
94
|
+
"\u30B9\u30DD\u30F3\u30B5\u30FC\u30EA\u30F3\u30AF",
|
|
95
|
+
"\u30DA\u30FC\u30B8\u306E\u5148\u982D\u3078",
|
|
96
|
+
"\u30C8\u30C3\u30D7\u3078\u623B\u308B",
|
|
97
|
+
"\u524D\u3078",
|
|
98
|
+
"\u6B21\u3078",
|
|
99
|
+
"\u9589\u3058\u308B",
|
|
100
|
+
"\u691C\u7D22",
|
|
101
|
+
"\u30ED\u30B0\u30A4\u30F3",
|
|
102
|
+
"\u4F1A\u54E1\u767B\u9332"
|
|
103
|
+
]);
|
|
104
|
+
const MAX_PHRASE_LENGTH = 40;
|
|
105
|
+
const normalize = (text) => text.toLowerCase().replace(/[?!.,:;·・…"'“”‘’()[\]{}<>|/\\—–-]/g, " ").replace(/\s+/g, " ").trim();
|
|
106
|
+
const isUiChromeText = (text) => {
|
|
107
|
+
if (text.length === 0 || text.length > MAX_PHRASE_LENGTH) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
const normalized = normalize(text);
|
|
111
|
+
if (normalized.length === 0) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
return UI_PHRASES.has(normalized);
|
|
115
|
+
};
|
|
116
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
117
|
+
0 && (module.exports = {
|
|
118
|
+
isUiChromeText
|
|
119
|
+
});
|
|
@@ -23,18 +23,21 @@ __export(pipeExtractors_exports, {
|
|
|
23
23
|
module.exports = __toCommonJS(pipeExtractors_exports);
|
|
24
24
|
var import_constants = require("../constants");
|
|
25
25
|
const pipeExtractors = (params, extractors = import_constants.DEFAULT_EXTRACTORS) => {
|
|
26
|
-
const { hast, lang } = params;
|
|
27
|
-
const
|
|
28
|
-
|
|
26
|
+
const { hast, lang, url, owned } = params;
|
|
27
|
+
const list = Array.isArray(extractors) ? extractors : [extractors];
|
|
28
|
+
let current = hast;
|
|
29
|
+
let currentOwned = owned ?? false;
|
|
30
|
+
for (const extractor of list) {
|
|
29
31
|
if (extractor === false) {
|
|
30
|
-
|
|
32
|
+
continue;
|
|
31
33
|
}
|
|
32
|
-
if (typeof extractor
|
|
33
|
-
|
|
34
|
+
if (typeof extractor !== "function") {
|
|
35
|
+
throw new Error(`Invalid extractor: ${String(extractor)}`);
|
|
34
36
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
current = extractor({ hast: current, lang, url, owned: currentOwned });
|
|
38
|
+
currentOwned = true;
|
|
39
|
+
}
|
|
40
|
+
return current;
|
|
38
41
|
};
|
|
39
42
|
// Annotate the CommonJS export names for ESM import in node:
|
|
40
43
|
0 && (module.exports = {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var auto_exports = {};
|
|
20
|
+
__export(auto_exports, {
|
|
21
|
+
autoExtractor: () => autoExtractor,
|
|
22
|
+
createAutoExtractor: () => createAutoExtractor
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(auto_exports);
|
|
25
|
+
var import_adapters = require("../../adapters");
|
|
26
|
+
var import_takumi = require("./takumi");
|
|
27
|
+
const createAutoExtractor = (options = {}) => {
|
|
28
|
+
const { adapters } = options;
|
|
29
|
+
return (params) => {
|
|
30
|
+
if (adapters !== false) {
|
|
31
|
+
const extracted = (0, import_adapters.runAdapters)({ hast: params.hast, url: params.url, lang: params.lang }, adapters ?? void 0);
|
|
32
|
+
if (extracted) {
|
|
33
|
+
return extracted;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return (0, import_takumi.takumiExtractor)(params);
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const autoExtractor = createAutoExtractor();
|
|
40
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
41
|
+
0 && (module.exports = {
|
|
42
|
+
autoExtractor,
|
|
43
|
+
createAutoExtractor
|
|
44
|
+
});
|
|
@@ -21,65 +21,44 @@ __export(minimal_filter_exports, {
|
|
|
21
21
|
minimalFilter: () => minimalFilter
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(minimal_filter_exports);
|
|
24
|
-
var
|
|
25
|
-
var
|
|
26
|
-
var
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
byline: /byline|author|dateline|writtenby|p-author/i,
|
|
32
|
-
specialUnlikelyCandidates: /frb-|uls-menu|language-link/i,
|
|
33
|
-
unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|tooltip|disqus|extra|footer|gdpr|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote|speechify-ignore|avatar/i,
|
|
34
|
-
okMaybeItsaCandidate: /and|article|body|column|content|main|shadow|code/i
|
|
35
|
-
};
|
|
36
|
-
const metadataFilter = (node) => {
|
|
37
|
-
return !(["comment", "doctype"].includes(node.type) || node.type === "element" && ["script", "style", "link", "meta", "noscript", "svg", "title"].includes(node.tagName));
|
|
38
|
-
};
|
|
39
|
-
const universalElementFilter = (node) => {
|
|
40
|
-
if (node.type !== "element") {
|
|
24
|
+
var import_hast_fast = require("../../utils/hast-fast");
|
|
25
|
+
var import_constants = require("../lib/constants");
|
|
26
|
+
var import_sanitize = require("../lib/sanitize");
|
|
27
|
+
const MIN_RETAINED_FRACTION = 1 / 3;
|
|
28
|
+
const ALWAYS_ACCEPT_LENGTH = 5e3;
|
|
29
|
+
const isChrome = (element) => {
|
|
30
|
+
if (element.tagName === "aside" || element.tagName === "nav" || element.tagName === "dialog") {
|
|
41
31
|
return true;
|
|
42
32
|
}
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
return
|
|
46
|
-
}
|
|
47
|
-
if (["hidden", "aria-hidden"].some((key) => element.properties[key])) {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
if ((0, import_utils.classnames)(element).some((classname) => REGEXPS.hidden.test(classname))) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
if (element.tagName === "dialog") {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
if (element.properties.role === "dialog" && element.properties["aria-modal"]) {
|
|
57
|
-
return false;
|
|
33
|
+
const role = (0, import_hast_fast.stringProperty)(element, "role");
|
|
34
|
+
if (role && import_constants.UNLIKELY_ROLES.has(role)) {
|
|
35
|
+
return true;
|
|
58
36
|
}
|
|
59
|
-
if (
|
|
60
|
-
return
|
|
37
|
+
if (role === "dialog" && (0, import_hast_fast.isTruthyAttribute)(element, "aria-modal")) {
|
|
38
|
+
return true;
|
|
61
39
|
}
|
|
62
|
-
if (
|
|
63
|
-
return
|
|
40
|
+
if ((0, import_hast_fast.stringProperty)(element, "rel") === "author") {
|
|
41
|
+
return true;
|
|
64
42
|
}
|
|
65
|
-
if (
|
|
66
|
-
return
|
|
43
|
+
if (import_constants.REGEXPS.byline.test((0, import_hast_fast.matchString)(element))) {
|
|
44
|
+
return true;
|
|
67
45
|
}
|
|
68
|
-
return
|
|
46
|
+
return false;
|
|
69
47
|
};
|
|
70
48
|
const minimalFilter = (params) => {
|
|
71
49
|
const { hast } = params;
|
|
72
|
-
const body = (0,
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
50
|
+
const body = (0, import_hast_fast.cloneHast)((0, import_hast_fast.findElement)(hast, (element) => element.tagName === "body") ?? hast);
|
|
51
|
+
(0, import_sanitize.stripNonContent)(body);
|
|
52
|
+
const collector = new import_hast_fast.MetricsCollector();
|
|
53
|
+
const baseText = collector.textLength(body);
|
|
54
|
+
if (baseText === 0) {
|
|
76
55
|
return body;
|
|
77
56
|
}
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
return
|
|
57
|
+
const filtered = (0, import_hast_fast.cloneHast)(body);
|
|
58
|
+
(0, import_hast_fast.pruneInPlace)(filtered, (node) => !((0, import_hast_fast.isElement)(node) && isChrome(node)));
|
|
59
|
+
const filteredText = new import_hast_fast.MetricsCollector().textLength(filtered);
|
|
60
|
+
const isOverExtracted = filteredText < baseText * MIN_RETAINED_FRACTION && filteredText < ALWAYS_ACCEPT_LENGTH;
|
|
61
|
+
return isOverExtracted ? body : filtered;
|
|
83
62
|
};
|
|
84
63
|
// Annotate the CommonJS export names for ESM import in node:
|
|
85
64
|
0 && (module.exports = {
|
|
@@ -21,136 +21,98 @@ __export(takumi_exports, {
|
|
|
21
21
|
takumiExtractor: () => takumiExtractor
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(takumi_exports);
|
|
24
|
-
var
|
|
25
|
-
var
|
|
26
|
-
var
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (["aside", "nav"].includes(element.tagName)) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
if (["hidden", "aria-hidden"].some((key) => element.properties[key])) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
if ((0, import_utils.classnames)(element).some((classname) => REGEXPS.hidden.test(classname))) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
if (element.tagName === "dialog") {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
if (element.properties.role === "dialog" && element.properties["aria-modal"]) {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
if (element.properties.rel === "author" && (0, import_utils.isStrInclude)(element.properties.itemprop, "author")) {
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
if (REGEXPS.byline.test((0, import_utils.matchString)(element))) {
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
if (element.properties.role && UNLIKELY_ROLES.includes(element.properties.role)) {
|
|
71
|
-
return false;
|
|
24
|
+
var import_hast_fast = require("../../utils/hast-fast");
|
|
25
|
+
var import_constants = require("../lib/constants");
|
|
26
|
+
var import_sanitize = require("../lib/sanitize");
|
|
27
|
+
var import_score = require("../lib/score");
|
|
28
|
+
var import_terminators = require("../lib/terminators");
|
|
29
|
+
const MIN_RETAINED_FRACTION = 0.25;
|
|
30
|
+
const SEMANTIC_SELECTORS = [
|
|
31
|
+
(element) => (0, import_hast_fast.stringProperty)(element, "itemprop")?.includes("articleBody") ?? false,
|
|
32
|
+
(element) => element.tagName === "article",
|
|
33
|
+
(element) => element.tagName === "main",
|
|
34
|
+
(element) => (0, import_hast_fast.stringProperty)(element, "role") === "main"
|
|
35
|
+
];
|
|
36
|
+
const findBody = (hast) => (0, import_hast_fast.findElement)(hast, (element) => element.tagName === "body") ?? hast;
|
|
37
|
+
const semanticShortcut = (tree, collector, minLength) => {
|
|
38
|
+
for (const matches of SEMANTIC_SELECTORS) {
|
|
39
|
+
const found = [];
|
|
40
|
+
collectMatching(tree, matches, found);
|
|
41
|
+
if (found.length !== 1) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const candidate = found[0];
|
|
45
|
+
const metrics = collector.metrics(candidate);
|
|
46
|
+
if (metrics.text >= minLength && collector.linkDensity(candidate) < 0.5) {
|
|
47
|
+
return candidate;
|
|
48
|
+
}
|
|
72
49
|
}
|
|
73
|
-
return
|
|
50
|
+
return void 0;
|
|
74
51
|
};
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return false;
|
|
52
|
+
const collectMatching = (tree, matches, into) => {
|
|
53
|
+
const stack = [tree];
|
|
54
|
+
while (stack.length > 0 && into.length < 2) {
|
|
55
|
+
const node = stack.pop();
|
|
56
|
+
if ((0, import_hast_fast.isElement)(node) && matches(node)) {
|
|
57
|
+
into.push(node);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if ("children" in node) {
|
|
61
|
+
for (const child of node.children) {
|
|
62
|
+
stack.push(child);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
89
65
|
}
|
|
90
|
-
return true;
|
|
91
66
|
};
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
return true;
|
|
67
|
+
const asRootOf = (nodes) => ({ type: "root", children: nodes });
|
|
68
|
+
const scoredSelection = (tree, collector, lang) => {
|
|
69
|
+
const context = (0, import_score.buildScoringContext)(tree, collector, lang);
|
|
70
|
+
const candidates = (0, import_score.scoreCandidates)(tree, context);
|
|
71
|
+
const top = candidates[0];
|
|
72
|
+
if (!top) {
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
const promoted = (0, import_score.climbToArticleBoundary)(top, candidates, context);
|
|
76
|
+
const anchor = promoted === top.element ? top : { element: promoted, score: top.score };
|
|
77
|
+
const selected = (0, import_score.collectArticleNodes)(anchor, candidates, context);
|
|
78
|
+
return selected.length === 1 ? selected[0] : asRootOf(selected);
|
|
107
79
|
};
|
|
108
80
|
const takumiExtractor = (params) => {
|
|
109
|
-
const { hast, lang
|
|
110
|
-
const body = (0,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
81
|
+
const { hast, lang, owned } = params;
|
|
82
|
+
const body = owned ? findBody(hast) : (0, import_hast_fast.cloneHast)(findBody(hast));
|
|
83
|
+
(0, import_sanitize.stripNonContent)(body);
|
|
84
|
+
let collector = new import_hast_fast.MetricsCollector();
|
|
85
|
+
const baseText = collector.textLength(body);
|
|
86
|
+
if (baseText === 0) {
|
|
114
87
|
return body;
|
|
115
88
|
}
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const finalFilteredTree = (0, import_unist_util_filter.filter)(extractedTree, (node) => {
|
|
144
|
-
if (!removeEmptyFilter(node, lang)) {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
if (!unlikelyElementFilter(node)) {
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
return true;
|
|
151
|
-
});
|
|
152
|
-
const finalTree = (0, import_hast_util_to_string.toString)(finalFilteredTree).length > extractedText.length / 3 ? finalFilteredTree : extractedTree;
|
|
153
|
-
return finalTree;
|
|
89
|
+
const minLength = Math.min((0, import_constants.minContentLength)(lang), Math.max(0, baseText - 200));
|
|
90
|
+
const shortcut = semanticShortcut(body, collector, minLength);
|
|
91
|
+
const searchRoot = shortcut ?? body;
|
|
92
|
+
const searchText = collector.textLength(searchRoot);
|
|
93
|
+
const doomed = (0, import_sanitize.findUnlikelyElements)(searchRoot);
|
|
94
|
+
const doomedText = doomed.reduce((sum, element) => sum + collector.metrics(element).text, 0);
|
|
95
|
+
if (searchText - doomedText > Math.max(minLength, searchText * MIN_RETAINED_FRACTION)) {
|
|
96
|
+
const doomedSet = new Set(doomed);
|
|
97
|
+
(0, import_hast_fast.pruneInPlace)(searchRoot, (node) => !((0, import_hast_fast.isElement)(node) && doomedSet.has(node)));
|
|
98
|
+
collector = new import_hast_fast.MetricsCollector();
|
|
99
|
+
}
|
|
100
|
+
const scoringRoot = searchRoot;
|
|
101
|
+
const scoringRootText = collector.textLength(scoringRoot);
|
|
102
|
+
const selection = shortcut ? scoringRoot : scoredSelection(scoringRoot, collector, lang) ?? scoringRoot;
|
|
103
|
+
const selectionText = collector.textLength(selection);
|
|
104
|
+
const selectionIsSound = selectionText >= minLength || selectionText > scoringRootText * MIN_RETAINED_FRACTION;
|
|
105
|
+
const chosen = selectionIsSound ? selection : scoringRoot;
|
|
106
|
+
(0, import_terminators.truncateTrailingBoilerplate)(chosen);
|
|
107
|
+
const cleanupCollector = new import_hast_fast.MetricsCollector();
|
|
108
|
+
const chosenText = cleanupCollector.textLength(chosen);
|
|
109
|
+
const widgets = (0, import_sanitize.findCleanupTargets)(chosen, cleanupCollector);
|
|
110
|
+
const widgetText = widgets.reduce((sum, element) => sum + cleanupCollector.metrics(element).text, 0);
|
|
111
|
+
const remainingText = chosenText - widgetText;
|
|
112
|
+
if (remainingText < chosenText * MIN_RETAINED_FRACTION && remainingText < minLength) {
|
|
113
|
+
return chosen;
|
|
114
|
+
}
|
|
115
|
+
return (0, import_sanitize.cleanContent)(chosen, cleanupCollector);
|
|
154
116
|
};
|
|
155
117
|
// Annotate the CommonJS export names for ESM import in node:
|
|
156
118
|
0 && (module.exports = {
|