slopless 0.2.25 → 0.2.27
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
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](package.json)
|
|
8
8
|
|
|
9
|
-
[](/actions/workflows/ci.yml)
|
|
10
10
|
[](https://socket.dev/npm/package/slopless)
|
|
11
11
|
|
|
12
12
|
Give it to your writing agent and it stops handing you AI-slop prose. Slopless is a deterministic linter - a textlint preset and a zero-config CLI - that flags the LLM tells (hollow framing, fake contrasts, hedging, em-dash tics, vacuous closers, and many more) so the agent rewrites until the text reads human. No model calls, no API key.
|
|
@@ -33,7 +33,7 @@ to the teams that slow down to think.
|
|
|
33
33
|
[slopless/prohibited-phrases] the future belongs to
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
Full JSON output is the default. See the [Rules](https://github.com/
|
|
36
|
+
Full JSON output is the default. See the [Rules](https://github.com/berelevant-ai/slopless/wiki/Rules) page for the complete inventory.
|
|
37
37
|
|
|
38
38
|
## Intended Usage Loop
|
|
39
39
|
|
|
@@ -141,12 +141,12 @@ Something shifted in the room.
|
|
|
141
141
|
|
|
142
142
|
## More
|
|
143
143
|
|
|
144
|
-
- [Philosophy](https://github.com/
|
|
145
|
-
- [Comparison](https://github.com/
|
|
146
|
-
- [Rules](https://github.com/
|
|
147
|
-
- [Behavior](https://github.com/
|
|
148
|
-
- [Ignore rules](https://github.com/
|
|
149
|
-
- [Thanks](https://github.com/
|
|
144
|
+
- [Philosophy](https://github.com/berelevant-ai/slopless/wiki/Philosophy) - what slopless is for, design principles, why deterministic.
|
|
145
|
+
- [Comparison](https://github.com/berelevant-ai/slopless/wiki/Comparison) - slopless vs proselint, write-good, alex, vale, default textlint presets.
|
|
146
|
+
- [Rules](https://github.com/berelevant-ai/slopless/wiki/Rules) - full 50+ rule inventory across seven families.
|
|
147
|
+
- [Behavior](https://github.com/berelevant-ai/slopless/wiki/Behavior) - CLI flags, exit codes, JSON output shape, direct textlint integration.
|
|
148
|
+
- [Ignore rules](https://github.com/berelevant-ai/slopless/wiki/Ignore-Rules) - inline `textlint-disable` block syntax.
|
|
149
|
+
- [Thanks](https://github.com/berelevant-ai/slopless/wiki/Thanks) - direct rule sources, dependencies, and acknowledgments.
|
|
150
150
|
- [Roadmap](ROADMAP.md) - near-term direction and links to active plans.
|
|
151
151
|
- [Contributing](.github/CONTRIBUTING.md) - open a detailed issue first; PRs must pass the G3TS pre-commit gate.
|
|
152
152
|
|
|
@@ -166,4 +166,4 @@ This confirms the tarball you installed was built in the published source reposi
|
|
|
166
166
|
|
|
167
167
|
---
|
|
168
168
|
|
|
169
|
-
Developed by [
|
|
169
|
+
Developed by [berelevant.ai](https://berelevant.ai) to keep content specific, useful, and recognizably human.
|
|
@@ -159,7 +159,7 @@ function matchWhatFrame(words) {
|
|
|
159
159
|
function matchAbstractFrame(text) {
|
|
160
160
|
const words = tokens(text);
|
|
161
161
|
return (matchRelativeDiscourseFrame(text, words) ??
|
|
162
|
-
matchExpandedDiscourseFrame(words) ??
|
|
162
|
+
matchExpandedDiscourseFrame(text, words) ??
|
|
163
163
|
matchModifiedAbstractFrame(words) ??
|
|
164
164
|
matchDiscourseEvaluationFrame(words) ??
|
|
165
165
|
matchPointIsToFrame(words) ??
|
|
@@ -221,6 +221,7 @@ function matchSignposting(sentence) {
|
|
|
221
221
|
const generatedFormula = matchGeneratedFormula(stripped);
|
|
222
222
|
if (abstract !== undefined &&
|
|
223
223
|
(abstract === "what-matters-is" ||
|
|
224
|
+
abstract.startsWith("deictic-evaluative-") ||
|
|
224
225
|
abstract.startsWith("relative-") ||
|
|
225
226
|
!concreteImplementation)) {
|
|
226
227
|
return { kind: "abstract-evaluation-frame", signal: abstract };
|
|
@@ -5,6 +5,53 @@ const DISCOURSE_WORK_TAILS = [
|
|
|
5
5
|
["load", "bearing"]
|
|
6
6
|
];
|
|
7
7
|
const DETERMINERS = new Set(["a", "an", "the", "this", "that"]);
|
|
8
|
+
const DEICTIC_OPENERS = new Set(["here", "this", "that"]);
|
|
9
|
+
const DEICTIC_CONTRACTIONS = new Map([
|
|
10
|
+
["here's", "here"],
|
|
11
|
+
["this's", "this"],
|
|
12
|
+
["that's", "that"]
|
|
13
|
+
]);
|
|
14
|
+
const DEICTIC_EVALUATIVE_ADJECTIVES = new Set([
|
|
15
|
+
"best",
|
|
16
|
+
"better",
|
|
17
|
+
"biggest",
|
|
18
|
+
"central",
|
|
19
|
+
"core",
|
|
20
|
+
"crucial",
|
|
21
|
+
"funny",
|
|
22
|
+
"good",
|
|
23
|
+
"great",
|
|
24
|
+
"hard",
|
|
25
|
+
"important",
|
|
26
|
+
"interesting",
|
|
27
|
+
"key",
|
|
28
|
+
"main",
|
|
29
|
+
"neat",
|
|
30
|
+
"nice",
|
|
31
|
+
"odd",
|
|
32
|
+
"obvious",
|
|
33
|
+
"remarkable",
|
|
34
|
+
"strange",
|
|
35
|
+
"surprising",
|
|
36
|
+
"tricky",
|
|
37
|
+
"useful",
|
|
38
|
+
"weird",
|
|
39
|
+
"wild"
|
|
40
|
+
]);
|
|
41
|
+
const DEICTIC_DISCOURSE_NOUNS = new Set([
|
|
42
|
+
"angle",
|
|
43
|
+
"aspect",
|
|
44
|
+
"bit",
|
|
45
|
+
"catch",
|
|
46
|
+
"detail",
|
|
47
|
+
"element",
|
|
48
|
+
"idea",
|
|
49
|
+
"part",
|
|
50
|
+
"piece",
|
|
51
|
+
"point",
|
|
52
|
+
"thing",
|
|
53
|
+
"twist"
|
|
54
|
+
]);
|
|
8
55
|
const FRAME_ADJECTIVES = new Set([
|
|
9
56
|
"basic",
|
|
10
57
|
"best",
|
|
@@ -202,13 +249,45 @@ function matchEvaluativeFrame(words) {
|
|
|
202
249
|
? `the-${adjective}-${noun}-${verb}`
|
|
203
250
|
: undefined;
|
|
204
251
|
}
|
|
252
|
+
function matchDeicticEvaluativeFrame(text, words) {
|
|
253
|
+
const contractedOpener = DEICTIC_CONTRACTIONS.get(words[0] ?? "");
|
|
254
|
+
const opener = contractedOpener ?? words[0];
|
|
255
|
+
const determinerIndex = contractedOpener === undefined ? 2 : 1;
|
|
256
|
+
if (opener === undefined ||
|
|
257
|
+
!DEICTIC_OPENERS.has(opener) ||
|
|
258
|
+
(contractedOpener === undefined &&
|
|
259
|
+
!["is", "was"].includes(words[1] ?? "")) ||
|
|
260
|
+
!["a", "an", "the"].includes(words[determinerIndex] ?? "")) {
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
const adjective = words[determinerIndex + 1];
|
|
264
|
+
const noun = words[determinerIndex + 2];
|
|
265
|
+
const frame = adjective !== undefined && noun !== undefined
|
|
266
|
+
? words.slice(0, determinerIndex + 3).join(" ")
|
|
267
|
+
: undefined;
|
|
268
|
+
const boundary = frame === undefined ? undefined : text.at(frame.length);
|
|
269
|
+
return adjective !== undefined &&
|
|
270
|
+
noun !== undefined &&
|
|
271
|
+
(boundary === undefined ||
|
|
272
|
+
boundary === "." ||
|
|
273
|
+
boundary === "!" ||
|
|
274
|
+
boundary === "?" ||
|
|
275
|
+
boundary === ":" ||
|
|
276
|
+
boundary === ";" ||
|
|
277
|
+
boundary === ",") &&
|
|
278
|
+
DEICTIC_EVALUATIVE_ADJECTIVES.has(adjective) &&
|
|
279
|
+
DEICTIC_DISCOURSE_NOUNS.has(noun)
|
|
280
|
+
? `deictic-evaluative-${opener}-${adjective}-${noun}`
|
|
281
|
+
: undefined;
|
|
282
|
+
}
|
|
205
283
|
export function isAbstractAuditFrame(words) {
|
|
206
284
|
return words[0] === "the" && frameNounIndex(words) > 0
|
|
207
285
|
? words[frameNounIndex(words)] === "audit"
|
|
208
286
|
: false;
|
|
209
287
|
}
|
|
210
|
-
export function matchExpandedDiscourseFrame(words) {
|
|
211
|
-
return (
|
|
288
|
+
export function matchExpandedDiscourseFrame(text, words) {
|
|
289
|
+
return (matchDeicticEvaluativeFrame(text, words) ??
|
|
290
|
+
matchWorthAttentionFrame(words) ??
|
|
212
291
|
matchVagueFrameLocation(words) ??
|
|
213
292
|
matchEvaluativeFrame(words));
|
|
214
293
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slopless",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.27",
|
|
4
4
|
"description": "Deterministic textlint rules and CLI for catching prose slop in English Markdown.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"textlint",
|
|
@@ -19,18 +19,18 @@
|
|
|
19
19
|
"cli"
|
|
20
20
|
],
|
|
21
21
|
"license": "MIT",
|
|
22
|
-
"author": "
|
|
22
|
+
"author": "berelevant.ai (https://berelevant.ai)",
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public",
|
|
25
25
|
"provenance": true
|
|
26
26
|
},
|
|
27
27
|
"repository": {
|
|
28
28
|
"type": "git",
|
|
29
|
-
"url": "git+https://github.com/
|
|
29
|
+
"url": "git+https://github.com/berelevant-ai/slopless.git"
|
|
30
30
|
},
|
|
31
|
-
"homepage": "https://github.com/
|
|
31
|
+
"homepage": "https://github.com/berelevant-ai/slopless#readme",
|
|
32
32
|
"bugs": {
|
|
33
|
-
"url": "https://github.com/
|
|
33
|
+
"url": "https://github.com/berelevant-ai/slopless/issues"
|
|
34
34
|
},
|
|
35
35
|
"type": "module",
|
|
36
36
|
"main": "./dist/index.js",
|