webforai 4.2.0 → 4.3.1
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/THIRD_PARTY_NOTICES.md +42 -0
- package/dist/adapters/sites/hackernews.js +3 -3
- package/dist/adapters/sites/youtube.js +4 -2
- package/dist/bin.js +738 -474
- package/dist/cjs/adapters/sites/hackernews.js +3 -3
- package/dist/cjs/adapters/sites/youtube.js +5 -2
- package/dist/cjs/detect-client-shell.js +2 -0
- package/dist/cjs/extractors/lib/layout-tables.js +48 -9
- package/dist/cjs/extractors/lib/sanitize.js +38 -2
- package/dist/cjs/extractors/lib/terminators.js +2 -0
- package/dist/cjs/index.js +3 -0
- package/dist/cjs/mdast-handlers/custom-code-handler.js +31 -2
- package/dist/cjs/normalize/index.js +97 -4
- package/dist/cjs/utils/detect-code-lang.js +4 -5
- package/dist/cjs/utils/parse-html.js +73 -5
- package/dist/detect-client-shell.js +1 -0
- package/dist/extractors/lib/layout-tables.js +48 -9
- package/dist/extractors/lib/sanitize.js +38 -2
- package/dist/extractors/lib/terminators.js +2 -0
- package/dist/index.js +2 -0
- package/dist/mdast-handlers/custom-code-handler.js +31 -2
- package/dist/normalize/index.js +94 -3
- package/dist/types/adapters/sites/hackernews.js.map +1 -1
- package/dist/types/adapters/sites/youtube.d.ts +2 -0
- package/dist/types/adapters/sites/youtube.js.map +1 -1
- package/dist/types/detect-client-shell.d.ts +2 -0
- package/dist/types/detect-client-shell.js.map +1 -1
- package/dist/types/extractors/lib/layout-tables.d.ts +9 -2
- package/dist/types/extractors/lib/layout-tables.js.map +1 -1
- package/dist/types/extractors/lib/sanitize.js.map +1 -1
- package/dist/types/extractors/lib/terminators.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/mdast-handlers/custom-code-handler.d.ts +5 -0
- package/dist/types/mdast-handlers/custom-code-handler.js.map +1 -1
- package/dist/types/normalize/index.d.ts +21 -0
- package/dist/types/normalize/index.js.map +1 -1
- package/dist/types/utils/detect-code-lang.d.ts +7 -1
- package/dist/types/utils/detect-code-lang.js.map +1 -1
- package/dist/types/utils/parse-html.d.ts +12 -6
- package/dist/types/utils/parse-html.js.map +1 -1
- package/dist/utils/detect-code-lang.js +4 -5
- package/dist/utils/parse-html.js +73 -5
- package/package.json +3 -2
|
@@ -45,11 +45,11 @@ const commentDepth = (row) => {
|
|
|
45
45
|
return width === void 0 ? 0 : Math.round(width / 40);
|
|
46
46
|
};
|
|
47
47
|
const nest = (content, depth) => {
|
|
48
|
-
let current = content;
|
|
48
|
+
let current = element("div", content);
|
|
49
49
|
for (let level = 0; level < Math.min(depth, MAX_QUOTE_DEPTH); level++) {
|
|
50
|
-
current =
|
|
50
|
+
current = element("blockquote", [current]);
|
|
51
51
|
}
|
|
52
|
-
return current
|
|
52
|
+
return current;
|
|
53
53
|
};
|
|
54
54
|
const storyNodes = (root) => {
|
|
55
55
|
const nodes = [];
|
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var youtube_exports = {};
|
|
20
20
|
__export(youtube_exports, {
|
|
21
|
+
PLAYER_RESPONSE_VARIABLE: () => PLAYER_RESPONSE_VARIABLE,
|
|
21
22
|
extractAssignedJson: () => extractAssignedJson,
|
|
22
23
|
isYoutubeElement: () => isYoutubeElement,
|
|
23
24
|
youtubeAdapter: () => youtubeAdapter,
|
|
@@ -69,12 +70,13 @@ const extractAssignedJson = (source, name) => {
|
|
|
69
70
|
const scriptText = (root) => (0, import_hast_fast.collectElements)(root, (element2) => element2.tagName === "script").map(
|
|
70
71
|
(script) => script.children.map((child) => child.type === "text" ? child.value : "").join("")
|
|
71
72
|
);
|
|
73
|
+
const PLAYER_RESPONSE_VARIABLE = "ytInitialPlayerResponse";
|
|
72
74
|
const findPlayerResponse = (root) => {
|
|
73
75
|
for (const source of scriptText(root)) {
|
|
74
|
-
if (!source.includes(
|
|
76
|
+
if (!source.includes(PLAYER_RESPONSE_VARIABLE)) {
|
|
75
77
|
continue;
|
|
76
78
|
}
|
|
77
|
-
const parsed = extractAssignedJson(source,
|
|
79
|
+
const parsed = extractAssignedJson(source, PLAYER_RESPONSE_VARIABLE);
|
|
78
80
|
if (parsed && typeof parsed === "object") {
|
|
79
81
|
return parsed;
|
|
80
82
|
}
|
|
@@ -184,6 +186,7 @@ const youtubeAdapter = {
|
|
|
184
186
|
const isYoutubeElement = import_hast_fast.isElement;
|
|
185
187
|
// Annotate the CommonJS export names for ESM import in node:
|
|
186
188
|
0 && (module.exports = {
|
|
189
|
+
PLAYER_RESPONSE_VARIABLE,
|
|
187
190
|
extractAssignedJson,
|
|
188
191
|
isYoutubeElement,
|
|
189
192
|
youtubeAdapter,
|
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var detect_client_shell_exports = {};
|
|
20
20
|
__export(detect_client_shell_exports, {
|
|
21
|
+
CHALLENGE_PATTERN: () => CHALLENGE_PATTERN,
|
|
21
22
|
SHELL_EMPTY_THRESHOLD: () => SHELL_EMPTY_THRESHOLD,
|
|
22
23
|
SHELL_SUSPICION_THRESHOLD: () => SHELL_SUSPICION_THRESHOLD,
|
|
23
24
|
detectClientShell: () => detectClientShell
|
|
@@ -72,6 +73,7 @@ const detectClientShell = (html) => {
|
|
|
72
73
|
};
|
|
73
74
|
// Annotate the CommonJS export names for ESM import in node:
|
|
74
75
|
0 && (module.exports = {
|
|
76
|
+
CHALLENGE_PATTERN,
|
|
75
77
|
SHELL_EMPTY_THRESHOLD,
|
|
76
78
|
SHELL_SUSPICION_THRESHOLD,
|
|
77
79
|
detectClientShell
|
|
@@ -27,10 +27,51 @@ const DATA_MARKERS = /* @__PURE__ */ new Set(["caption", "thead", "tfoot", "th",
|
|
|
27
27
|
const BLOCK_IN_CELL = /* @__PURE__ */ new Set(["h1", "h2", "h3", "h4", "h5", "h6", "table", "form"]);
|
|
28
28
|
const TABLE_PARTS = /* @__PURE__ */ new Set(["tbody", "thead", "tfoot", "tr", "td", "th"]);
|
|
29
29
|
const TABLE_CONTEXT = /* @__PURE__ */ new Set(["table", "tbody", "thead", "tfoot", "tr"]);
|
|
30
|
+
const MAX_SMALL_TABLE_CELL = 150;
|
|
31
|
+
const MAX_SMALL_TABLE_LINK_SHARE = 0.5;
|
|
32
|
+
const collapsedLength = (text) => text.replace(/\s+/g, " ").trim().length;
|
|
33
|
+
const cellText = (cell) => {
|
|
34
|
+
let text = "";
|
|
35
|
+
let linkText = "";
|
|
36
|
+
const visit = (node, inLink) => {
|
|
37
|
+
for (const child of node.children) {
|
|
38
|
+
if (child.type === "text") {
|
|
39
|
+
text += child.value;
|
|
40
|
+
if (inLink) {
|
|
41
|
+
linkText += child.value;
|
|
42
|
+
}
|
|
43
|
+
} else if ((0, import_hast_fast.isElement)(child) && child.tagName !== "table") {
|
|
44
|
+
visit(child, inLink || child.tagName === "a");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
visit(cell, false);
|
|
49
|
+
return { text: collapsedLength(text), linkText: collapsedLength(linkText) };
|
|
50
|
+
};
|
|
30
51
|
const cellsOf = (row) => row.children.filter((cell) => (0, import_hast_fast.isElement)(cell) && (cell.tagName === "td" || cell.tagName === "th"));
|
|
31
52
|
const HEADING = /^h[1-6]$/;
|
|
53
|
+
const measureRow = (shape, row) => {
|
|
54
|
+
const cells = cellsOf(row);
|
|
55
|
+
shape.rows += 1;
|
|
56
|
+
shape.columns = Math.max(shape.columns, cells.length);
|
|
57
|
+
for (const cell of cells) {
|
|
58
|
+
const { text, linkText } = cellText(cell);
|
|
59
|
+
shape.longestCell = Math.max(shape.longestCell, text);
|
|
60
|
+
shape.text += text;
|
|
61
|
+
shape.linkText += linkText;
|
|
62
|
+
}
|
|
63
|
+
return cells.length === 1;
|
|
64
|
+
};
|
|
32
65
|
const shapeOf = (table) => {
|
|
33
|
-
const shape = {
|
|
66
|
+
const shape = {
|
|
67
|
+
rows: 0,
|
|
68
|
+
columns: 0,
|
|
69
|
+
dataMarker: false,
|
|
70
|
+
blockInCell: false,
|
|
71
|
+
longestCell: 0,
|
|
72
|
+
text: 0,
|
|
73
|
+
linkText: 0
|
|
74
|
+
};
|
|
34
75
|
let captionHeadings = 0;
|
|
35
76
|
const noteBlockInCell = (tag, aloneInRow) => {
|
|
36
77
|
if (HEADING.test(tag) && aloneInRow) {
|
|
@@ -52,13 +93,7 @@ const shapeOf = (table) => {
|
|
|
52
93
|
if (DATA_MARKERS.has(tag)) {
|
|
53
94
|
shape.dataMarker = true;
|
|
54
95
|
}
|
|
55
|
-
|
|
56
|
-
if (tag === "tr") {
|
|
57
|
-
shape.rows += 1;
|
|
58
|
-
const cells = cellsOf(child).length;
|
|
59
|
-
shape.columns = Math.max(shape.columns, cells);
|
|
60
|
-
alone = cells === 1;
|
|
61
|
-
}
|
|
96
|
+
const alone = tag === "tr" ? measureRow(shape, child) : aloneInRow;
|
|
62
97
|
if (inCell && BLOCK_IN_CELL.has(tag)) {
|
|
63
98
|
noteBlockInCell(tag, aloneInRow);
|
|
64
99
|
}
|
|
@@ -89,7 +124,11 @@ const isLayoutTable = (table) => {
|
|
|
89
124
|
if (shape.rows >= 10 || shape.columns > 4) {
|
|
90
125
|
return false;
|
|
91
126
|
}
|
|
92
|
-
|
|
127
|
+
if (shape.rows * shape.columns > 10) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
const linkShare = shape.text === 0 ? 1 : shape.linkText / shape.text;
|
|
131
|
+
return shape.longestCell > MAX_SMALL_TABLE_CELL || linkShare > MAX_SMALL_TABLE_LINK_SHARE;
|
|
93
132
|
};
|
|
94
133
|
const unwrap = (table) => {
|
|
95
134
|
const cells = [];
|
|
@@ -189,16 +189,52 @@ const containsMath = (element) => {
|
|
|
189
189
|
}
|
|
190
190
|
return false;
|
|
191
191
|
};
|
|
192
|
+
const collapsedText = (element) => {
|
|
193
|
+
let text = "";
|
|
194
|
+
(0, import_hast_fast.walk)(element, (node) => {
|
|
195
|
+
if (node.type === "text") {
|
|
196
|
+
text += node.value;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
return text.replace(/\s+/g, " ").trim();
|
|
200
|
+
};
|
|
201
|
+
const visibleSiblingText = (parent, cache) => {
|
|
202
|
+
let texts = cache.get(parent);
|
|
203
|
+
if (!texts) {
|
|
204
|
+
texts = /* @__PURE__ */ new Set();
|
|
205
|
+
for (const child of parent.children) {
|
|
206
|
+
if ((0, import_hast_fast.isElement)(child) && !(0, import_hast_fast.isTruthyAttribute)(child, "aria-hidden") && !looksHidden(child)) {
|
|
207
|
+
texts.add(collapsedText(child));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
cache.set(parent, texts);
|
|
211
|
+
}
|
|
212
|
+
return texts;
|
|
213
|
+
};
|
|
214
|
+
const isAriaHiddenDuplicate = (element, parent, cache) => {
|
|
215
|
+
if (!(0, import_hast_fast.isTruthyAttribute)(element, "aria-hidden") || containsMath(element)) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
const text = collapsedText(element);
|
|
219
|
+
return text.length > 0 && visibleSiblingText(parent, cache).has(text);
|
|
220
|
+
};
|
|
192
221
|
const stripNonContent = (tree) => {
|
|
193
222
|
const tabs = new import_code_tabs.CodeTabCollector((element) => looksHidden(element) || import_constants.NON_CONTENT_TAGS.has(element.tagName));
|
|
194
|
-
|
|
223
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
224
|
+
const siblingText = /* @__PURE__ */ new WeakMap();
|
|
225
|
+
hoistNoscriptImages(tree, (element, depth, parent) => {
|
|
226
|
+
tabs.visit(element, depth, parent);
|
|
227
|
+
if (isAriaHiddenDuplicate(element, parent, siblingText)) {
|
|
228
|
+
duplicates.add(element);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
195
231
|
tabs.apply();
|
|
196
232
|
const siblingCode = /* @__PURE__ */ new WeakMap();
|
|
197
233
|
return (0, import_hast_fast.pruneInPlace)(tree, (node, parent) => {
|
|
198
234
|
if (isNonContent(node)) {
|
|
199
235
|
return false;
|
|
200
236
|
}
|
|
201
|
-
if ((0, import_hast_fast.isElement)(node) && isHidden(node, parent, siblingCode)) {
|
|
237
|
+
if ((0, import_hast_fast.isElement)(node) && (duplicates.has(node) || isHidden(node, parent, siblingCode))) {
|
|
202
238
|
return false;
|
|
203
239
|
}
|
|
204
240
|
return true;
|
|
@@ -26,6 +26,8 @@ var import_hast_fast = require("../../utils/hast-fast");
|
|
|
26
26
|
const TERMINATOR_PATTERNS = [
|
|
27
27
|
/^was this (page|article|document) helpful/i,
|
|
28
28
|
/^thanks for the feedback/i,
|
|
29
|
+
// Site-generator credit closing the page ("Powered by Docsify.js", "Powered by GitBook").
|
|
30
|
+
/^powered by\b/i,
|
|
29
31
|
/^(this page was )?last (modified|updated) (on|at|:)?\s/i,
|
|
30
32
|
/^learn how to contribute/i,
|
|
31
33
|
/^help (us )?improve\b/i,
|
package/dist/cjs/index.js
CHANGED
|
@@ -49,6 +49,7 @@ __export(src_exports, {
|
|
|
49
49
|
readabilityExtractor: () => import_extractors.readabilityExtractor,
|
|
50
50
|
resolveAdapter: () => import_adapters.resolveAdapter,
|
|
51
51
|
runAdapters: () => import_adapters.runAdapters,
|
|
52
|
+
stripScriptBodies: () => import_parse_html.stripScriptBodies,
|
|
52
53
|
takumiExtractor: () => import_extractors.takumiExtractor,
|
|
53
54
|
toFrontmatter: () => import_metadata.toFrontmatter,
|
|
54
55
|
youtubeCaptionTracks: () => import_adapters.youtubeCaptionTracks
|
|
@@ -64,6 +65,7 @@ var import_detect_client_shell = require("./detect-client-shell");
|
|
|
64
65
|
var import_extract_meta_refresh = require("./extract-meta-refresh");
|
|
65
66
|
var import_metadata = require("./metadata");
|
|
66
67
|
var import_normalize = require("./normalize");
|
|
68
|
+
var import_parse_html = require("./utils/parse-html");
|
|
67
69
|
// Annotate the CommonJS export names for ESM import in node:
|
|
68
70
|
0 && (module.exports = {
|
|
69
71
|
BUILTIN_ADAPTERS,
|
|
@@ -97,6 +99,7 @@ var import_normalize = require("./normalize");
|
|
|
97
99
|
readabilityExtractor,
|
|
98
100
|
resolveAdapter,
|
|
99
101
|
runAdapters,
|
|
102
|
+
stripScriptBodies,
|
|
100
103
|
takumiExtractor,
|
|
101
104
|
toFrontmatter,
|
|
102
105
|
youtubeCaptionTracks
|
|
@@ -29,17 +29,46 @@ var import_hast_fast = require("../utils/hast-fast");
|
|
|
29
29
|
var import_pre_text = require("../utils/pre-text");
|
|
30
30
|
var import_twoslash = require("./twoslash");
|
|
31
31
|
const LANGUAGE_MATCH_REGEX = [/^language-(\S+)$/, /^highlight-source-(\S+)$/, /^CodeBlock--language-(\S+)$/];
|
|
32
|
+
const LANGUAGE_TOKEN = /^[\w+#.-]+$/;
|
|
33
|
+
const NO_LANGUAGE = /* @__PURE__ */ new Set(["plain", "plaintext", "text", "none", "nohighlight"]);
|
|
32
34
|
const LANGUAGE_ATTRIBUTES = ["dataLanguage", "dataLang"];
|
|
33
35
|
const attributeLanguage = (element) => {
|
|
34
36
|
for (const name of LANGUAGE_ATTRIBUTES) {
|
|
35
37
|
const value = element.properties?.[name];
|
|
36
|
-
if (typeof value === "string" &&
|
|
38
|
+
if (typeof value === "string" && LANGUAGE_TOKEN.test(value.trim()) && value.trim() !== "plaintext") {
|
|
37
39
|
return value.trim();
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
return void 0;
|
|
41
43
|
};
|
|
42
|
-
const
|
|
44
|
+
const SANDPACK_LANGUAGES = /* @__PURE__ */ new Set([
|
|
45
|
+
"javascript",
|
|
46
|
+
"typescript",
|
|
47
|
+
"jsx",
|
|
48
|
+
"tsx",
|
|
49
|
+
"html",
|
|
50
|
+
"css",
|
|
51
|
+
"less",
|
|
52
|
+
"scss",
|
|
53
|
+
"sass",
|
|
54
|
+
"json",
|
|
55
|
+
"markdown",
|
|
56
|
+
"python",
|
|
57
|
+
"vue",
|
|
58
|
+
"svelte"
|
|
59
|
+
]);
|
|
60
|
+
const conventionLanguage = (element) => {
|
|
61
|
+
const classes = (0, import_hast_fast.classList)(element);
|
|
62
|
+
const brushAt = classes.findIndex((name) => name.startsWith("brush:"));
|
|
63
|
+
if (brushAt >= 0) {
|
|
64
|
+
const brush = classes[brushAt] === "brush:" ? classes[brushAt + 1] : classes[brushAt].slice("brush:".length);
|
|
65
|
+
const lang = brush?.toLowerCase();
|
|
66
|
+
return lang && LANGUAGE_TOKEN.test(lang) && !NO_LANGUAGE.has(lang) ? lang : void 0;
|
|
67
|
+
}
|
|
68
|
+
const sandpack = classes.find((name) => name.startsWith("sp-") && SANDPACK_LANGUAGES.has(name.slice(3)));
|
|
69
|
+
return sandpack?.slice(3);
|
|
70
|
+
};
|
|
71
|
+
const codeLanguage = (...elements) => elements.flatMap(import_hast_fast.classList).map((className) => LANGUAGE_MATCH_REGEX.map((regex) => className.match(regex)).find(Boolean)?.[1]).find(Boolean) ?? elements.map(attributeLanguage).find(Boolean) ?? elements.map(conventionLanguage).find(Boolean);
|
|
43
72
|
const codeMeta = (pre) => {
|
|
44
73
|
const title = pre.properties?.dataTitle;
|
|
45
74
|
if (typeof title !== "string") {
|
|
@@ -20,11 +20,13 @@ var normalize_exports = {};
|
|
|
20
20
|
__export(normalize_exports, {
|
|
21
21
|
bestFromSrcset: () => bestFromSrcset,
|
|
22
22
|
dedupeRenderedMath: () => dedupeRenderedMath,
|
|
23
|
+
foldCodeLabels: () => foldCodeLabels,
|
|
23
24
|
normalizeHast: () => normalizeHast,
|
|
24
25
|
promoteAriaHeadings: () => promoteAriaHeadings,
|
|
25
26
|
removeIconFonts: () => removeIconFonts,
|
|
26
27
|
resolveImageSources: () => resolveImageSources,
|
|
27
|
-
separateAdjacentInlines: () => separateAdjacentInlines
|
|
28
|
+
separateAdjacentInlines: () => separateAdjacentInlines,
|
|
29
|
+
unwrapHeadingAnchors: () => unwrapHeadingAnchors
|
|
28
30
|
});
|
|
29
31
|
module.exports = __toCommonJS(normalize_exports);
|
|
30
32
|
var import_hast_fast = require("../utils/hast-fast");
|
|
@@ -164,6 +166,82 @@ const removeIconFonts = (tree) => {
|
|
|
164
166
|
(0, import_hast_fast.pruneInPlace)(tree, (node) => !isIcon(node));
|
|
165
167
|
}
|
|
166
168
|
};
|
|
169
|
+
const textOfNode = (node) => node.type === "text" ? node.value : "children" in node ? node.children.map(textOfNode).join("") : "";
|
|
170
|
+
const unwrapHeadingAnchors = (tree) => {
|
|
171
|
+
(0, import_hast_fast.walk)(tree, (node) => {
|
|
172
|
+
if (!((0, import_hast_fast.isElement)(node) && /^h[1-6]$/.test(node.tagName))) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const title = textOfNode(node).trim();
|
|
176
|
+
if (title === "") {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const anchorAt = node.children.findIndex(
|
|
180
|
+
(child) => (0, import_hast_fast.isElement)(child) && child.tagName === "a" && (0, import_hast_fast.stringProperty)(child, "href")?.startsWith("#") && textOfNode(child).trim() === title
|
|
181
|
+
);
|
|
182
|
+
const anchor = node.children[anchorAt];
|
|
183
|
+
if ((0, import_hast_fast.isElement)(anchor)) {
|
|
184
|
+
node.children.splice(anchorAt, 1, ...anchor.children);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
const LABEL_LANGUAGES = /* @__PURE__ */ new Set([
|
|
189
|
+
"js",
|
|
190
|
+
"javascript",
|
|
191
|
+
"ts",
|
|
192
|
+
"typescript",
|
|
193
|
+
"jsx",
|
|
194
|
+
"tsx",
|
|
195
|
+
"html",
|
|
196
|
+
"css",
|
|
197
|
+
"scss",
|
|
198
|
+
"json",
|
|
199
|
+
"bash",
|
|
200
|
+
"sh",
|
|
201
|
+
"shell",
|
|
202
|
+
"console",
|
|
203
|
+
"python",
|
|
204
|
+
"py",
|
|
205
|
+
"sql",
|
|
206
|
+
"xml",
|
|
207
|
+
"yaml",
|
|
208
|
+
"toml",
|
|
209
|
+
"http",
|
|
210
|
+
"rust",
|
|
211
|
+
"go",
|
|
212
|
+
"java",
|
|
213
|
+
"kotlin",
|
|
214
|
+
"swift",
|
|
215
|
+
"c",
|
|
216
|
+
"cpp",
|
|
217
|
+
"md",
|
|
218
|
+
"markdown",
|
|
219
|
+
"diff"
|
|
220
|
+
]);
|
|
221
|
+
const LABEL_NO_LANGUAGE = /* @__PURE__ */ new Set(["plain", "plaintext", "text"]);
|
|
222
|
+
const foldCodeLabels = (tree) => {
|
|
223
|
+
(0, import_hast_fast.walk)(tree, (node) => {
|
|
224
|
+
if (!(0, import_hast_fast.isElement)(node) || node.tagName === "pre") {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const elements = node.children.filter(import_hast_fast.isElement);
|
|
228
|
+
if (elements.length !== 2 || node.children.some((child) => child.type === "text" && child.value.trim() !== "")) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const [label, pre] = elements;
|
|
232
|
+
if (pre.tagName !== "pre" || /^(h[1-6]|pre)$/.test(label.tagName) || (0, import_hast_fast.findElement)(label, (el) => el.tagName === "pre")) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const name = textOfNode(label).trim().toLowerCase();
|
|
236
|
+
if (!(LABEL_LANGUAGES.has(name) || LABEL_NO_LANGUAGE.has(name))) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (LABEL_LANGUAGES.has(name) && pre.properties.dataLanguage === void 0) {
|
|
240
|
+
pre.properties.dataLanguage = name;
|
|
241
|
+
}
|
|
242
|
+
node.children = node.children.filter((child) => child !== label);
|
|
243
|
+
});
|
|
244
|
+
};
|
|
167
245
|
const SPACED_INLINE = /* @__PURE__ */ new Set(["span", "time", "label"]);
|
|
168
246
|
const SCRIPTS = [
|
|
169
247
|
["latin", /\p{Script=Latin}/u],
|
|
@@ -180,7 +258,6 @@ const needsSpace = (left, right) => {
|
|
|
180
258
|
return a !== void 0 && b !== void 0 && a !== b;
|
|
181
259
|
};
|
|
182
260
|
const NO_SPACING = /* @__PURE__ */ new Set(["pre", "code", "kbd", "samp", "ruby", "math", "svg"]);
|
|
183
|
-
const textOfNode = (node) => node.type === "text" ? node.value : "children" in node ? node.children.map(textOfNode).join("") : "";
|
|
184
261
|
const separateAdjacentInlines = (tree) => {
|
|
185
262
|
const visit = (node) => {
|
|
186
263
|
if (!("children" in node) || (0, import_hast_fast.isElement)(node) && NO_SPACING.has(node.tagName)) {
|
|
@@ -201,7 +278,15 @@ const separateAdjacentInlines = (tree) => {
|
|
|
201
278
|
visit(tree);
|
|
202
279
|
};
|
|
203
280
|
const normalizeHast = (tree, options = {}) => {
|
|
204
|
-
const {
|
|
281
|
+
const {
|
|
282
|
+
images = true,
|
|
283
|
+
math = true,
|
|
284
|
+
ariaHeadings = true,
|
|
285
|
+
iconFonts = true,
|
|
286
|
+
headingAnchors = true,
|
|
287
|
+
codeLabels = true,
|
|
288
|
+
inlineSpacing = true
|
|
289
|
+
} = options;
|
|
205
290
|
if (images) {
|
|
206
291
|
resolveImageSources(tree);
|
|
207
292
|
}
|
|
@@ -214,6 +299,12 @@ const normalizeHast = (tree, options = {}) => {
|
|
|
214
299
|
if (iconFonts) {
|
|
215
300
|
removeIconFonts(tree);
|
|
216
301
|
}
|
|
302
|
+
if (headingAnchors) {
|
|
303
|
+
unwrapHeadingAnchors(tree);
|
|
304
|
+
}
|
|
305
|
+
if (codeLabels) {
|
|
306
|
+
foldCodeLabels(tree);
|
|
307
|
+
}
|
|
217
308
|
if (inlineSpacing) {
|
|
218
309
|
separateAdjacentInlines(tree);
|
|
219
310
|
}
|
|
@@ -223,9 +314,11 @@ const normalizeHast = (tree, options = {}) => {
|
|
|
223
314
|
0 && (module.exports = {
|
|
224
315
|
bestFromSrcset,
|
|
225
316
|
dedupeRenderedMath,
|
|
317
|
+
foldCodeLabels,
|
|
226
318
|
normalizeHast,
|
|
227
319
|
promoteAriaHeadings,
|
|
228
320
|
removeIconFonts,
|
|
229
321
|
resolveImageSources,
|
|
230
|
-
separateAdjacentInlines
|
|
322
|
+
separateAdjacentInlines,
|
|
323
|
+
unwrapHeadingAnchors
|
|
231
324
|
});
|
|
@@ -62,11 +62,10 @@ const languages = [
|
|
|
62
62
|
["json", [/\b(true|false|null|\{})\b|\"[^"]+\":/g, 10]],
|
|
63
63
|
["yaml", [/^(\s+)?[a-z][a-z0-9]*:/gim, 10]]
|
|
64
64
|
];
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
};
|
|
65
|
+
const MIN_CONFIDENT_SCORE = 400;
|
|
66
|
+
const detectLanguage = (code) => languages.map(
|
|
67
|
+
([lang, ...features]) => [lang, features.reduce((acc, [match, score]) => acc + [...code.matchAll(match)].length * score, 0)]
|
|
68
|
+
).filter(([_, score]) => score >= MIN_CONFIDENT_SCORE).sort((a, b) => b[1] - a[1])[0]?.[0];
|
|
70
69
|
// Annotate the CommonJS export names for ESM import in node:
|
|
71
70
|
0 && (module.exports = {
|
|
72
71
|
detectLanguage
|
|
@@ -26,6 +26,8 @@ __export(parse_html_exports, {
|
|
|
26
26
|
module.exports = __toCommonJS(parse_html_exports);
|
|
27
27
|
var import_hast_util_from_parse5 = require("hast-util-from-parse5");
|
|
28
28
|
var import_parse5 = require("parse5");
|
|
29
|
+
var import_youtube = require("../adapters/sites/youtube");
|
|
30
|
+
var import_detect_client_shell = require("../detect-client-shell");
|
|
29
31
|
const MAX_ELEMENT_DEPTH = 256;
|
|
30
32
|
const isParent = (node) => "childNodes" in node;
|
|
31
33
|
const LINE_ELEMENTS = /* @__PURE__ */ new Set([
|
|
@@ -92,12 +94,78 @@ const flattenDeep = (root, maxDepth) => {
|
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
};
|
|
95
|
-
const
|
|
97
|
+
const SCRIPT_OR_STYLE_START = /<!--|<(script|style)(?=[\s/>])/gi;
|
|
98
|
+
const CLOSING_TAG = {
|
|
99
|
+
script: /<\/script[\s/>]/gi,
|
|
100
|
+
style: /<\/style[\s/>]/gi
|
|
101
|
+
};
|
|
102
|
+
const startTagEnd = (html, from) => {
|
|
103
|
+
let index = from;
|
|
104
|
+
while (index < html.length) {
|
|
105
|
+
const char = html[index];
|
|
106
|
+
if (char === ">") {
|
|
107
|
+
return index + 1;
|
|
108
|
+
}
|
|
109
|
+
if (char === "=") {
|
|
110
|
+
let value = index + 1;
|
|
111
|
+
while (value < html.length && /\s/.test(html[value] ?? "")) {
|
|
112
|
+
value++;
|
|
113
|
+
}
|
|
114
|
+
const quote = html[value];
|
|
115
|
+
if (quote === '"' || quote === "'") {
|
|
116
|
+
const close = html.indexOf(quote, value + 1);
|
|
117
|
+
if (close < 0) {
|
|
118
|
+
return -1;
|
|
119
|
+
}
|
|
120
|
+
index = close + 1;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
index = value;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
index++;
|
|
127
|
+
}
|
|
128
|
+
return -1;
|
|
129
|
+
};
|
|
130
|
+
const isReadScript = (attributes, element) => /application\/ld\+json/i.test(attributes) || element.includes(import_youtube.PLAYER_RESPONSE_VARIABLE) || import_detect_client_shell.CHALLENGE_PATTERN.test(element);
|
|
96
131
|
const LARGE_DOCUMENT_CHARS = 2e6;
|
|
97
|
-
const stripScriptBodies = (html) =>
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
);
|
|
132
|
+
const stripScriptBodies = (html) => {
|
|
133
|
+
const out = [];
|
|
134
|
+
let copied = 0;
|
|
135
|
+
const start = new RegExp(SCRIPT_OR_STYLE_START);
|
|
136
|
+
for (let match = start.exec(html); match; match = start.exec(html)) {
|
|
137
|
+
if (match[1] === void 0) {
|
|
138
|
+
const commentEnd = html.indexOf("-->", match.index + 4);
|
|
139
|
+
if (commentEnd < 0) {
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
start.lastIndex = commentEnd + 3;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const tag = match[1].toLowerCase();
|
|
146
|
+
const bodyStart = startTagEnd(html, match.index + match[0].length);
|
|
147
|
+
if (bodyStart < 0) {
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
const closing = CLOSING_TAG[tag];
|
|
151
|
+
closing.lastIndex = bodyStart;
|
|
152
|
+
const close = closing.exec(html);
|
|
153
|
+
if (!close) {
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
const tagEnd = html.indexOf(">", close.index);
|
|
157
|
+
const elementEnd = tagEnd < 0 ? html.length : tagEnd + 1;
|
|
158
|
+
const element = html.slice(match.index, elementEnd);
|
|
159
|
+
const openingTag = html.slice(match.index, bodyStart);
|
|
160
|
+
if (!(tag === "script" && isReadScript(openingTag, element))) {
|
|
161
|
+
out.push(html.slice(copied, bodyStart), html.slice(close.index, elementEnd));
|
|
162
|
+
copied = elementEnd;
|
|
163
|
+
}
|
|
164
|
+
start.lastIndex = elementEnd;
|
|
165
|
+
}
|
|
166
|
+
out.push(html.slice(copied));
|
|
167
|
+
return out.join("");
|
|
168
|
+
};
|
|
101
169
|
const parseHtml = (html, options = {}) => {
|
|
102
170
|
const source = html.length > LARGE_DOCUMENT_CHARS ? stripScriptBodies(html) : html;
|
|
103
171
|
const document = options.fragment ? (0, import_parse5.parseFragment)(source, { scriptingEnabled: false }) : (0, import_parse5.parse)(source, { scriptingEnabled: false });
|
|
@@ -4,10 +4,51 @@ var DATA_MARKERS = /* @__PURE__ */ new Set(["caption", "thead", "tfoot", "th", "
|
|
|
4
4
|
var BLOCK_IN_CELL = /* @__PURE__ */ new Set(["h1", "h2", "h3", "h4", "h5", "h6", "table", "form"]);
|
|
5
5
|
var TABLE_PARTS = /* @__PURE__ */ new Set(["tbody", "thead", "tfoot", "tr", "td", "th"]);
|
|
6
6
|
var TABLE_CONTEXT = /* @__PURE__ */ new Set(["table", "tbody", "thead", "tfoot", "tr"]);
|
|
7
|
+
var MAX_SMALL_TABLE_CELL = 150;
|
|
8
|
+
var MAX_SMALL_TABLE_LINK_SHARE = 0.5;
|
|
9
|
+
var collapsedLength = (text) => text.replace(/\s+/g, " ").trim().length;
|
|
10
|
+
var cellText = (cell) => {
|
|
11
|
+
let text = "";
|
|
12
|
+
let linkText = "";
|
|
13
|
+
const visit = (node, inLink) => {
|
|
14
|
+
for (const child of node.children) {
|
|
15
|
+
if (child.type === "text") {
|
|
16
|
+
text += child.value;
|
|
17
|
+
if (inLink) {
|
|
18
|
+
linkText += child.value;
|
|
19
|
+
}
|
|
20
|
+
} else if (isElement(child) && child.tagName !== "table") {
|
|
21
|
+
visit(child, inLink || child.tagName === "a");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
visit(cell, false);
|
|
26
|
+
return { text: collapsedLength(text), linkText: collapsedLength(linkText) };
|
|
27
|
+
};
|
|
7
28
|
var cellsOf = (row) => row.children.filter((cell) => isElement(cell) && (cell.tagName === "td" || cell.tagName === "th"));
|
|
8
29
|
var HEADING = /^h[1-6]$/;
|
|
30
|
+
var measureRow = (shape, row) => {
|
|
31
|
+
const cells = cellsOf(row);
|
|
32
|
+
shape.rows += 1;
|
|
33
|
+
shape.columns = Math.max(shape.columns, cells.length);
|
|
34
|
+
for (const cell of cells) {
|
|
35
|
+
const { text, linkText } = cellText(cell);
|
|
36
|
+
shape.longestCell = Math.max(shape.longestCell, text);
|
|
37
|
+
shape.text += text;
|
|
38
|
+
shape.linkText += linkText;
|
|
39
|
+
}
|
|
40
|
+
return cells.length === 1;
|
|
41
|
+
};
|
|
9
42
|
var shapeOf = (table) => {
|
|
10
|
-
const shape = {
|
|
43
|
+
const shape = {
|
|
44
|
+
rows: 0,
|
|
45
|
+
columns: 0,
|
|
46
|
+
dataMarker: false,
|
|
47
|
+
blockInCell: false,
|
|
48
|
+
longestCell: 0,
|
|
49
|
+
text: 0,
|
|
50
|
+
linkText: 0
|
|
51
|
+
};
|
|
11
52
|
let captionHeadings = 0;
|
|
12
53
|
const noteBlockInCell = (tag, aloneInRow) => {
|
|
13
54
|
if (HEADING.test(tag) && aloneInRow) {
|
|
@@ -29,13 +70,7 @@ var shapeOf = (table) => {
|
|
|
29
70
|
if (DATA_MARKERS.has(tag)) {
|
|
30
71
|
shape.dataMarker = true;
|
|
31
72
|
}
|
|
32
|
-
|
|
33
|
-
if (tag === "tr") {
|
|
34
|
-
shape.rows += 1;
|
|
35
|
-
const cells = cellsOf(child).length;
|
|
36
|
-
shape.columns = Math.max(shape.columns, cells);
|
|
37
|
-
alone = cells === 1;
|
|
38
|
-
}
|
|
73
|
+
const alone = tag === "tr" ? measureRow(shape, child) : aloneInRow;
|
|
39
74
|
if (inCell && BLOCK_IN_CELL.has(tag)) {
|
|
40
75
|
noteBlockInCell(tag, aloneInRow);
|
|
41
76
|
}
|
|
@@ -66,7 +101,11 @@ var isLayoutTable = (table) => {
|
|
|
66
101
|
if (shape.rows >= 10 || shape.columns > 4) {
|
|
67
102
|
return false;
|
|
68
103
|
}
|
|
69
|
-
|
|
104
|
+
if (shape.rows * shape.columns > 10) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const linkShare = shape.text === 0 ? 1 : shape.linkText / shape.text;
|
|
108
|
+
return shape.longestCell > MAX_SMALL_TABLE_CELL || linkShare > MAX_SMALL_TABLE_LINK_SHARE;
|
|
70
109
|
};
|
|
71
110
|
var unwrap = (table) => {
|
|
72
111
|
const cells = [];
|