@postalsys/email-content 0.0.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/LICENSE +21 -0
- package/README.md +288 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/analyze.d.ts +91 -0
- package/dist/analyze.d.ts.map +1 -0
- package/dist/analyze.js +274 -0
- package/dist/analyze.js.map +1 -0
- package/dist/annotate/client.d.ts +64 -0
- package/dist/annotate/client.d.ts.map +1 -0
- package/dist/annotate/client.js +139 -0
- package/dist/annotate/client.js.map +1 -0
- package/dist/annotate/llm.d.ts +46 -0
- package/dist/annotate/llm.d.ts.map +1 -0
- package/dist/annotate/llm.js +107 -0
- package/dist/annotate/llm.js.map +1 -0
- package/dist/annotate/prompt.d.ts +38 -0
- package/dist/annotate/prompt.d.ts.map +1 -0
- package/dist/annotate/prompt.js +165 -0
- package/dist/annotate/prompt.js.map +1 -0
- package/dist/annotate/store.d.ts +43 -0
- package/dist/annotate/store.d.ts.map +1 -0
- package/dist/annotate/store.js +46 -0
- package/dist/annotate/store.js.map +1 -0
- package/dist/canonical/html.d.ts +33 -0
- package/dist/canonical/html.d.ts.map +1 -0
- package/dist/canonical/html.js +156 -0
- package/dist/canonical/html.js.map +1 -0
- package/dist/canonical/text.d.ts +75 -0
- package/dist/canonical/text.d.ts.map +1 -0
- package/dist/canonical/text.js +217 -0
- package/dist/canonical/text.js.map +1 -0
- package/dist/classify/confidence.d.ts +38 -0
- package/dist/classify/confidence.d.ts.map +1 -0
- package/dist/classify/confidence.js +59 -0
- package/dist/classify/confidence.js.map +1 -0
- package/dist/classify/reconcile.d.ts +52 -0
- package/dist/classify/reconcile.d.ts.map +1 -0
- package/dist/classify/reconcile.js +100 -0
- package/dist/classify/reconcile.js.map +1 -0
- package/dist/classify/rules.d.ts +51 -0
- package/dist/classify/rules.d.ts.map +1 -0
- package/dist/classify/rules.js +648 -0
- package/dist/classify/rules.js.map +1 -0
- package/dist/cli/annotate.d.ts +23 -0
- package/dist/cli/annotate.d.ts.map +1 -0
- package/dist/cli/annotate.js +328 -0
- package/dist/cli/annotate.js.map +1 -0
- package/dist/cli/args.d.ts +17 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +72 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/benchmark.d.ts +13 -0
- package/dist/cli/benchmark.d.ts.map +1 -0
- package/dist/cli/benchmark.js +172 -0
- package/dist/cli/benchmark.js.map +1 -0
- package/dist/cli/corpus.d.ts +9 -0
- package/dist/cli/corpus.d.ts.map +1 -0
- package/dist/cli/corpus.js +152 -0
- package/dist/cli/corpus.js.map +1 -0
- package/dist/cli/disagreements.d.ts +14 -0
- package/dist/cli/disagreements.d.ts.map +1 -0
- package/dist/cli/disagreements.js +133 -0
- package/dist/cli/disagreements.js.map +1 -0
- package/dist/cli/evaluate.d.ts +15 -0
- package/dist/cli/evaluate.d.ts.map +1 -0
- package/dist/cli/evaluate.js +215 -0
- package/dist/cli/evaluate.js.map +1 -0
- package/dist/cli/extract.d.ts +10 -0
- package/dist/cli/extract.d.ts.map +1 -0
- package/dist/cli/extract.js +139 -0
- package/dist/cli/extract.js.map +1 -0
- package/dist/cli/main.d.ts +9 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +147 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/corpus/analyze.d.ts +66 -0
- package/dist/corpus/analyze.d.ts.map +1 -0
- package/dist/corpus/analyze.js +214 -0
- package/dist/corpus/analyze.js.map +1 -0
- package/dist/corpus/migrations/index.d.ts +14 -0
- package/dist/corpus/migrations/index.d.ts.map +1 -0
- package/dist/corpus/migrations/index.js +158 -0
- package/dist/corpus/migrations/index.js.map +1 -0
- package/dist/corpus/sample.d.ts +66 -0
- package/dist/corpus/sample.d.ts.map +1 -0
- package/dist/corpus/sample.js +98 -0
- package/dist/corpus/sample.js.map +1 -0
- package/dist/corpus/scanner.d.ts +79 -0
- package/dist/corpus/scanner.d.ts.map +1 -0
- package/dist/corpus/scanner.js +256 -0
- package/dist/corpus/scanner.js.map +1 -0
- package/dist/corpus/stats.d.ts +76 -0
- package/dist/corpus/stats.d.ts.map +1 -0
- package/dist/corpus/stats.js +240 -0
- package/dist/corpus/stats.js.map +1 -0
- package/dist/corpus/store.d.ts +67 -0
- package/dist/corpus/store.d.ts.map +1 -0
- package/dist/corpus/store.js +196 -0
- package/dist/corpus/store.js.map +1 -0
- package/dist/corpus/thread-index.d.ts +31 -0
- package/dist/corpus/thread-index.d.ts.map +1 -0
- package/dist/corpus/thread-index.js +182 -0
- package/dist/corpus/thread-index.js.map +1 -0
- package/dist/corpus/worker.d.ts +21 -0
- package/dist/corpus/worker.d.ts.map +1 -0
- package/dist/corpus/worker.js +74 -0
- package/dist/corpus/worker.js.map +1 -0
- package/dist/detect/client.d.ts +28 -0
- package/dist/detect/client.d.ts.map +1 -0
- package/dist/detect/client.js +121 -0
- package/dist/detect/client.js.map +1 -0
- package/dist/detect/disclaimer.d.ts +12 -0
- package/dist/detect/disclaimer.d.ts.map +1 -0
- package/dist/detect/disclaimer.js +28 -0
- package/dist/detect/disclaimer.js.map +1 -0
- package/dist/detect/forward-header.d.ts +10 -0
- package/dist/detect/forward-header.d.ts.map +1 -0
- package/dist/detect/forward-header.js +35 -0
- package/dist/detect/forward-header.js.map +1 -0
- package/dist/detect/patterns/disclaimers.json +113 -0
- package/dist/detect/patterns/forward-headers.json +40 -0
- package/dist/detect/patterns/html-clients.json +157 -0
- package/dist/detect/patterns/quoted-headers.json +41 -0
- package/dist/detect/patterns/reply-headers.json +139 -0
- package/dist/detect/patterns/signatures.json +58 -0
- package/dist/detect/patterns.d.ts +43 -0
- package/dist/detect/patterns.d.ts.map +1 -0
- package/dist/detect/patterns.js +125 -0
- package/dist/detect/patterns.js.map +1 -0
- package/dist/detect/reply-header.d.ts +44 -0
- package/dist/detect/reply-header.d.ts.map +1 -0
- package/dist/detect/reply-header.js +134 -0
- package/dist/detect/reply-header.js.map +1 -0
- package/dist/detect/signature.d.ts +28 -0
- package/dist/detect/signature.d.ts.map +1 -0
- package/dist/detect/signature.js +77 -0
- package/dist/detect/signature.js.map +1 -0
- package/dist/detect/traffic.d.ts +26 -0
- package/dist/detect/traffic.d.ts.map +1 -0
- package/dist/detect/traffic.js +98 -0
- package/dist/detect/traffic.js.map +1 -0
- package/dist/eval/metrics.d.ts +87 -0
- package/dist/eval/metrics.d.ts.map +1 -0
- package/dist/eval/metrics.js +185 -0
- package/dist/eval/metrics.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +163 -0
- package/dist/index.js.map +1 -0
- package/dist/match/history.d.ts +62 -0
- package/dist/match/history.d.ts.map +1 -0
- package/dist/match/history.js +128 -0
- package/dist/match/history.js.map +1 -0
- package/dist/match/normalize.d.ts +33 -0
- package/dist/match/normalize.d.ts.map +1 -0
- package/dist/match/normalize.js +63 -0
- package/dist/match/normalize.js.map +1 -0
- package/dist/match/shingle.d.ts +44 -0
- package/dist/match/shingle.d.ts.map +1 -0
- package/dist/match/shingle.js +78 -0
- package/dist/match/shingle.js.map +1 -0
- package/dist/mime/charset.d.ts +33 -0
- package/dist/mime/charset.d.ts.map +1 -0
- package/dist/mime/charset.js +118 -0
- package/dist/mime/charset.js.map +1 -0
- package/dist/mime/headers.d.ts +32 -0
- package/dist/mime/headers.d.ts.map +1 -0
- package/dist/mime/headers.js +127 -0
- package/dist/mime/headers.js.map +1 -0
- package/dist/mime/model.d.ts +111 -0
- package/dist/mime/model.d.ts.map +1 -0
- package/dist/mime/model.js +17 -0
- package/dist/mime/model.js.map +1 -0
- package/dist/mime/parse.d.ts +27 -0
- package/dist/mime/parse.d.ts.map +1 -0
- package/dist/mime/parse.js +343 -0
- package/dist/mime/parse.js.map +1 -0
- package/dist/segment/features.d.ts +29 -0
- package/dist/segment/features.d.ts.map +1 -0
- package/dist/segment/features.js +102 -0
- package/dist/segment/features.js.map +1 -0
- package/dist/segment/html-blocks.d.ts +28 -0
- package/dist/segment/html-blocks.d.ts.map +1 -0
- package/dist/segment/html-blocks.js +596 -0
- package/dist/segment/html-blocks.js.map +1 -0
- package/dist/segment/text-blocks.d.ts +30 -0
- package/dist/segment/text-blocks.d.ts.map +1 -0
- package/dist/segment/text-blocks.js +204 -0
- package/dist/segment/text-blocks.js.map +1 -0
- package/dist/segment/types.d.ts +88 -0
- package/dist/segment/types.d.ts.map +1 -0
- package/dist/segment/types.js +11 -0
- package/dist/segment/types.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/util/hash.d.ts +49 -0
- package/dist/util/hash.d.ts.map +1 -0
- package/dist/util/hash.js +0 -0
- package/dist/util/hash.js.map +1 -0
- package/dist/util/lang.d.ts +25 -0
- package/dist/util/lang.d.ts.map +1 -0
- package/dist/util/lang.js +135 -0
- package/dist/util/lang.js.map +1 -0
- package/dist/util/worker-pool.d.ts +51 -0
- package/dist/util/worker-pool.d.ts.map +1 -0
- package/dist/util/worker-pool.js +155 -0
- package/dist/util/worker-pool.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,596 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Stage 3: HTML block segmentation.
|
|
4
|
+
*
|
|
5
|
+
* The DOM is walked with node-html-parser, which exposes a source `range` on every node. That is
|
|
6
|
+
* the reason it is used here rather than a faster tag stripper: a block that cannot point back at
|
|
7
|
+
* the exact source offsets it came from cannot be traced, and traceability is a requirement.
|
|
8
|
+
*
|
|
9
|
+
* Segmentation emits one block per run of inline content between block level elements. A container
|
|
10
|
+
* such as a Gmail quote wrapper does not become a block itself; instead every block inside it
|
|
11
|
+
* records its ancestry. That is deliberate, because interleaved replies put new content inside and
|
|
12
|
+
* between quote containers, and a container-level decision cannot express that.
|
|
13
|
+
*
|
|
14
|
+
* Blocks tile the source: each block's range is extended backwards to the end of the previous
|
|
15
|
+
* block, and the last block runs to the end of the document, so concatenating block texts
|
|
16
|
+
* reproduces the HTML exactly.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.isPathologicalHtml = isPathologicalHtml;
|
|
20
|
+
exports.segmentHtmlBlocks = segmentHtmlBlocks;
|
|
21
|
+
const node_html_parser_1 = require("node-html-parser");
|
|
22
|
+
const patterns_1 = require("../detect/patterns");
|
|
23
|
+
const reply_header_1 = require("../detect/reply-header");
|
|
24
|
+
const forward_header_1 = require("../detect/forward-header");
|
|
25
|
+
const signature_1 = require("../detect/signature");
|
|
26
|
+
const disclaimer_1 = require("../detect/disclaimer");
|
|
27
|
+
const html_1 = require("../canonical/html");
|
|
28
|
+
const features_1 = require("./features");
|
|
29
|
+
/** Elements that break a run of inline content. */
|
|
30
|
+
const BLOCK_TAGS = new Set([
|
|
31
|
+
'address',
|
|
32
|
+
'article',
|
|
33
|
+
'aside',
|
|
34
|
+
'blockquote',
|
|
35
|
+
'body',
|
|
36
|
+
'center',
|
|
37
|
+
'dd',
|
|
38
|
+
'div',
|
|
39
|
+
'dl',
|
|
40
|
+
'dt',
|
|
41
|
+
'fieldset',
|
|
42
|
+
'figcaption',
|
|
43
|
+
'figure',
|
|
44
|
+
'footer',
|
|
45
|
+
'form',
|
|
46
|
+
'h1',
|
|
47
|
+
'h2',
|
|
48
|
+
'h3',
|
|
49
|
+
'h4',
|
|
50
|
+
'h5',
|
|
51
|
+
'h6',
|
|
52
|
+
'header',
|
|
53
|
+
'hr',
|
|
54
|
+
'html',
|
|
55
|
+
'li',
|
|
56
|
+
'main',
|
|
57
|
+
'nav',
|
|
58
|
+
'ol',
|
|
59
|
+
'p',
|
|
60
|
+
'pre',
|
|
61
|
+
'section',
|
|
62
|
+
'table',
|
|
63
|
+
'tbody',
|
|
64
|
+
'td',
|
|
65
|
+
'tfoot',
|
|
66
|
+
'th',
|
|
67
|
+
'thead',
|
|
68
|
+
'tr',
|
|
69
|
+
'ul'
|
|
70
|
+
]);
|
|
71
|
+
/** Elements whose content is never visible text. */
|
|
72
|
+
const INVISIBLE_TAGS = new Set(['script', 'style', 'head', 'title', 'noscript', 'template', 'meta', 'link']);
|
|
73
|
+
/**
|
|
74
|
+
* Parse the simple selector forms used in html-clients.json.
|
|
75
|
+
*
|
|
76
|
+
* Only `tag`, `tag.class`, `tag#id`, `tag[attr=value]` and their bare forms are supported. A full
|
|
77
|
+
* CSS engine is not needed, and a hand written matcher makes the behaviour predictable, including
|
|
78
|
+
* the Outlook Web nesting rule below.
|
|
79
|
+
*/
|
|
80
|
+
function parseSelector(selector) {
|
|
81
|
+
const attrMatch = selector.match(/^([a-z0-9-]*)\[([a-z-]+)=["']?([^\]"']+)["']?\]$/i);
|
|
82
|
+
if (attrMatch) {
|
|
83
|
+
return { tag: attrMatch[1] || null, className: null, id: null, attr: { name: attrMatch[2], value: attrMatch[3].toLowerCase() } };
|
|
84
|
+
}
|
|
85
|
+
const idMatch = selector.match(/^([a-z0-9-]*)#([\w-]+)$/i);
|
|
86
|
+
if (idMatch) {
|
|
87
|
+
return { tag: idMatch[1] || null, className: null, id: idMatch[2].toLowerCase(), attr: null };
|
|
88
|
+
}
|
|
89
|
+
const classMatch = selector.match(/^([a-z0-9-]*)\.([\w-]+)$/i);
|
|
90
|
+
if (classMatch) {
|
|
91
|
+
return { tag: classMatch[1] || null, className: classMatch[2].toLowerCase(), id: null, attr: null };
|
|
92
|
+
}
|
|
93
|
+
return { tag: selector.toLowerCase() || null, className: null, id: null, attr: null };
|
|
94
|
+
}
|
|
95
|
+
const SELECTOR_CACHE = new Map();
|
|
96
|
+
function selectorFor(selector) {
|
|
97
|
+
let parsed = SELECTOR_CACHE.get(selector);
|
|
98
|
+
if (!parsed) {
|
|
99
|
+
parsed = parseSelector(selector);
|
|
100
|
+
SELECTOR_CACHE.set(selector, parsed);
|
|
101
|
+
}
|
|
102
|
+
return parsed;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Class name comparison that tolerates the Outlook Web nesting prefix.
|
|
106
|
+
*
|
|
107
|
+
* When Outlook Web quotes a message it rewrites the quoted markup's class names with an `x_`
|
|
108
|
+
* prefix, so a quoted Gmail reply arrives as `x_gmail_quote`. Stripping the prefix keeps the
|
|
109
|
+
* detectors working one level deeper into the history, which is exactly where they are needed.
|
|
110
|
+
*/
|
|
111
|
+
function classMatches(classNames, wanted) {
|
|
112
|
+
for (const name of classNames) {
|
|
113
|
+
const lowered = name.toLowerCase();
|
|
114
|
+
if (lowered === wanted || lowered.replace(/^x_/, '') === wanted) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
function elementMatches(element, selector) {
|
|
121
|
+
if (selector.tag && element.rawTagName?.toLowerCase() !== selector.tag) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
if (selector.className) {
|
|
125
|
+
const classes = String(element.getAttribute('class') || '')
|
|
126
|
+
.split(/\s+/)
|
|
127
|
+
.filter(Boolean);
|
|
128
|
+
if (!classMatches(classes, selector.className)) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (selector.id) {
|
|
133
|
+
const id = String(element.getAttribute('id') || '').toLowerCase();
|
|
134
|
+
if (id !== selector.id && id.replace(/^x_/, '') !== selector.id) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (selector.attr) {
|
|
139
|
+
const value = String(element.getAttribute(selector.attr.name) || '').toLowerCase();
|
|
140
|
+
if (value !== selector.attr.value) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
/** Outlook and Word mark a reply boundary with a top border on an otherwise empty element. */
|
|
147
|
+
function hasTopBorder(element) {
|
|
148
|
+
const style = String(element.getAttribute('style') || '');
|
|
149
|
+
return /border-top\s*:\s*(?!none)[^;]+/i.test(style);
|
|
150
|
+
}
|
|
151
|
+
function isElement(node) {
|
|
152
|
+
return node.nodeType === node_html_parser_1.NodeType.ELEMENT_NODE;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Markup that leaked into a text node.
|
|
156
|
+
*
|
|
157
|
+
* node-html-parser treats `<pre>` as a raw text element, so its children are never parsed and its
|
|
158
|
+
* markup arrives as literal text. Per the HTML specification `<pre>` content is ordinary parsed
|
|
159
|
+
* markup, and a browser renders a `<table>` inside a `<pre>` as a table, so the reader never saw
|
|
160
|
+
* those angle brackets. Leaving them in would put raw HTML into the extracted text, which is
|
|
161
|
+
* exactly what happened to Gmail signature tables wrapped in `<pre>`.
|
|
162
|
+
*
|
|
163
|
+
* Someone genuinely quoting HTML source escapes it as `<table>`, which is a text node with no
|
|
164
|
+
* tags in it and is therefore untouched by this.
|
|
165
|
+
*/
|
|
166
|
+
const CONDITIONAL_COMMENT = /<!\[[^\]]*\]>/g;
|
|
167
|
+
const LEAKED_MARKUP = /<[a-z][a-z0-9]*(?:\s[^>]*)?>/i;
|
|
168
|
+
/** Leading lines of a block, for line anchored detectors. */
|
|
169
|
+
function firstLines(text, limit = 3) {
|
|
170
|
+
return text
|
|
171
|
+
.split('\n', limit)
|
|
172
|
+
.map(line => line.trim())
|
|
173
|
+
.filter(Boolean);
|
|
174
|
+
}
|
|
175
|
+
/** Text projection of an inline run, with <br> and block boundaries becoming newlines. */
|
|
176
|
+
function projectText(nodes) {
|
|
177
|
+
let out = '';
|
|
178
|
+
const visit = (node) => {
|
|
179
|
+
if (node.nodeType === node_html_parser_1.NodeType.TEXT_NODE) {
|
|
180
|
+
const raw = node.rawText ?? '';
|
|
181
|
+
const cleaned = raw.replace(CONDITIONAL_COMMENT, '');
|
|
182
|
+
out += LEAKED_MARKUP.test(cleaned) ? (0, html_1.stripTagsToText)(cleaned) : (0, html_1.decodeEntities)(cleaned);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (!isElement(node)) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const tag = node.rawTagName?.toLowerCase() ?? '';
|
|
189
|
+
if (INVISIBLE_TAGS.has(tag)) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (tag === 'br') {
|
|
193
|
+
out += '\n';
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (tag === 'img') {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
for (const child of node.childNodes) {
|
|
200
|
+
visit(child);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
for (const node of nodes) {
|
|
204
|
+
visit(node);
|
|
205
|
+
}
|
|
206
|
+
// Collapse runs of spaces the way a renderer would, but keep explicit newlines.
|
|
207
|
+
return out
|
|
208
|
+
.replace(/\r\n?/g, '\n')
|
|
209
|
+
.replace(/[^\S\n]+/g, ' ')
|
|
210
|
+
.replace(/ *\n */g, '\n')
|
|
211
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
212
|
+
.trim();
|
|
213
|
+
}
|
|
214
|
+
/** Descendant nodes inspected per block. Bounds per block work on pathological subtrees. */
|
|
215
|
+
const MAX_SCAN_NODES = 2000;
|
|
216
|
+
function countTag(nodes, tag) {
|
|
217
|
+
let count = 0;
|
|
218
|
+
let budget = MAX_SCAN_NODES;
|
|
219
|
+
const visit = (node) => {
|
|
220
|
+
if (budget-- <= 0) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (isElement(node)) {
|
|
224
|
+
if (node.rawTagName?.toLowerCase() === tag) {
|
|
225
|
+
count++;
|
|
226
|
+
}
|
|
227
|
+
for (const child of node.childNodes) {
|
|
228
|
+
visit(child);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
for (const node of nodes) {
|
|
233
|
+
visit(node);
|
|
234
|
+
}
|
|
235
|
+
return count;
|
|
236
|
+
}
|
|
237
|
+
function collectTagsAndClasses(nodes, ancestors) {
|
|
238
|
+
const tags = new Set();
|
|
239
|
+
const classes = new Set();
|
|
240
|
+
let budget = MAX_SCAN_NODES;
|
|
241
|
+
const addElement = (element) => {
|
|
242
|
+
const tag = element.rawTagName?.toLowerCase();
|
|
243
|
+
if (tag) {
|
|
244
|
+
tags.add(tag);
|
|
245
|
+
}
|
|
246
|
+
for (const name of String(element.getAttribute('class') || '').split(/\s+/)) {
|
|
247
|
+
if (name) {
|
|
248
|
+
classes.add(name.toLowerCase());
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
for (const ancestor of ancestors) {
|
|
253
|
+
addElement(ancestor.element);
|
|
254
|
+
}
|
|
255
|
+
const visit = (node) => {
|
|
256
|
+
if (budget-- <= 0) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (isElement(node)) {
|
|
260
|
+
addElement(node);
|
|
261
|
+
for (const child of node.childNodes) {
|
|
262
|
+
visit(child);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
for (const node of nodes) {
|
|
267
|
+
visit(node);
|
|
268
|
+
}
|
|
269
|
+
return { tags: [...tags], classes: [...classes] };
|
|
270
|
+
}
|
|
271
|
+
function evidenceFromAncestry(ancestors) {
|
|
272
|
+
const evidence = new Map();
|
|
273
|
+
for (const ancestor of ancestors) {
|
|
274
|
+
for (const pattern of ancestor.matches) {
|
|
275
|
+
const kind = pattern.role === 'quote'
|
|
276
|
+
? 'quote-container'
|
|
277
|
+
: pattern.role === 'attribution'
|
|
278
|
+
? 'attribution'
|
|
279
|
+
: pattern.role === 'separator'
|
|
280
|
+
? 'separator'
|
|
281
|
+
: pattern.role === 'signature'
|
|
282
|
+
? 'signature'
|
|
283
|
+
: pattern.role === 'new'
|
|
284
|
+
? 'new-content'
|
|
285
|
+
: 'hint';
|
|
286
|
+
const id = `html:${pattern.id}`;
|
|
287
|
+
const existing = evidence.get(id);
|
|
288
|
+
if (!existing || existing.strength < pattern.strength) {
|
|
289
|
+
evidence.set(id, { id, kind, strength: pattern.strength });
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return [...evidence.values()];
|
|
294
|
+
}
|
|
295
|
+
function kindFor(nodes, ancestors, text, evidence) {
|
|
296
|
+
if (!text.trim()) {
|
|
297
|
+
const onlyImages = nodes.some(node => isElement(node) && node.rawTagName?.toLowerCase() === 'img');
|
|
298
|
+
if (onlyImages) {
|
|
299
|
+
return 'image';
|
|
300
|
+
}
|
|
301
|
+
const onlyRule = nodes.some(node => isElement(node) && node.rawTagName?.toLowerCase() === 'hr');
|
|
302
|
+
return onlyRule ? 'separator' : 'blank';
|
|
303
|
+
}
|
|
304
|
+
// Checked before the embedded header block below, and the order matters: a forwarded message
|
|
305
|
+
// begins with its marker and then repeats the original From/Date/Subject/To fields, so a header
|
|
306
|
+
// block test would claim it first and turn every forward into reply history.
|
|
307
|
+
// A forward marker is the same thing in HTML as in plain text, and must open a forwarded region
|
|
308
|
+
// the same way. Without this, an HTML forward is invisible to the classifier and its contents
|
|
309
|
+
// fall through to the reply history rules, which is how forwarded mail was being hidden.
|
|
310
|
+
//
|
|
311
|
+
// Matched per line, not against the whole block. In HTML the marker and the forwarded message's
|
|
312
|
+
// headers usually collapse into one block, so a whole-block test against line anchored patterns
|
|
313
|
+
// never fires.
|
|
314
|
+
if (firstLines(text).some(line => (0, forward_header_1.detectForwardMarker)(line))) {
|
|
315
|
+
return 'forward_header';
|
|
316
|
+
}
|
|
317
|
+
// An embedded copy of the previous message's headers. Outlook and several webmail clients emit
|
|
318
|
+
// From/Sent/To/Subject as one block, with <br> between the fields. This was wired into the plain
|
|
319
|
+
// text segmenter only, so in HTML the strongest reply anchor there is went undetected and every
|
|
320
|
+
// block after it stayed NEW_CONTENT. It was the single largest error cell against the reference.
|
|
321
|
+
if ((0, reply_header_1.detectQuotedHeaderBlock)(text.split('\n').map(line => line.trim())) !== null) {
|
|
322
|
+
return 'quoted_header_block';
|
|
323
|
+
}
|
|
324
|
+
// A container the client marked as an attribution line, such as Gmail's gmail_attr, is the same
|
|
325
|
+
// thing as a plain text "On ... wrote:" line and must anchor the region the same way.
|
|
326
|
+
if (evidence.some(item => item.kind === 'attribution')) {
|
|
327
|
+
return 'reply_header';
|
|
328
|
+
}
|
|
329
|
+
// Clients that use no marker class still emit the attribution as its own short element.
|
|
330
|
+
if (text.length <= 300 && !text.includes('\n') && (0, reply_header_1.detectAttributionLine)(text)) {
|
|
331
|
+
return 'reply_header';
|
|
332
|
+
}
|
|
333
|
+
if (ancestors.some(ancestor => ancestor.element.rawTagName?.toLowerCase() === 'blockquote')) {
|
|
334
|
+
return 'quote';
|
|
335
|
+
}
|
|
336
|
+
const tags = new Set(ancestors.map(ancestor => ancestor.element.rawTagName?.toLowerCase()));
|
|
337
|
+
if (tags.has('li')) {
|
|
338
|
+
return 'list';
|
|
339
|
+
}
|
|
340
|
+
if (tags.has('td') || tags.has('th')) {
|
|
341
|
+
return 'table';
|
|
342
|
+
}
|
|
343
|
+
return 'paragraph';
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Segment an HTML part into blocks.
|
|
347
|
+
*
|
|
348
|
+
* @param html decoded HTML source of the part
|
|
349
|
+
* @param mimePart part id for traceability
|
|
350
|
+
*/
|
|
351
|
+
/**
|
|
352
|
+
* Unclosed block tags tolerated before the DOM parse is skipped.
|
|
353
|
+
*
|
|
354
|
+
* node-html-parser degrades badly on deeply unbalanced markup: 5,000 unclosed divs, which is only
|
|
355
|
+
* 25 KB, take six and a half seconds inside the parser itself, before any of this module's code
|
|
356
|
+
* runs. Size is not the signal, imbalance is. Real mail, including thoroughly broken real mail,
|
|
357
|
+
* does not come close to this threshold.
|
|
358
|
+
*/
|
|
359
|
+
const MAX_UNCLOSED_TAGS = 500;
|
|
360
|
+
const OPEN_BLOCK_TAG = /<(?:div|table|tr|td|span|p|blockquote|ul|ol|li|font)\b/gi;
|
|
361
|
+
const CLOSE_BLOCK_TAG = /<\/(?:div|table|tr|td|span|p|blockquote|ul|ol|li|font)\b/gi;
|
|
362
|
+
function countPattern(text, regex) {
|
|
363
|
+
regex.lastIndex = 0;
|
|
364
|
+
let count = 0;
|
|
365
|
+
while (regex.exec(text) !== null) {
|
|
366
|
+
count++;
|
|
367
|
+
}
|
|
368
|
+
regex.lastIndex = 0;
|
|
369
|
+
return count;
|
|
370
|
+
}
|
|
371
|
+
/** True when markup is unbalanced enough that parsing it is not worth the time. */
|
|
372
|
+
function isPathologicalHtml(html) {
|
|
373
|
+
return countPattern(html, OPEN_BLOCK_TAG) - countPattern(html, CLOSE_BLOCK_TAG) > MAX_UNCLOSED_TAGS;
|
|
374
|
+
}
|
|
375
|
+
function segmentHtmlBlocks(html, mimePart) {
|
|
376
|
+
const patterns = (0, patterns_1.loadPatterns)();
|
|
377
|
+
let root;
|
|
378
|
+
try {
|
|
379
|
+
if (isPathologicalHtml(html)) {
|
|
380
|
+
// Degrade to a single visible block rather than spending seconds in the parser. Nothing
|
|
381
|
+
// is lost: the caller still receives the whole body, just unsegmented.
|
|
382
|
+
throw new Error('unbalanced markup');
|
|
383
|
+
}
|
|
384
|
+
root = (0, node_html_parser_1.parse)(html, { comment: false });
|
|
385
|
+
}
|
|
386
|
+
catch {
|
|
387
|
+
// A parse failure must still yield the content, as one unknown block.
|
|
388
|
+
return {
|
|
389
|
+
source: html,
|
|
390
|
+
degraded: true,
|
|
391
|
+
blocks: [
|
|
392
|
+
{
|
|
393
|
+
index: 0,
|
|
394
|
+
kind: 'unknown',
|
|
395
|
+
representation: 'html',
|
|
396
|
+
mimePart,
|
|
397
|
+
text: html,
|
|
398
|
+
content: '',
|
|
399
|
+
start: 0,
|
|
400
|
+
end: html.length,
|
|
401
|
+
html,
|
|
402
|
+
features: (0, features_1.computeFeatures)('', { index: 0, total: 1, start: 0, totalChars: html.length, quoteDepth: 0 }),
|
|
403
|
+
evidence: []
|
|
404
|
+
}
|
|
405
|
+
]
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
const runs = [];
|
|
409
|
+
/**
|
|
410
|
+
* Depth cap.
|
|
411
|
+
*
|
|
412
|
+
* Real mail nests deeply: a long thread quoted by Outlook Web inside Gmail can reach thirty
|
|
413
|
+
* levels. Five thousand unclosed divs is not real mail, and walking it made the per block
|
|
414
|
+
* ancestor and descendant scans quadratic, taking six seconds. Beyond this depth the remaining
|
|
415
|
+
* subtree is emitted as a single run rather than descended into, so content is still returned.
|
|
416
|
+
*/
|
|
417
|
+
const MAX_DEPTH = 150;
|
|
418
|
+
const walk = (node, ancestors, path) => {
|
|
419
|
+
if (ancestors.length > MAX_DEPTH) {
|
|
420
|
+
if (node.childNodes.length) {
|
|
421
|
+
runs.push({ run: { nodes: [...node.childNodes], ancestors: [...ancestors] }, domPath: path });
|
|
422
|
+
}
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
let pending = [];
|
|
426
|
+
let pendingIndex = 0;
|
|
427
|
+
const flush = () => {
|
|
428
|
+
if (pending.length) {
|
|
429
|
+
runs.push({ run: { nodes: pending, ancestors: [...ancestors] }, domPath: `${path}/${pendingIndex}` });
|
|
430
|
+
pending = [];
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
node.childNodes.forEach((child, childIndex) => {
|
|
434
|
+
if (isElement(child)) {
|
|
435
|
+
const tag = child.rawTagName?.toLowerCase() ?? '';
|
|
436
|
+
if (INVISIBLE_TAGS.has(tag)) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
if (BLOCK_TAGS.has(tag)) {
|
|
440
|
+
flush();
|
|
441
|
+
const matches = patterns.htmlSelectors.filter(pattern => elementMatches(child, selectorFor(pattern.selector)));
|
|
442
|
+
if (hasTopBorder(child)) {
|
|
443
|
+
matches.push({
|
|
444
|
+
id: 'outlook_border_separator',
|
|
445
|
+
client: 'outlook-desktop',
|
|
446
|
+
role: 'separator',
|
|
447
|
+
strength: 0.6,
|
|
448
|
+
selector: '[style*=border-top]',
|
|
449
|
+
prevalence: 0.03
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
walk(child, [...ancestors, { element: child, matches }], `${path}/${childIndex}`);
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (!pending.length) {
|
|
457
|
+
pendingIndex = childIndex;
|
|
458
|
+
}
|
|
459
|
+
pending.push(child);
|
|
460
|
+
});
|
|
461
|
+
flush();
|
|
462
|
+
// An empty block element still carries structural meaning, for example an <hr> used as a
|
|
463
|
+
// reply separator, so it becomes a block of its own.
|
|
464
|
+
if (!node.childNodes.length) {
|
|
465
|
+
const tag = node.rawTagName?.toLowerCase();
|
|
466
|
+
if (tag === 'hr' || tag === 'br') {
|
|
467
|
+
runs.push({ run: { nodes: [node], ancestors: [...ancestors] }, domPath: path });
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
walk(root, [], '');
|
|
472
|
+
const blocks = [];
|
|
473
|
+
let previousEnd = 0;
|
|
474
|
+
for (const { run, domPath } of runs) {
|
|
475
|
+
const ranges = run.nodes.map(node => node.range).filter(Boolean);
|
|
476
|
+
if (!ranges.length) {
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
const nodeStart = Math.min(...ranges.map(range => range[0]));
|
|
480
|
+
const nodeEnd = Math.max(...ranges.map(range => range[1]));
|
|
481
|
+
if (nodeEnd <= previousEnd) {
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
// Extend backwards so that markup between blocks belongs to exactly one block.
|
|
485
|
+
const start = Math.min(previousEnd, nodeStart);
|
|
486
|
+
const text = projectText(run.nodes);
|
|
487
|
+
const { tags, classes } = collectTagsAndClasses(run.nodes, run.ancestors);
|
|
488
|
+
const blockquoteDepth = run.ancestors.filter(ancestor => ancestor.element.rawTagName?.toLowerCase() === 'blockquote').length;
|
|
489
|
+
const evidence = evidenceFromAncestry(run.ancestors);
|
|
490
|
+
const kind = kindFor(run.nodes, run.ancestors, text, evidence);
|
|
491
|
+
if (kind === 'reply_header' && !evidence.some(item => item.kind === 'reply-anchor' || item.kind === 'attribution')) {
|
|
492
|
+
const attribution = (0, reply_header_1.detectAttributionLine)(text);
|
|
493
|
+
if (attribution) {
|
|
494
|
+
evidence.push(attribution);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (kind === 'quoted_header_block') {
|
|
498
|
+
const match = (0, reply_header_1.detectQuotedHeaderBlock)(text.split('\n').map(line => line.trim()));
|
|
499
|
+
if (match) {
|
|
500
|
+
evidence.push(match.evidence);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
if (kind === 'forward_header') {
|
|
504
|
+
for (const line of firstLines(text)) {
|
|
505
|
+
const forward = (0, forward_header_1.detectForwardMarker)(line);
|
|
506
|
+
if (forward) {
|
|
507
|
+
evidence.push(forward);
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
blocks.push({
|
|
513
|
+
index: blocks.length,
|
|
514
|
+
kind,
|
|
515
|
+
representation: 'html',
|
|
516
|
+
mimePart,
|
|
517
|
+
text: html.slice(start, nodeEnd),
|
|
518
|
+
content: text,
|
|
519
|
+
start,
|
|
520
|
+
end: nodeEnd,
|
|
521
|
+
html: html.slice(nodeStart, nodeEnd),
|
|
522
|
+
domPath,
|
|
523
|
+
features: (0, features_1.computeFeatures)(text, {
|
|
524
|
+
index: blocks.length,
|
|
525
|
+
total: runs.length,
|
|
526
|
+
start,
|
|
527
|
+
totalChars: html.length,
|
|
528
|
+
quoteDepth: blockquoteDepth,
|
|
529
|
+
blockquoteDepth,
|
|
530
|
+
elementCount: run.nodes.filter(isElement).length,
|
|
531
|
+
tags,
|
|
532
|
+
classes,
|
|
533
|
+
hasTopBorder: run.ancestors.some(ancestor => hasTopBorder(ancestor.element)),
|
|
534
|
+
linkCount: countTag(run.nodes, 'a'),
|
|
535
|
+
imageCount: countTag(run.nodes, 'img')
|
|
536
|
+
}),
|
|
537
|
+
evidence
|
|
538
|
+
});
|
|
539
|
+
previousEnd = nodeEnd;
|
|
540
|
+
}
|
|
541
|
+
// Trailing markup belongs to the last block, so that the blocks tile the whole document.
|
|
542
|
+
if (blocks.length) {
|
|
543
|
+
const last = blocks[blocks.length - 1];
|
|
544
|
+
if (last.end < html.length) {
|
|
545
|
+
last.end = html.length;
|
|
546
|
+
last.text = html.slice(last.start, html.length);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
else if (html.length) {
|
|
550
|
+
blocks.push({
|
|
551
|
+
index: 0,
|
|
552
|
+
kind: 'blank',
|
|
553
|
+
representation: 'html',
|
|
554
|
+
mimePart,
|
|
555
|
+
text: html,
|
|
556
|
+
content: '',
|
|
557
|
+
start: 0,
|
|
558
|
+
end: html.length,
|
|
559
|
+
html,
|
|
560
|
+
features: (0, features_1.computeFeatures)('', { index: 0, total: 1, start: 0, totalChars: html.length, quoteDepth: 0 }),
|
|
561
|
+
evidence: []
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
// Block level footer evidence, once positions are known.
|
|
565
|
+
//
|
|
566
|
+
// These detectors were originally wired into the plain text segmenter only, which meant HTML
|
|
567
|
+
// blocks never received signature or disclaimer evidence at all. Since most messages are HTML
|
|
568
|
+
// primary, that alone accounted for signature recall of 2.5 percent and disclaimer recall of
|
|
569
|
+
// zero against the reference set.
|
|
570
|
+
for (const block of blocks) {
|
|
571
|
+
block.features.indexFromEnd = blocks.length - 1 - block.index;
|
|
572
|
+
if (block.kind === 'blank' || block.features.isAllBlank) {
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
const lines = block.content.split('\n');
|
|
576
|
+
for (const line of lines) {
|
|
577
|
+
const delimiter = (0, signature_1.detectSignatureDelimiter)(line.trim());
|
|
578
|
+
if (delimiter) {
|
|
579
|
+
block.evidence.push(delimiter);
|
|
580
|
+
break;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
for (const evidence of (0, signature_1.detectSignaturePhrases)(lines)) {
|
|
584
|
+
block.evidence.push(evidence);
|
|
585
|
+
}
|
|
586
|
+
const shape = (0, signature_1.detectSignatureShape)(block.features);
|
|
587
|
+
if (shape) {
|
|
588
|
+
block.evidence.push(shape);
|
|
589
|
+
}
|
|
590
|
+
for (const evidence of (0, disclaimer_1.detectDisclaimer)(block.content, block.features)) {
|
|
591
|
+
block.evidence.push(evidence);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return { source: html, blocks, degraded: false };
|
|
595
|
+
}
|
|
596
|
+
//# sourceMappingURL=html-blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-blocks.js","sourceRoot":"","sources":["../../src/segment/html-blocks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage 3: plain text block segmentation.
|
|
3
|
+
*
|
|
4
|
+
* Blocks tile the canonical text completely and without overlap. Every character belongs to exactly
|
|
5
|
+
* one block, including blank lines and trailing whitespace, so that concatenating block texts
|
|
6
|
+
* reproduces the input exactly. That is maintained by construction here, and asserted as a property
|
|
7
|
+
* test, because it is what guarantees content cannot vanish between stages.
|
|
8
|
+
*
|
|
9
|
+
* Boundaries are placed at:
|
|
10
|
+
* - a change of quote depth
|
|
11
|
+
* - a blank line, which separates paragraphs
|
|
12
|
+
* - a reply attribution line, which becomes its own block
|
|
13
|
+
* - a forward marker, which becomes its own block
|
|
14
|
+
* - a signature delimiter, which becomes its own block
|
|
15
|
+
* - a rule separator
|
|
16
|
+
* - the start of an embedded header block
|
|
17
|
+
*/
|
|
18
|
+
import { type CanonicalText } from '../canonical/text';
|
|
19
|
+
import { type Block } from './types';
|
|
20
|
+
/**
|
|
21
|
+
* Segment a plain text part into blocks.
|
|
22
|
+
*
|
|
23
|
+
* @param raw decoded text of the part
|
|
24
|
+
* @param mimePart part id for traceability
|
|
25
|
+
*/
|
|
26
|
+
export declare function segmentTextBlocks(raw: string, mimePart: string): {
|
|
27
|
+
canonical: CanonicalText;
|
|
28
|
+
blocks: Block[];
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=text-blocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-blocks.d.ts","sourceRoot":"","sources":["../../src/segment/text-blocks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAoB,KAAK,aAAa,EAAiB,MAAM,mBAAmB,CAAC;AAMxF,OAAO,EAAE,KAAK,KAAK,EAAiC,MAAM,SAAS,CAAC;AAkDpE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,KAAK,EAAE,CAAA;CAAE,CAiJ9G"}
|