webforai 4.0.0 → 4.1.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/README.md +74 -69
- package/dist/bin.js +1895 -74
- package/dist/cjs/extract-mdast.js +58 -0
- package/dist/cjs/extractors/index.js +5 -0
- package/dist/cjs/extractors/lib/block-features.js +465 -0
- package/dist/cjs/extractors/lib/block-model.generated.js +45 -0
- package/dist/cjs/extractors/lib/block-model.js +72 -0
- package/dist/cjs/extractors/lib/blocks.js +212 -0
- package/dist/cjs/extractors/lib/code-tabs.js +191 -0
- package/dist/cjs/extractors/lib/constants.js +1 -1
- package/dist/cjs/extractors/lib/layout-tables.js +123 -0
- package/dist/cjs/extractors/lib/sanitize.js +144 -28
- package/dist/cjs/extractors/lib/takumi-signal.js +76 -0
- package/dist/cjs/extractors/lib/ui-chrome.js +7 -0
- package/dist/cjs/extractors/presets/auto.js +3 -3
- package/dist/cjs/extractors/presets/kiwame.js +231 -0
- package/dist/cjs/extractors/presets/takumi.js +34 -3
- package/dist/cjs/html-to-markdown.js +58 -4
- package/dist/cjs/html-to-mdast.js +2 -2
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/mdast-handlers/custom-code-handler.js +16 -4
- package/dist/cjs/mdast-handlers/custom-div-handler.js +3 -3
- package/dist/cjs/mdast-handlers/custom-img-handler.js +10 -1
- package/dist/cjs/mdast-handlers/custom-table-handler.js +18 -1
- package/dist/cjs/mdast-handlers/table-cell-flatten.js +195 -0
- package/dist/cjs/mdast-handlers/twoslash.js +71 -0
- package/dist/cjs/metadata/index.js +4 -3
- package/dist/cjs/utils/hast-fast.js +1 -1
- package/dist/cjs/utils/parse-html.js +113 -0
- package/dist/cjs/utils/pre-text.js +104 -0
- package/dist/extract-mdast.js +58 -0
- package/dist/extractors/index.js +3 -0
- package/dist/extractors/lib/block-features.js +437 -0
- package/dist/extractors/lib/block-model.generated.js +21 -0
- package/dist/extractors/lib/block-model.js +48 -0
- package/dist/extractors/lib/blocks.js +185 -0
- package/dist/extractors/lib/code-tabs.js +168 -0
- package/dist/extractors/lib/constants.js +1 -1
- package/dist/extractors/lib/layout-tables.js +99 -0
- package/dist/extractors/lib/sanitize.js +142 -28
- package/dist/extractors/lib/takumi-signal.js +53 -0
- package/dist/extractors/lib/ui-chrome.js +5 -0
- package/dist/extractors/presets/auto.js +3 -3
- package/dist/extractors/presets/kiwame.js +206 -0
- package/dist/extractors/presets/takumi.js +34 -3
- package/dist/html-to-markdown.js +57 -4
- package/dist/html-to-mdast.js +2 -2
- package/dist/index.js +4 -0
- package/dist/mdast-handlers/custom-code-handler.js +15 -4
- package/dist/mdast-handlers/custom-div-handler.js +4 -4
- package/dist/mdast-handlers/custom-img-handler.js +10 -1
- package/dist/mdast-handlers/custom-table-handler.js +19 -2
- package/dist/mdast-handlers/table-cell-flatten.js +170 -0
- package/dist/mdast-handlers/twoslash.js +48 -0
- package/dist/metadata/index.js +4 -3
- package/dist/types/cli/commands/jobs/options.d.ts +2 -2
- package/dist/types/cli/commands/jobs/options.js.map +1 -1
- package/dist/types/cli/commands/webforai/options.js.map +1 -1
- package/dist/types/cli/commands/webforai/run.js.map +1 -1
- package/dist/types/cli/constants.d.ts +3 -1
- package/dist/types/cli/constants.js.map +1 -1
- package/dist/types/extract-mdast.js.map +1 -1
- package/dist/types/extractors/index.d.ts +1 -0
- package/dist/types/extractors/index.js.map +1 -1
- package/dist/types/extractors/lib/block-features.d.ts +43 -0
- package/dist/types/extractors/lib/block-features.js.map +1 -0
- package/dist/types/extractors/lib/block-model.d.ts +28 -0
- package/dist/types/extractors/lib/block-model.generated.d.ts +5 -0
- package/dist/types/extractors/lib/block-model.generated.js.map +1 -0
- package/dist/types/extractors/lib/block-model.js.map +1 -0
- package/dist/types/extractors/lib/blocks.d.ts +53 -0
- package/dist/types/extractors/lib/blocks.js.map +1 -0
- package/dist/types/extractors/lib/code-tabs.d.ts +30 -0
- package/dist/types/extractors/lib/code-tabs.js.map +1 -0
- package/dist/types/extractors/lib/constants.js.map +1 -1
- package/dist/types/extractors/lib/layout-tables.d.ts +17 -0
- package/dist/types/extractors/lib/layout-tables.js.map +1 -0
- package/dist/types/extractors/lib/sanitize.d.ts +33 -3
- package/dist/types/extractors/lib/sanitize.js.map +1 -1
- package/dist/types/extractors/lib/takumi-signal.d.ts +12 -0
- package/dist/types/extractors/lib/takumi-signal.js.map +1 -0
- package/dist/types/extractors/lib/ui-chrome.d.ts +8 -0
- package/dist/types/extractors/lib/ui-chrome.js.map +1 -1
- package/dist/types/extractors/presets/auto.d.ts +6 -1
- package/dist/types/extractors/presets/auto.js.map +1 -1
- package/dist/types/extractors/presets/kiwame.d.ts +31 -0
- package/dist/types/extractors/presets/kiwame.js.map +1 -0
- package/dist/types/extractors/presets/takumi.js.map +1 -1
- package/dist/types/html-to-markdown.d.ts +9 -0
- package/dist/types/html-to-markdown.js.map +1 -1
- package/dist/types/html-to-mdast.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/mdast-handlers/custom-code-handler.d.ts +7 -0
- package/dist/types/mdast-handlers/custom-code-handler.js.map +1 -1
- package/dist/types/mdast-handlers/custom-div-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/table-cell-flatten.d.ts +18 -0
- package/dist/types/mdast-handlers/table-cell-flatten.js.map +1 -0
- package/dist/types/mdast-handlers/twoslash.d.ts +14 -0
- package/dist/types/mdast-handlers/twoslash.js.map +1 -0
- package/dist/types/metadata/index.js.map +1 -1
- package/dist/types/utils/hast-fast.d.ts +1 -1
- package/dist/types/utils/hast-fast.js.map +1 -1
- package/dist/types/utils/parse-html.d.ts +33 -0
- package/dist/types/utils/parse-html.js.map +1 -0
- package/dist/types/utils/pre-text.d.ts +12 -0
- package/dist/types/utils/pre-text.js.map +1 -0
- package/dist/utils/hast-fast.js +1 -1
- package/dist/utils/parse-html.js +87 -0
- package/dist/utils/pre-text.js +81 -0
- package/package.json +3 -1
|
@@ -0,0 +1,191 @@
|
|
|
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 code_tabs_exports = {};
|
|
20
|
+
__export(code_tabs_exports, {
|
|
21
|
+
CodeTabCollector: () => CodeTabCollector
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(code_tabs_exports);
|
|
24
|
+
var import_hast_fast = require("../../utils/hast-fast");
|
|
25
|
+
const MAX_LABEL_LENGTH = 80;
|
|
26
|
+
class CodeTabCollector {
|
|
27
|
+
#groups = [];
|
|
28
|
+
/** Groups whose tab list's parent is still being traversed, innermost last. */
|
|
29
|
+
#open = [];
|
|
30
|
+
#isHidden;
|
|
31
|
+
#radioStrips = [];
|
|
32
|
+
/** @param isHidden - Elements whose text a reader never sees, excluded from labels. */
|
|
33
|
+
constructor(isHidden) {
|
|
34
|
+
this.#isHidden = isHidden;
|
|
35
|
+
}
|
|
36
|
+
#applyRadioStrip(strip, parent) {
|
|
37
|
+
const labels = strip.children.filter((child) => (0, import_hast_fast.isElement)(child) && child.tagName === "label");
|
|
38
|
+
const panels = radioStripPanels(strip, parent);
|
|
39
|
+
if (!panels || panels.length !== labels.length) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
panels.forEach((panel, index) => labelCode(panel, tabLabel(labels[index], this.#isHidden)));
|
|
43
|
+
parent.children.splice(parent.children.indexOf(strip), 1);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Call for every element, in document order, with its depth.
|
|
47
|
+
*
|
|
48
|
+
* A group only collects panels inside the tab list's parent: a page-level tab strip must not
|
|
49
|
+
* lend its labels to an unrelated code switcher further down, and an inner group closes before
|
|
50
|
+
* the outer group's next panel.
|
|
51
|
+
*/
|
|
52
|
+
visit(element, depth, parent) {
|
|
53
|
+
if (isRadioTabStrip(element)) {
|
|
54
|
+
this.#radioStrips.push({ strip: element, parent });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
while (this.#open.length > 0 && depth < (this.#open.at(-1)?.depth ?? 0)) {
|
|
58
|
+
this.#open.pop();
|
|
59
|
+
}
|
|
60
|
+
const role = (0, import_hast_fast.stringProperty)(element, "role");
|
|
61
|
+
if (role === "tablist") {
|
|
62
|
+
const group2 = { tabs: [], panels: [] };
|
|
63
|
+
this.#groups.push(group2);
|
|
64
|
+
this.#open.push({ group: group2, depth });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const group = this.#open.at(-1)?.group;
|
|
68
|
+
if (!group) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (role === "tab") {
|
|
72
|
+
group.tabs.push(element);
|
|
73
|
+
} else if (role === "tabpanel") {
|
|
74
|
+
group.panels.push(element);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Labels the code block of every panel whose tab could be identified. */
|
|
78
|
+
apply() {
|
|
79
|
+
for (const { strip, parent } of this.#radioStrips) {
|
|
80
|
+
this.#applyRadioStrip(strip, parent);
|
|
81
|
+
}
|
|
82
|
+
for (const group of this.#groups) {
|
|
83
|
+
if (group.tabs.length < 2 || group.panels.length === 0) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
for (const [panel, tab] of matchTabs(group)) {
|
|
87
|
+
labelCode(panel, tabLabel(tab, this.#isHidden));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const radioStripPanels = (strip, parent) => {
|
|
93
|
+
const index = parent.children.indexOf(strip);
|
|
94
|
+
for (let cursor = index + 1; cursor < parent.children.length; cursor++) {
|
|
95
|
+
const sibling = parent.children[cursor];
|
|
96
|
+
if ((0, import_hast_fast.isElement)(sibling)) {
|
|
97
|
+
return sibling.children.filter(import_hast_fast.isElement);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return void 0;
|
|
101
|
+
};
|
|
102
|
+
const isRadioTabStrip = (element) => {
|
|
103
|
+
const first = element.children.find(import_hast_fast.isElement);
|
|
104
|
+
if (!(first?.tagName === "input" && (0, import_hast_fast.stringProperty)(first, "type") === "radio")) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
let labels = 0;
|
|
108
|
+
for (const child of element.children) {
|
|
109
|
+
if (!(0, import_hast_fast.isElement)(child)) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (child.tagName === "label") {
|
|
113
|
+
labels += 1;
|
|
114
|
+
} else if (!(child.tagName === "input" && (0, import_hast_fast.stringProperty)(child, "type") === "radio")) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return labels >= 2;
|
|
119
|
+
};
|
|
120
|
+
const indexById = (elements) => {
|
|
121
|
+
const byId = /* @__PURE__ */ new Map();
|
|
122
|
+
for (const element of elements) {
|
|
123
|
+
const id = (0, import_hast_fast.stringProperty)(element, "id");
|
|
124
|
+
if (id) {
|
|
125
|
+
byId.set(id, element);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return byId;
|
|
129
|
+
};
|
|
130
|
+
const matchTabs = ({ tabs, panels }) => {
|
|
131
|
+
const tabById = indexById(tabs);
|
|
132
|
+
const panelById = indexById(panels);
|
|
133
|
+
const tabOf = /* @__PURE__ */ new Map();
|
|
134
|
+
for (const panel of panels) {
|
|
135
|
+
const tab = tabById.get((0, import_hast_fast.stringProperty)(panel, "ariaLabelledBy") ?? "");
|
|
136
|
+
if (tab) {
|
|
137
|
+
tabOf.set(panel, tab);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
for (const tab of tabs) {
|
|
141
|
+
const panel = panelById.get((0, import_hast_fast.stringProperty)(tab, "ariaControls") ?? "");
|
|
142
|
+
if (panel && !tabOf.has(panel)) {
|
|
143
|
+
tabOf.set(panel, tab);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (tabOf.size === 0 && tabs.length === panels.length) {
|
|
147
|
+
panels.forEach((panel, index) => tabOf.set(panel, tabs[index]));
|
|
148
|
+
}
|
|
149
|
+
return tabOf;
|
|
150
|
+
};
|
|
151
|
+
const tabLabel = (tab, isHidden) => {
|
|
152
|
+
const label = (textOf(tab, isHidden) || (0, import_hast_fast.stringProperty)(tab, "dataTitle") || "").replace(/\s+/g, " ").trim();
|
|
153
|
+
return label.length > 0 && label.length <= MAX_LABEL_LENGTH ? label : void 0;
|
|
154
|
+
};
|
|
155
|
+
const labelCode = (panel, label) => {
|
|
156
|
+
if (!label) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const blocks = [];
|
|
160
|
+
collectPre(panel, blocks);
|
|
161
|
+
if (blocks.length === 1 && (0, import_hast_fast.stringProperty)(blocks[0], "dataTitle") === void 0) {
|
|
162
|
+
blocks[0].properties.dataTitle = label;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
const collectPre = (element, into) => {
|
|
166
|
+
for (const child of element.children) {
|
|
167
|
+
if (!(0, import_hast_fast.isElement)(child) || into.length > 1) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (child.tagName === "pre") {
|
|
171
|
+
into.push(child);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
collectPre(child, into);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
const textOf = (element, isHidden) => {
|
|
178
|
+
let text = "";
|
|
179
|
+
for (const child of element.children) {
|
|
180
|
+
if (child.type === "text") {
|
|
181
|
+
text += child.value;
|
|
182
|
+
} else if ((0, import_hast_fast.isElement)(child) && !isHidden(child)) {
|
|
183
|
+
text += textOf(child, isHidden);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return text;
|
|
187
|
+
};
|
|
188
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
189
|
+
0 && (module.exports = {
|
|
190
|
+
CodeTabCollector
|
|
191
|
+
});
|
|
@@ -43,7 +43,7 @@ const REGEXPS = {
|
|
|
43
43
|
* `class="post-header"`), so matching them here deletes the page's headings. The landmark
|
|
44
44
|
* versions of those elements are handled structurally instead.
|
|
45
45
|
*/
|
|
46
|
-
unlikelyCandidates: /-ad-|ai2html|banner|breadcrumb|combx|comment(?!ary)|community|cover-wrap|disqus|gdpr|legends|menu|related|remark|replies|rss|shoutbox|sidebar|site-index|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote|speechify-ignore|avatar|subscribe|newsletter|paywall|consent|cookie|toolbar|masthead|promo|share|sharing|widget|tooltip|dropdown|modal|overlay|backdrop|carousel|announcement|notification|toast|skip-link|screen-reader|visually-hidden|sr-only/i,
|
|
46
|
+
unlikelyCandidates: /-ad-|ai2html|banner|breadcrumb|combx|comment(?!ary)|community|cover-wrap|disqus|gdpr|legends|menu|related|remark|replies|rss|shoutbox|sidebar|site-index|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote|speechify-ignore|avatar|subscribe|newsletter|paywall|consent|cookie|toolbar|masthead|promo|share|sharing|widget|tooltip|dropdown|modal|overlay|backdrop|carousel|announcement|notification|toast|skip-link|screen-reader|(?<!not-)visually-hidden|(?<!not-)sr-only/i,
|
|
47
47
|
/** Rescues containers whose class merely happens to contain an unlikely substring. */
|
|
48
48
|
okMaybeItsaCandidate: /and|article|body|column|content|main|shadow|code|post|entry|story|markdown|prose|doc/i,
|
|
49
49
|
/** Very high-confidence boilerplate, not rescued by the clause above. */
|
|
@@ -0,0 +1,123 @@
|
|
|
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 layout_tables_exports = {};
|
|
20
|
+
__export(layout_tables_exports, {
|
|
21
|
+
isLayoutTable: () => isLayoutTable,
|
|
22
|
+
unwrapLayoutTables: () => unwrapLayoutTables
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(layout_tables_exports);
|
|
25
|
+
var import_hast_fast = require("../../utils/hast-fast");
|
|
26
|
+
const DATA_MARKERS = /* @__PURE__ */ new Set(["caption", "thead", "tfoot", "th", "col", "colgroup"]);
|
|
27
|
+
const BLOCK_IN_CELL = /* @__PURE__ */ new Set(["h1", "h2", "h3", "h4", "h5", "h6", "table", "form"]);
|
|
28
|
+
const TABLE_PARTS = /* @__PURE__ */ new Set(["tbody", "thead", "tfoot", "tr", "td", "th"]);
|
|
29
|
+
const TABLE_CONTEXT = /* @__PURE__ */ new Set(["table", "tbody", "thead", "tfoot", "tr"]);
|
|
30
|
+
const shapeOf = (table) => {
|
|
31
|
+
const shape = { rows: 0, columns: 0, dataMarker: false, blockInCell: false };
|
|
32
|
+
const visit = (node, inCell) => {
|
|
33
|
+
for (const child of node.children) {
|
|
34
|
+
if (!(0, import_hast_fast.isElement)(child)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const tag = child.tagName;
|
|
38
|
+
if (tag === "table") {
|
|
39
|
+
shape.blockInCell = shape.blockInCell || inCell;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (DATA_MARKERS.has(tag)) {
|
|
43
|
+
shape.dataMarker = true;
|
|
44
|
+
}
|
|
45
|
+
if (tag === "tr") {
|
|
46
|
+
shape.rows += 1;
|
|
47
|
+
const cells = child.children.filter(
|
|
48
|
+
(cell) => (0, import_hast_fast.isElement)(cell) && (cell.tagName === "td" || cell.tagName === "th")
|
|
49
|
+
).length;
|
|
50
|
+
shape.columns = Math.max(shape.columns, cells);
|
|
51
|
+
}
|
|
52
|
+
if (inCell && BLOCK_IN_CELL.has(tag)) {
|
|
53
|
+
shape.blockInCell = true;
|
|
54
|
+
}
|
|
55
|
+
visit(child, inCell || tag === "td" || tag === "th");
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
visit(table, false);
|
|
59
|
+
return shape;
|
|
60
|
+
};
|
|
61
|
+
const isLayoutTable = (table) => {
|
|
62
|
+
const role = (0, import_hast_fast.stringProperty)(table, "role");
|
|
63
|
+
if (role === "presentation" || role === "none" || (0, import_hast_fast.stringProperty)(table, "datatable") === "0") {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
const shape = shapeOf(table);
|
|
67
|
+
if (shape.blockInCell) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
if (shape.dataMarker) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (shape.rows <= 1 || shape.columns <= 1) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (shape.rows >= 10 || shape.columns > 4) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return shape.rows * shape.columns <= 10;
|
|
80
|
+
};
|
|
81
|
+
const unwrap = (table) => {
|
|
82
|
+
const cells = [];
|
|
83
|
+
const collect = (node) => {
|
|
84
|
+
for (const child of node.children) {
|
|
85
|
+
if (!(0, import_hast_fast.isElement)(child)) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (child.tagName === "td" || child.tagName === "th") {
|
|
89
|
+
cells.push({ type: "element", tagName: "div", properties: {}, children: child.children });
|
|
90
|
+
} else if (child.tagName !== "table") {
|
|
91
|
+
collect(child);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
collect(table);
|
|
96
|
+
return { type: "element", tagName: "div", properties: {}, children: cells };
|
|
97
|
+
};
|
|
98
|
+
const unwrapLayoutTables = (root) => {
|
|
99
|
+
const visit = (parent) => {
|
|
100
|
+
const parentTag = (0, import_hast_fast.isElement)(parent) ? parent.tagName : "";
|
|
101
|
+
for (let index = 0; index < parent.children.length; index++) {
|
|
102
|
+
const child = parent.children[index];
|
|
103
|
+
if (!(0, import_hast_fast.isElement)(child)) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (TABLE_PARTS.has(child.tagName) && !TABLE_CONTEXT.has(parentTag)) {
|
|
107
|
+
child.tagName = "div";
|
|
108
|
+
}
|
|
109
|
+
visit(child);
|
|
110
|
+
if (child.tagName === "table" && isLayoutTable(child)) {
|
|
111
|
+
parent.children[index] = unwrap(child);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
if ("children" in root) {
|
|
116
|
+
visit(root);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
120
|
+
0 && (module.exports = {
|
|
121
|
+
isLayoutTable,
|
|
122
|
+
unwrapLayoutTables
|
|
123
|
+
});
|
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var sanitize_exports = {};
|
|
20
20
|
__export(sanitize_exports, {
|
|
21
|
+
REFERENCE_HEADING: () => REFERENCE_HEADING,
|
|
21
22
|
cleanContent: () => cleanContent,
|
|
22
23
|
dropEmptyElements: () => dropEmptyElements,
|
|
23
24
|
findCleanupTargets: () => findCleanupTargets,
|
|
@@ -25,30 +26,46 @@ __export(sanitize_exports, {
|
|
|
25
26
|
findUnlikelyElements: () => findUnlikelyElements,
|
|
26
27
|
hoistNoscriptImages: () => hoistNoscriptImages,
|
|
27
28
|
stripNonContent: () => stripNonContent,
|
|
28
|
-
stripUnlikely: () => stripUnlikely
|
|
29
|
+
stripUnlikely: () => stripUnlikely,
|
|
30
|
+
unlikelyTier: () => unlikelyTier
|
|
29
31
|
});
|
|
30
32
|
module.exports = __toCommonJS(sanitize_exports);
|
|
31
33
|
var import_hast_fast = require("../../utils/hast-fast");
|
|
34
|
+
var import_code_tabs = require("./code-tabs");
|
|
32
35
|
var import_constants = require("./constants");
|
|
33
36
|
var import_ui_chrome = require("./ui-chrome");
|
|
34
37
|
const INVISIBLE_STYLE = /(^|;)\s*(display\s*:\s*none|visibility\s*:\s*hidden)\s*(;|$)/i;
|
|
35
38
|
const hasHiddenClass = (element) => {
|
|
36
39
|
const classes = (0, import_hast_fast.classList)(element);
|
|
37
40
|
if (!classes.some((name) => import_constants.HIDDEN_CLASS_NAMES.has(name))) {
|
|
38
|
-
return classes.some((name) => import_constants.REGEXPS.hidden.test(name));
|
|
41
|
+
return classes.some((name) => import_constants.REGEXPS.hidden.test(name) || isScreenReaderOnlyClass(name));
|
|
39
42
|
}
|
|
40
43
|
return !classes.some((name) => import_constants.RESPONSIVE_DISPLAY_OVERRIDE.test(name));
|
|
41
44
|
};
|
|
45
|
+
const SCREEN_READER_ONLY = /^(sronly|visuallyhidden|screenreader(only|text))(focusable|styles\w*)?$/;
|
|
46
|
+
const isScreenReaderOnlyClass = (name) => {
|
|
47
|
+
const first = name.charCodeAt(0) | 32;
|
|
48
|
+
if (first !== 115 && first !== 118) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return SCREEN_READER_ONLY.test(name.toLowerCase().replace(/[-_]/g, ""));
|
|
52
|
+
};
|
|
42
53
|
const isNonContent = (node) => {
|
|
43
54
|
if (node.type === "comment" || node.type === "doctype") {
|
|
44
55
|
return true;
|
|
45
56
|
}
|
|
46
57
|
return (0, import_hast_fast.isElement)(node) && import_constants.NON_CONTENT_TAGS.has(node.tagName);
|
|
47
58
|
};
|
|
48
|
-
const isHidden = (element) => {
|
|
59
|
+
const isHidden = (element, parent, siblingCode) => {
|
|
60
|
+
if (!looksHidden(element)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
49
63
|
if (containsMath(element)) {
|
|
50
64
|
return false;
|
|
51
65
|
}
|
|
66
|
+
return !isHiddenCodePanel(element, parent, siblingCode);
|
|
67
|
+
};
|
|
68
|
+
const looksHidden = (element) => {
|
|
52
69
|
if ((0, import_hast_fast.isTruthyAttribute)(element, "hidden")) {
|
|
53
70
|
return true;
|
|
54
71
|
}
|
|
@@ -61,10 +78,57 @@ const isHidden = (element) => {
|
|
|
61
78
|
}
|
|
62
79
|
const width = (0, import_hast_fast.numericProperty)(element, "data-rwidth");
|
|
63
80
|
const height = (0, import_hast_fast.numericProperty)(element, "data-rheight");
|
|
64
|
-
|
|
81
|
+
return width === 0 && height === 0;
|
|
82
|
+
};
|
|
83
|
+
const MAX_CODE_PANEL_PROSE = 200;
|
|
84
|
+
const panelCode = (element) => {
|
|
85
|
+
let code = "";
|
|
86
|
+
let prose = 0;
|
|
87
|
+
const visit = (node, insideCode) => {
|
|
88
|
+
for (const child of node.children) {
|
|
89
|
+
if (child.type === "text") {
|
|
90
|
+
if (insideCode) {
|
|
91
|
+
code += child.value;
|
|
92
|
+
} else {
|
|
93
|
+
prose += child.value.trim().length;
|
|
94
|
+
if (prose > MAX_CODE_PANEL_PROSE) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} else if ((0, import_hast_fast.isElement)(child) && !visit(child, insideCode || child.tagName === "pre")) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
65
102
|
return true;
|
|
103
|
+
};
|
|
104
|
+
return visit(element, element.tagName === "pre") && code.trim().length > 0 ? code : void 0;
|
|
105
|
+
};
|
|
106
|
+
const visibleSiblingCode = (parent, cache) => {
|
|
107
|
+
let codes = cache.get(parent);
|
|
108
|
+
if (!codes) {
|
|
109
|
+
codes = /* @__PURE__ */ new Set();
|
|
110
|
+
for (const child of parent.children) {
|
|
111
|
+
if ((0, import_hast_fast.isElement)(child) && !looksHidden(child)) {
|
|
112
|
+
const code = panelCode(child);
|
|
113
|
+
if (code !== void 0) {
|
|
114
|
+
codes.add(code);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
cache.set(parent, codes);
|
|
66
119
|
}
|
|
67
|
-
return
|
|
120
|
+
return codes;
|
|
121
|
+
};
|
|
122
|
+
const isHiddenCodePanel = (element, parent, cache) => {
|
|
123
|
+
const code = panelCode(element);
|
|
124
|
+
if (code === void 0) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
const siblings = visibleSiblingCode(parent, cache);
|
|
128
|
+
if (siblings.has(code)) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
return (0, import_hast_fast.stringProperty)(element, "role") === "tabpanel" || siblings.size > 0;
|
|
68
132
|
};
|
|
69
133
|
const PLACEHOLDER_IMAGE_SRC = /^data:image\/|^about:blank$|spacer\.gif$|blank\.(gif|png)$/i;
|
|
70
134
|
const isPlaceholderImage = (element) => {
|
|
@@ -82,15 +146,16 @@ const isPlaceholderImage = (element) => {
|
|
|
82
146
|
}
|
|
83
147
|
return false;
|
|
84
148
|
};
|
|
85
|
-
const hoistNoscriptImages = (tree) => {
|
|
86
|
-
const visit = (parent) => {
|
|
149
|
+
const hoistNoscriptImages = (tree, onElement) => {
|
|
150
|
+
const visit = (parent, depth) => {
|
|
87
151
|
for (let index = 0; index < parent.children.length; index++) {
|
|
88
152
|
const child = parent.children[index];
|
|
89
153
|
if (!(0, import_hast_fast.isElement)(child)) {
|
|
90
154
|
continue;
|
|
91
155
|
}
|
|
92
156
|
if (child.tagName !== "noscript") {
|
|
93
|
-
|
|
157
|
+
onElement?.(child, depth, parent);
|
|
158
|
+
visit(child, depth + 1);
|
|
94
159
|
continue;
|
|
95
160
|
}
|
|
96
161
|
const hasImage = child.children.some(
|
|
@@ -110,7 +175,7 @@ const hoistNoscriptImages = (tree) => {
|
|
|
110
175
|
}
|
|
111
176
|
};
|
|
112
177
|
if ("children" in tree) {
|
|
113
|
-
visit(tree);
|
|
178
|
+
visit(tree, 0);
|
|
114
179
|
}
|
|
115
180
|
};
|
|
116
181
|
const containsMath = (element) => {
|
|
@@ -125,12 +190,15 @@ const containsMath = (element) => {
|
|
|
125
190
|
return false;
|
|
126
191
|
};
|
|
127
192
|
const stripNonContent = (tree) => {
|
|
128
|
-
|
|
129
|
-
|
|
193
|
+
const tabs = new import_code_tabs.CodeTabCollector((element) => looksHidden(element) || import_constants.NON_CONTENT_TAGS.has(element.tagName));
|
|
194
|
+
hoistNoscriptImages(tree, (element, depth, parent) => tabs.visit(element, depth, parent));
|
|
195
|
+
tabs.apply();
|
|
196
|
+
const siblingCode = /* @__PURE__ */ new WeakMap();
|
|
197
|
+
return (0, import_hast_fast.pruneInPlace)(tree, (node, parent) => {
|
|
130
198
|
if (isNonContent(node)) {
|
|
131
199
|
return false;
|
|
132
200
|
}
|
|
133
|
-
if ((0, import_hast_fast.isElement)(node) && isHidden(node)) {
|
|
201
|
+
if ((0, import_hast_fast.isElement)(node) && isHidden(node, parent, siblingCode)) {
|
|
134
202
|
return false;
|
|
135
203
|
}
|
|
136
204
|
return true;
|
|
@@ -157,32 +225,32 @@ const findLandmarkChrome = (tree) => {
|
|
|
157
225
|
visit(tree, 0, false);
|
|
158
226
|
return chrome;
|
|
159
227
|
};
|
|
160
|
-
const
|
|
228
|
+
const unlikelyTier = (element) => {
|
|
161
229
|
if (element.tagName === "article" || element.tagName === "main" || element.tagName === "body") {
|
|
162
|
-
return
|
|
230
|
+
return void 0;
|
|
163
231
|
}
|
|
164
232
|
const role = (0, import_hast_fast.stringProperty)(element, "role");
|
|
165
233
|
if (role && import_constants.UNLIKELY_ROLES.has(role)) {
|
|
166
|
-
return
|
|
234
|
+
return "strong";
|
|
167
235
|
}
|
|
168
236
|
if (import_constants.CHROME_TAGS.has(element.tagName)) {
|
|
169
|
-
return
|
|
237
|
+
return "strong";
|
|
170
238
|
}
|
|
171
239
|
const match = (0, import_hast_fast.matchString)(element);
|
|
172
240
|
if (import_constants.REGEXPS.specialUnlikelyCandidates.test(match)) {
|
|
173
|
-
return
|
|
241
|
+
return "strong";
|
|
174
242
|
}
|
|
175
243
|
for (const name of [...(0, import_hast_fast.classList)(element), (0, import_hast_fast.stringProperty)(element, "id") ?? ""]) {
|
|
176
244
|
if (import_constants.REGEXPS.stronglyUnlikely.test(name)) {
|
|
177
|
-
return
|
|
245
|
+
return "strong";
|
|
178
246
|
}
|
|
179
247
|
}
|
|
180
248
|
if (import_constants.REGEXPS.unlikelyCandidates.test(match) && !import_constants.REGEXPS.okMaybeItsaCandidate.test(match)) {
|
|
181
|
-
return
|
|
249
|
+
return "weak";
|
|
182
250
|
}
|
|
183
|
-
return
|
|
251
|
+
return void 0;
|
|
184
252
|
};
|
|
185
|
-
const findUnlikelyElements = (tree) => {
|
|
253
|
+
const findUnlikelyElements = (tree, spareWeak) => {
|
|
186
254
|
const landmarks = findLandmarkChrome(tree);
|
|
187
255
|
const doomed = [];
|
|
188
256
|
const visit = (node) => {
|
|
@@ -193,7 +261,15 @@ const findUnlikelyElements = (tree) => {
|
|
|
193
261
|
if (!(0, import_hast_fast.isElement)(child)) {
|
|
194
262
|
continue;
|
|
195
263
|
}
|
|
196
|
-
if (landmarks.has(child)
|
|
264
|
+
if (landmarks.has(child)) {
|
|
265
|
+
doomed.push(child);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (PREFORMATTED_TAGS.has(child.tagName)) {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
const tier = unlikelyTier(child);
|
|
272
|
+
if (tier === "strong" || tier === "weak" && !spareWeak?.(child)) {
|
|
197
273
|
doomed.push(child);
|
|
198
274
|
continue;
|
|
199
275
|
}
|
|
@@ -338,11 +414,15 @@ const findCleanupTargets = (tree, collector) => {
|
|
|
338
414
|
visit(child);
|
|
339
415
|
continue;
|
|
340
416
|
}
|
|
417
|
+
if (LITERAL_TEXT_TAGS.has(child.tagName)) {
|
|
418
|
+
collectButtons(child, doomed);
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
341
421
|
if (isLinkOnlyBlock(child, collector)) {
|
|
342
422
|
condemnLinkBlock(child, siblings, index, collector, doomed);
|
|
343
423
|
continue;
|
|
344
424
|
}
|
|
345
|
-
if (isMidArticleWidget(child)) {
|
|
425
|
+
if (isMidArticleWidget(child, collector)) {
|
|
346
426
|
doomed.push(child);
|
|
347
427
|
continue;
|
|
348
428
|
}
|
|
@@ -384,18 +464,52 @@ const countAnchors = (element) => {
|
|
|
384
464
|
return count;
|
|
385
465
|
};
|
|
386
466
|
const LITERAL_TEXT_TAGS = /* @__PURE__ */ new Set(["code", "kbd", "samp", "var", "pre"]);
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
467
|
+
const PREFORMATTED_TAGS = /* @__PURE__ */ new Set(["pre", "code"]);
|
|
468
|
+
const collectButtons = (element, into) => {
|
|
469
|
+
for (const child of element.children) {
|
|
470
|
+
if (!(0, import_hast_fast.isElement)(child)) {
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
if (child.tagName === "button") {
|
|
474
|
+
into.push(child);
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
collectButtons(child, into);
|
|
390
478
|
}
|
|
479
|
+
};
|
|
480
|
+
const isMidArticleWidget = (element, collector) => {
|
|
391
481
|
if (element.tagName === "form" || element.tagName === "fieldset") {
|
|
392
482
|
return true;
|
|
393
483
|
}
|
|
394
484
|
if (element.tagName === "button") {
|
|
395
485
|
return true;
|
|
396
486
|
}
|
|
397
|
-
|
|
487
|
+
if (collector.metrics(element).text > import_ui_chrome.MAX_CONSENT_PLACEHOLDER_LENGTH) {
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
const text = elementText(element);
|
|
491
|
+
return (0, import_ui_chrome.isUiChromeText)(text) || (0, import_ui_chrome.isConsentPlaceholderText)(text) && !hasBlockDescendant(element);
|
|
398
492
|
};
|
|
493
|
+
const BLOCK_TAGS = /* @__PURE__ */ new Set([
|
|
494
|
+
"p",
|
|
495
|
+
"div",
|
|
496
|
+
"section",
|
|
497
|
+
"article",
|
|
498
|
+
"figure",
|
|
499
|
+
"figcaption",
|
|
500
|
+
"blockquote",
|
|
501
|
+
"ul",
|
|
502
|
+
"ol",
|
|
503
|
+
"table",
|
|
504
|
+
"pre",
|
|
505
|
+
"h1",
|
|
506
|
+
"h2",
|
|
507
|
+
"h3",
|
|
508
|
+
"h4",
|
|
509
|
+
"h5",
|
|
510
|
+
"h6"
|
|
511
|
+
]);
|
|
512
|
+
const hasBlockDescendant = (element) => element.children.some((child) => (0, import_hast_fast.isElement)(child) && (BLOCK_TAGS.has(child.tagName) || hasBlockDescendant(child)));
|
|
399
513
|
const cleanContent = (tree, collector) => {
|
|
400
514
|
const doomed = new Set(findCleanupTargets(tree, collector));
|
|
401
515
|
if (doomed.size > 0) {
|
|
@@ -418,6 +532,7 @@ const elementText = (node) => {
|
|
|
418
532
|
};
|
|
419
533
|
// Annotate the CommonJS export names for ESM import in node:
|
|
420
534
|
0 && (module.exports = {
|
|
535
|
+
REFERENCE_HEADING,
|
|
421
536
|
cleanContent,
|
|
422
537
|
dropEmptyElements,
|
|
423
538
|
findCleanupTargets,
|
|
@@ -425,5 +540,6 @@ const elementText = (node) => {
|
|
|
425
540
|
findUnlikelyElements,
|
|
426
541
|
hoistNoscriptImages,
|
|
427
542
|
stripNonContent,
|
|
428
|
-
stripUnlikely
|
|
543
|
+
stripUnlikely,
|
|
544
|
+
unlikelyTier
|
|
429
545
|
});
|