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.
Files changed (28) hide show
  1. package/dist/rules/semantic-thinness/patterns/abstract-metaphor-claim.json +83 -1
  2. package/dist/rules/semantic-thinness/patterns/deictic-summary.json +31 -2
  3. package/dist/rules/semantic-thinness/patterns/empty-scene-transition.json +2 -1
  4. package/dist/rules/semantic-thinness/private/concrete-guards.js +2 -0
  5. package/dist/rules/semantic-thinness/private/pattern-matcher.js +22 -6
  6. package/dist/rules/syntactic-patterns/contrast/contrastive-aphorism.js +2 -0
  7. package/dist/rules/syntactic-patterns/contrast/negation-reframe.js +1 -1
  8. package/dist/rules/syntactic-patterns/contrast/private/action-reframe-vocabulary.js +47 -0
  9. package/dist/rules/syntactic-patterns/contrast/private/audience-replacement.js +267 -0
  10. package/dist/rules/syntactic-patterns/contrast/private/copular-reframe.js +39 -1
  11. package/dist/rules/syntactic-patterns/contrast/private/evidence-limitation-pair.js +307 -0
  12. package/dist/rules/syntactic-patterns/contrast/private/inline-semicolon-reframe.js +50 -0
  13. package/dist/rules/syntactic-patterns/contrast/private/inline-short-negation.js +1 -0
  14. package/dist/rules/syntactic-patterns/contrast/private/negation-reframe-matcher.js +64 -7
  15. package/dist/rules/syntactic-patterns/contrast/private/negation-reframe-parts.js +37 -25
  16. package/dist/rules/syntactic-patterns/contrast/private/negation-vocabulary.js +27 -0
  17. package/dist/rules/syntactic-patterns/contrast/private/negative-consequence.js +301 -0
  18. package/dist/rules/syntactic-patterns/contrast/private/negative-slop-frames.js +51 -38
  19. package/dist/rules/syntactic-patterns/contrast/private/reframe-classification.js +21 -0
  20. package/dist/rules/syntactic-patterns/contrast/private/sequence-reframes.js +9 -0
  21. package/dist/rules/syntactic-patterns/contrast/private/temporal-reframe.js +318 -0
  22. package/dist/rules/syntactic-patterns/lead-ins/generic-signposting.js +85 -22
  23. package/dist/rules/syntactic-patterns/lead-ins/private/component-assignment-frame.js +239 -0
  24. package/dist/rules/syntactic-patterns/lead-ins/private/discourse-evaluation.js +1 -0
  25. package/dist/rules/syntactic-patterns/lead-ins/private/evaluative-colon-frame.js +166 -0
  26. package/dist/rules/syntactic-patterns/lead-ins/private/reaction-frame.js +29 -0
  27. package/dist/rules/syntactic-patterns/lead-ins/private/relative-discourse-frame.js +119 -0
  28. package/package.json +1 -1
@@ -17,7 +17,39 @@
17
17
  "{abstractSubject} {linkingVerb} {infrastructureNoun} with {abstractObject}.",
18
18
  "{abstractSubject} behaves like a {filterNoun}.",
19
19
  "{artifactSubject} adds another {layerNoun} to {diagnosisObject}.",
