slopless 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -0
- package/dist/families/metrics/avg-sentence-length.js +22 -0
- package/dist/families/metrics/avg-sentence-length.js.map +1 -0
- package/dist/families/metrics/coleman-liau.js +27 -0
- package/dist/families/metrics/coleman-liau.js.map +1 -0
- package/dist/families/metrics/flesch-kincaid.js +27 -0
- package/dist/families/metrics/flesch-kincaid.js.map +1 -0
- package/dist/families/metrics/gunning-fog.js +27 -0
- package/dist/families/metrics/gunning-fog.js.map +1 -0
- package/dist/families/metrics/paragraph-length.js +21 -0
- package/dist/families/metrics/paragraph-length.js.map +1 -0
- package/dist/families/metrics/word-repetition.js +46 -0
- package/dist/families/metrics/word-repetition.js.map +1 -0
- package/dist/families/orthography/colon-dramatic.js +117 -0
- package/dist/families/orthography/colon-dramatic.js.map +1 -0
- package/dist/families/orthography/em-dashes.js +41 -0
- package/dist/families/orthography/em-dashes.js.map +1 -0
- package/dist/families/orthography/exclamation-density.js +51 -0
- package/dist/families/orthography/exclamation-density.js.map +1 -0
- package/dist/families/orthography/fake-timestamps.js +103 -0
- package/dist/families/orthography/fake-timestamps.js.map +1 -0
- package/dist/families/orthography/sentence-case.js +66 -0
- package/dist/families/orthography/sentence-case.js.map +1 -0
- package/dist/families/orthography/smart-quotes.js +53 -0
- package/dist/families/orthography/smart-quotes.js.map +1 -0
- package/dist/families/phrases/cliches.js +17 -0
- package/dist/families/phrases/cliches.js.map +1 -0
- package/dist/families/phrases/corporate-speak.js +23 -0
- package/dist/families/phrases/corporate-speak.js.map +1 -0
- package/dist/families/phrases/data/cliches.json +699 -0
- package/dist/families/phrases/data/corporate-speak.json +27 -0
- package/dist/families/phrases/data/prohibited-phrases.json +8 -0
- package/dist/families/phrases/data/skunked-terms.json +10 -0
- package/dist/families/phrases/data/uncomparables.json +57 -0
- package/dist/families/phrases/humble-bragger.js +26 -0
- package/dist/families/phrases/humble-bragger.js.map +1 -0
- package/dist/families/phrases/jargon-faker.js +84 -0
- package/dist/families/phrases/jargon-faker.js.map +1 -0
- package/dist/families/phrases/llm-disclaimer.js +54 -0
- package/dist/families/phrases/llm-disclaimer.js.map +1 -0
- package/dist/families/phrases/prohibited-phrases.js +17 -0
- package/dist/families/phrases/prohibited-phrases.js.map +1 -0
- package/dist/families/phrases/skunked-terms.js +23 -0
- package/dist/families/phrases/skunked-terms.js.map +1 -0
- package/dist/families/phrases/uncomparables.js +78 -0
- package/dist/families/phrases/uncomparables.js.map +1 -0
- package/dist/families/semantic-thinness/patterns/abstract-contrast.json +85 -0
- package/dist/families/semantic-thinness/patterns/abstract-metaphor-claim.json +112 -0
- package/dist/families/semantic-thinness/patterns/body-emotion-shorthand.json +77 -0
- package/dist/families/semantic-thinness/patterns/body-knows.json +80 -0
- package/dist/families/semantic-thinness/patterns/deictic-summary.json +109 -0
- package/dist/families/semantic-thinness/patterns/empty-atmosphere-shift.json +70 -0
- package/dist/families/semantic-thinness/patterns/empty-emotional-weather.json +104 -0
- package/dist/families/semantic-thinness/patterns/empty-scene-state.json +117 -0
- package/dist/families/semantic-thinness/patterns/empty-scene-transition.json +98 -0
- package/dist/families/semantic-thinness/patterns/gaze-choreography.json +87 -0
- package/dist/families/semantic-thinness/patterns/generic-lesson-extraction.json +82 -0
- package/dist/families/semantic-thinness/patterns/generic-pressure-or-stakes.json +107 -0
- package/dist/families/semantic-thinness/patterns/generic-realization.json +113 -0
- package/dist/families/semantic-thinness/patterns/hollow-significance.json +103 -0
- package/dist/families/semantic-thinness/patterns/low-information-physical-blocking.json +113 -0
- package/dist/families/semantic-thinness/patterns/point-is-frame.json +81 -0
- package/dist/families/semantic-thinness/patterns/real-work-begins.json +66 -0
- package/dist/families/semantic-thinness/patterns/silence-as-actor.json +69 -0
- package/dist/families/semantic-thinness/patterns/something-shifted.json +73 -0
- package/dist/families/semantic-thinness/patterns/truth-answer-moves.json +75 -0
- package/dist/families/semantic-thinness/patterns/vague-connective-payoff.json +90 -0
- package/dist/families/semantic-thinness/patterns/vague-threshold-change.json +98 -0
- package/dist/families/semantic-thinness/private/pattern-data-a.js +15 -0
- package/dist/families/semantic-thinness/private/pattern-data-a.js.map +1 -0
- package/dist/families/semantic-thinness/private/pattern-data-b.js +15 -0
- package/dist/families/semantic-thinness/private/pattern-data-b.js.map +1 -0
- package/dist/families/semantic-thinness/private/pattern-data-c.js +9 -0
- package/dist/families/semantic-thinness/private/pattern-data-c.js.map +1 -0
- package/dist/families/semantic-thinness/private/pattern-data-d.js +17 -0
- package/dist/families/semantic-thinness/private/pattern-data-d.js.map +1 -0
- package/dist/families/semantic-thinness/private/pattern-data.js +11 -0
- package/dist/families/semantic-thinness/private/pattern-data.js.map +1 -0
- package/dist/families/semantic-thinness/private/pattern-matcher.js +172 -0
- package/dist/families/semantic-thinness/private/pattern-matcher.js.map +1 -0
- package/dist/families/semantic-thinness/semantic-thinness.js +25 -0
- package/dist/families/semantic-thinness/semantic-thinness.js.map +1 -0
- package/dist/families/syntactic-patterns/authority/authority-padding.js +81 -0
- package/dist/families/syntactic-patterns/authority/authority-padding.js.map +1 -0
- package/dist/families/syntactic-patterns/closers/affirmation-closers.js +48 -0
- package/dist/families/syntactic-patterns/closers/affirmation-closers.js.map +1 -0
- package/dist/families/syntactic-patterns/closers/boilerplate-conclusion.js +131 -0
- package/dist/families/syntactic-patterns/closers/boilerplate-conclusion.js.map +1 -0
- package/dist/families/syntactic-patterns/closers/false-question.js +30 -0
- package/dist/families/syntactic-patterns/closers/false-question.js.map +1 -0
- package/dist/families/syntactic-patterns/closers/summative-closer.js +33 -0
- package/dist/families/syntactic-patterns/closers/summative-closer.js.map +1 -0
- package/dist/families/syntactic-patterns/contrast/blame-reframe.js +59 -0
- package/dist/families/syntactic-patterns/contrast/blame-reframe.js.map +1 -0
- package/dist/families/syntactic-patterns/contrast/contrastive-aphorism.js +203 -0
- package/dist/families/syntactic-patterns/contrast/contrastive-aphorism.js.map +1 -0
- package/dist/families/syntactic-patterns/contrast/negation-reframe.js +20 -0
- package/dist/families/syntactic-patterns/contrast/negation-reframe.js.map +1 -0
- package/dist/families/syntactic-patterns/contrast/private/negation-reframe-matcher.js +218 -0
- package/dist/families/syntactic-patterns/contrast/private/negation-reframe-matcher.js.map +1 -0
- package/dist/families/syntactic-patterns/contrast/private/negation-reframe-parts.js +136 -0
- package/dist/families/syntactic-patterns/contrast/private/negation-reframe-parts.js.map +1 -0
- package/dist/families/syntactic-patterns/generalization/softening-language.js +143 -0
- package/dist/families/syntactic-patterns/generalization/softening-language.js.map +1 -0
- package/dist/families/syntactic-patterns/generalization/universalizing-claims.js +137 -0
- package/dist/families/syntactic-patterns/generalization/universalizing-claims.js.map +1 -0
- package/dist/families/syntactic-patterns/lead-ins/boilerplate-framing.js +104 -0
- package/dist/families/syntactic-patterns/lead-ins/boilerplate-framing.js.map +1 -0
- package/dist/families/syntactic-patterns/lead-ins/generic-signposting.js +230 -0
- package/dist/families/syntactic-patterns/lead-ins/generic-signposting.js.map +1 -0
- package/dist/families/syntactic-patterns/lead-ins/lesson-framing.js +76 -0
- package/dist/families/syntactic-patterns/lead-ins/lesson-framing.js.map +1 -0
- package/dist/families/syntactic-patterns/lead-ins/llm-openers.js +24 -0
- package/dist/families/syntactic-patterns/lead-ins/llm-openers.js.map +1 -0
- package/dist/families/syntactic-patterns/lead-ins/observer-guidance.js +95 -0
- package/dist/families/syntactic-patterns/lead-ins/observer-guidance.js.map +1 -0
- package/dist/families/syntactic-patterns/llm-artifacts/response-wrapper.js +106 -0
- package/dist/families/syntactic-patterns/llm-artifacts/response-wrapper.js.map +1 -0
- package/dist/families/syntactic-patterns/repetition/demonstrative-emphasis.js +251 -0
- package/dist/families/syntactic-patterns/repetition/demonstrative-emphasis.js.map +1 -0
- package/dist/families/syntactic-patterns/repetition/empty-emphasis.js +108 -0
- package/dist/families/syntactic-patterns/repetition/empty-emphasis.js.map +1 -0
- package/dist/families/syntactic-patterns/repetition/fragment-stacking.js +306 -0
- package/dist/families/syntactic-patterns/repetition/fragment-stacking.js.map +1 -0
- package/dist/families/syntactic-patterns/repetition/triple-repeat.js +149 -0
- package/dist/families/syntactic-patterns/repetition/triple-repeat.js.map +1 -0
- package/dist/families/term-policy/recommended-terms.js +87 -0
- package/dist/families/term-policy/recommended-terms.js.map +1 -0
- package/dist/families/term-policy/required-terms.js +32 -0
- package/dist/families/term-policy/required-terms.js.map +1 -0
- package/dist/families/words/data/prohibited-words.json +12 -0
- package/dist/families/words/data/simplicity-pairs.json +7 -0
- package/dist/families/words/hedge-stacking.js +43 -0
- package/dist/families/words/hedge-stacking.js.map +1 -0
- package/dist/families/words/llm-vocabulary.js +33 -0
- package/dist/families/words/llm-vocabulary.js.map +1 -0
- package/dist/families/words/prohibited-words.js +17 -0
- package/dist/families/words/prohibited-words.js.map +1 -0
- package/dist/families/words/simplicity.js +27 -0
- package/dist/families/words/simplicity.js.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/presets/everything.js +52 -0
- package/dist/presets/everything.js.map +1 -0
- package/dist/registries/metrics.js +15 -0
- package/dist/registries/metrics.js.map +1 -0
- package/dist/registries/orthography.js +15 -0
- package/dist/registries/orthography.js.map +1 -0
- package/dist/registries/phrases.js +19 -0
- package/dist/registries/phrases.js.map +1 -0
- package/dist/registries/semantic-thinness.js +5 -0
- package/dist/registries/semantic-thinness.js.map +1 -0
- package/dist/registries/syntactic-patterns/authority.js +5 -0
- package/dist/registries/syntactic-patterns/authority.js.map +1 -0
- package/dist/registries/syntactic-patterns/closers.js +11 -0
- package/dist/registries/syntactic-patterns/closers.js.map +1 -0
- package/dist/registries/syntactic-patterns/contrast.js +9 -0
- package/dist/registries/syntactic-patterns/contrast.js.map +1 -0
- package/dist/registries/syntactic-patterns/generalization.js +7 -0
- package/dist/registries/syntactic-patterns/generalization.js.map +1 -0
- package/dist/registries/syntactic-patterns/lead-ins.js +13 -0
- package/dist/registries/syntactic-patterns/lead-ins.js.map +1 -0
- package/dist/registries/syntactic-patterns/llm-artifacts.js +5 -0
- package/dist/registries/syntactic-patterns/llm-artifacts.js.map +1 -0
- package/dist/registries/syntactic-patterns/repetition.js +11 -0
- package/dist/registries/syntactic-patterns/repetition.js.map +1 -0
- package/dist/registries/syntactic-patterns.js +17 -0
- package/dist/registries/syntactic-patterns.js.map +1 -0
- package/dist/registries/term-policy.js +7 -0
- package/dist/registries/term-policy.js.map +1 -0
- package/dist/registries/words.js +11 -0
- package/dist/registries/words.js.map +1 -0
- package/dist/shared/matchers/phrases.js +71 -0
- package/dist/shared/matchers/phrases.js.map +1 -0
- package/dist/shared/matchers/prose-patterns.js +104 -0
- package/dist/shared/matchers/prose-patterns.js.map +1 -0
- package/dist/shared/text/document.js +18 -0
- package/dist/shared/text/document.js.map +1 -0
- package/dist/shared/text/normalize.js +30 -0
- package/dist/shared/text/normalize.js.map +1 -0
- package/dist/shared/text/quotes.js +20 -0
- package/dist/shared/text/quotes.js.map +1 -0
- package/dist/shared/text/sections.js +119 -0
- package/dist/shared/text/sections.js.map +1 -0
- package/dist/shared/text/sentences.js +79 -0
- package/dist/shared/text/sentences.js.map +1 -0
- package/dist/shared/text/tokens.js +18 -0
- package/dist/shared/text/tokens.js.map +1 -0
- package/dist/shared/text/traverse.js +10 -0
- package/dist/shared/text/traverse.js.map +1 -0
- package/dist/shared/text/whitespace.js +25 -0
- package/dist/shared/text/whitespace.js.map +1 -0
- package/package.json +115 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { cleanSentence } from "../../../shared/matchers/prose-patterns.js";
|
|
2
|
+
import { wordTokens } from "../../../shared/text/tokens.js";
|
|
3
|
+
const CONTAINS_MAX_TOKENS = 80;
|
|
4
|
+
const FULL_MAX_TOKENS = 12;
|
|
5
|
+
const REJECT_TOKENS = new Set([
|
|
6
|
+
"because",
|
|
7
|
+
"therefore",
|
|
8
|
+
"unless",
|
|
9
|
+
"when",
|
|
10
|
+
"whenever",
|
|
11
|
+
"whereas",
|
|
12
|
+
"which",
|
|
13
|
+
"while"
|
|
14
|
+
]);
|
|
15
|
+
function normalizedTokens(text) {
|
|
16
|
+
return wordTokens(text).map((token) => token.normalized);
|
|
17
|
+
}
|
|
18
|
+
function flushLiteral(parts, literal) {
|
|
19
|
+
const tokens = normalizedTokens(literal);
|
|
20
|
+
if (tokens.length > 0) {
|
|
21
|
+
parts.push({ kind: "literal", tokens });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function readSlotName(template, start) {
|
|
25
|
+
let name = "";
|
|
26
|
+
let index = start + 1;
|
|
27
|
+
while (index < template.length) {
|
|
28
|
+
const character = template[index];
|
|
29
|
+
if (character === "}") {
|
|
30
|
+
return [name, index + 1];
|
|
31
|
+
}
|
|
32
|
+
name += character ?? "";
|
|
33
|
+
index += 1;
|
|
34
|
+
}
|
|
35
|
+
return [name, index];
|
|
36
|
+
}
|
|
37
|
+
function compileTemplate(template) {
|
|
38
|
+
const parts = [];
|
|
39
|
+
let literal = "";
|
|
40
|
+
let index = 0;
|
|
41
|
+
while (index < template.length) {
|
|
42
|
+
const character = template[index];
|
|
43
|
+
if (character === "{") {
|
|
44
|
+
flushLiteral(parts, literal);
|
|
45
|
+
literal = "";
|
|
46
|
+
const [name, nextIndex] = readSlotName(template, index);
|
|
47
|
+
parts.push({ kind: "slot", name });
|
|
48
|
+
index = nextIndex;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
literal += character ?? "";
|
|
52
|
+
index += 1;
|
|
53
|
+
}
|
|
54
|
+
flushLiteral(parts, literal);
|
|
55
|
+
return { parts, signal: template };
|
|
56
|
+
}
|
|
57
|
+
function compileSlotValues(slots) {
|
|
58
|
+
const compiled = {};
|
|
59
|
+
for (const [name, values] of Object.entries(slots)) {
|
|
60
|
+
compiled[name] = values.map((value) => normalizedTokens(value));
|
|
61
|
+
}
|
|
62
|
+
return compiled;
|
|
63
|
+
}
|
|
64
|
+
export function compileSemanticThinnessPatterns(patterns) {
|
|
65
|
+
const matchModeFor = (pattern) => pattern.matchMode === "contains" ? "contains" : "full";
|
|
66
|
+
const defaultMaxTokensFor = (pattern) => matchModeFor(pattern) === "contains"
|
|
67
|
+
? CONTAINS_MAX_TOKENS
|
|
68
|
+
: FULL_MAX_TOKENS;
|
|
69
|
+
return patterns.map((pattern) => ({
|
|
70
|
+
class: pattern.class,
|
|
71
|
+
id: pattern.id,
|
|
72
|
+
matchMode: matchModeFor(pattern),
|
|
73
|
+
maxTokens: pattern.maxTokens ?? defaultMaxTokensFor(pattern),
|
|
74
|
+
purpose: pattern.purpose,
|
|
75
|
+
slotValues: compileSlotValues(pattern.slots),
|
|
76
|
+
templates: pattern.templates.map((template) => compileTemplate(template))
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
function hasDigit(text) {
|
|
80
|
+
for (const character of text) {
|
|
81
|
+
if (character >= "0" && character <= "9") {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
function shouldRejectCommon(text, tokens) {
|
|
88
|
+
return tokens.length === 0 || hasDigit(text);
|
|
89
|
+
}
|
|
90
|
+
function shouldRejectForPattern(pattern, tokens) {
|
|
91
|
+
if (tokens.length > pattern.maxTokens) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
return (pattern.matchMode === "full" &&
|
|
95
|
+
tokens.some((token) => REJECT_TOKENS.has(token.normalized)));
|
|
96
|
+
}
|
|
97
|
+
function tokensMatchAt(source, expected, start) {
|
|
98
|
+
if (start + expected.length > source.length) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
for (let index = 0; index < expected.length; index += 1) {
|
|
102
|
+
if (source[start + index]?.normalized !== expected[index]) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
function matchPart(source, pattern, part, tokenIndex) {
|
|
109
|
+
if (part.kind === "literal") {
|
|
110
|
+
return tokensMatchAt(source, part.tokens, tokenIndex)
|
|
111
|
+
? [tokenIndex + part.tokens.length]
|
|
112
|
+
: [];
|
|
113
|
+
}
|
|
114
|
+
return (pattern.slotValues[part.name] ?? [])
|
|
115
|
+
.filter((tokens) => tokensMatchAt(source, tokens, tokenIndex))
|
|
116
|
+
.map((tokens) => tokenIndex + tokens.length);
|
|
117
|
+
}
|
|
118
|
+
function templateMatches(source, pattern, template, start) {
|
|
119
|
+
let positions = [start];
|
|
120
|
+
for (const part of template.parts) {
|
|
121
|
+
positions = positions.flatMap((position) => matchPart(source, pattern, part, position));
|
|
122
|
+
if (positions.length === 0) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (pattern.matchMode === "contains") {
|
|
127
|
+
return positions.length > 0;
|
|
128
|
+
}
|
|
129
|
+
return positions.includes(source.length);
|
|
130
|
+
}
|
|
131
|
+
function templateMatchesPattern(source, pattern, template) {
|
|
132
|
+
if (pattern.matchMode === "full") {
|
|
133
|
+
return templateMatches(source, pattern, template, 0);
|
|
134
|
+
}
|
|
135
|
+
for (let start = 0; start < source.length; start += 1) {
|
|
136
|
+
if (templateMatches(source, pattern, template, start)) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
function matchCompiledPattern(tokens, pattern) {
|
|
143
|
+
if (shouldRejectForPattern(pattern, tokens)) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
for (const template of pattern.templates) {
|
|
147
|
+
if (templateMatchesPattern(tokens, pattern, template)) {
|
|
148
|
+
return {
|
|
149
|
+
patternClass: pattern.class,
|
|
150
|
+
patternId: pattern.id,
|
|
151
|
+
purpose: pattern.purpose,
|
|
152
|
+
signal: template.signal
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
export function findSemanticThinnessMatch(text, patterns) {
|
|
159
|
+
const cleaned = cleanSentence(text, ["and ", "but ", "so "]);
|
|
160
|
+
const tokens = wordTokens(cleaned);
|
|
161
|
+
if (shouldRejectCommon(cleaned, tokens)) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
for (const pattern of patterns) {
|
|
165
|
+
const match = matchCompiledPattern(tokens, pattern);
|
|
166
|
+
if (match !== undefined) {
|
|
167
|
+
return match;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=pattern-matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-matcher.js","sourceRoot":"","sources":["../../../../src/families/semantic-thinness/private/pattern-matcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { allParagraphSentences } from "../../shared/text/sections.js";
|
|
2
|
+
import { semanticThinnessPatterns } from "./private/pattern-data.js";
|
|
3
|
+
import { compileSemanticThinnessPatterns, findSemanticThinnessMatch } from "./private/pattern-matcher.js";
|
|
4
|
+
const COMPILED_PATTERNS = compileSemanticThinnessPatterns(semanticThinnessPatterns);
|
|
5
|
+
const rule = (context) => {
|
|
6
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
7
|
+
return {
|
|
8
|
+
[Syntax.Document](node) {
|
|
9
|
+
for (const item of allParagraphSentences(node)) {
|
|
10
|
+
const match = findSemanticThinnessMatch(item.sentence.text, COMPILED_PATTERNS);
|
|
11
|
+
if (match === undefined) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
report(item.paragraph, new RuleError(`Semantic thinness (${match.patternId}): ${match.purpose} Matched template: ${match.signal}`, {
|
|
15
|
+
padding: locator.range([
|
|
16
|
+
item.source.originalStartFor(item.sentence.start),
|
|
17
|
+
item.source.originalEndFor(item.sentence.end)
|
|
18
|
+
])
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export default rule;
|
|
25
|
+
//# sourceMappingURL=semantic-thinness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-thinness.js","sourceRoot":"","sources":["../../../src/families/semantic-thinness/semantic-thinness.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EACL,+BAA+B,EAC/B,yBAAyB,EAC1B,MAAM,8BAA8B,CAAC;AAEtC,MAAM,iBAAiB,GAAG,+BAA+B,CACvD,wBAAwB,CACzB,CAAC;AAEF,MAAM,IAAI,GAAuB,CAAC,OAAO,EAAE,EAAE;IAC3C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAEvD,OAAO;QACL,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAqB;YACrC,KAAK,MAAM,IAAI,IAAI,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/C,MAAM,KAAK,GAAG,yBAAyB,CACrC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAClB,iBAAiB,CAClB,CAAC;gBACF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,SAAS;gBACX,CAAC;gBAED,MAAM,CACJ,IAAI,CAAC,SAAS,EACd,IAAI,SAAS,CACX,sBAAsB,KAAK,CAAC,SAAS,MAAM,KAAK,CAAC,OAAO,sBAAsB,KAAK,CAAC,MAAM,EAAE,EAC5F;oBACE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC;wBACrB,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;wBACjD,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;qBAC9C,CAAC;iBACH,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { cleanSentence } from "../../../shared/matchers/prose-patterns.js";
|
|
2
|
+
import { allParagraphSentences } from "../../../shared/text/sections.js";
|
|
3
|
+
const PREFIXES = ["however, ", "but ", "and ", "so "];
|
|
4
|
+
const EVIDENCE_SUBJECTS = [
|
|
5
|
+
"the evidence",
|
|
6
|
+
"the strongest evidence",
|
|
7
|
+
"the recent evidence",
|
|
8
|
+
"the broader evidence"
|
|
9
|
+
];
|
|
10
|
+
const RESEARCH_SUBJECTS = [
|
|
11
|
+
"the research",
|
|
12
|
+
"what the research",
|
|
13
|
+
"the broader research",
|
|
14
|
+
"the recent research",
|
|
15
|
+
"the science",
|
|
16
|
+
"the data",
|
|
17
|
+
"studies"
|
|
18
|
+
];
|
|
19
|
+
const RESEARCHER_SUBJECTS = ["researchers", "scientists"];
|
|
20
|
+
const EVIDENCE_PREDICATES = ["is strongest", "is not subtle", "points"];
|
|
21
|
+
const RESEARCH_PREDICATES = [
|
|
22
|
+
"backs",
|
|
23
|
+
"does show is",
|
|
24
|
+
"is clear",
|
|
25
|
+
"is not mysterious",
|
|
26
|
+
"points",
|
|
27
|
+
"shows",
|
|
28
|
+
"suggests"
|
|
29
|
+
];
|
|
30
|
+
const RESEARCHER_PREDICATES = ["keep finding", "keep showing"];
|
|
31
|
+
const AUTHORITY_ADVERBS = ["clearly", "consistently", "strongly"];
|
|
32
|
+
const PRESTIGE_SUFFIXES = [
|
|
33
|
+
"'s work is famous for a reason",
|
|
34
|
+
"\u2019s work is famous for a reason"
|
|
35
|
+
];
|
|
36
|
+
function matchesSubjectPredicate(text, subjects, predicates) {
|
|
37
|
+
return subjects.some((subject) => predicates.some((predicate) => text.startsWith(`${subject} ${predicate}`)));
|
|
38
|
+
}
|
|
39
|
+
function matchesAdverbialSubjectPredicate(text, subjects, predicates) {
|
|
40
|
+
return subjects.some((subject) => AUTHORITY_ADVERBS.some((adverb) => predicates.some((predicate) => text.startsWith(`${subject} ${adverb} ${predicate}`))));
|
|
41
|
+
}
|
|
42
|
+
function matchAuthorityPadding(sentence) {
|
|
43
|
+
const stripped = cleanSentence(sentence, PREFIXES);
|
|
44
|
+
if (PRESTIGE_SUFFIXES.some((suffix) => stripped.includes(suffix))) {
|
|
45
|
+
return { kind: "prestige-frame", signal: "work is famous for a reason" };
|
|
46
|
+
}
|
|
47
|
+
if (matchesSubjectPredicate(stripped, EVIDENCE_SUBJECTS, EVIDENCE_PREDICATES) ||
|
|
48
|
+
matchesAdverbialSubjectPredicate(stripped, EVIDENCE_SUBJECTS, EVIDENCE_PREDICATES) ||
|
|
49
|
+
stripped.startsWith("the strongest recent evidence points")) {
|
|
50
|
+
return { kind: "evidence-frame", signal: "the evidence" };
|
|
51
|
+
}
|
|
52
|
+
if (matchesSubjectPredicate(stripped, RESEARCH_SUBJECTS, RESEARCH_PREDICATES) ||
|
|
53
|
+
matchesAdverbialSubjectPredicate(stripped, RESEARCH_SUBJECTS, RESEARCH_PREDICATES) ||
|
|
54
|
+
stripped.startsWith("the broader research backs") ||
|
|
55
|
+
matchesSubjectPredicate(stripped, RESEARCHER_SUBJECTS, RESEARCHER_PREDICATES) ||
|
|
56
|
+
matchesAdverbialSubjectPredicate(stripped, RESEARCHER_SUBJECTS, RESEARCHER_PREDICATES)) {
|
|
57
|
+
return { kind: "research-frame", signal: "the research" };
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const rule = (context) => {
|
|
62
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
63
|
+
return {
|
|
64
|
+
[Syntax.Document](node) {
|
|
65
|
+
for (const item of allParagraphSentences(node)) {
|
|
66
|
+
const matched = matchAuthorityPadding(item.sentence.text);
|
|
67
|
+
if (matched === undefined) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
report(item.paragraph, new RuleError(`Authority padding found: ${matched.signal}. Cite the actual evidence or remove the frame.`, {
|
|
71
|
+
padding: locator.range([
|
|
72
|
+
item.source.originalStartFor(item.sentence.start),
|
|
73
|
+
item.source.originalEndFor(item.sentence.end)
|
|
74
|
+
])
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
export default rule;
|
|
81
|
+
//# sourceMappingURL=authority-padding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authority-padding.js","sourceRoot":"","sources":["../../../../src/families/syntactic-patterns/authority/authority-padding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { allParagraphSentences, sectionLastSentences } from "../../../shared/text/sections.js";
|
|
2
|
+
import { wordTokens } from "../../../shared/text/tokens.js";
|
|
3
|
+
const CLOSERS = ["and that's the key.", "that's what matters."];
|
|
4
|
+
function isFormulaLine(text) {
|
|
5
|
+
const lower = text.toLocaleLowerCase("en");
|
|
6
|
+
return (wordTokens(text).length <= 6 &&
|
|
7
|
+
(lower.startsWith("that's the ") || lower.startsWith("that is the ")));
|
|
8
|
+
}
|
|
9
|
+
function evidenceKey(item) {
|
|
10
|
+
return `${item.paragraph.range[0]}:${item.sentence.start}:${item.sentence.end}`;
|
|
11
|
+
}
|
|
12
|
+
const rule = (context) => {
|
|
13
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
14
|
+
return {
|
|
15
|
+
[Syntax.Document](node) {
|
|
16
|
+
const reported = new Set();
|
|
17
|
+
for (const item of sectionLastSentences(node)) {
|
|
18
|
+
const lower = item.sentence.text.toLocaleLowerCase("en");
|
|
19
|
+
const closer = CLOSERS.find((phrase) => lower.endsWith(phrase));
|
|
20
|
+
if (closer === undefined) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
reported.add(evidenceKey(item));
|
|
24
|
+
report(item.paragraph, new RuleError(`Affirmation closer found: "${closer}". Replace the empty affirmation with the actual conclusion.`, {
|
|
25
|
+
padding: locator.range([
|
|
26
|
+
item.source.originalStartFor(item.sentence.start),
|
|
27
|
+
item.source.originalEndFor(item.sentence.end)
|
|
28
|
+
])
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
for (const item of allParagraphSentences(node)) {
|
|
32
|
+
const key = evidenceKey(item);
|
|
33
|
+
if (reported.has(key) || !isFormulaLine(item.sentence.text)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
reported.add(key);
|
|
37
|
+
report(item.paragraph, new RuleError(`Formula affirmation found: "${item.sentence.text}". Replace the empty formula line with substance.`, {
|
|
38
|
+
padding: locator.range([
|
|
39
|
+
item.source.originalStartFor(item.sentence.start),
|
|
40
|
+
item.source.originalEndFor(item.sentence.end)
|
|
41
|
+
])
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export default rule;
|
|
48
|
+
//# sourceMappingURL=affirmation-closers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"affirmation-closers.js","sourceRoot":"","sources":["../../../../src/families/syntactic-patterns/closers/affirmation-closers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { cleanSentence, containsAny, tokens } from "../../../shared/matchers/prose-patterns.js";
|
|
2
|
+
import { allParagraphSentences } from "../../../shared/text/sections.js";
|
|
3
|
+
const PREFIXES = [
|
|
4
|
+
"ultimately, ",
|
|
5
|
+
"overall, ",
|
|
6
|
+
"in the end, ",
|
|
7
|
+
"in short, ",
|
|
8
|
+
"and ",
|
|
9
|
+
"but "
|
|
10
|
+
];
|
|
11
|
+
const IMPORTANCE_CUES = ["most important", "single most important", "deepest"];
|
|
12
|
+
const SUMMARY_NOUNS = ["insight", "reason", "idea", "step"];
|
|
13
|
+
const AUTHORITY_CLOSE_PATTERNS = [
|
|
14
|
+
"the research is clear",
|
|
15
|
+
"science is clear",
|
|
16
|
+
"decades of research",
|
|
17
|
+
"research leaves no doubt"
|
|
18
|
+
];
|
|
19
|
+
const ACCEPTANCE_CLOSE_PATTERNS = [
|
|
20
|
+
"not something you have to accept as normal",
|
|
21
|
+
"not something you need to accept as normal",
|
|
22
|
+
"is not a luxury"
|
|
23
|
+
];
|
|
24
|
+
const RESPONSE_CLOSE_PATTERNS = ["the practical response is plain"];
|
|
25
|
+
const BASIC_RULE_SIMPLE_PATTERN = "the basic rule is simple";
|
|
26
|
+
const COMPRESSION_CLOSE_PATTERNS = [
|
|
27
|
+
"the whole trick",
|
|
28
|
+
"the core fact",
|
|
29
|
+
"the rest is detail"
|
|
30
|
+
];
|
|
31
|
+
const FORMULA_SUBJECTS = ["that", "this", "it"];
|
|
32
|
+
const FORMULA_NOUNS = [
|
|
33
|
+
"answer",
|
|
34
|
+
"fact",
|
|
35
|
+
"frame",
|
|
36
|
+
"game",
|
|
37
|
+
"idea",
|
|
38
|
+
"lesson",
|
|
39
|
+
"move",
|
|
40
|
+
"point",
|
|
41
|
+
"rule",
|
|
42
|
+
"test",
|
|
43
|
+
"thing",
|
|
44
|
+
"trick"
|
|
45
|
+
];
|
|
46
|
+
function matchInsightClose(text) {
|
|
47
|
+
if (IMPORTANCE_CUES.some((cue) => text.includes(cue)) &&
|
|
48
|
+
SUMMARY_NOUNS.some((noun) => text.includes(noun))) {
|
|
49
|
+
return "importance+summary-noun";
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
function matchResponseClose(text) {
|
|
54
|
+
const response = containsAny(text, RESPONSE_CLOSE_PATTERNS);
|
|
55
|
+
if (response !== undefined) {
|
|
56
|
+
return response;
|
|
57
|
+
}
|
|
58
|
+
const tail = text.slice(BASIC_RULE_SIMPLE_PATTERN.length).trim();
|
|
59
|
+
return text.startsWith(BASIC_RULE_SIMPLE_PATTERN) &&
|
|
60
|
+
(tail.length === 0 || tail === ".")
|
|
61
|
+
? BASIC_RULE_SIMPLE_PATTERN
|
|
62
|
+
: undefined;
|
|
63
|
+
}
|
|
64
|
+
function matchFormulaClose(text) {
|
|
65
|
+
const words = tokens(text);
|
|
66
|
+
if (words.length > 8) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const [first, second, third, fourth] = words;
|
|
70
|
+
if (first !== undefined &&
|
|
71
|
+
FORMULA_SUBJECTS.includes(first) &&
|
|
72
|
+
second === "is" &&
|
|
73
|
+
third === "the" &&
|
|
74
|
+
fourth !== undefined &&
|
|
75
|
+
FORMULA_NOUNS.includes(fourth)) {
|
|
76
|
+
return `${first}-is-the-${fourth}`;
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
function matchConclusion(sentence, isTail) {
|
|
81
|
+
const stripped = cleanSentence(sentence, PREFIXES);
|
|
82
|
+
if (isTail) {
|
|
83
|
+
const formula = matchFormulaClose(stripped);
|
|
84
|
+
if (formula !== undefined) {
|
|
85
|
+
return { kind: "formula-close", signal: formula };
|
|
86
|
+
}
|
|
87
|
+
const insight = matchInsightClose(stripped);
|
|
88
|
+
if (insight !== undefined) {
|
|
89
|
+
return { kind: "insight-close", signal: insight };
|
|
90
|
+
}
|
|
91
|
+
const authority = containsAny(stripped, AUTHORITY_CLOSE_PATTERNS);
|
|
92
|
+
if (authority !== undefined) {
|
|
93
|
+
return { kind: "authority-close", signal: authority };
|
|
94
|
+
}
|
|
95
|
+
const acceptance = containsAny(stripped, ACCEPTANCE_CLOSE_PATTERNS);
|
|
96
|
+
if (acceptance !== undefined) {
|
|
97
|
+
return { kind: "acceptance-close", signal: acceptance };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const response = matchResponseClose(stripped);
|
|
101
|
+
if (response !== undefined) {
|
|
102
|
+
return { kind: "response-close", signal: response };
|
|
103
|
+
}
|
|
104
|
+
const compression = containsAny(stripped, COMPRESSION_CLOSE_PATTERNS);
|
|
105
|
+
return compression === undefined
|
|
106
|
+
? undefined
|
|
107
|
+
: { kind: "compression-close", signal: compression };
|
|
108
|
+
}
|
|
109
|
+
const rule = (context) => {
|
|
110
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
111
|
+
return {
|
|
112
|
+
[Syntax.Document](node) {
|
|
113
|
+
const sentences = allParagraphSentences(node);
|
|
114
|
+
const tailStart = Math.max(sentences.length - 3, 0);
|
|
115
|
+
sentences.forEach((item, index) => {
|
|
116
|
+
const matched = matchConclusion(item.sentence.text, index >= tailStart);
|
|
117
|
+
if (matched === undefined) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
report(item.paragraph, new RuleError(`Boilerplate conclusion found: ${matched.signal}. Replace the closer with a specific ending.`, {
|
|
121
|
+
padding: locator.range([
|
|
122
|
+
item.source.originalStartFor(item.sentence.start),
|
|
123
|
+
item.source.originalEndFor(item.sentence.end)
|
|
124
|
+
])
|
|
125
|
+
}));
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
export default rule;
|
|
131
|
+
//# sourceMappingURL=boilerplate-conclusion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boilerplate-conclusion.js","sourceRoot":"","sources":["../../../../src/families/syntactic-patterns/closers/boilerplate-conclusion.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { sectionLastSentences } from "../../../shared/text/sections.js";
|
|
2
|
+
const FALSE_QUESTION_PATTERNS = [
|
|
3
|
+
"isn't that what we all",
|
|
4
|
+
"isn't that the point",
|
|
5
|
+
"isn't that the goal",
|
|
6
|
+
"isn't that what matters",
|
|
7
|
+
"isn't that why"
|
|
8
|
+
];
|
|
9
|
+
const rule = (context) => {
|
|
10
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
11
|
+
return {
|
|
12
|
+
[Syntax.Document](node) {
|
|
13
|
+
for (const item of sectionLastSentences(node)) {
|
|
14
|
+
const lower = item.sentence.text.toLocaleLowerCase("en");
|
|
15
|
+
const pattern = FALSE_QUESTION_PATTERNS.find((phrase) => lower.includes(phrase));
|
|
16
|
+
if (pattern === undefined || !item.sentence.text.endsWith("?")) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
report(item.paragraph, new RuleError(`False question found: "${pattern}". Make the claim directly.`, {
|
|
20
|
+
padding: locator.range([
|
|
21
|
+
item.source.originalStartFor(item.sentence.start),
|
|
22
|
+
item.source.originalEndFor(item.sentence.end)
|
|
23
|
+
])
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export default rule;
|
|
30
|
+
//# sourceMappingURL=false-question.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"false-question.js","sourceRoot":"","sources":["../../../../src/families/syntactic-patterns/closers/false-question.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAExE,MAAM,uBAAuB,GAAG;IAC9B,wBAAwB;IACxB,sBAAsB;IACtB,qBAAqB;IACrB,yBAAyB;IACzB,gBAAgB;CACjB,CAAC;AAEF,MAAM,IAAI,GAAuB,CAAC,OAAO,EAAE,EAAE;IAC3C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAEvD,OAAO;QACL,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAqB;YACrC,KAAK,MAAM,IAAI,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACzD,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CACtD,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CACvB,CAAC;gBAEF,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC/D,SAAS;gBACX,CAAC;gBAED,MAAM,CACJ,IAAI,CAAC,SAAS,EACd,IAAI,SAAS,CACX,0BAA0B,OAAO,6BAA6B,EAC9D;oBACE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC;wBACrB,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;wBACjD,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;qBAC9C,CAAC;iBACH,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { sectionLastSentences } from "../../../shared/text/sections.js";
|
|
2
|
+
const SUMMATIVE_PATTERNS = [
|
|
3
|
+
"and that's what makes",
|
|
4
|
+
"that's why this",
|
|
5
|
+
"that's why it works",
|
|
6
|
+
"that is why it works",
|
|
7
|
+
"that's why it matters",
|
|
8
|
+
"that is why it matters",
|
|
9
|
+
"that's why this matters",
|
|
10
|
+
"that is why this matters"
|
|
11
|
+
];
|
|
12
|
+
const rule = (context) => {
|
|
13
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
14
|
+
return {
|
|
15
|
+
[Syntax.Document](node) {
|
|
16
|
+
for (const item of sectionLastSentences(node)) {
|
|
17
|
+
const lower = item.sentence.text.toLocaleLowerCase("en");
|
|
18
|
+
const pattern = SUMMATIVE_PATTERNS.find((phrase) => lower.startsWith(phrase));
|
|
19
|
+
if (pattern === undefined) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
report(item.paragraph, new RuleError(`Summative closer found: "${pattern}". End with the concrete point instead.`, {
|
|
23
|
+
padding: locator.range([
|
|
24
|
+
item.source.originalStartFor(item.sentence.start),
|
|
25
|
+
item.source.originalEndFor(item.sentence.end)
|
|
26
|
+
])
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export default rule;
|
|
33
|
+
//# sourceMappingURL=summative-closer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summative-closer.js","sourceRoot":"","sources":["../../../../src/families/syntactic-patterns/closers/summative-closer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAExE,MAAM,kBAAkB,GAAG;IACzB,uBAAuB;IACvB,iBAAiB;IACjB,qBAAqB;IACrB,sBAAsB;IACtB,uBAAuB;IACvB,wBAAwB;IACxB,yBAAyB;IACzB,0BAA0B;CAC3B,CAAC;AAEF,MAAM,IAAI,GAAuB,CAAC,OAAO,EAAE,EAAE;IAC3C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAEvD,OAAO;QACL,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAqB;YACrC,KAAK,MAAM,IAAI,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACzD,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CACjD,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CACzB,CAAC;gBAEF,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;oBAC1B,SAAS;gBACX,CAAC;gBAED,MAAM,CACJ,IAAI,CAAC,SAAS,EACd,IAAI,SAAS,CACX,4BAA4B,OAAO,yCAAyC,EAC5E;oBACE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC;wBACrB,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;wBACjD,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;qBAC9C,CAAC;iBACH,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { cleanSentence } from "../../../shared/matchers/prose-patterns.js";
|
|
2
|
+
import { allParagraphSentences } from "../../../shared/text/sections.js";
|
|
3
|
+
const PREFIXES = ["and ", "but ", "so "];
|
|
4
|
+
const BLAME_NOUNS = ["malice", "shame", "guilt", "blame", "humiliation"];
|
|
5
|
+
const GROWTH_NOUNS = ["development", "skill-building", "learning", "practice"];
|
|
6
|
+
const CAUSAL_CUES = ["comes from ", "come from ", "stems from ", "stem from "];
|
|
7
|
+
function matchesSourceNotBlame(text) {
|
|
8
|
+
if (!BLAME_NOUNS.some((noun) => text.endsWith(`not ${noun}.`) || text.endsWith(`not ${noun}`))) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return CAUSAL_CUES.some((cue) => {
|
|
12
|
+
const cueIndex = text.indexOf(cue);
|
|
13
|
+
if (cueIndex < 0) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const prefix = text.slice(0, cueIndex);
|
|
17
|
+
const after = text.slice(cueIndex + cue.length);
|
|
18
|
+
const growthSegment = after.split(", not ").at(0) ?? "";
|
|
19
|
+
return (prefix.split(" ").filter((word) => word.length > 0).length <= 4 &&
|
|
20
|
+
GROWTH_NOUNS.some((noun) => growthSegment.includes(noun)));
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function matchesGrowthInsteadOfBlame(text) {
|
|
24
|
+
return (text.includes(" instead of ") &&
|
|
25
|
+
text.includes(" as ") &&
|
|
26
|
+
GROWTH_NOUNS.some((noun) => text.includes(`as ${noun}`)) &&
|
|
27
|
+
BLAME_NOUNS.some((noun) => text.includes(`instead of ${noun}`)));
|
|
28
|
+
}
|
|
29
|
+
function matchBlameReframe(sentence) {
|
|
30
|
+
const stripped = cleanSentence(sentence, PREFIXES);
|
|
31
|
+
if (matchesSourceNotBlame(stripped)) {
|
|
32
|
+
return "source-not-blame";
|
|
33
|
+
}
|
|
34
|
+
if (matchesGrowthInsteadOfBlame(stripped)) {
|
|
35
|
+
return "growth-instead-of-blame";
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const rule = (context) => {
|
|
40
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
41
|
+
return {
|
|
42
|
+
[Syntax.Document](node) {
|
|
43
|
+
for (const item of allParagraphSentences(node)) {
|
|
44
|
+
const matched = matchBlameReframe(item.sentence.text);
|
|
45
|
+
if (matched === undefined) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
report(item.paragraph, new RuleError(`Blame reframe found: ${matched}. Replace the moralized contrast with a concrete claim.`, {
|
|
49
|
+
padding: locator.range([
|
|
50
|
+
item.source.originalStartFor(item.sentence.start),
|
|
51
|
+
item.source.originalEndFor(item.sentence.end)
|
|
52
|
+
])
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export default rule;
|
|
59
|
+
//# sourceMappingURL=blame-reframe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blame-reframe.js","sourceRoot":"","sources":["../../../../src/families/syntactic-patterns/contrast/blame-reframe.ts"],"names":[],"mappings":"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"}
|