slopless 0.2.24 → 0.2.26

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.
Files changed (29) hide show
  1. package/README.md +9 -9
  2. package/dist/rules/semantic-thinness/patterns/abstract-metaphor-claim.json +83 -1
  3. package/dist/rules/semantic-thinness/patterns/deictic-summary.json +31 -2
  4. package/dist/rules/semantic-thinness/patterns/empty-scene-transition.json +2 -1
  5. package/dist/rules/semantic-thinness/private/concrete-guards.js +2 -0
  6. package/dist/rules/semantic-thinness/private/pattern-matcher.js +22 -6
  7. package/dist/rules/syntactic-patterns/contrast/contrastive-aphorism.js +2 -0
  8. package/dist/rules/syntactic-patterns/contrast/negation-reframe.js +1 -1
  9. package/dist/rules/syntactic-patterns/contrast/private/action-reframe-vocabulary.js +47 -0
  10. package/dist/rules/syntactic-patterns/contrast/private/audience-replacement.js +267 -0
  11. package/dist/rules/syntactic-patterns/contrast/private/copular-reframe.js +39 -1
  12. package/dist/rules/syntactic-patterns/contrast/private/evidence-limitation-pair.js +307 -0
  13. package/dist/rules/syntactic-patterns/contrast/private/inline-semicolon-reframe.js +50 -0
  14. package/dist/rules/syntactic-patterns/contrast/private/inline-short-negation.js +1 -0
  15. package/dist/rules/syntactic-patterns/contrast/private/negation-reframe-matcher.js +64 -7
  16. package/dist/rules/syntactic-patterns/contrast/private/negation-reframe-parts.js +37 -25
  17. package/dist/rules/syntactic-patterns/contrast/private/negation-vocabulary.js +27 -0
  18. package/dist/rules/syntactic-patterns/contrast/private/negative-consequence.js +301 -0
  19. package/dist/rules/syntactic-patterns/contrast/private/negative-slop-frames.js +51 -38
  20. package/dist/rules/syntactic-patterns/contrast/private/reframe-classification.js +21 -0
  21. package/dist/rules/syntactic-patterns/contrast/private/sequence-reframes.js +9 -0
  22. package/dist/rules/syntactic-patterns/contrast/private/temporal-reframe.js +318 -0
  23. package/dist/rules/syntactic-patterns/lead-ins/generic-signposting.js +85 -22
  24. package/dist/rules/syntactic-patterns/lead-ins/private/component-assignment-frame.js +239 -0
  25. package/dist/rules/syntactic-patterns/lead-ins/private/discourse-evaluation.js +1 -0
  26. package/dist/rules/syntactic-patterns/lead-ins/private/evaluative-colon-frame.js +166 -0
  27. package/dist/rules/syntactic-patterns/lead-ins/private/reaction-frame.js +29 -0
  28. package/dist/rules/syntactic-patterns/lead-ins/private/relative-discourse-frame.js +119 -0
  29. package/package.json +5 -5
@@ -1,4 +1,27 @@
1
- import { NEGATION_WORDS, findCopularNegation, pronounCopulaStart, skipOptionalAdverbs, startsWithPronounCopula, startsWithWords, startsWithSubjectCopula, validSubject, words } from "./negation-reframe-parts.js";
1
+ import { FACTUAL_NEGATION_CONNECTORS, NEGATION_WORDS, findCopularNegation, pronounCopulaStart, skipOptionalAdverbs, startsWithPronounCopula, startsWithWords, startsWithSubjectCopula, validSubject, words } from "./negation-reframe-parts.js";
2
+ const AGENTIC_SYSTEM_SUBJECTS = new Set([
3
+ "agent",
4
+ "assistant",
5
+ "engine",
6
+ "model",
7
+ "system",
8
+ "tool"
9
+ ]);
10
+ const PAYOFF_VERBS = new Set([
11
+ "compared",
12
+ "considered",
13
+ "encountered",
14
+ "entered",
15
+ "evaluated",
16
+ "found",
17
+ "met",
18
+ "qualified",
19
+ "ranked",
20
+ "reached",
21
+ "reviewed",
22
+ "selected",
23
+ "seen"
24
+ ]);
2
25
  export function sameSubjectCopularReframe(aTokens, bTokens) {
3
26
  const negation = findCopularNegation(aTokens);
4
27
  if (negation === undefined || !validSubject(negation.subject)) {
@@ -38,4 +61,19 @@ export function startsWithNegatedPronounCopula(tokens) {
38
61
  const predicateIndex = skipOptionalAdverbs(tokenWords, start.predicateStart);
39
62
  return NEGATION_WORDS.has(tokenWords[predicateIndex] ?? "");
40
63
  }
64
+ export function negatedProgressiveNeverPayoff(first, second) {
65
+ const negation = findCopularNegation(first);
66
+ if (negation === undefined ||
67
+ !AGENTIC_SYSTEM_SUBJECTS.has(negation.subject.at(-1) ?? "") ||
68
+ words(first)[negation.negatedPredicateStart]?.endsWith("ing") !== true) {
69
+ return false;
70
+ }
71
+ const secondWords = words(second);
72
+ const neverIndex = secondWords.slice(1, 4).indexOf("never") + 1;
73
+ return (["it", "they"].includes(secondWords[0] ?? "") &&
74
+ neverIndex > 0 &&
75
+ PAYOFF_VERBS.has(secondWords[neverIndex + 1] ?? "") &&
76
+ !secondWords.some((word) => FACTUAL_NEGATION_CONNECTORS.has(word)) &&
77
+ secondWords.length <= 10);
78
+ }
41
79
  //# sourceMappingURL=copular-reframe.js.map
@@ -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 (DO_NEGATIONS.has(current ?? "")) {
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
- matches.push(inlineMatch);
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
- matches.push(pairMatch);
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
- export const NEGATION_WORDS = new Set([
2
- "not",
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
- return [verb, IRREGULAR_PAST_TENSE.get(verb) ?? regularPastTense(verb)];
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
- NEGATIVE_COPULAR_PREDICATES.has(next)) {
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 === "no" &&
213
- (tokenWords[index + 2] === "one" || tokenWords[index + 2] === "single")) {
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