20
- "{artifactSubject} add another {layerNoun} to {diagnosisObject}."
20
+ "{artifactSubject} add another {layerNoun} to {diagnosisObject}.",
21
+ {
22
+ "text": "{identityArtifact} {linkingVerb} the {artifactRole}.",
23
+ "matchMode": "full"
24
+ },
25
+ {
26
+ "text": "the {identityArtifact} {linkingVerb} the {artifactRole}.",
27
+ "matchMode": "full"
28
+ },
29
+ {
30
+ "text": "{identityArtifact} {linkingVerb} the {artifactRole} now.",
31
+ "matchMode": "full"
32
+ },
33
+ {
34
+ "text": "the {identityArtifact} {linkingVerb} the {artifactRole} now.",
35
+ "matchMode": "full"
36
+ },
37
+ {
38
+ "text": "{audiencePreposition} the {automatedAudience}, the {identityArtifact} {linkingVerb} the {artifactRole}.",
39
+ "matchMode": "full"
40
+ },
41
+ {
42
+ "text": "{audiencePreposition} the {automatedAudience}, {identityArtifact} {linkingVerb} the {artifactRole}.",
43
+ "matchMode": "full"
44
+ },
45
+ {
46
+ "text": "{audiencePreposition} the {automatedAudience} {audienceActivity}, the {identityArtifact} {linkingVerb} the {artifactRole}.",
47
+ "matchMode": "full"
48
+ },
49
+ {
50
+ "text": "{audiencePreposition} the {automatedAudience} {audienceActivity}, {identityArtifact} {linkingVerb} the {artifactRole}.",
51
+ "matchMode": "full"
52
+ }
21
53
  ],
