slopless 0.2.24 → 0.2.25
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/dist/rules/semantic-thinness/patterns/abstract-metaphor-claim.json +83 -1
- package/dist/rules/semantic-thinness/patterns/deictic-summary.json +31 -2
- package/dist/rules/semantic-thinness/patterns/empty-scene-transition.json +2 -1
- package/dist/rules/semantic-thinness/private/concrete-guards.js +2 -0
- package/dist/rules/semantic-thinness/private/pattern-matcher.js +22 -6
- package/dist/rules/syntactic-patterns/contrast/contrastive-aphorism.js +2 -0
- package/dist/rules/syntactic-patterns/contrast/negation-reframe.js +1 -1
- package/dist/rules/syntactic-patterns/contrast/private/action-reframe-vocabulary.js +47 -0
- package/dist/rules/syntactic-patterns/contrast/private/audience-replacement.js +267 -0
- package/dist/rules/syntactic-patterns/contrast/private/copular-reframe.js +39 -1
- package/dist/rules/syntactic-patterns/contrast/private/evidence-limitation-pair.js +307 -0
- package/dist/rules/syntactic-patterns/contrast/private/inline-semicolon-reframe.js +50 -0
- package/dist/rules/syntactic-patterns/contrast/private/inline-short-negation.js +1 -0
- package/dist/rules/syntactic-patterns/contrast/private/negation-reframe-matcher.js +64 -7
- package/dist/rules/syntactic-patterns/contrast/private/negation-reframe-parts.js +37 -25
- package/dist/rules/syntactic-patterns/contrast/private/negation-vocabulary.js +27 -0
- package/dist/rules/syntactic-patterns/contrast/private/negative-consequence.js +301 -0
- package/dist/rules/syntactic-patterns/contrast/private/negative-slop-frames.js +51 -38
- package/dist/rules/syntactic-patterns/contrast/private/reframe-classification.js +21 -0
- package/dist/rules/syntactic-patterns/contrast/private/sequence-reframes.js +9 -0
- package/dist/rules/syntactic-patterns/contrast/private/temporal-reframe.js +318 -0
- package/dist/rules/syntactic-patterns/lead-ins/generic-signposting.js +85 -22
- package/dist/rules/syntactic-patterns/lead-ins/private/component-assignment-frame.js +239 -0
- package/dist/rules/syntactic-patterns/lead-ins/private/discourse-evaluation.js +1 -0
- package/dist/rules/syntactic-patterns/lead-ins/private/evaluative-colon-frame.js +166 -0
- package/dist/rules/syntactic-patterns/lead-ins/private/reaction-frame.js +29 -0
- package/dist/rules/syntactic-patterns/lead-ins/private/relative-discourse-frame.js +119 -0
- package/package.json +1 -1
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { cleanSentence, tokens } from "../../../../shared/matchers/prose-patterns.js";
|
|
2
|
+
const PREFIXES = ["and ", "but ", "so "];
|
|
3
|
+
const SIMPLE_SUBJECT_STARTERS = new Set([
|
|
4
|
+
"a",
|
|
5
|
+
"an",
|
|
6
|
+
"my",
|
|
7
|
+
"our",
|
|
8
|
+
"that",
|
|
9
|
+
"the",
|
|
10
|
+
"their",
|
|
11
|
+
"these",
|
|
12
|
+
"this",
|
|
13
|
+
"those",
|
|
14
|
+
"your"
|
|
15
|
+
]);
|
|
16
|
+
const EVIDENCE_PROXY_HEADS = new Set([
|
|
17
|
+
"award",
|
|
18
|
+
"awards",
|
|
19
|
+
"benchmark",
|
|
20
|
+
"benchmarks",
|
|
21
|
+
"case",
|
|
22
|
+
"cases",
|
|
23
|
+
"comment",
|
|
24
|
+
"comments",
|
|
25
|
+
"dashboard",
|
|
26
|
+
"dashboards",
|
|
27
|
+
"demo",
|
|
28
|
+
"demos",
|
|
29
|
+
"example",
|
|
30
|
+
"examples",
|
|
31
|
+
"metric",
|
|
32
|
+
"metrics",
|
|
33
|
+
"number",
|
|
34
|
+
"numbers",
|
|
35
|
+
"rating",
|
|
36
|
+
"ratings",
|
|
37
|
+
"review",
|
|
38
|
+
"reviews",
|
|
39
|
+
"score",
|
|
40
|
+
"scores",
|
|
41
|
+
"screenshot",
|
|
42
|
+
"screenshots",
|
|
43
|
+
"signal",
|
|
44
|
+
"signals",
|
|
45
|
+
"survey",
|
|
46
|
+
"surveys",
|
|
47
|
+
"testimonial",
|
|
48
|
+
"testimonials"
|
|
49
|
+
]);
|
|
50
|
+
const PLURAL_EVIDENCE_PROXY_HEADS = new Set([
|
|
51
|
+
"awards",
|
|
52
|
+
"benchmarks",
|
|
53
|
+
"cases",
|
|
54
|
+
"comments",
|
|
55
|
+
"dashboards",
|
|
56
|
+
"demos",
|
|
57
|
+
"examples",
|
|
58
|
+
"metrics",
|
|
59
|
+
"numbers",
|
|
60
|
+
"ratings",
|
|
61
|
+
"reviews",
|
|
62
|
+
"scores",
|
|
63
|
+
"screenshots",
|
|
64
|
+
"signals",
|
|
65
|
+
"surveys",
|
|
66
|
+
"testimonials"
|
|
67
|
+
]);
|
|
68
|
+
const COMPLEX_SUBJECT_MARKERS = new Set([
|
|
69
|
+
"about",
|
|
70
|
+
"against",
|
|
71
|
+
"among",
|
|
72
|
+
"around",
|
|
73
|
+
"as",
|
|
74
|
+
"at",
|
|
75
|
+
"beside",
|
|
76
|
+
"between",
|
|
77
|
+
"by",
|
|
78
|
+
"compared",
|
|
79
|
+
"containing",
|
|
80
|
+
"for",
|
|
81
|
+
"from",
|
|
82
|
+
"in",
|
|
83
|
+
"including",
|
|
84
|
+
"near",
|
|
85
|
+
"of",
|
|
86
|
+
"on",
|
|
87
|
+
"or",
|
|
88
|
+
"over",
|
|
89
|
+
"under",
|
|
90
|
+
"with",
|
|
91
|
+
"without",
|
|
92
|
+
"and"
|
|
93
|
+
]);
|
|
94
|
+
const EVIDENCE_AUXILIARIES = new Set([
|
|
95
|
+
"can",
|
|
96
|
+
"could",
|
|
97
|
+
"had",
|
|
98
|
+
"has",
|
|
99
|
+
"have",
|
|
100
|
+
"may",
|
|
101
|
+
"might",
|
|
102
|
+
"will",
|
|
103
|
+
"would"
|
|
104
|
+
]);
|
|
105
|
+
const EVIDENCE_ASSERTION_VERBS = new Set([
|
|
106
|
+
"confirm",
|
|
107
|
+
"confirmed",
|
|
108
|
+
"confirms",
|
|
109
|
+
"demonstrate",
|
|
110
|
+
"demonstrated",
|
|
111
|
+
"demonstrates",
|
|
112
|
+
"document",
|
|
113
|
+
"documented",
|
|
114
|
+
"documents",
|
|
115
|
+
"establish",
|
|
116
|
+
"established",
|
|
117
|
+
"establishes",
|
|
118
|
+
"imply",
|
|
119
|
+
"implied",
|
|
120
|
+
"implies",
|
|
121
|
+
"indicate",
|
|
122
|
+
"indicated",
|
|
123
|
+
"indicates",
|
|
124
|
+
"prove",
|
|
125
|
+
"proved",
|
|
126
|
+
"proven",
|
|
127
|
+
"proves",
|
|
128
|
+
"reveal",
|
|
129
|
+
"revealed",
|
|
130
|
+
"reveals",
|
|
131
|
+
"show",
|
|
132
|
+
"showed",
|
|
133
|
+
"shown",
|
|
134
|
+
"shows",
|
|
135
|
+
"signal",
|
|
136
|
+
"signaled",
|
|
137
|
+
"signalled",
|
|
138
|
+
"signals",
|
|
139
|
+
"suggest",
|
|
140
|
+
"suggested",
|
|
141
|
+
"suggests",
|
|
142
|
+
"support",
|
|
143
|
+
"supported",
|
|
144
|
+
"supports",
|
|
145
|
+
"tell",
|
|
146
|
+
"told",
|
|
147
|
+
"validate",
|
|
148
|
+
"validated",
|
|
149
|
+
"validates",
|
|
150
|
+
"verified",
|
|
151
|
+
"verifies",
|
|
152
|
+
"verify"
|
|
153
|
+
]);
|
|
154
|
+
const LIMITATION_REPORTING_VERBS = new Set([
|
|
155
|
+
"communicate",
|
|
156
|
+
"communicated",
|
|
157
|
+
"communicates",
|
|
158
|
+
"convey",
|
|
159
|
+
"conveyed",
|
|
160
|
+
"conveys",
|
|
161
|
+
"demonstrate",
|
|
162
|
+
"demonstrated",
|
|
163
|
+
"demonstrates",
|
|
164
|
+
"establish",
|
|
165
|
+
"established",
|
|
166
|
+
"establishes",
|
|
167
|
+
"explain",
|
|
168
|
+
"explained",
|
|
169
|
+
"explains",
|
|
170
|
+
"indicate",
|
|
171
|
+
"indicated",
|
|
172
|
+
"indicates",
|
|
173
|
+
"offer",
|
|
174
|
+
"offered",
|
|
175
|
+
"offers",
|
|
176
|
+
"provide",
|
|
177
|
+
"provided",
|
|
178
|
+
"provides",
|
|
179
|
+
"prove",
|
|
180
|
+
"proved",
|
|
181
|
+
"proves",
|
|
182
|
+
"reveal",
|
|
183
|
+
"revealed",
|
|
184
|
+
"reveals",
|
|
185
|
+
"say",
|
|
186
|
+
"said",
|
|
187
|
+
"says",
|
|
188
|
+
"show",
|
|
189
|
+
"showed",
|
|
190
|
+
"shows",
|
|
191
|
+
"signal",
|
|
192
|
+
"signaled",
|
|
193
|
+
"signalled",
|
|
194
|
+
"signals",
|
|
195
|
+
"suggest",
|
|
196
|
+
"suggested",
|
|
197
|
+
"suggests",
|
|
198
|
+
"tell",
|
|
199
|
+
"told",
|
|
200
|
+
"tells"
|
|
201
|
+
]);
|
|
202
|
+
const LIMITATION_AUXILIARIES = new Set(["did", "does"]);
|
|
203
|
+
const CONTRACTED_LIMITATION_AUXILIARIES = new Set(["didn't", "doesn't"]);
|
|
204
|
+
const REPORTING_OBJECTS = new Set(["buyers", "readers", "us", "you"]);
|
|
205
|
+
const LIMITATION_PRONOUNS = new Set([
|
|
206
|
+
"it",
|
|
207
|
+
"that",
|
|
208
|
+
"these",
|
|
209
|
+
"they",
|
|
210
|
+
"this",
|
|
211
|
+
"those"
|
|
212
|
+
]);
|
|
213
|
+
const LOW_INFORMATION_LIMITS = [
|
|
214
|
+
["little"],
|
|
215
|
+
["very", "little"],
|
|
216
|
+
["nothing"],
|
|
217
|
+
["not", "much"],
|
|
218
|
+
["only", "so", "much"],
|
|
219
|
+
["something"],
|
|
220
|
+
["no", "context"],
|
|
221
|
+
["no", "evidence"],
|
|
222
|
+
["no", "information"],
|
|
223
|
+
["no", "insight"]
|
|
224
|
+
];
|
|
225
|
+
function evidenceSubjectHead(words) {
|
|
226
|
+
const firstWord = words[0] ?? "";
|
|
227
|
+
if (firstWord === "that" && SIMPLE_SUBJECT_STARTERS.has(words[1] ?? "")) {
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
if (!SIMPLE_SUBJECT_STARTERS.has(firstWord) &&
|
|
231
|
+
!EVIDENCE_PROXY_HEADS.has(firstWord)) {
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
const verbIndex = words.findIndex((word) => EVIDENCE_ASSERTION_VERBS.has(word));
|
|
235
|
+
const headIndex = EVIDENCE_AUXILIARIES.has(words[verbIndex - 1] ?? "")
|
|
236
|
+
? verbIndex - 2
|
|
237
|
+
: verbIndex - 1;
|
|
238
|
+
const head = words[headIndex];
|
|
239
|
+
const subjectModifiers = words.slice(0, headIndex);
|
|
240
|
+
return verbIndex > 0 &&
|
|
241
|
+
verbIndex < words.length - 1 &&
|
|
242
|
+
head !== undefined &&
|
|
243
|
+
EVIDENCE_PROXY_HEADS.has(head) &&
|
|
244
|
+
!subjectModifiers.some((word) => COMPLEX_SUBJECT_MARKERS.has(word))
|
|
245
|
+
? head
|
|
246
|
+
: undefined;
|
|
247
|
+
}
|
|
248
|
+
function startsWithLimit(words, start, limit) {
|
|
249
|
+
return limit.every((word, index) => words[start + index] === word);
|
|
250
|
+
}
|
|
251
|
+
function hasVagueContinuation(words, start, limit) {
|
|
252
|
+
const next = words[start + limit.length];
|
|
253
|
+
const finalWord = limit.at(-1);
|
|
254
|
+
if (["context", "evidence", "information", "insight"].includes(finalWord ?? "")) {
|
|
255
|
+
return next === undefined || next === "about" || next === "into";
|
|
256
|
+
}
|
|
257
|
+
return (!["anything", "little", "much", "nothing", "something"].includes(finalWord ?? "") ||
|
|
258
|
+
next === undefined ||
|
|
259
|
+
next === "about");
|
|
260
|
+
}
|
|
261
|
+
function limitationStart(words) {
|
|
262
|
+
if (LIMITATION_REPORTING_VERBS.has(words[1] ?? "")) {
|
|
263
|
+
return REPORTING_OBJECTS.has(words[2] ?? "") ? 3 : 2;
|
|
264
|
+
}
|
|
265
|
+
if (LIMITATION_AUXILIARIES.has(words[1] ?? "") &&
|
|
266
|
+
words[2] === "not" &&
|
|
267
|
+
LIMITATION_REPORTING_VERBS.has(words[3] ?? "")) {
|
|
268
|
+
return 4;
|
|
269
|
+
}
|
|
270
|
+
return CONTRACTED_LIMITATION_AUXILIARIES.has(words[1] ?? "") &&
|
|
271
|
+
LIMITATION_REPORTING_VERBS.has(words[2] ?? "")
|
|
272
|
+
? 3
|
|
273
|
+
: -1;
|
|
274
|
+
}
|
|
275
|
+
function hasLowInformationLimitation(words, pluralSubject) {
|
|
276
|
+
const pronoun = words[0] ?? "";
|
|
277
|
+
const pluralPronoun = ["these", "they", "those"].includes(pronoun);
|
|
278
|
+
if (!LIMITATION_PRONOUNS.has(pronoun) || pluralPronoun !== pluralSubject) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
const start = limitationStart(words);
|
|
282
|
+
if (start >= 3 &&
|
|
283
|
+
(LIMITATION_AUXILIARIES.has(words[1] ?? "") ||
|
|
284
|
+
CONTRACTED_LIMITATION_AUXILIARIES.has(words[1] ?? ""))) {
|
|
285
|
+
return (["anything", "much"].includes(words[start] ?? "") &&
|
|
286
|
+
(words[start + 1] === undefined || words[start + 1] === "about"));
|
|
287
|
+
}
|
|
288
|
+
if (start < 0) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
return LOW_INFORMATION_LIMITS.some((limit) => {
|
|
292
|
+
if (!startsWithLimit(words, start, limit)) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
return hasVagueContinuation(words, start, limit);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
export function matchEvidenceLimitationPair(first, second) {
|
|
299
|
+
const firstWords = tokens(cleanSentence(first, PREFIXES));
|
|
300
|
+
const secondWords = tokens(cleanSentence(second, PREFIXES));
|
|
301
|
+
const subjectHead = evidenceSubjectHead(firstWords);
|
|
302
|
+
return subjectHead !== undefined &&
|
|
303
|
+
hasLowInformationLimitation(secondWords, PLURAL_EVIDENCE_PROXY_HEADS.has(subjectHead))
|
|
304
|
+
? "evidence-limitation-pair"
|
|
305
|
+
: undefined;
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=evidence-limitation-pair.js.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { wordTokens } from "../../../../shared/text/tokens.js";
|
|
2
|
+
import { findCopularNegation, pronounCopulaStart, words } from "./negation-reframe-parts.js";
|
|
3
|
+
const EVALUATIVE_PREDICATES = new Set([
|
|
4
|
+
"bad",
|
|
5
|
+
"broken",
|
|
6
|
+
"empty",
|
|
7
|
+
"incomplete",
|
|
8
|
+
"messy",
|
|
9
|
+
"sloppy",
|
|
10
|
+
"untidy",
|
|
11
|
+
"useless"
|
|
12
|
+
]);
|
|
13
|
+
const IDENTITY_METAPHOR_HEADS = new Set([
|
|
14
|
+
"barrier",
|
|
15
|
+
"bottleneck",
|
|
16
|
+
"bridge",
|
|
17
|
+
"dead-end",
|
|
18
|
+
"door",
|
|
19
|
+
"gate",
|
|
20
|
+
"market",
|
|
21
|
+
"shelf",
|
|
22
|
+
"wall",
|
|
23
|
+
"window"
|
|
24
|
+
]);
|
|
25
|
+
const IDENTITY_DETERMINERS = new Set(["a", "an", "the"]);
|
|
26
|
+
function startsWithIdentityMetaphor(text) {
|
|
27
|
+
const tokens = wordTokens(text);
|
|
28
|
+
const copula = pronounCopulaStart(tokens);
|
|
29
|
+
if (copula === undefined) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const predicate = words(tokens).slice(copula.predicateStart);
|
|
33
|
+
const headIndex = IDENTITY_DETERMINERS.has(predicate[0] ?? "") ? 1 : 0;
|
|
34
|
+
return IDENTITY_METAPHOR_HEADS.has(predicate[headIndex] ?? "");
|
|
35
|
+
}
|
|
36
|
+
export function matchesInlineSemicolonReframe(text) {
|
|
37
|
+
const clauses = text.split(";");
|
|
38
|
+
if (clauses.length !== 2) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const firstTokens = wordTokens(clauses[0] ?? "");
|
|
42
|
+
const negation = findCopularNegation(firstTokens);
|
|
43
|
+
if (negation === undefined) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const predicate = words(firstTokens).slice(negation.negatedPredicateStart);
|
|
47
|
+
return (predicate.some((word) => EVALUATIVE_PREDICATES.has(word)) &&
|
|
48
|
+
startsWithIdentityMetaphor(clauses[1] ?? ""));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=inline-semicolon-reframe.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { hasConcreteCorrectionEvidence } from "../../../../shared/matchers/concrete-evidence.js";
|
|
2
2
|
import { hasFactualConnectorAfterNegation } from "./negation-context-gates.js";
|
|
3
3
|
import { findCopularNegation, findNegationIndex, startsWithWords, words } from "./negation-reframe-parts.js";
|
|
4
|
+
export { matchesInlineSemicolonReframe } from "./inline-semicolon-reframe.js";
|
|
4
5
|
export function inlineNotJustCopularReframe(sentence, tokens) {
|
|
5
6
|
const negation = findCopularNegation(tokens);
|
|
6
7
|
const negationIndex = findNegationIndex(tokens);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { DO_NEGATIONS, EXPLICIT_DO_AUXILIARIES, contrastPivotSubject, findCopularNegation, findNegationIndex, isCompleteSentence, skipOptionalAdverbs, startsWithSubjectOrPronoun, startsWithSubjectVerb, startsWithWords, stripLeadingPairPivot, validSubject, words } from "./negation-reframe-parts.js";
|
|
1
|
+
import { ACTION_NEGATIONS, DO_NEGATIONS, EXPLICIT_DO_AUXILIARIES, FACTUAL_NEGATION_CONNECTORS, contrastPivotSubject, findCopularNegation, findNegationIndex, isCompleteSentence, skipOptionalAdverbs, startsWithSubjectOrPronoun, startsWithSubjectVerb, startsWithWords, stripLeadingPairPivot, validSubject, words } from "./negation-reframe-parts.js";
|
|
2
2
|
import { hasAbstractCommaContrast, hasAbstractNegationPayoff, hasFactualConnectorAfterNegation, hasMetaContext } from "./negation-context-gates.js";
|
|
3
3
|
import { hasInlineContrastConnectorAfterNegation } from "./inline-contrast-connector.js";
|
|
4
4
|
import { inlineNotBecauseReframe } from "./inline-not-because-reframe.js";
|
|
5
|
-
import { inlineNotJustCopularReframe, inlineShortNegatedBeat } from "./inline-short-negation.js";
|
|
6
|
-
import { hasNegativeSlopPairSignal, negatedActionPronounPayoff, negatedActionSetReplacement, negativeSlopReframe, progressiveVerbMirror, pronounCopularReframe, sameSubjectCopularReframe, shouldReportCopularReframe, startsWithNegatedPronounCopula } from "./negative-slop-frames.js";
|
|
5
|
+
import { matchesInlineSemicolonReframe, inlineNotJustCopularReframe, inlineShortNegatedBeat } from "./inline-short-negation.js";
|
|
6
|
+
import { hasNegativeSlopPairSignal, matchSequenceReframe, negatedActionPronounPayoff, negatedActionSetReplacement, negativeSlopReframe, progressiveVerbMirror, pronounCopularReframe, sameSubjectCopularReframe, shouldReportCopularReframe, startsWithNegatedPronounCopula } from "./negative-slop-frames.js";
|
|
7
7
|
import { makeMeaningReframe, meaningReframe } from "./meaning-reframe.js";
|
|
8
8
|
import { hasConcreteCorrectionEvidence } from "../../../../shared/matchers/concrete-evidence.js";
|
|
9
9
|
import { splitSentences } from "../../../../shared/text/sentences.js";
|
|
@@ -19,8 +19,25 @@ const INLINE_NON_CONTRAST_NEGATION_FOLLOWERS = new Set([
|
|
|
19
19
|
"only",
|
|
20
20
|
"too"
|
|
21
21
|
]);
|
|
22
|
+
const ACTION_PAIR_CONNECTORS = new Set([
|
|
23
|
+
...FACTUAL_NEGATION_CONNECTORS,
|
|
24
|
+
"after"
|
|
25
|
+
]);
|
|
26
|
+
function inlineSemicolonEvaluativeReframe(sentence) {
|
|
27
|
+
return matchesInlineSemicolonReframe(sentence.text)
|
|
28
|
+
? {
|
|
29
|
+
end: sentence.end,
|
|
30
|
+
start: sentence.start,
|
|
31
|
+
text: sentence.text
|
|
32
|
+
}
|
|
33
|
+
: undefined;
|
|
34
|
+
}
|
|
22
35
|
function inlineNegationContrast(sentence) {
|
|
23
36
|
const tokens = wordTokens(sentence.text);
|
|
37
|
+
const semicolonMatch = inlineSemicolonEvaluativeReframe(sentence);
|
|
38
|
+
if (semicolonMatch !== undefined) {
|
|
39
|
+
return semicolonMatch;
|
|
40
|
+
}
|
|
24
41
|
const negationIndex = findNegationIndex(tokens);
|
|
25
42
|
if (negationIndex === undefined) {
|
|
26
43
|
return undefined;
|
|
@@ -90,6 +107,11 @@ function startsWithNeedAffirmative(bTokens, subject) {
|
|
|
90
107
|
function actionVerbMirror(aTokens, bTokens) {
|
|
91
108
|
const tokenWords = words(aTokens);
|
|
92
109
|
const bContentTokens = stripLeadingPairPivot(bTokens);
|
|
110
|
+
const bWords = words(bContentTokens);
|
|
111
|
+
const firstConnectors = new Set(tokenWords.filter((word) => ACTION_PAIR_CONNECTORS.has(word)));
|
|
112
|
+
if (bWords.some((word) => ACTION_PAIR_CONNECTORS.has(word) && !firstConnectors.has(word))) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
93
115
|
for (let index = 0; index < tokenWords.length; index += 1) {
|
|
94
116
|
const current = tokenWords[index];
|
|
95
117
|
const next = tokenWords[index + 1];
|
|
@@ -97,7 +119,7 @@ function actionVerbMirror(aTokens, bTokens) {
|
|
|
97
119
|
if (!validSubject(subject)) {
|
|
98
120
|
continue;
|
|
99
121
|
}
|
|
100
|
-
if (
|
|
122
|
+
if (ACTION_NEGATIONS.has(current ?? "")) {
|
|
101
123
|
const verbIndex = skipOptionalAdverbs(tokenWords, index + 1);
|
|
102
124
|
const verb = tokenWords[verbIndex];
|
|
103
125
|
if (verb !== undefined &&
|
|
@@ -168,10 +190,26 @@ function sentencePairReframe(a, b) {
|
|
|
168
190
|
export function findSentenceNegationReframes(text) {
|
|
169
191
|
const sentences = splitSentences(text);
|
|
170
192
|
const matches = [];
|
|
193
|
+
const matchedRanges = new Set();
|
|
194
|
+
const addMatch = (match) => {
|
|
195
|
+
const range = `${match.start}:${match.end}`;
|
|
196
|
+
if (!matchedRanges.has(range)) {
|
|
197
|
+
matchedRanges.add(range);
|
|
198
|
+
matches.push(match);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
171
201
|
for (const sentence of sentences) {
|
|
172
202
|
const inlineMatch = inlineNegationContrast(sentence);
|
|
173
203
|
if (inlineMatch !== undefined) {
|
|
174
|
-
|
|
204
|
+
addMatch(inlineMatch);
|
|
205
|
+
}
|
|
206
|
+
const consequence = matchSequenceReframe(sentence.text, "");
|
|
207
|
+
if (consequence !== undefined) {
|
|
208
|
+
addMatch({
|
|
209
|
+
end: sentence.end,
|
|
210
|
+
start: sentence.start,
|
|
211
|
+
text: consequence
|
|
212
|
+
});
|
|
175
213
|
}
|
|
176
214
|
}
|
|
177
215
|
for (let index = 0; index < sentences.length - 1; index += 1) {
|
|
@@ -180,11 +218,30 @@ export function findSentenceNegationReframes(text) {
|
|
|
180
218
|
if (current === undefined || next === undefined) {
|
|
181
219
|
continue;
|
|
182
220
|
}
|
|
221
|
+
const third = sentences[index + 2];
|
|
222
|
+
const sequence = matchSequenceReframe(current.text, next.text, third?.text);
|
|
223
|
+
if (sequence !== undefined) {
|
|
224
|
+
const threeSentenceText = third === undefined
|
|
225
|
+
? undefined
|
|
226
|
+
: `${current.text} ${next.text} ${third.text}`;
|
|
227
|
+
addMatch({
|
|
228
|
+
end: sequence === current.text
|
|
229
|
+
? current.end
|
|
230
|
+
: sequence === threeSentenceText
|
|
231
|
+
? (third?.end ?? next.end)
|
|
232
|
+
: next.end,
|
|
233
|
+
start: current.start,
|
|
234
|
+
text: sequence
|
|
235
|
+
});
|
|
236
|
+
}
|
|
183
237
|
const pairMatch = sentencePairReframe(current, next);
|
|
184
238
|
if (pairMatch !== undefined) {
|
|
185
|
-
|
|
239
|
+
addMatch(pairMatch);
|
|
186
240
|
}
|
|
187
241
|
}
|
|
188
|
-
return matches
|
|
242
|
+
return matches.filter((match, index) => !matches.some((other, otherIndex) => otherIndex !== index &&
|
|
243
|
+
other.start <= match.start &&
|
|
244
|
+
other.end >= match.end &&
|
|
245
|
+
(other.start < match.start || other.end > match.end)));
|
|
189
246
|
}
|
|
190
247
|
//# sourceMappingURL=negation-reframe-matcher.js.map
|
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
"never",
|
|
4
|
-
"isn't",
|
|
5
|
-
"aren't",
|
|
6
|
-
"wasn't",
|
|
7
|
-
"weren't",
|
|
8
|
-
"don't",
|
|
9
|
-
"doesn't",
|
|
10
|
-
"didn't",
|
|
11
|
-
"can't",
|
|
12
|
-
"cannot",
|
|
13
|
-
"won't",
|
|
14
|
-
"wouldn't",
|
|
15
|
-
"shouldn't",
|
|
16
|
-
"couldn't"
|
|
17
|
-
]);
|
|
1
|
+
import { NEGATION_WORDS } from "./negation-vocabulary.js";
|
|
2
|
+
export { ACTION_NEGATIONS, DO_NEGATIONS, NEGATION_WORDS } from "./negation-vocabulary.js";
|
|
18
3
|
export const COPULAR_FORMS = new Map([
|
|
4
|
+
["am", "am"],
|
|
19
5
|
["are", "are"],
|
|
20
6
|
["aren't", "are"],
|
|
21
7
|
["is", "is"],
|
|
@@ -25,7 +11,6 @@ export const COPULAR_FORMS = new Map([
|
|
|
25
11
|
["were", "were"],
|
|
26
12
|
["weren't", "were"]
|
|
27
13
|
]);
|
|
28
|
-
export const DO_NEGATIONS = new Set(["don't", "doesn't", "didn't"]);
|
|
29
14
|
export const EXPLICIT_DO_AUXILIARIES = new Set(["do", "does", "did"]);
|
|
30
15
|
export const OPTIONAL_ADVERBS = new Set([
|
|
31
16
|
"actually",
|
|
@@ -39,13 +24,17 @@ export const FACTUAL_NEGATION_CONNECTORS = new Set([
|
|
|
39
24
|
"because",
|
|
40
25
|
"if",
|
|
41
26
|
"since",
|
|
27
|
+
"though",
|
|
42
28
|
"until",
|
|
43
29
|
"when",
|
|
44
30
|
"while"
|
|
45
31
|
]);
|
|
46
32
|
export const PRONOUN_REFRAME_STARTS = [
|
|
33
|
+
["i", "am"],
|
|
34
|
+
["he", "is"],
|
|
47
35
|
["it", "is"],
|
|
48
36
|
["it", "was"],
|
|
37
|
+
["she", "is"],
|
|
49
38
|
["this", "is"],
|
|
50
39
|
["that", "is"],
|
|
51
40
|
["they", "are"],
|
|
@@ -62,8 +51,12 @@ const NEGATIVE_COPULAR_PREDICATES = new Set([
|
|
|
62
51
|
"nothing",
|
|
63
52
|
"nowhere"
|
|
64
53
|
]);
|
|
54
|
+
const NEGATIVE_NOUN_DETERMINERS = new Set(["no"]);
|
|
65
55
|
const CONTRACTED_PRONOUN_COPULAS = new Map([
|
|
56
|
+
["i'm", { affirmativeAux: "am", subject: ["i"] }],
|
|
57
|
+
["he's", { affirmativeAux: "is", subject: ["he"] }],
|
|
66
58
|
["it's", { affirmativeAux: "is", subject: ["it"] }],
|
|
59
|
+
["she's", { affirmativeAux: "is", subject: ["she"] }],
|
|
67
60
|
["that's", { affirmativeAux: "is", subject: ["that"] }],
|
|
68
61
|
["they're", { affirmativeAux: "are", subject: ["they"] }],
|
|
69
62
|
["we're", { affirmativeAux: "are", subject: ["we"] }],
|
|
@@ -93,7 +86,16 @@ function regularPastTense(verb) {
|
|
|
93
86
|
return verb.endsWith("e") ? `${verb}d` : `${verb}ed`;
|
|
94
87
|
}
|
|
95
88
|
function affirmativeVerbForms(verb) {
|
|
96
|
-
|
|
89
|
+
const thirdPerson = verb.endsWith("y")
|
|
90
|
+
? `${verb.slice(0, -1)}ies`
|
|
91
|
+
: ["s", "x", "z", "ch", "sh", "o"].some((ending) => verb.endsWith(ending))
|
|
92
|
+
? `${verb}es`
|
|
93
|
+
: `${verb}s`;
|
|
94
|
+
return [
|
|
95
|
+
verb,
|
|
96
|
+
thirdPerson,
|
|
97
|
+
IRREGULAR_PAST_TENSE.get(verb) ?? regularPastTense(verb)
|
|
98
|
+
];
|
|
97
99
|
}
|
|
98
100
|
export function stripLeadingPairPivot(tokens) {
|
|
99
101
|
return tokens[0]?.normalized === "instead" ? tokens.slice(1) : tokens;
|
|
@@ -113,9 +115,6 @@ export function startsWithSubjectVerb(tokens, subject, verb) {
|
|
|
113
115
|
export function words(tokens) {
|
|
114
116
|
return tokens.map((token) => token.normalized);
|
|
115
117
|
}
|
|
116
|
-
export function hasAnyWord(tokens, candidates) {
|
|
117
|
-
return tokens.some((token) => candidates.has(token));
|
|
118
|
-
}
|
|
119
118
|
export function skipOptionalAdverbs(tokens, start) {
|
|
120
119
|
let index = start;
|
|
121
120
|
while (OPTIONAL_ADVERBS.has(tokens[index] ?? "")) {
|
|
@@ -178,6 +177,18 @@ export function hasCommaBeforeNegation(text, negationStart) {
|
|
|
178
177
|
}
|
|
179
178
|
export function findCopularNegation(tokens) {
|
|
180
179
|
const tokenWords = words(tokens);
|
|
180
|
+
const contracted = CONTRACTED_PRONOUN_COPULAS.get(tokenWords[0] ?? "");
|
|
181
|
+
const contractedNegator = tokenWords[1];
|
|
182
|
+
if (contracted !== undefined &&
|
|
183
|
+
contractedNegator !== undefined &&
|
|
184
|
+
(contractedNegator === "not" ||
|
|
185
|
+
NEGATIVE_COPULAR_PREDICATES.has(contractedNegator) ||
|
|
186
|
+
NEGATIVE_NOUN_DETERMINERS.has(contractedNegator))) {
|
|
187
|
+
return {
|
|
188
|
+
...contracted,
|
|
189
|
+
negatedPredicateStart: contractedNegator === "not" ? 2 : 1
|
|
190
|
+
};
|
|
191
|
+
}
|
|
181
192
|
for (let index = 0; index < tokenWords.length; index += 1) {
|
|
182
193
|
const current = tokenWords[index];
|
|
183
194
|
const next = tokenWords[index + 1];
|
|
@@ -201,7 +212,8 @@ export function findCopularNegation(tokens) {
|
|
|
201
212
|
}
|
|
202
213
|
if (explicitAux !== undefined &&
|
|
203
214
|
next !== undefined &&
|
|
204
|
-
|
|
215
|
+
NEGATIVE_NOUN_DETERMINERS.has(next) &&
|
|
216
|
+
tokenWords[index + 2] !== "longer") {
|
|
205
217
|
return {
|
|
206
218
|
affirmativeAux: explicitAux,
|
|
207
219
|
negatedPredicateStart: index + 1,
|
|
@@ -209,8 +221,8 @@ export function findCopularNegation(tokens) {
|
|
|
209
221
|
};
|
|
210
222
|
}
|
|
211
223
|
if (explicitAux !== undefined &&
|
|
212
|
-
next
|
|
213
|
-
(
|
|
224
|
+
next !== undefined &&
|
|
225
|
+
NEGATIVE_COPULAR_PREDICATES.has(next)) {
|
|
214
226
|
return {
|
|
215
227
|
affirmativeAux: explicitAux,
|
|
216
228
|
negatedPredicateStart: index + 1,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const DO_NEGATIONS = new Set(["don't", "doesn't", "didn't"]);
|
|
2
|
+
export const ACTION_NEGATIONS = new Set([
|
|
3
|
+
...DO_NEGATIONS,
|
|
4
|
+
"can't",
|
|
5
|
+
"couldn't",
|
|
6
|
+
"hadn't",
|
|
7
|
+
"hasn't",
|
|
8
|
+
"haven't",
|
|
9
|
+
"mightn't",
|
|
10
|
+
"mustn't",
|
|
11
|
+
"needn't",
|
|
12
|
+
"shan't",
|
|
13
|
+
"shouldn't",
|
|
14
|
+
"won't",
|
|
15
|
+
"wouldn't"
|
|
16
|
+
]);
|
|
17
|
+
export const NEGATION_WORDS = new Set([
|
|
18
|
+
"not",
|
|
19
|
+
"never",
|
|
20
|
+
"isn't",
|
|
21
|
+
"aren't",
|
|
22
|
+
"wasn't",
|
|
23
|
+
"weren't",
|
|
24
|
+
...ACTION_NEGATIONS,
|
|
25
|
+
"cannot"
|
|
26
|
+
]);
|
|
27
|
+
//# sourceMappingURL=negation-vocabulary.js.map
|