slopless 0.2.23 → 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-quantification.json +33 -0
- 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-data-e.js +2 -0
- package/dist/rules/semantic-thinness/private/pattern-matcher.js +28 -7
- package/dist/rules/syntactic-patterns/closers/affirmation-closers.js +13 -3
- 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 +79 -0
- 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 +78 -73
- package/dist/rules/syntactic-patterns/contrast/private/negation-reframe-parts.js +99 -31
- 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 +155 -39
- package/dist/rules/syntactic-patterns/contrast/private/policy-object.js +55 -0
- package/dist/rules/syntactic-patterns/contrast/private/reframe-classification.js +214 -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 +96 -102
- 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 +150 -4
- 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,214 @@
|
|
|
1
|
+
import { FACTUAL_NEGATION_CONNECTORS, findCopularNegation, pronounCopulaStart, stripLeadingPairPivot, words } from "./negation-reframe-parts.js";
|
|
2
|
+
const FRAMING_SUBJECT_NOUNS = new Set([
|
|
3
|
+
"answer",
|
|
4
|
+
"fix",
|
|
5
|
+
"goal",
|
|
6
|
+
"issue",
|
|
7
|
+
"key",
|
|
8
|
+
"point",
|
|
9
|
+
"problem",
|
|
10
|
+
"solution",
|
|
11
|
+
"strategy"
|
|
12
|
+
]);
|
|
13
|
+
const INSTRUCTION_ADJECTIVES = new Set([
|
|
14
|
+
"best",
|
|
15
|
+
"better",
|
|
16
|
+
"critical",
|
|
17
|
+
"essential",
|
|
18
|
+
"important",
|
|
19
|
+
"necessary",
|
|
20
|
+
"recommended",
|
|
21
|
+
"safest"
|
|
22
|
+
]);
|
|
23
|
+
const CONCRETE_PASSIVE_VERBS = new Set([
|
|
24
|
+
"associated",
|
|
25
|
+
"caused",
|
|
26
|
+
"classified",
|
|
27
|
+
"created",
|
|
28
|
+
"entered",
|
|
29
|
+
"linked",
|
|
30
|
+
"owned",
|
|
31
|
+
"paid",
|
|
32
|
+
"passed",
|
|
33
|
+
"produced",
|
|
34
|
+
"recorded",
|
|
35
|
+
"regulated",
|
|
36
|
+
"sent",
|
|
37
|
+
"stored",
|
|
38
|
+
"used"
|
|
39
|
+
]);
|
|
40
|
+
const REFERENCE_PASSIVE_VERBS = new Set(["defined", "described", "marked"]);
|
|
41
|
+
const PASSIVE_EXPLANATION_LINKS = new Set([
|
|
42
|
+
"as",
|
|
43
|
+
"by",
|
|
44
|
+
"for",
|
|
45
|
+
"from",
|
|
46
|
+
"in",
|
|
47
|
+
"to",
|
|
48
|
+
"with"
|
|
49
|
+
]);
|
|
50
|
+
const CLAUSE_BOUNDARIES = new Set([
|
|
51
|
+
"and",
|
|
52
|
+
"but",
|
|
53
|
+
"that",
|
|
54
|
+
"when",
|
|
55
|
+
"where",
|
|
56
|
+
"which",
|
|
57
|
+
"while"
|
|
58
|
+
]);
|
|
59
|
+
const CONCRETE_RELATIONS = [
|
|
60
|
+
["amount", "of"],
|
|
61
|
+
["defined", "to", "be"],
|
|
62
|
+
["derived", "from"],
|
|
63
|
+
["intended", "for"],
|
|
64
|
+
["owned", "by"],
|
|
65
|
+
["property", "of"],
|
|
66
|
+
["symptom", "of"],
|
|
67
|
+
["unit", "of"]
|
|
68
|
+
];
|
|
69
|
+
const MAX_SHORT_SENTENCE_WORDS = 6;
|
|
70
|
+
const QUANTITY_WORDS = new Set([
|
|
71
|
+
"half",
|
|
72
|
+
"one",
|
|
73
|
+
"two",
|
|
74
|
+
"three",
|
|
75
|
+
"four",
|
|
76
|
+
"five",
|
|
77
|
+
"six",
|
|
78
|
+
"seven",
|
|
79
|
+
"eight",
|
|
80
|
+
"nine",
|
|
81
|
+
"ten"
|
|
82
|
+
]);
|
|
83
|
+
const TIME_DETAIL_WORDS = new Set([
|
|
84
|
+
"today",
|
|
85
|
+
"tomorrow",
|
|
86
|
+
"tonight",
|
|
87
|
+
"yesterday",
|
|
88
|
+
"noon",
|
|
89
|
+
"midnight",
|
|
90
|
+
"monday",
|
|
91
|
+
"tuesday",
|
|
92
|
+
"wednesday",
|
|
93
|
+
"thursday",
|
|
94
|
+
"friday",
|
|
95
|
+
"saturday",
|
|
96
|
+
"sunday"
|
|
97
|
+
]);
|
|
98
|
+
function digitTokenCount(tokens) {
|
|
99
|
+
return tokens.filter((token) => [...token.text].some((character) => character >= "0" && character <= "9")).length;
|
|
100
|
+
}
|
|
101
|
+
function quantityTokenCount(tokens) {
|
|
102
|
+
return (digitTokenCount(tokens) +
|
|
103
|
+
tokens.filter((token) => QUANTITY_WORDS.has(token.normalized)).length);
|
|
104
|
+
}
|
|
105
|
+
function acronymCount(tokens) {
|
|
106
|
+
return tokens.filter((token) => token.text.length >= 2 &&
|
|
107
|
+
token.text === token.text.toLocaleUpperCase("en") &&
|
|
108
|
+
token.text !== token.text.toLocaleLowerCase("en")).length;
|
|
109
|
+
}
|
|
110
|
+
function properNameCount(tokens) {
|
|
111
|
+
return tokens.filter((token, index) => {
|
|
112
|
+
const first = token.text[0];
|
|
113
|
+
return (index > 0 &&
|
|
114
|
+
first !== undefined &&
|
|
115
|
+
first >= "A" &&
|
|
116
|
+
first <= "Z" &&
|
|
117
|
+
token.text !== token.text.toLocaleUpperCase("en"));
|
|
118
|
+
}).length;
|
|
119
|
+
}
|
|
120
|
+
function hasReferenceEvidence(aTokens, bTokens, pairText) {
|
|
121
|
+
const digits = digitTokenCount(aTokens) + digitTokenCount(bTokens);
|
|
122
|
+
const quantities = quantityTokenCount(aTokens) + quantityTokenCount(bTokens);
|
|
123
|
+
const names = properNameCount(aTokens) + properNameCount(bTokens);
|
|
124
|
+
return (digits >= 2 ||
|
|
125
|
+
pairText.includes("/") ||
|
|
126
|
+
pairText.includes("_") ||
|
|
127
|
+
pairText.includes("@") ||
|
|
128
|
+
(acronymCount(aTokens) + acronymCount(bTokens) >= 1 && digits >= 1) ||
|
|
129
|
+
names >= 3 ||
|
|
130
|
+
(names >= 2 && quantities >= 1));
|
|
131
|
+
}
|
|
132
|
+
function startsWithSequence(source, sequence) {
|
|
133
|
+
return sequence.every((word, index) => source[index] === word);
|
|
134
|
+
}
|
|
135
|
+
function containsSequence(source, sequence) {
|
|
136
|
+
for (let index = 0; index <= source.length - sequence.length; index += 1) {
|
|
137
|
+
if (startsWithSequence(source.slice(index), sequence)) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
function hasConcreteRelation(tokenWords) {
|
|
144
|
+
return CONCRETE_RELATIONS.some((relation) => containsSequence(tokenWords, relation));
|
|
145
|
+
}
|
|
146
|
+
function hasInstruction(tokens) {
|
|
147
|
+
const tokenWords = words(tokens);
|
|
148
|
+
const start = pronounCopulaStart(tokens);
|
|
149
|
+
return (start !== undefined &&
|
|
150
|
+
INSTRUCTION_ADJECTIVES.has(tokenWords[start.predicateStart] ?? "") &&
|
|
151
|
+
tokenWords[start.predicateStart + 1] === "to");
|
|
152
|
+
}
|
|
153
|
+
function hasPassiveExplanation(bTokens) {
|
|
154
|
+
const tokenWords = words(bTokens);
|
|
155
|
+
const start = pronounCopulaStart(bTokens);
|
|
156
|
+
const isConcretePassive = (word) => CONCRETE_PASSIVE_VERBS.has(word) || REFERENCE_PASSIVE_VERBS.has(word);
|
|
157
|
+
if (start !== undefined &&
|
|
158
|
+
isConcretePassive(tokenWords[start.predicateStart] ?? "")) {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
const boundary = tokenWords.findIndex((word) => CLAUSE_BOUNDARIES.has(word));
|
|
162
|
+
const firstClause = boundary < 0 ? tokenWords : tokenWords.slice(0, boundary);
|
|
163
|
+
return firstClause.some((word, index) => isConcretePassive(word) &&
|
|
164
|
+
PASSIVE_EXPLANATION_LINKS.has(firstClause[index + 1] ?? ""));
|
|
165
|
+
}
|
|
166
|
+
function hasPurposeOrProvenance(tokenWords) {
|
|
167
|
+
return (containsSequence(tokenWords, ["used", "to"]) ||
|
|
168
|
+
(["uses", "used"].includes(tokenWords[1] ?? "") &&
|
|
169
|
+
tokenWords.some((word, index) => ["created", "produced"].includes(word) &&
|
|
170
|
+
["by", "from", "in"].includes(tokenWords[index + 1] ?? ""))));
|
|
171
|
+
}
|
|
172
|
+
function hasCausalPassiveExplanation(aTokens, bTokens) {
|
|
173
|
+
return (words(aTokens).some((word) => FACTUAL_NEGATION_CONNECTORS.has(word)) &&
|
|
174
|
+
hasPassiveExplanation(bTokens));
|
|
175
|
+
}
|
|
176
|
+
function hasCausalConcreteCorrection(aTokens, bTokens) {
|
|
177
|
+
return (words(aTokens).some((word) => FACTUAL_NEGATION_CONNECTORS.has(word)) &&
|
|
178
|
+
(quantityTokenCount(bTokens) > 0 ||
|
|
179
|
+
words(bTokens).some((word) => TIME_DETAIL_WORDS.has(word))));
|
|
180
|
+
}
|
|
181
|
+
function hasDistinctCauseExplanation(aTokens, bTokens) {
|
|
182
|
+
const aWords = words(aTokens);
|
|
183
|
+
const bWords = words(stripLeadingPairPivot(bTokens));
|
|
184
|
+
return (!aWords.includes("caused") && containsSequence(bWords, ["caused", "by"]));
|
|
185
|
+
}
|
|
186
|
+
function hasConcreteExplanatoryEvidence(aTokens, bTokens, pairText) {
|
|
187
|
+
const tokenWords = words(stripLeadingPairPivot(bTokens));
|
|
188
|
+
return (hasInstruction(bTokens) ||
|
|
189
|
+
hasConcreteRelation(tokenWords) ||
|
|
190
|
+
hasPurposeOrProvenance(tokenWords) ||
|
|
191
|
+
hasDistinctCauseExplanation(aTokens, bTokens) ||
|
|
192
|
+
hasCausalPassiveExplanation(aTokens, bTokens) ||
|
|
193
|
+
hasCausalConcreteCorrection(aTokens, bTokens) ||
|
|
194
|
+
(hasReferenceEvidence(aTokens, bTokens, pairText) &&
|
|
195
|
+
hasPassiveExplanation(bTokens)));
|
|
196
|
+
}
|
|
197
|
+
function hasFramingNoun(tokens) {
|
|
198
|
+
const negation = findCopularNegation(tokens);
|
|
199
|
+
if (negation === undefined) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
const predicate = words(tokens).slice(negation.negatedPredicateStart, negation.negatedPredicateStart + 4);
|
|
203
|
+
return [...negation.subject, ...predicate].some((word) => FRAMING_SUBJECT_NOUNS.has(word));
|
|
204
|
+
}
|
|
205
|
+
function isShortReversal(aTokens, bTokens) {
|
|
206
|
+
return (aTokens.length <= MAX_SHORT_SENTENCE_WORDS &&
|
|
207
|
+
bTokens.length <= MAX_SHORT_SENTENCE_WORDS);
|
|
208
|
+
}
|
|
209
|
+
export function shouldReportCopularReframe(aTokens, bTokens, pairText) {
|
|
210
|
+
return (isShortReversal(aTokens, bTokens) ||
|
|
211
|
+
hasFramingNoun(aTokens) ||
|
|
212
|
+
!hasConcreteExplanatoryEvidence(aTokens, bTokens, pairText));
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=reframe-classification.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { matchAudienceReplacement } from "./audience-replacement.js";
|
|
2
|
+
import { matchNegativeConsequence } from "./negative-consequence.js";
|
|
3
|
+
import { matchTemporalReframe } from "./temporal-reframe.js";
|
|
4
|
+
export function matchSequenceReframe(first, second, third) {
|
|
5
|
+
return (matchTemporalReframe(first, second) ??
|
|
6
|
+
matchAudienceReplacement(first, second) ??
|
|
7
|
+
matchNegativeConsequence(first, second, third));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=sequence-reframes.js.map
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { wordTokens } from "../../../../shared/text/tokens.js";
|
|
2
|
+
const ABSTRACT_CATEGORY_HEADS = new Set([
|
|
3
|
+
"acquisition",
|
|
4
|
+
"administration",
|
|
5
|
+
"advertising",
|
|
6
|
+
"analytics",
|
|
7
|
+
"answer",
|
|
8
|
+
"automation",
|
|
9
|
+
"awareness",
|
|
10
|
+
"brand",
|
|
11
|
+
"channel",
|
|
12
|
+
"commerce",
|
|
13
|
+
"compliance",
|
|
14
|
+
"content",
|
|
15
|
+
"control",
|
|
16
|
+
"conversion",
|
|
17
|
+
"copy",
|
|
18
|
+
"decision",
|
|
19
|
+
"delivery",
|
|
20
|
+
"demand",
|
|
21
|
+
"discoverability",
|
|
22
|
+
"discovery",
|
|
23
|
+
"distribution",
|
|
24
|
+
"documentation",
|
|
25
|
+
"editorial",
|
|
26
|
+
"enablement",
|
|
27
|
+
"engagement",
|
|
28
|
+
"execution",
|
|
29
|
+
"experience",
|
|
30
|
+
"governance",
|
|
31
|
+
"growth",
|
|
32
|
+
"hygiene",
|
|
33
|
+
"implementation",
|
|
34
|
+
"indexing",
|
|
35
|
+
"infrastructure",
|
|
36
|
+
"management",
|
|
37
|
+
"maintenance",
|
|
38
|
+
"market",
|
|
39
|
+
"marketing",
|
|
40
|
+
"media",
|
|
41
|
+
"merchandising",
|
|
42
|
+
"operations",
|
|
43
|
+
"optimization",
|
|
44
|
+
"page",
|
|
45
|
+
"plumbing",
|
|
46
|
+
"policy",
|
|
47
|
+
"positioning",
|
|
48
|
+
"procurement",
|
|
49
|
+
"product",
|
|
50
|
+
"production",
|
|
51
|
+
"publishing",
|
|
52
|
+
"ranking",
|
|
53
|
+
"recommendation",
|
|
54
|
+
"regulation",
|
|
55
|
+
"reporting",
|
|
56
|
+
"retrieval",
|
|
57
|
+
"retention",
|
|
58
|
+
"revenue",
|
|
59
|
+
"risk",
|
|
60
|
+
"sales",
|
|
61
|
+
"search",
|
|
62
|
+
"security",
|
|
63
|
+
"service",
|
|
64
|
+
"sourcing",
|
|
65
|
+
"storefront",
|
|
66
|
+
"strategy",
|
|
67
|
+
"support",
|
|
68
|
+
"trust",
|
|
69
|
+
"visibility",
|
|
70
|
+
"workflow",
|
|
71
|
+
"work"
|
|
72
|
+
]);
|
|
73
|
+
const ARTICLES = new Set(["a", "an", "the"]);
|
|
74
|
+
const PRESENT_COPULAS = new Set(["am", "are", "is"]);
|
|
75
|
+
const CONTRACTED_COPULAS = new Map([
|
|
76
|
+
["i'm", { copula: "am", subject: ["i"] }],
|
|
77
|
+
["you're", { copula: "are", subject: ["you"] }],
|
|
78
|
+
["we're", { copula: "are", subject: ["we"] }],
|
|
79
|
+
["they're", { copula: "are", subject: ["they"] }],
|
|
80
|
+
["he's", { copula: "is", subject: ["he"] }],
|
|
81
|
+
["she's", { copula: "is", subject: ["she"] }],
|
|
82
|
+
["it's", { copula: "is", subject: ["it"] }],
|
|
83
|
+
["that's", { copula: "is", subject: ["that"] }]
|
|
84
|
+
]);
|
|
85
|
+
const PRONOUNS = new Set([
|
|
86
|
+
"he",
|
|
87
|
+
"i",
|
|
88
|
+
"it",
|
|
89
|
+
"she",
|
|
90
|
+
"that",
|
|
91
|
+
"they",
|
|
92
|
+
"this",
|
|
93
|
+
"we",
|
|
94
|
+
"you"
|
|
95
|
+
]);
|
|
96
|
+
const PLURAL_PRONOUNS = new Set(["they", "we", "you"]);
|
|
97
|
+
const SINGULAR_S_SUBJECTS = new Set([
|
|
98
|
+
"analytics",
|
|
99
|
+
"business",
|
|
100
|
+
"economics",
|
|
101
|
+
"logistics",
|
|
102
|
+
"news",
|
|
103
|
+
"operations",
|
|
104
|
+
"sales"
|
|
105
|
+
]);
|
|
106
|
+
const FACTUAL_CONNECTORS = new Set([
|
|
107
|
+
"after",
|
|
108
|
+
"although",
|
|
109
|
+
"because",
|
|
110
|
+
"before",
|
|
111
|
+
"if",
|
|
112
|
+
"since",
|
|
113
|
+
"therefore",
|
|
114
|
+
"until",
|
|
115
|
+
"when",
|
|
116
|
+
"while"
|
|
117
|
+
]);
|
|
118
|
+
const DETAIL_PREPOSITIONS = new Set([
|
|
119
|
+
"above",
|
|
120
|
+
"at",
|
|
121
|
+
"behind",
|
|
122
|
+
"below",
|
|
123
|
+
"beside",
|
|
124
|
+
"between",
|
|
125
|
+
"by",
|
|
126
|
+
"from",
|
|
127
|
+
"in",
|
|
128
|
+
"inside",
|
|
129
|
+
"into",
|
|
130
|
+
"near",
|
|
131
|
+
"of",
|
|
132
|
+
"on",
|
|
133
|
+
"outside",
|
|
134
|
+
"through",
|
|
135
|
+
"to",
|
|
136
|
+
"under",
|
|
137
|
+
"with",
|
|
138
|
+
"within"
|
|
139
|
+
]);
|
|
140
|
+
const PHYSICAL_PROPERTY_WORDS = new Set([
|
|
141
|
+
"blue",
|
|
142
|
+
"cold",
|
|
143
|
+
"dry",
|
|
144
|
+
"empty",
|
|
145
|
+
"full",
|
|
146
|
+
"green",
|
|
147
|
+
"heavy",
|
|
148
|
+
"hot",
|
|
149
|
+
"large",
|
|
150
|
+
"light",
|
|
151
|
+
"local",
|
|
152
|
+
"long",
|
|
153
|
+
"optional",
|
|
154
|
+
"red",
|
|
155
|
+
"required",
|
|
156
|
+
"shared",
|
|
157
|
+
"short",
|
|
158
|
+
"small",
|
|
159
|
+
"tall",
|
|
160
|
+
"warm",
|
|
161
|
+
"weekly",
|
|
162
|
+
"wet",
|
|
163
|
+
"wide"
|
|
164
|
+
]);
|
|
165
|
+
const FRAME_SUBJECTS = new Set([
|
|
166
|
+
"audit",
|
|
167
|
+
"content",
|
|
168
|
+
"data",
|
|
169
|
+
"feed",
|
|
170
|
+
"index",
|
|
171
|
+
"indexing",
|
|
172
|
+
"metadata",
|
|
173
|
+
"page",
|
|
174
|
+
"product",
|
|
175
|
+
"search",
|
|
176
|
+
"seo",
|
|
177
|
+
"visibility"
|
|
178
|
+
]);
|
|
179
|
+
function isCompleteSentence(text) {
|
|
180
|
+
return [".", "!", "?"].includes(text.trim().at(-1) ?? "");
|
|
181
|
+
}
|
|
182
|
+
function isLetter(character) {
|
|
183
|
+
return (character.toLocaleLowerCase("en") !== character.toLocaleUpperCase("en"));
|
|
184
|
+
}
|
|
185
|
+
function isInteriorApostrophe(text, index) {
|
|
186
|
+
return isLetter(text[index - 1] ?? "") && isLetter(text[index + 1] ?? "");
|
|
187
|
+
}
|
|
188
|
+
function hasQuotedValueOrNumber(text) {
|
|
189
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
190
|
+
const character = text[index] ?? "";
|
|
191
|
+
if ((character >= "0" && character <= "9") ||
|
|
192
|
+
['"', "`", "\u201c", "\u201d"].includes(character)) {
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
if (["'", "\u2018", "\u2019"].includes(character) &&
|
|
196
|
+
!isInteriorApostrophe(text, index)) {
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
function withoutArticle(words) {
|
|
203
|
+
return ARTICLES.has(words[0] ?? "") ? words.slice(1) : words;
|
|
204
|
+
}
|
|
205
|
+
function parsePastClause(text) {
|
|
206
|
+
const words = wordTokens(text).map((token) => token.normalized);
|
|
207
|
+
const usedIndex = words.findIndex((word, index) => word === "used" && words[index + 1] === "to" && words[index + 2] === "be");
|
|
208
|
+
const subject = words.slice(0, usedIndex);
|
|
209
|
+
const label = withoutArticle(words.slice(usedIndex + 3));
|
|
210
|
+
return usedIndex > 0 &&
|
|
211
|
+
subject.length <= 4 &&
|
|
212
|
+
label.length > 0 &&
|
|
213
|
+
label.length <= 4
|
|
214
|
+
? { label, subject }
|
|
215
|
+
: undefined;
|
|
216
|
+
}
|
|
217
|
+
function parsePresentClause(text) {
|
|
218
|
+
const words = wordTokens(text).map((token) => token.normalized);
|
|
219
|
+
const start = words[0] === "now" ? 1 : 0;
|
|
220
|
+
const contracted = CONTRACTED_COPULAS.get(words[start] ?? "");
|
|
221
|
+
if (contracted !== undefined) {
|
|
222
|
+
const label = withoutArticle(words.slice(start + 1));
|
|
223
|
+
return label.length > 0 && label.length <= 4
|
|
224
|
+
? { ...contracted, label }
|
|
225
|
+
: undefined;
|
|
226
|
+
}
|
|
227
|
+
const copulaIndex = words.findIndex((word, index) => index >= start && PRESENT_COPULAS.has(word));
|
|
228
|
+
const copula = words[copulaIndex];
|
|
229
|
+
const subject = words.slice(start, copulaIndex);
|
|
230
|
+
const label = withoutArticle(words.slice(copulaIndex + 1));
|
|
231
|
+
return copulaIndex > start &&
|
|
232
|
+
copula !== undefined &&
|
|
233
|
+
subject.length <= 4 &&
|
|
234
|
+
label.length > 0 &&
|
|
235
|
+
label.length <= 4
|
|
236
|
+
? { copula, label, subject }
|
|
237
|
+
: undefined;
|
|
238
|
+
}
|
|
239
|
+
function sameSubjectOrPronoun(first, second) {
|
|
240
|
+
if (first.length === second.length &&
|
|
241
|
+
first.every((word, index) => word === second[index])) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
if (second.length !== 1 || !PRONOUNS.has(second[0] ?? "")) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
const firstPronoun = first.length === 1 ? first[0] : undefined;
|
|
248
|
+
if (firstPronoun !== undefined && PRONOUNS.has(firstPronoun)) {
|
|
249
|
+
return firstPronoun === second[0];
|
|
250
|
+
}
|
|
251
|
+
const subjectHead = first.at(-1) ?? "";
|
|
252
|
+
const pluralSubject = isPluralSubjectHead(subjectHead);
|
|
253
|
+
return pluralSubject
|
|
254
|
+
? second[0] === "they"
|
|
255
|
+
: ["it", "that", "this"].includes(second[0] ?? "");
|
|
256
|
+
}
|
|
257
|
+
function isPluralSubjectHead(head) {
|
|
258
|
+
return (head.endsWith("s") && !head.endsWith("ss") && !SINGULAR_S_SUBJECTS.has(head));
|
|
259
|
+
}
|
|
260
|
+
function hasCopulaAgreement(clause) {
|
|
261
|
+
const subject = clause.subject;
|
|
262
|
+
const copula = clause.copula;
|
|
263
|
+
if (copula === undefined) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
if (subject.length === 1 && PRONOUNS.has(subject[0] ?? "")) {
|
|
267
|
+
if (subject[0] === "i") {
|
|
268
|
+
return copula === "am";
|
|
269
|
+
}
|
|
270
|
+
return PLURAL_PRONOUNS.has(subject[0] ?? "")
|
|
271
|
+
? copula === "are"
|
|
272
|
+
: copula === "is";
|
|
273
|
+
}
|
|
274
|
+
const head = subject.at(-1) ?? "";
|
|
275
|
+
const plural = isPluralSubjectHead(head);
|
|
276
|
+
return copula === (plural ? "are" : "is");
|
|
277
|
+
}
|
|
278
|
+
function isAbstractLabel(label) {
|
|
279
|
+
return ABSTRACT_CATEGORY_HEADS.has(label.at(-1) ?? "");
|
|
280
|
+
}
|
|
281
|
+
function hasBlockedDetail(words) {
|
|
282
|
+
return words.some((word) => FACTUAL_CONNECTORS.has(word) ||
|
|
283
|
+
DETAIL_PREPOSITIONS.has(word) ||
|
|
284
|
+
PHYSICAL_PROPERTY_WORDS.has(word));
|
|
285
|
+
}
|
|
286
|
+
function isPassiveLabel(label) {
|
|
287
|
+
const head = label[0] ?? "";
|
|
288
|
+
return head.endsWith("ed") || head.endsWith("en");
|
|
289
|
+
}
|
|
290
|
+
function isFrameSubject(subject) {
|
|
291
|
+
const head = subject.at(-1) ?? "";
|
|
292
|
+
return (FRAME_SUBJECTS.has(head) ||
|
|
293
|
+
(subject.length === 1 && ["it", "that", "this"].includes(head)));
|
|
294
|
+
}
|
|
295
|
+
export function matchTemporalReframe(first, second) {
|
|
296
|
+
if (!isCompleteSentence(first) ||
|
|
297
|
+
!isCompleteSentence(second) ||
|
|
298
|
+
hasQuotedValueOrNumber(first) ||
|
|
299
|
+
hasQuotedValueOrNumber(second)) {
|
|
300
|
+
return undefined;
|
|
301
|
+
}
|
|
302
|
+
const past = parsePastClause(first);
|
|
303
|
+
const present = parsePresentClause(second);
|
|
304
|
+
if (past === undefined || present === undefined) {
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
const allWords = [...past.subject, ...past.label, ...present.label];
|
|
308
|
+
return sameSubjectOrPronoun(past.subject, present.subject) &&
|
|
309
|
+
isFrameSubject(past.subject) &&
|
|
310
|
+
hasCopulaAgreement(present) &&
|
|
311
|
+
(isAbstractLabel(past.label) || isAbstractLabel(present.label)) &&
|
|
312
|
+
!hasBlockedDetail(allWords) &&
|
|
313
|
+
!isPassiveLabel(past.label) &&
|
|
314
|
+
!isPassiveLabel(present.label)
|
|
315
|
+
? `${first} ${second}`
|
|
316
|
+
: undefined;
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=temporal-reframe.js.map
|