22
54
  "slots": {
23
55
  "abstractSubject": [
@@ -87,6 +119,56 @@
87
119
  "the report",
88
120
  "visibility"
89
121
  ],
122
+ "identityArtifact": [
123
+ "feed",
124
+ "page",
125
+ "prompt",
126
+ "dashboard",
127
+ "database",
128
+ "index",
129
+ "schema",
130
+ "metadata",
131
+ "report",
132
+ "spreadsheet",
133
+ "interface",
134
+ "pipeline",
135
+ "model",
136
+ "content"
137
+ ],
138
+ "artifactRole": [
139
+ "product",
140
+ "strategy",
141
+ "decision",
142
+ "answer",
143
+ "business",
144
+ "brand",
145
+ "storefront",
146
+ "market",
147
+ "distribution",
148
+ "experience",
149
+ "work",
150
+ "source of truth"
151
+ ],
152
+ "audiencePreposition": ["for", "to"],
153
+ "automatedAudience": [
154
+ "agent",
155
+ "ai assistant",
156
+ "algorithm",
157
+ "assistant",
158
+ "crawler",
159
+ "machine",
160
+ "model",
161
+ "ranking system",
162
+ "recommendation engine",
163
+ "search agent"
164
+ ],
165
+ "audienceActivity": [
166
+ "choosing the product",
167
+ "doing the shopping",
168
+ "making the decision",
169
+ "ranking the results",
170
+ "reading the page"
171
+ ],
90
172
  "abstractObject": [
91
173
  "consequences",
92
174
  "diagnosis",
@@ -5,8 +5,26 @@
5
5
  "matchMode": "contains",
6
6
  "maxTokens": 80,
7
7
  "templates": [
8
- "{deicticSubject} {linkingVerb} the {summaryNoun}.",
9
- "{deicticSubject} {linkingVerb} the {evaluativeAdjective} {summaryNoun}.",
8
+ {
9
+ "text": "{deicticCopula} the {summaryNoun}.",
10
+ "matchMode": "full"
11
+ },
12
+ {
13
+ "text": "{deicticCopula} the {evaluativeAdjective} {summaryNoun}.",
14
+ "matchMode": "full"
15
+ },
16
+ {
17
+ "text": "{deicticSubject} {linkingVerb} the {summaryNoun}.",
18
+ "matchMode": "full"
19
+ },
20
+ {
21
+ "text": "{deicticSubject} {linkingVerb} the {summaryNoun}.",
22
+ "matchMode": "connector"
23
+ },
24
+ {
25
+ "text": "{deicticSubject} {linkingVerb} the {evaluativeAdjective} {summaryNoun}.",
26
+ "matchMode": "full"
27
+ },
10
28
  "{deicticSubject} {linkingVerb} the {summaryNoun} that {thinPredicate}.",
11
29
  "{deicticSubject} {linkingVerb} the {summaryNoun} {genericAudience} {reactionVerb}.",
12
30
  "{deicticSubject} {summaryVerb} the {summaryNoun}.",
@@ -14,6 +32,7 @@
14
32
  "{deicticSubject} {meaningVerb} {summaryNoun}.",
15
33
  "{deicticSubject} {explanationVerb} {summaryNoun}.",
16
34
  "{deicticSubject} {explanationVerb} the {summaryNoun}.",
35
+ "{deicticSubject} {speechVerb} {deicticSubject} {linkingVerb} the {summaryNoun}.",
17
36
  "{deicticSubject} {meaningVerb} {abstractSubject} {linkingVerb} {weakJudgment}.",
18
37
  "{deicticSubject} {explanationVerb} why {abstractSubject} {abstractVerb}.",
19
38
  "{deicticSubject} {explanationVerb} how {abstractSubject} {abstractVerb}.",
@@ -30,6 +49,14 @@
30
49
  "{deicticSubject} {linkingVerb} the reason {abstractSubject} {importanceVerb}."
31
50
  ],
32
51
  "slots": {
52
+ "deicticCopula": [
53
+ "that is",
54
+ "this is",
55
+ "it is",
56
+ "that's",
57
+ "this's",
58
+ "it's"
59
+ ],
33
60
  "deicticSubject": ["that", "this", "it"],
34
61
  "linkingVerb": ["is", "was"],
35
62
  "evaluativeAdjective": [
@@ -51,6 +78,7 @@
51
78
  ],
52
79
  "summaryNoun": [
53
80
  "part",
81
+ "piece",
54
82
  "promise",
55
83
  "truth",
56
84
  "lesson",
@@ -99,6 +127,7 @@
99
127
  ],
100
128
  "meaningVerb": ["means", "meant", "does not mean", "doesn't mean"],
101
129
  "explanationVerb": ["shows", "showed", "explains", "explained", "proves"],
130
+ "speechVerb": ["says", "said", "tells", "told"],
102
131
  "weakJudgment": [
103
132
  "useless",
104
133
  "useful",
@@ -2,11 +2,12 @@
2
2
  "id": "empty-scene-transition",
3
3
  "class": "transition-change",
4
4
  "purpose": "Catch generic transition lines that declare change, passage, or motion without naming what changed or why.",
5
- "matchMode": "contains",
5
+ "matchMode": "full",
6
6
  "templates": [
7
7
  "{genericSubject} {changeVerb}.",
8
8
  "{genericSubject} {changeVerb} {weakModifier}.",
9
9
  "{genericSubject} {changeVerb} {genericObject}.",
10
+ "{weakModifier}, {genericSubject} {changeVerb}.",
10
11
  "{genericSubject} {passageVerb}."
11
12
  ],
12
13
  "slots": {
@@ -1,6 +1,7 @@
1
1
  const CONCRETE_EXPLANATION_TOKENS = new Set([
2
2
  "api",
3
3
  "archive",
4
+ "assigned",
4
5
  "auditor",
5
6
  "billing",
6
7
  "bids",
@@ -20,6 +21,7 @@ const CONCRETE_EXPLANATION_TOKENS = new Set([
20
21
  "invoice",
21
22
  "key",
22
23
  "ledger",
24
+ "lists",
23
25
  "masonry",
24
26
  "mark",
25
27
  "meter",
@@ -16,6 +16,7 @@ const REJECT_TOKENS = new Set([
16
16
  ]);
17
17
  const BROAD_PATTERN_IDS = new Set([
18
18
  "abstract-agency-personification",
19
+ "abstract-metaphor-claim",
19
20
  "abstract-personification-line",
20
21
  "body-emotion-shorthand",
21
22
  "deictic-summary",
@@ -59,15 +60,16 @@ function readSlotName(template, start) {
59
60
  return [name, index];
60
61
  }
61
62
  function compileTemplate(template) {
63
+ const text = typeof template === "string" ? template : template.text;
62
64
  const parts = [];
63
65
  let literal = "";
64
66
  let index = 0;
65
- while (index < template.length) {
66
- const character = template[index];
67
+ while (index < text.length) {
68
+ const character = text[index];
67
69
  if (character === "{") {
68
70
  flushLiteral(parts, literal);
69
71
  literal = "";
70
- const [name, nextIndex] = readSlotName(template, index);
72
+ const [name, nextIndex] = readSlotName(text, index);
71
73
  parts.push({ kind: "slot", name });
72
74
  index = nextIndex;
73
75
  continue;
@@ -76,7 +78,16 @@ function compileTemplate(template) {
76
78
  index += 1;
77
79
  }
78
80
  flushLiteral(parts, literal);
79
- return { parts, signal: template };
81
+ const matchMode = typeof template !== "string" &&
82
+ (template.matchMode === "contains" ||
83
+ template.matchMode === "connector" ||
84
+ template.matchMode === "full" ||
85
+ template.matchMode === "suffix")
86
+ ? template.matchMode
87
+ : undefined;
88
+ return matchMode === undefined
89
+ ? { parts, signal: text }
90
+ : { matchMode, parts, signal: text };
80
91
  }
81
92
  function compileSlotValues(slots) {
82
93
  const compiled = {};
@@ -138,6 +149,7 @@ function matchPart(source, pattern, part, tokenIndex) {
138
149
  .map((tokens) => tokenIndex + tokens.length);
139
150
  }
140
151
  function templateMatches(source, pattern, template, start) {
152
+ const matchMode = template.matchMode ?? pattern.matchMode;
141
153
  let positions = [start];
142
154
  for (const part of template.parts) {
143
155
  positions = positions.flatMap((position) => matchPart(source, pattern, part, position));
@@ -145,13 +157,17 @@ function templateMatches(source, pattern, template, start) {
145
157
  return false;
146
158
  }
147
159
  }
148
- if (pattern.matchMode === "contains") {
160
+ if (matchMode === "contains") {
149
161
  return positions.length > 0;
150
162
  }
163
+ if (matchMode === "connector") {
164
+ return positions.some((position) => ["and", "but", "so", "yet"].includes(source[position]?.normalized ?? ""));
165
+ }
151
166
  return positions.includes(source.length);
152
167
  }
153
168
  function templateMatchesPattern(source, pattern, template) {
154
- if (pattern.matchMode === "full") {
169
+ const matchMode = template.matchMode ?? pattern.matchMode;
170
+ if (matchMode === "full" || matchMode === "connector") {
155
171
  return templateMatches(source, pattern, template, 0);
156
172
  }
157
173
  for (let start = 0; start < source.length; start += 1) {
@@ -2,6 +2,7 @@ import { defineTextlintRule } from "../../../adapters/textlint/rule.js";
2
2
  import { sentenceUnits } from "../../../adapters/textlint/units.js";
3
3
  import { cleanSentence, startsWithWords, tokens, trimTerminalPunctuation } from "../../../shared/matchers/prose-patterns.js";
4
4
  import { pairHasAbstractSubjectOrObject } from "./private/abstract-pair-gates.js";
5
+ import { matchEvidenceLimitationPair } from "./private/evidence-limitation-pair.js";
5
6
  import { matchSameSentenceContrast } from "./private/same-sentence-contrast.js";
6
7
  import { matchSingleSentenceAphorism } from "./private/single-sentence-aphorism.js";
7
8
  const PREFIXES = ["and ", "but ", "so ", "because "];
@@ -104,6 +105,7 @@ const rule = defineTextlintRule({
104
105
  matchLessMorePair(current.text, next.text) ??
105
106
  matchGivesYouPair(current.text, next.text) ??
106
107
  matchGetsOneAnotherPair(current.text, next.text) ??
108
+ matchEvidenceLimitationPair(current.text, next.text) ??
107
109
  matchEvaluativeContrastPair(current.text, next.text);
108
110
  if (signal !== undefined) {
109
111
  detections.push({
@@ -21,7 +21,7 @@ const rule = defineTextlintRule({
21
21
  family: "syntactic-patterns",
22
22
  id: RULE_ID
23
23
  },
24
- formatMessage: (report) => `Negation reframe found: "${report.evidence}". Rewrite without the not-X-then-Y construction.`,
24
+ formatMessage: (report) => `Negation reframe found: "${report.evidence}". Rewrite the staged negation as a direct claim.`,
25
25
  reportPolicy: { kind: "one-to-one" },
26
26
  units: (document) => [
27
27
  ...allParagraphUnits(document),
@@ -0,0 +1,47 @@
1
+ export const GENERIC_ACTION_VERBS = new Set([
2
+ "asked",
3
+ "built",
4
+ "called",
5
+ "checked",
6
+ "checks",
7
+ "compare",
8
+ "compared",
9
+ "compares",
10
+ "crossed",
11
+ "decided",
12
+ "decides",
13
+ "followed",
14
+ "follows",
15
+ "found",
16
+ "gave",
17
+ "kept",
18
+ "left",
19
+ "looked",
20
+ "made",
21
+ "moved",
22
+ "opened",
23
+ "pointed",
24
+ "pulled",
25
+ "raised",
26
+ "rank",
27
+ "ranked",
28
+ "ranks",
29
+ "read",
30
+ "reads",
31
+ "reached",
32
+ "reasoned",
33
+ "reasons",
34
+ "returned",
35
+ "returns",
36
+ "said",
37
+ "sat",
38
+ "shifted",
39
+ "started",
40
+ "stood",
41
+ "stopped",
42
+ "took",
43
+ "turned",
44
+ "walked",
45
+ "went"
46
+ ]);
47
+ //# sourceMappingURL=action-reframe-vocabulary.js.map
@@ -0,0 +1,267 @@
1
+ import { wordTokens } from "../../../../shared/text/tokens.js";
2
+ const HUMAN_AUDIENCES = new Set([
3
+ "buyers",
4
+ "customers",
5
+ "people",
6
+ "readers",
7
+ "researchers",
8
+ "shoppers",
9
+ "users",
10
+ "visitors"
11
+ ]);
12
+ const MACHINE_ACTORS = new Set([
13
+ "agent",
14
+ "agents",
15
+ "ai",
16
+ "algorithm",
17
+ "algorithms",
18
+ "assistant",
19
+ "assistants",
20
+ "bot",
21
+ "bots",
22
+ "crawler",
23
+ "crawlers",
24
+ "machine",
25
+ "machines",
26
+ "model",
27
+ "models",
28
+ "system",
29
+ "systems"
30
+ ]);
31
+ const PREDICATES = new Map([
32
+ ["buy", "buy"],
33
+ ["buys", "buy"],
34
+ ["bought", "buy"],
35
+ ["choose", "choose"],
36
+ ["chooses", "choose"],
37
+ ["chose", "choose"],
38
+ ["compare", "compare"],
39
+ ["compares", "compare"],
40
+ ["compared", "compare"],
41
+ ["evaluate", "evaluate"],
42
+ ["evaluates", "evaluate"],
43
+ ["evaluated", "evaluate"],
44
+ ["find", "find"],
45
+ ["finds", "find"],
46
+ ["found", "find"],
47
+ ["inspect", "inspect"],
48
+ ["inspects", "inspect"],
49
+ ["inspected", "inspect"],
50
+ ["purchase", "purchase"],
51
+ ["purchases", "purchase"],
52
+ ["purchased", "purchase"],
53
+ ["read", "read"],
54
+ ["reads", "read"],
55
+ ["review", "review"],
56
+ ["reviews", "review"],
57
+ ["reviewed", "review"],
58
+ ["search", "search"],
59
+ ["searches", "search"],
60
+ ["searched", "search"],
61
+ ["select", "select"],
62
+ ["selects", "select"],
63
+ ["selected", "select"],
64
+ ["scan", "scan"],
65
+ ["scans", "scan"],
66
+ ["scanned", "scan"]
67
+ ]);
68
+ const CAUSAL_CONNECTORS = new Set([
69
+ "after",
70
+ "because",
71
+ "if",
72
+ "since",
73
+ "therefore",
74
+ "until",
75
+ "when",
76
+ "while"
77
+ ]);
78
+ const OBJECT_FILLERS = new Set([
79
+ "a",
80
+ "an",
81
+ "and",
82
+ "at",
83
+ "for",
84
+ "from",
85
+ "in",
86
+ "its",
87
+ "my",
88
+ "of",
89
+ "on",
90
+ "our",
91
+ "the",
92
+ "their",
93
+ "to",
94
+ "your"
95
+ ]);
96
+ const OBJECT_PRONOUNS = new Set([
97
+ "he",
98
+ "her",
99
+ "him",
100
+ "it",
101
+ "me",
102
+ "she",
103
+ "them",
104
+ "they",
105
+ "us",
106
+ "we",
107
+ "you"
108
+ ]);
109
+ const ARTIFACT_SURFACES = new Set([
110
+ "catalog",
111
+ "dashboard",
112
+ "database",
113
+ "feed",
114
+ "index",
115
+ "listing",
116
+ "page",
117
+ "report",
118
+ "site"
119
+ ]);
120
+ function words(text) {
121
+ return wordTokens(text).map((token) => token.normalized);
122
+ }
123
+ function hasQuote(text) {
124
+ return [...text].some((character) => character === '"' ||
125
+ character === "\u201c" ||
126
+ character === "\u201d" ||
127
+ character === "`");
128
+ }
129
+ function hasDigit(word) {
130
+ return [...word].some((character) => character >= "0" && character <= "9");
131
+ }
132
+ function hasRejectedSurface(text, sentenceWords) {
133
+ return (hasQuote(text) ||
134
+ sentenceWords.some((word) => CAUSAL_CONNECTORS.has(word) || hasDigit(word)));
135
+ }
136
+ function stripTimeMarker(sentenceWords) {
137
+ const suffixes = [
138
+ ["anymore"],
139
+ ["now"],
140
+ ["any", "longer"],
141
+ ["these", "days"]
142
+ ];
143
+ for (const suffix of suffixes) {
144
+ const start = sentenceWords.length - suffix.length;
145
+ if (start > 0 &&
146
+ suffix.every((word, index) => sentenceWords[start + index] === word)) {
147
+ return sentenceWords.slice(0, start);
148
+ }
149
+ }
150
+ return undefined;
151
+ }
152
+ function humanAudienceEnd(sentenceWords) {
153
+ const first = sentenceWords[0];
154
+ if (first === "nobody") {
155
+ return 1;
156
+ }
157
+ if (first === "no" && sentenceWords[1] === "one") {
158
+ return 2;
159
+ }
160
+ const headIndex = first === "the" || first === "most" || first === "many" ? 1 : 0;
161
+ return HUMAN_AUDIENCES.has(sentenceWords[headIndex] ?? "")
162
+ ? headIndex + 1
163
+ : undefined;
164
+ }
165
+ function firstClaim(sentenceWords) {
166
+ const originalSubjectEnd = humanAudienceEnd(sentenceWords);
167
+ const withoutTime = stripTimeMarker(sentenceWords) ??
168
+ (originalSubjectEnd !== undefined &&
169
+ sentenceWords[originalSubjectEnd] === "no" &&
170
+ sentenceWords[originalSubjectEnd + 1] === "longer"
171
+ ? sentenceWords
172
+ : undefined);
173
+ if (withoutTime === undefined) {
174
+ return undefined;
175
+ }
176
+ const subjectEnd = humanAudienceEnd(withoutTime);
177
+ if (subjectEnd === undefined) {
178
+ return undefined;
179
+ }
180
+ let predicateIndex = subjectEnd;
181
+ const subjectStart = withoutTime[0];
182
+ if (subjectStart !== "nobody" && subjectStart !== "no") {
183
+ if (withoutTime[predicateIndex] === "don't" ||
184
+ withoutTime[predicateIndex] === "doesn't" ||
185
+ withoutTime[predicateIndex] === "didn't") {
186
+ predicateIndex += 1;
187
+ }
188
+ else if (withoutTime[predicateIndex] === "do" &&
189
+ withoutTime[predicateIndex + 1] === "not") {
190
+ predicateIndex += 2;
191
+ }
192
+ else if (withoutTime[predicateIndex] === "no" &&
193
+ withoutTime[predicateIndex + 1] === "longer") {
194
+ predicateIndex += 2;
195
+ }
196
+ else {
197
+ return undefined;
198
+ }
199
+ }
200
+ const predicate = PREDICATES.get(withoutTime[predicateIndex] ?? "");
201
+ const object = withoutTime.slice(predicateIndex + 1);
202
+ return predicate !== undefined && object.length > 0
203
+ ? { object, predicate }
204
+ : undefined;
205
+ }
206
+ function machineActorEnd(sentenceWords) {
207
+ let index = sentenceWords[0] === "a" ||
208
+ sentenceWords[0] === "an" ||
209
+ sentenceWords[0] === "the"
210
+ ? 1
211
+ : 0;
212
+ const actorStart = index;
213
+ while (index < actorStart + 2 &&
214
+ MACHINE_ACTORS.has(sentenceWords[index] ?? "")) {
215
+ index += 1;
216
+ }
217
+ return index > actorStart ? index : undefined;
218
+ }
219
+ function secondClaim(sentenceWords) {
220
+ const actorEnd = machineActorEnd(sentenceWords);
221
+ if (actorEnd === undefined) {
222
+ return undefined;
223
+ }
224
+ const predicate = PREDICATES.get(sentenceWords[actorEnd] ?? "");
225
+ const object = sentenceWords.slice(actorEnd + 1);
226
+ return predicate !== undefined && object.length > 0
227
+ ? { object, predicate }
228
+ : undefined;
229
+ }
230
+ function contentWords(object) {
231
+ return new Set(object.filter((word) => !OBJECT_FILLERS.has(word) && !OBJECT_PRONOUNS.has(word)));
232
+ }
233
+ function sharesContent(firstObject, secondObject) {
234
+ if (secondObject.length === 0 ||
235
+ secondObject.every((word) => OBJECT_PRONOUNS.has(word))) {
236
+ return false;
237
+ }
238
+ const firstContent = contentWords(firstObject);
239
+ const secondContent = contentWords(secondObject);
240
+ const sameContent = firstContent.size === secondContent.size &&
241
+ [...firstContent].every((word) => secondContent.has(word));
242
+ const firstCore = [...firstContent].filter((word) => !ARTIFACT_SURFACES.has(word));
243
+ const secondCore = [...secondContent].filter((word) => !ARTIFACT_SURFACES.has(word));
244
+ return (sameContent ||
245
+ (firstCore.length > 0 &&
246
+ firstCore.length === secondCore.length &&
247
+ firstCore.every((word) => secondCore.includes(word))));
248
+ }
249
+ export function matchAudienceReplacement(first, second) {
250
+ const firstWords = words(first);
251
+ const secondWords = words(second);
252
+ if (firstWords.length > 24 ||
253
+ secondWords.length > 20 ||
254
+ hasRejectedSurface(first, firstWords) ||
255
+ hasRejectedSurface(second, secondWords)) {
256
+ return undefined;
257
+ }
258
+ const humanClaim = firstClaim(firstWords);
259
+ const machineClaim = secondClaim(secondWords);
260
+ if (humanClaim === undefined ||
261
+ machineClaim?.predicate !== humanClaim.predicate ||
262
+ !sharesContent(humanClaim.object, machineClaim.object)) {
263
+ return undefined;
264
+ }
265
+ return `${first} ${second}`;
266
+ }
267
+ //# sourceMappingURL=audience-replacement.js.map
@@ -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