@postalsys/email-content 0.0.5 → 0.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 +205 -17
- package/dist/.tsbuildinfo +1 -1
- package/dist/analyze.d.ts +55 -15
- package/dist/analyze.d.ts.map +1 -1
- package/dist/analyze.js +275 -61
- package/dist/analyze.js.map +1 -1
- package/dist/canonical/html.d.ts +21 -2
- package/dist/canonical/html.d.ts.map +1 -1
- package/dist/canonical/html.js +213 -14
- package/dist/canonical/html.js.map +1 -1
- package/dist/classify/confidence.d.ts +12 -0
- package/dist/classify/confidence.d.ts.map +1 -1
- package/dist/classify/confidence.js +54 -4
- package/dist/classify/confidence.js.map +1 -1
- package/dist/classify/reconcile.d.ts +25 -17
- package/dist/classify/reconcile.d.ts.map +1 -1
- package/dist/classify/reconcile.js +52 -20
- package/dist/classify/reconcile.js.map +1 -1
- package/dist/classify/rules.d.ts +7 -0
- package/dist/classify/rules.d.ts.map +1 -1
- package/dist/classify/rules.js +58 -0
- package/dist/classify/rules.js.map +1 -1
- package/dist/cli/annotate.d.ts.map +1 -1
- package/dist/cli/annotate.js +6 -3
- package/dist/cli/annotate.js.map +1 -1
- package/dist/cli/args.d.ts +14 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +48 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/benchmark.d.ts +39 -0
- package/dist/cli/benchmark.d.ts.map +1 -1
- package/dist/cli/benchmark.js +179 -66
- package/dist/cli/benchmark.js.map +1 -1
- package/dist/cli/corpus.d.ts.map +1 -1
- package/dist/cli/corpus.js +13 -8
- package/dist/cli/corpus.js.map +1 -1
- package/dist/cli/disagreements.d.ts.map +1 -1
- package/dist/cli/disagreements.js +7 -4
- package/dist/cli/disagreements.js.map +1 -1
- package/dist/cli/evaluate.d.ts.map +1 -1
- package/dist/cli/evaluate.js +34 -10
- package/dist/cli/evaluate.js.map +1 -1
- package/dist/cli/extract.d.ts.map +1 -1
- package/dist/cli/extract.js +8 -3
- package/dist/cli/extract.js.map +1 -1
- package/dist/cli/main.js +8 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/corpus/scanner.d.ts +9 -1
- package/dist/corpus/scanner.d.ts.map +1 -1
- package/dist/corpus/scanner.js +52 -13
- package/dist/corpus/scanner.js.map +1 -1
- package/dist/corpus/store.d.ts +29 -2
- package/dist/corpus/store.d.ts.map +1 -1
- package/dist/corpus/store.js +45 -2
- package/dist/corpus/store.js.map +1 -1
- package/dist/detect/patterns.d.ts +29 -0
- package/dist/detect/patterns.d.ts.map +1 -1
- package/dist/detect/patterns.js +80 -6
- package/dist/detect/patterns.js.map +1 -1
- package/dist/detect/reply-header.d.ts +14 -0
- package/dist/detect/reply-header.d.ts.map +1 -1
- package/dist/detect/reply-header.js +80 -37
- package/dist/detect/reply-header.js.map +1 -1
- package/dist/eval/oracle.d.ts +80 -0
- package/dist/eval/oracle.d.ts.map +1 -0
- package/dist/eval/oracle.js +250 -0
- package/dist/eval/oracle.js.map +1 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +94 -56
- package/dist/index.js.map +1 -1
- package/dist/match/history.d.ts +12 -0
- package/dist/match/history.d.ts.map +1 -1
- package/dist/match/history.js +16 -0
- package/dist/match/history.js.map +1 -1
- package/dist/mime/model.d.ts +28 -3
- package/dist/mime/model.d.ts.map +1 -1
- package/dist/mime/model.js +41 -1
- package/dist/mime/model.js.map +1 -1
- package/dist/mime/parse.d.ts.map +1 -1
- package/dist/mime/parse.js +19 -2
- package/dist/mime/parse.js.map +1 -1
- package/dist/mime/select.d.ts +71 -0
- package/dist/mime/select.d.ts.map +1 -0
- package/dist/mime/select.js +198 -0
- package/dist/mime/select.js.map +1 -0
- package/dist/segment/html-blocks.d.ts +1 -1
- package/dist/segment/html-blocks.d.ts.map +1 -1
- package/dist/segment/html-blocks.js +77 -8
- package/dist/segment/html-blocks.js.map +1 -1
- package/dist/segment/text-blocks.d.ts.map +1 -1
- package/dist/segment/text-blocks.js +18 -1
- package/dist/segment/text-blocks.js.map +1 -1
- package/dist/segment/types.d.ts +14 -0
- package/dist/segment/types.d.ts.map +1 -1
- package/dist/types.d.ts +132 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +37 -3
- package/dist/types.js.map +1 -1
- package/dist/util/worker-pool.d.ts +21 -0
- package/dist/util/worker-pool.d.ts.map +1 -1
- package/dist/util/worker-pool.js +61 -13
- package/dist/util/worker-pool.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Independent safety oracles for the structural benchmark.
|
|
4
|
+
*
|
|
5
|
+
* The benchmark exists to detect the failure this project is built to prevent: a message that had
|
|
6
|
+
* content going in and has none coming out. It cannot do that by asking the extractor, and the
|
|
7
|
+
* previous version did exactly that:
|
|
8
|
+
*
|
|
9
|
+
* const hadContent = visibleChars + hiddenChars > 0;
|
|
10
|
+
*
|
|
11
|
+
* That reads "did the input have content" off the output. When extraction dropped everything the
|
|
12
|
+
* flag went false, the catastrophic counter did not increment, and the benchmark reported zero
|
|
13
|
+
* losses while a reproducible total loss case existed.
|
|
14
|
+
*
|
|
15
|
+
* So the code here shares the *definition* of a body with the extractor, and shares none of its
|
|
16
|
+
* *implementation*. It re-parses the message, walks the flat part list itself, and never calls the
|
|
17
|
+
* selection logic it is meant to check. Re-parsing costs a second MIME pass per message, which is
|
|
18
|
+
* the right trade for a release gate.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.embeddedPartIds = embeddedPartIds;
|
|
22
|
+
exports.eligibleBodyParts = eligibleBodyParts;
|
|
23
|
+
exports.inventoryVisibleInput = inventoryVisibleInput;
|
|
24
|
+
exports.requiredCoverageGroups = requiredCoverageGroups;
|
|
25
|
+
exports.coverageOf = coverageOf;
|
|
26
|
+
const text_1 = require("../canonical/text");
|
|
27
|
+
const html_1 = require("../canonical/html");
|
|
28
|
+
const normalize_1 = require("../match/normalize");
|
|
29
|
+
const shingle_1 = require("../match/shingle");
|
|
30
|
+
/** Part ids that sit inside an embedded `message/rfc822`, which is content and not the outer body. */
|
|
31
|
+
function embeddedPartIds(message) {
|
|
32
|
+
const containers = message.parts.filter(part => part.rfc822 || part.embeddedRoot);
|
|
33
|
+
const inside = new Set();
|
|
34
|
+
if (!containers.length) {
|
|
35
|
+
return inside;
|
|
36
|
+
}
|
|
37
|
+
for (const part of message.parts) {
|
|
38
|
+
let cursor = part;
|
|
39
|
+
while (cursor?.parentId) {
|
|
40
|
+
if (containers.some(container => container.partId === cursor?.parentId)) {
|
|
41
|
+
inside.add(part.partId);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
cursor = message.partsById.get(cursor.parentId);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return inside;
|
|
48
|
+
}
|
|
49
|
+
/** A decoded body-bearing leaf, by the written MIME rules rather than by the selection heuristic. */
|
|
50
|
+
function eligibleBodyParts(message) {
|
|
51
|
+
const embedded = embeddedPartIds(message);
|
|
52
|
+
return message.parts.filter(part => (part.contentType === 'text/plain' || part.contentType === 'text/html') &&
|
|
53
|
+
part.disposition !== 'attachment' &&
|
|
54
|
+
Boolean(part.decoded) &&
|
|
55
|
+
!embedded.has(part.partId));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Count plausible visible body text in a parsed message, before extraction runs.
|
|
59
|
+
*
|
|
60
|
+
* Deliberately over-inclusive: it counts every eligible part, including both members of a
|
|
61
|
+
* `multipart/alternative`, because its only question is whether the message had anything visible to
|
|
62
|
+
* show. It is not, and must not be used as, a demand that every part appear in the output.
|
|
63
|
+
*
|
|
64
|
+
* Script, style, comment and markup text is excluded, so an image-only newsletter or a body that is
|
|
65
|
+
* nothing but a tracking pixel does not count as visible text that extraction then lost.
|
|
66
|
+
*/
|
|
67
|
+
function inventoryVisibleInput(message) {
|
|
68
|
+
let visibleChars = 0;
|
|
69
|
+
const parts = eligibleBodyParts(message);
|
|
70
|
+
for (const part of parts) {
|
|
71
|
+
visibleChars += visibleTextOf(part).length;
|
|
72
|
+
}
|
|
73
|
+
return { visibleChars, eligibleParts: parts.length, hasVisibleText: visibleChars > 0 };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Text a reader would actually have seen in one part.
|
|
77
|
+
*
|
|
78
|
+
* Quote prefixes are stripped rather than counted. A plain part whose entire body is `>` on three
|
|
79
|
+
* lines contains no text at all, and counting the markers made the gate report a total content loss
|
|
80
|
+
* on a message that had nothing to lose. Script, style, comment and markup text is excluded the
|
|
81
|
+
* same way, so an image-only body does not look like text that extraction dropped.
|
|
82
|
+
*/
|
|
83
|
+
function visibleTextOf(part) {
|
|
84
|
+
const raw = part.decoded?.text ?? '';
|
|
85
|
+
if (!raw) {
|
|
86
|
+
return '';
|
|
87
|
+
}
|
|
88
|
+
if (part.contentType === 'text/html') {
|
|
89
|
+
return (0, html_1.stripTagsToText)(raw).trim();
|
|
90
|
+
}
|
|
91
|
+
return (0, text_1.canonicaliseText)(raw)
|
|
92
|
+
.lines.filter(line => !line.blank)
|
|
93
|
+
.map(line => line.content)
|
|
94
|
+
.join('\n')
|
|
95
|
+
.trim();
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Supported body leaf, by the same written rules the plan uses, deliberately reimplemented here.
|
|
99
|
+
*
|
|
100
|
+
* A part with no visible text is not required coverage. An image-only newsletter and a body that is
|
|
101
|
+
* nothing but a tracking pixel both have a body part and nothing for the output to carry, and
|
|
102
|
+
* demanding a segment for them would report "content lost" on messages where none existed.
|
|
103
|
+
*/
|
|
104
|
+
function isSupportedLeaf(part) {
|
|
105
|
+
return ((part.contentType === 'text/plain' || part.contentType === 'text/html') &&
|
|
106
|
+
part.disposition !== 'attachment' &&
|
|
107
|
+
Boolean(part.decoded) &&
|
|
108
|
+
visibleTextOf(part) !== '');
|
|
109
|
+
}
|
|
110
|
+
function supportedLeavesUnder(message, part, into, depth = 0) {
|
|
111
|
+
if (depth > 32 || part.disposition === 'attachment' || part.rfc822 || part.embeddedRoot) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (isSupportedLeaf(part)) {
|
|
115
|
+
into.push(part.partId);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
for (const childId of part.childIds) {
|
|
119
|
+
const child = message.partsById.get(childId);
|
|
120
|
+
if (child) {
|
|
121
|
+
supportedLeavesUnder(message, child, into, depth + 1);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function bareContentId(value) {
|
|
126
|
+
return (value ?? '').trim().replace(/^</, '').replace(/>$/, '').toLowerCase();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Fold a `mixed` container's misencoded alternatives into single equivalence groups.
|
|
130
|
+
*
|
|
131
|
+
* Some clients use `multipart/mixed` where they mean `multipart/alternative`, `mixed(H,P)` most
|
|
132
|
+
* often. The extractor merges such a pair into one section when their content matches, so only one
|
|
133
|
+
* of the two part ids reaches the output, and a per-part rule would report the other as lost
|
|
134
|
+
* content when nothing was lost.
|
|
135
|
+
*
|
|
136
|
+
* Decided by content rather than structure, exactly as the selection code decides it, and
|
|
137
|
+
* implemented separately here on purpose. An oracle that called the selection code would agree with
|
|
138
|
+
* it by construction and could never catch it being wrong. These two must be reviewed together
|
|
139
|
+
* against `docs/adr-001-document-global-classification.md`; when they disagree, one of them is
|
|
140
|
+
* wrong and the run says so.
|
|
141
|
+
*/
|
|
142
|
+
function mergeMisencodedAlternatives(message, groups, from) {
|
|
143
|
+
for (let i = from; i + 1 < groups.length; i++) {
|
|
144
|
+
const left = groups[i];
|
|
145
|
+
const right = groups[i + 1];
|
|
146
|
+
if (left.alternative || right.alternative || left.members.length !== 1 || right.members.length !== 1) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const a = message.partsById.get(left.members[0]);
|
|
150
|
+
const b = message.partsById.get(right.members[0]);
|
|
151
|
+
if (!a || !b) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const plain = a.contentType === 'text/plain' ? a : b.contentType === 'text/plain' ? b : null;
|
|
155
|
+
const markup = a.contentType === 'text/html' ? a : b.contentType === 'text/html' ? b : null;
|
|
156
|
+
if (!plain || !markup) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const left_ = (0, shingle_1.buildShingleIndex)((0, normalize_1.normaliseForMatch)(visibleTextOf(plain)));
|
|
160
|
+
const right_ = (0, shingle_1.buildShingleIndex)((0, normalize_1.normaliseForMatch)(visibleTextOf(markup)));
|
|
161
|
+
if (!(0, shingle_1.isMatchable)(left_) || !(0, shingle_1.isMatchable)(right_)) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if ((0, shingle_1.containment)(left_, right_).containment < shingle_1.CONTAINMENT_THRESHOLD && (0, shingle_1.containment)(right_, left_).containment < shingle_1.CONTAINMENT_THRESHOLD) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
groups.splice(i, 2, { id: left.id, alternative: true, members: [...left.members, ...right.members] });
|
|
168
|
+
i--;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Required coverage groups for a parsed message.
|
|
173
|
+
*
|
|
174
|
+
* Written from the decision table rather than by calling `planBody()`. Sharing the implementation
|
|
175
|
+
* would make the oracle agree with the selection code by construction, which is exactly the
|
|
176
|
+
* property a gate must not have. The two are reviewed against the same table and are expected to
|
|
177
|
+
* agree; when they do not, one of them is wrong and the run says so.
|
|
178
|
+
*/
|
|
179
|
+
function requiredCoverageGroups(message) {
|
|
180
|
+
const groups = [];
|
|
181
|
+
const walk = (part, depth) => {
|
|
182
|
+
if (depth > 32 || part.disposition === 'attachment') {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Embedded messages are content for the caller to render, not the container's body.
|
|
186
|
+
if (part.rfc822 || part.embeddedRoot) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (part.multipart === 'alternative') {
|
|
190
|
+
const members = [];
|
|
191
|
+
supportedLeavesUnder(message, part, members);
|
|
192
|
+
if (members.length) {
|
|
193
|
+
groups.push({ id: part.partId, alternative: true, members });
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const children = part.childIds.map(id => message.partsById.get(id)).filter(Boolean);
|
|
198
|
+
if (part.multipart === 'related') {
|
|
199
|
+
// Only the root carries body. Everything else is an inline resource.
|
|
200
|
+
const start = bareContentId(part.contentTypeParams.start);
|
|
201
|
+
const root = (start ? children.find(child => bareContentId(child.headers.find(entry => entry.key === 'content-id')?.value) === start) : undefined) ??
|
|
202
|
+
children[0];
|
|
203
|
+
if (root) {
|
|
204
|
+
walk(root, depth + 1);
|
|
205
|
+
}
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (part.multipart) {
|
|
209
|
+
// mixed and everything unrecognised: ordered independent content, each body-bearing
|
|
210
|
+
// child is its own required group.
|
|
211
|
+
const before = groups.length;
|
|
212
|
+
for (const child of children) {
|
|
213
|
+
walk(child, depth + 1);
|
|
214
|
+
}
|
|
215
|
+
mergeMisencodedAlternatives(message, groups, before);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (isSupportedLeaf(part)) {
|
|
219
|
+
groups.push({ id: part.partId, alternative: false, members: [part.partId] });
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
const root = message.partsById.get(message.rootId) ?? message.parts[0];
|
|
223
|
+
if (root) {
|
|
224
|
+
walk(root, 0);
|
|
225
|
+
}
|
|
226
|
+
return groups;
|
|
227
|
+
}
|
|
228
|
+
/** Compare the required groups against the MIME parts the result actually names. */
|
|
229
|
+
function coverageOf(groups, visibleParts, hiddenParts) {
|
|
230
|
+
const missing = [];
|
|
231
|
+
const alternativesNotEmitted = [];
|
|
232
|
+
const hiddenOnly = [];
|
|
233
|
+
let covered = 0;
|
|
234
|
+
for (const group of groups) {
|
|
235
|
+
const present = group.members.filter(member => visibleParts.has(member) || hiddenParts.has(member));
|
|
236
|
+
if (!present.length) {
|
|
237
|
+
missing.push(group.id);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
covered++;
|
|
241
|
+
if (group.alternative) {
|
|
242
|
+
alternativesNotEmitted.push(...group.members.filter(member => !present.includes(member)));
|
|
243
|
+
}
|
|
244
|
+
if (present.every(member => !visibleParts.has(member))) {
|
|
245
|
+
hiddenOnly.push(group.id);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return { required: groups.length, covered, missing, alternativesNotEmitted, hiddenOnly };
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=oracle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oracle.js","sourceRoot":"","sources":["../../src/eval/oracle.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,13 +12,16 @@ export * from './types';
|
|
|
12
12
|
export { parseMessage } from './mime/parse';
|
|
13
13
|
export type { ParsedMessage, MimePart } from './mime/model';
|
|
14
14
|
export type { Block, BlockFeatures, BlockKind, Evidence } from './segment/types';
|
|
15
|
-
export { DEFAULT_CONFIDENCE } from './classify/confidence';
|
|
15
|
+
export { DEFAULT_CONFIDENCE, validateConfidenceConfig, type ConfidenceConfig } from './classify/confidence';
|
|
16
|
+
export { validateParseOptions, DEFAULT_PARSE_OPTIONS } from './mime/model';
|
|
16
17
|
export { buildHistoryDocument, matchBlocks, type HistoryDocument, type BlockMatch } from './match/history';
|
|
17
18
|
export { corpusThreadResolver, folderThreadResolver, type ThreadResolver } from './corpus/thread-index';
|
|
18
|
-
export { analyze, resolveHistory, senderTokensFrom, type MessageContent, type AnalyzeOptions, type AnalyzeResult } from './analyze';
|
|
19
|
+
export { analyze, resolveHistory, senderTokensFrom, type BodySection, type MessageContent, type AnalyzeOptions, type AnalyzeResult } from './analyze';
|
|
20
|
+
export { planBody, reportableExclusions, type BodyPlan, type ExclusionReason, type PlannedSection, type SectionRole } from './mime/select';
|
|
21
|
+
export { loadPatterns, PatternAssetError } from './detect/patterns';
|
|
19
22
|
export interface ExtractOptions {
|
|
20
23
|
parse?: ParseOptions;
|
|
21
|
-
confidence?: ConfidenceConfig
|
|
24
|
+
confidence?: Partial<ConfidenceConfig>;
|
|
22
25
|
/**
|
|
23
26
|
* Earlier messages in the thread, most recent first. Optional: extraction works without any
|
|
24
27
|
* history, and history only ever adds evidence.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,KAAK,YAAY,EAA4C,MAAM,cAAc,CAAC;AAG3F,OAAO,EAA4B,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAqB,KAAK,gBAAgB,EAAE,KAAK,MAAM,EAAgB,MAAM,SAAS,CAAC;AAE9F,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC5D,YAAY,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC5G,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACxG,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACtJ,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,KAAK,QAAQ,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3I,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAWpE,MAAM,WAAW,cAAc;IAC3B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACvC;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,kGAAkG;IAClG,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACrD,qCAAqC;IACrC,WAAW,CAAC,EAAE;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,MAAM,EAAE;YACJ,KAAK,EAAE,MAAM,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,CAAC;YACd,UAAU,EAAE,MAAM,CAAC;YACnB,OAAO,EAAE,MAAM,EAAE,CAAC;YAClB,QAAQ,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAC;gBAAC,QAAQ,EAAE,MAAM,CAAA;aAAE,EAAE,CAAC;YAC3D,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAClC,OAAO,EAAE,MAAM,CAAC;SACnB,EAAE,CAAC;KACP,CAAC;CACL;AA2CD,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,eAAe,CAAC,CA2G1G"}
|
package/dist/index.js
CHANGED
|
@@ -20,16 +20,24 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
20
20
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
21
21
|
};
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.senderTokensFrom = exports.resolveHistory = exports.analyze = exports.folderThreadResolver = exports.corpusThreadResolver = exports.matchBlocks = exports.buildHistoryDocument = exports.DEFAULT_CONFIDENCE = exports.parseMessage = void 0;
|
|
23
|
+
exports.PatternAssetError = exports.loadPatterns = exports.reportableExclusions = exports.planBody = exports.senderTokensFrom = exports.resolveHistory = exports.analyze = exports.folderThreadResolver = exports.corpusThreadResolver = exports.matchBlocks = exports.buildHistoryDocument = exports.DEFAULT_PARSE_OPTIONS = exports.validateParseOptions = exports.validateConfidenceConfig = exports.DEFAULT_CONFIDENCE = exports.parseMessage = void 0;
|
|
24
24
|
exports.extract = extract;
|
|
25
25
|
const parse_1 = require("./mime/parse");
|
|
26
|
+
const model_1 = require("./mime/model");
|
|
27
|
+
const select_1 = require("./mime/select");
|
|
28
|
+
const patterns_1 = require("./detect/patterns");
|
|
29
|
+
const confidence_1 = require("./classify/confidence");
|
|
26
30
|
const analyze_1 = require("./analyze");
|
|
27
31
|
const types_1 = require("./types");
|
|
28
32
|
__exportStar(require("./types"), exports);
|
|
29
33
|
var parse_2 = require("./mime/parse");
|
|
30
34
|
Object.defineProperty(exports, "parseMessage", { enumerable: true, get: function () { return parse_2.parseMessage; } });
|
|
31
|
-
var
|
|
32
|
-
Object.defineProperty(exports, "DEFAULT_CONFIDENCE", { enumerable: true, get: function () { return
|
|
35
|
+
var confidence_2 = require("./classify/confidence");
|
|
36
|
+
Object.defineProperty(exports, "DEFAULT_CONFIDENCE", { enumerable: true, get: function () { return confidence_2.DEFAULT_CONFIDENCE; } });
|
|
37
|
+
Object.defineProperty(exports, "validateConfidenceConfig", { enumerable: true, get: function () { return confidence_2.validateConfidenceConfig; } });
|
|
38
|
+
var model_2 = require("./mime/model");
|
|
39
|
+
Object.defineProperty(exports, "validateParseOptions", { enumerable: true, get: function () { return model_2.validateParseOptions; } });
|
|
40
|
+
Object.defineProperty(exports, "DEFAULT_PARSE_OPTIONS", { enumerable: true, get: function () { return model_2.DEFAULT_PARSE_OPTIONS; } });
|
|
33
41
|
var history_1 = require("./match/history");
|
|
34
42
|
Object.defineProperty(exports, "buildHistoryDocument", { enumerable: true, get: function () { return history_1.buildHistoryDocument; } });
|
|
35
43
|
Object.defineProperty(exports, "matchBlocks", { enumerable: true, get: function () { return history_1.matchBlocks; } });
|
|
@@ -40,50 +48,20 @@ var analyze_2 = require("./analyze");
|
|
|
40
48
|
Object.defineProperty(exports, "analyze", { enumerable: true, get: function () { return analyze_2.analyze; } });
|
|
41
49
|
Object.defineProperty(exports, "resolveHistory", { enumerable: true, get: function () { return analyze_2.resolveHistory; } });
|
|
42
50
|
Object.defineProperty(exports, "senderTokensFrom", { enumerable: true, get: function () { return analyze_2.senderTokensFrom; } });
|
|
51
|
+
var select_2 = require("./mime/select");
|
|
52
|
+
Object.defineProperty(exports, "planBody", { enumerable: true, get: function () { return select_2.planBody; } });
|
|
53
|
+
Object.defineProperty(exports, "reportableExclusions", { enumerable: true, get: function () { return select_2.reportableExclusions; } });
|
|
54
|
+
var patterns_2 = require("./detect/patterns");
|
|
55
|
+
Object.defineProperty(exports, "loadPatterns", { enumerable: true, get: function () { return patterns_2.loadPatterns; } });
|
|
56
|
+
Object.defineProperty(exports, "PatternAssetError", { enumerable: true, get: function () { return patterns_2.PatternAssetError; } });
|
|
43
57
|
/**
|
|
44
|
-
*
|
|
58
|
+
* Classifier assets are validated when the package is required, not when a message arrives.
|
|
45
59
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* is content to be classified, not the container's own body.
|
|
60
|
+
* Missing or corrupt pattern files are an installation defect. Discovering that on the thousandth
|
|
61
|
+
* message, as one more degraded result, is far worse than discovering it at startup: every message
|
|
62
|
+
* until then came back looking like new content, because nothing could be recognised as history.
|
|
50
63
|
*/
|
|
51
|
-
|
|
52
|
-
const insideEmbedded = new Set();
|
|
53
|
-
for (const part of message.parts) {
|
|
54
|
-
if (!part.rfc822 && !part.embeddedRoot) {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
for (const other of message.parts) {
|
|
58
|
-
let cursor = other;
|
|
59
|
-
while (cursor?.parentId) {
|
|
60
|
-
if (cursor.parentId === part.partId) {
|
|
61
|
-
insideEmbedded.add(other.partId);
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
cursor = message.partsById.get(cursor.parentId);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
let text = null;
|
|
69
|
-
let html = null;
|
|
70
|
-
for (const part of message.parts) {
|
|
71
|
-
if (part.disposition === 'attachment' || !part.decoded || insideEmbedded.has(part.partId)) {
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
if (part.contentType === 'text/plain') {
|
|
75
|
-
if (!text || part.decoded.text.length > (text.decoded?.text.length ?? 0)) {
|
|
76
|
-
text = part;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
else if (part.contentType === 'text/html') {
|
|
80
|
-
if (!html || part.decoded.text.length > (html.decoded?.text.length ?? 0)) {
|
|
81
|
-
html = part;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return { text, html };
|
|
86
|
-
}
|
|
64
|
+
(0, patterns_1.loadPatterns)();
|
|
87
65
|
/**
|
|
88
66
|
* Extract the conversationally relevant content of a raw RFC 5322 message.
|
|
89
67
|
*
|
|
@@ -105,7 +83,9 @@ function degraded(text, warnings) {
|
|
|
105
83
|
confidence: 0.5,
|
|
106
84
|
visibility: 'show',
|
|
107
85
|
reasons: ['degraded_to_unknown'],
|
|
108
|
-
|
|
86
|
+
// No MIME tree was produced, so there is no part to name. Inventing one, which
|
|
87
|
+
// this used to do, points a reviewer at a part that does not exist.
|
|
88
|
+
source: { kind: 'raw-message', start: 0, end: text.length }
|
|
109
89
|
}
|
|
110
90
|
]
|
|
111
91
|
: [],
|
|
@@ -115,39 +95,93 @@ function degraded(text, warnings) {
|
|
|
115
95
|
originalAvailable: true,
|
|
116
96
|
primaryRepresentation: 'none',
|
|
117
97
|
extractorVersion: types_1.EXTRACTOR_VERSION,
|
|
118
|
-
historyUsed: false
|
|
98
|
+
historyUsed: false,
|
|
99
|
+
// Threading headers are exactly what a failed parse could not read. Reply status is left
|
|
100
|
+
// false and the uncertainty is made observable, rather than guessed at with a substring
|
|
101
|
+
// search over the raw bytes.
|
|
102
|
+
isReply: false
|
|
119
103
|
};
|
|
120
104
|
}
|
|
121
105
|
async function extract(raw, options = {}) {
|
|
106
|
+
// Assets first, then options. Both are checked outside the fail-soft path, because neither is
|
|
107
|
+
// a property of the message and both would otherwise repeat silently on every one of them.
|
|
108
|
+
(0, patterns_1.loadPatterns)();
|
|
109
|
+
// Validated before any work, so a bad option fails on the first message rather than producing
|
|
110
|
+
// subtly wrong results on every message.
|
|
111
|
+
const parseOptions = (0, model_1.validateParseOptions)(options.parse);
|
|
112
|
+
const confidence = (0, confidence_1.validateConfidenceConfig)(options.confidence);
|
|
122
113
|
const buffer = typeof raw === 'string' ? Buffer.from(raw) : raw;
|
|
114
|
+
if (buffer.length > parseOptions.maxMessageBytes) {
|
|
115
|
+
// A circuit breaker the caller asked for. Not an error: an oversized message is input, and
|
|
116
|
+
// input degrades rather than throwing. Nothing was read, so nothing is returned, and the
|
|
117
|
+
// caller still holds the original.
|
|
118
|
+
return degraded('', [
|
|
119
|
+
{ code: 'input_limit_exceeded', detail: `maxMessageBytes (${parseOptions.maxMessageBytes}), message was ${buffer.length}` },
|
|
120
|
+
{ code: 'extraction_degraded' },
|
|
121
|
+
{ code: 'reply_status_unknown' }
|
|
122
|
+
]);
|
|
123
|
+
}
|
|
123
124
|
let message;
|
|
124
125
|
try {
|
|
125
|
-
message = await (0, parse_1.parseMessage)(buffer,
|
|
126
|
+
message = await (0, parse_1.parseMessage)(buffer, parseOptions);
|
|
126
127
|
}
|
|
127
128
|
catch (err) {
|
|
128
129
|
return degraded(buffer.toString('utf8'), [
|
|
129
130
|
{ code: 'mime_parse_error', detail: err instanceof Error ? err.message.slice(0, 200) : 'unknown' },
|
|
130
|
-
{ code: 'extraction_degraded' }
|
|
131
|
+
{ code: 'extraction_degraded' },
|
|
132
|
+
{ code: 'reply_status_unknown' }
|
|
131
133
|
]);
|
|
132
134
|
}
|
|
133
|
-
const
|
|
135
|
+
const plan = (0, select_1.planBody)(message);
|
|
136
|
+
// A tree that failed to parse must not come back as nothing.
|
|
137
|
+
//
|
|
138
|
+
// `parseMessage()` never rejects: it records the failure as a warning and returns whatever it
|
|
139
|
+
// salvaged. When it salvaged no parts at all, the body plan is empty, and the result used to be
|
|
140
|
+
// zero segments plus `no_body_parts` even though the raw message plainly held text. That is the
|
|
141
|
+
// same defect as the malformed HTML fallback, one stage earlier, and with the same shape: total
|
|
142
|
+
// content loss whose only trace is a warning.
|
|
143
|
+
if (!plan.sections.length && message.warnings.some(warning => warning.code === 'mime_parse_error')) {
|
|
144
|
+
const text = buffer.toString('utf8');
|
|
145
|
+
if (text.trim()) {
|
|
146
|
+
return degraded(text, [
|
|
147
|
+
...message.warnings,
|
|
148
|
+
{ code: 'extraction_degraded', detail: 'no MIME body could be recovered' },
|
|
149
|
+
{ code: 'reply_status_unknown' }
|
|
150
|
+
]);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Every eligible inline body part the plan leaves out is named. Silent substitution is the
|
|
154
|
+
// failure mode this replaced: a long inline footer used to displace a short authored reply with
|
|
155
|
+
// nothing in the result to say so. Unused alternative members, attachments and embedded
|
|
156
|
+
// messages are excluded by a written rule and are not reported, because they are not losses.
|
|
157
|
+
const omissions = (0, select_1.reportableExclusions)(plan).map(entry => ({
|
|
158
|
+
code: 'body_section_not_selected',
|
|
159
|
+
mimePart: entry.partId,
|
|
160
|
+
detail: entry.reason
|
|
161
|
+
}));
|
|
162
|
+
// The whole plan goes through, in document order. Composition happens inside analyze() so that
|
|
163
|
+
// a caller who already has a parsed multipart message can express exactly the same thing.
|
|
164
|
+
const sections = plan.sections.map(section => ({
|
|
165
|
+
text: section.text?.decoded?.text ?? null,
|
|
166
|
+
html: section.html?.decoded?.text ?? null,
|
|
167
|
+
...(section.text ? { textPartId: section.text.partId } : {}),
|
|
168
|
+
...(section.html ? { htmlPartId: section.html.partId } : {}),
|
|
169
|
+
role: section.role
|
|
170
|
+
}));
|
|
134
171
|
const result = await (0, analyze_1.analyze)({
|
|
135
|
-
|
|
136
|
-
html: parts.html?.decoded?.text ?? null,
|
|
172
|
+
sections,
|
|
137
173
|
subject: message.headers.subject,
|
|
138
174
|
from: message.headers.from,
|
|
139
175
|
inReplyTo: message.headers.inReplyTo,
|
|
140
|
-
references: message.headers.references
|
|
141
|
-
...(parts.text ? { textPartId: parts.text.partId } : {}),
|
|
142
|
-
...(parts.html ? { htmlPartId: parts.html.partId } : {})
|
|
176
|
+
references: message.headers.references
|
|
143
177
|
}, {
|
|
144
|
-
|
|
178
|
+
confidence,
|
|
145
179
|
...(options.history ? { history: options.history } : {}),
|
|
146
180
|
...(options.historyDocuments ? { historyDocuments: options.historyDocuments } : {}),
|
|
147
181
|
...(options.explain ? { explain: true } : {})
|
|
148
182
|
});
|
|
149
183
|
// MIME level warnings belong to the message, not to the body analysis.
|
|
150
|
-
const warnings = [...message.warnings, ...result.warnings];
|
|
184
|
+
const warnings = [...message.warnings, ...omissions, ...result.warnings];
|
|
151
185
|
return {
|
|
152
186
|
segments: result.segments,
|
|
153
187
|
hiddenSegments: result.hiddenSegments,
|
|
@@ -157,6 +191,10 @@ async function extract(raw, options = {}) {
|
|
|
157
191
|
primaryRepresentation: result.primaryRepresentation,
|
|
158
192
|
extractorVersion: result.extractorVersion,
|
|
159
193
|
historyUsed: result.historyUsed,
|
|
194
|
+
isReply: result.isReply,
|
|
195
|
+
// `satisfies` rather than a bare return: an omitted mandatory field then fails the build
|
|
196
|
+
// instead of quietly disappearing from the public result, which is how `isReply` went
|
|
197
|
+
// missing from this entry point while the README documented it.
|
|
160
198
|
...(result.diagnostics ? { diagnostics: { ...result.diagnostics, structure: message.structure } } : {})
|
|
161
199
|
};
|
|
162
200
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/match/history.d.ts
CHANGED
|
@@ -59,4 +59,16 @@ export declare function buildHistoryDocumentFromContent(text: string, html: stri
|
|
|
59
59
|
export declare function matchBlocks(blocks: readonly Block[], history: readonly HistoryDocument[]): BlockMatch[];
|
|
60
60
|
/** Convenience view for the classifier, which only needs to know which indices matched. */
|
|
61
61
|
export declare function matchedIndices(matches: readonly BlockMatch[]): Set<number>;
|
|
62
|
+
/**
|
|
63
|
+
* Containment at or above which a match needs no corroboration from markup.
|
|
64
|
+
*
|
|
65
|
+
* The ordinary threshold admits a paraphrase or a heavily edited quote, which is right when markup
|
|
66
|
+
* already says the region is history and the match only confirms it. Identifying history that
|
|
67
|
+
* carries no markup at all is a stronger claim and takes a stronger match. Measured across the
|
|
68
|
+
* reference set the ratio of correct to incorrect reclassification is best here, at almost twelve
|
|
69
|
+
* to one.
|
|
70
|
+
*/
|
|
71
|
+
export declare const STRONG_CONTAINMENT = 0.95;
|
|
72
|
+
/** Matches strong enough to identify history that carries no markup of its own. */
|
|
73
|
+
export declare function strongMatchedIndices(matches: readonly BlockMatch[]): Set<number>;
|
|
62
74
|
//# sourceMappingURL=history.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/match/history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAsE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAGlH,MAAM,WAAW,eAAe;IAC5B,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,YAAY,CAAC;IACpB,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,KAAK,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAkBxH;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,eAAe,CAU1H;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,OAAO,EAAE,SAAS,eAAe,EAAE,GAAG,UAAU,EAAE,CA4CvG;AASD,2FAA2F;AAC3F,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAE1E"}
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/match/history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAsE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAGlH,MAAM,WAAW,eAAe;IAC5B,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAC;IACX,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,YAAY,CAAC;IACpB,yEAAyE;IACzE,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,KAAK,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAkBxH;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,eAAe,CAU1H;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,OAAO,EAAE,SAAS,eAAe,EAAE,GAAG,UAAU,EAAE,CA4CvG;AASD,2FAA2F;AAC3F,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAE1E;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAEvC,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAEhF"}
|
package/dist/match/history.js
CHANGED
|
@@ -17,10 +17,12 @@
|
|
|
17
17
|
* threshold is required. A non match never demotes anything.
|
|
18
18
|
*/
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.STRONG_CONTAINMENT = void 0;
|
|
20
21
|
exports.buildHistoryDocument = buildHistoryDocument;
|
|
21
22
|
exports.buildHistoryDocumentFromContent = buildHistoryDocumentFromContent;
|
|
22
23
|
exports.matchBlocks = matchBlocks;
|
|
23
24
|
exports.matchedIndices = matchedIndices;
|
|
25
|
+
exports.strongMatchedIndices = strongMatchedIndices;
|
|
24
26
|
const parse_1 = require("../mime/parse");
|
|
25
27
|
const text_1 = require("../canonical/text");
|
|
26
28
|
const html_1 = require("../canonical/html");
|
|
@@ -125,4 +127,18 @@ function betterMatch(candidate, current) {
|
|
|
125
127
|
function matchedIndices(matches) {
|
|
126
128
|
return new Set(matches.map(match => match.blockIndex));
|
|
127
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Containment at or above which a match needs no corroboration from markup.
|
|
132
|
+
*
|
|
133
|
+
* The ordinary threshold admits a paraphrase or a heavily edited quote, which is right when markup
|
|
134
|
+
* already says the region is history and the match only confirms it. Identifying history that
|
|
135
|
+
* carries no markup at all is a stronger claim and takes a stronger match. Measured across the
|
|
136
|
+
* reference set the ratio of correct to incorrect reclassification is best here, at almost twelve
|
|
137
|
+
* to one.
|
|
138
|
+
*/
|
|
139
|
+
exports.STRONG_CONTAINMENT = 0.95;
|
|
140
|
+
/** Matches strong enough to identify history that carries no markup of its own. */
|
|
141
|
+
function strongMatchedIndices(matches) {
|
|
142
|
+
return new Set(matches.filter(match => match.exact || match.containment >= exports.STRONG_CONTAINMENT).map(match => match.blockIndex));
|
|
143
|
+
}
|
|
128
144
|
//# sourceMappingURL=history.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/match/history.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/match/history.ts"],"names":[],"mappings":"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"}
|