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
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# slopless
|
|
2
|
+
|
|
3
|
+
Deterministic textlint rules for catching slop in prose.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -D textlint slopless
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configure
|
|
12
|
+
|
|
13
|
+
Create `.textlintrc.json`:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"rules": {
|
|
18
|
+
"preset-slopless": true
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Run
|
|
24
|
+
|
|
25
|
+
Add an npm script:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"scripts": {
|
|
30
|
+
"lint:prose": "textlint \"**/*.md\""
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Run it:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm run lint:prose
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## CI Output
|
|
42
|
+
|
|
43
|
+
Use standard textlint formatters:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx textlint "docs/**/*.md" --format stylish
|
|
47
|
+
npx textlint "docs/**/*.md" --format json
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## What It Checks
|
|
51
|
+
|
|
52
|
+
- stock AI-style phrasing
|
|
53
|
+
- empty or generic prose patterns
|
|
54
|
+
- rhetorical filler
|
|
55
|
+
- weak closers and lead-ins
|
|
56
|
+
- hedge stacking
|
|
57
|
+
- prohibited vocabulary
|
|
58
|
+
- readability and sentence metrics
|
|
59
|
+
- Markdown style signals
|
|
60
|
+
|
|
61
|
+
## Requirements
|
|
62
|
+
|
|
63
|
+
- Node.js 20 or newer
|
|
64
|
+
- textlint 15
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { documentMetrics } from "../../shared/text/document.js";
|
|
2
|
+
const MAX_WORDS = 24;
|
|
3
|
+
const rule = (context) => {
|
|
4
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
5
|
+
return {
|
|
6
|
+
[Syntax.Document](node) {
|
|
7
|
+
const metrics = documentMetrics(node);
|
|
8
|
+
if (metrics.sentenceCount === 0) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const average = Math.floor(metrics.wordCount / metrics.sentenceCount);
|
|
12
|
+
if (average <= MAX_WORDS) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
report(node, new RuleError(`Average sentence length is ${average} words. Keep it at ${MAX_WORDS} or fewer.`, {
|
|
16
|
+
padding: locator.at(0)
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export default rule;
|
|
22
|
+
//# sourceMappingURL=avg-sentence-length.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avg-sentence-length.js","sourceRoot":"","sources":["../../../src/families/metrics/avg-sentence-length.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,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,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,OAAO,CAAC,aAAa,KAAK,CAAC,EAAE,CAAC;gBAChC,OAAO;YACT,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;YACtE,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;gBACzB,OAAO;YACT,CAAC;YAED,MAAM,CACJ,IAAI,EACJ,IAAI,SAAS,CACX,8BAA8B,OAAO,sBAAsB,SAAS,YAAY,EAChF;gBACE,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;aACvB,CACF,CACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TextReadability } from "@lunarisapp/readability";
|
|
2
|
+
import { documentText } from "../../shared/text/document.js";
|
|
3
|
+
const MAX_SCORE = 12;
|
|
4
|
+
function rounded(score) {
|
|
5
|
+
return Math.round(score * 100) / 100;
|
|
6
|
+
}
|
|
7
|
+
const rule = (context) => {
|
|
8
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
9
|
+
const readability = new TextReadability({ lang: "en_US" });
|
|
10
|
+
return {
|
|
11
|
+
[Syntax.Document](node) {
|
|
12
|
+
const text = documentText(node);
|
|
13
|
+
if (text.length === 0) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const score = readability.colemanLiauIndex(text);
|
|
17
|
+
if (score <= MAX_SCORE) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
report(node, new RuleError(`Coleman-Liau is ${rounded(score)}. Keep it at ${MAX_SCORE} or lower.`, {
|
|
21
|
+
padding: locator.at(0)
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export default rule;
|
|
27
|
+
//# sourceMappingURL=coleman-liau.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coleman-liau.js","sourceRoot":"","sources":["../../../src/families/metrics/coleman-liau.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC;AAED,MAAM,IAAI,GAAuB,CAAC,OAAO,EAAE,EAAE;IAC3C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACvD,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAE3D,OAAO;QACL,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAqB;YACrC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,WAAW,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YACjD,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;gBACvB,OAAO;YACT,CAAC;YAED,MAAM,CACJ,IAAI,EACJ,IAAI,SAAS,CACX,mBAAmB,OAAO,CAAC,KAAK,CAAC,gBAAgB,SAAS,YAAY,EACtE;gBACE,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;aACvB,CACF,CACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TextReadability } from "@lunarisapp/readability";
|
|
2
|
+
import { documentText } from "../../shared/text/document.js";
|
|
3
|
+
const MIN_SCORE = 61;
|
|
4
|
+
function rounded(score) {
|
|
5
|
+
return Math.round(score * 100) / 100;
|
|
6
|
+
}
|
|
7
|
+
const rule = (context) => {
|
|
8
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
9
|
+
const readability = new TextReadability({ lang: "en_US" });
|
|
10
|
+
return {
|
|
11
|
+
[Syntax.Document](node) {
|
|
12
|
+
const text = documentText(node);
|
|
13
|
+
if (text.length === 0) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const score = readability.fleschReadingEase(text);
|
|
17
|
+
if (score >= MIN_SCORE) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
report(node, new RuleError(`Flesch Reading Ease is ${rounded(score)}. Keep it at ${MIN_SCORE} or higher.`, {
|
|
21
|
+
padding: locator.at(0)
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export default rule;
|
|
27
|
+
//# sourceMappingURL=flesch-kincaid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flesch-kincaid.js","sourceRoot":"","sources":["../../../src/families/metrics/flesch-kincaid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC;AAED,MAAM,IAAI,GAAuB,CAAC,OAAO,EAAE,EAAE;IAC3C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACvD,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAE3D,OAAO;QACL,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAqB;YACrC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;gBACvB,OAAO;YACT,CAAC;YAED,MAAM,CACJ,IAAI,EACJ,IAAI,SAAS,CACX,0BAA0B,OAAO,CAAC,KAAK,CAAC,gBAAgB,SAAS,aAAa,EAC9E;gBACE,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;aACvB,CACF,CACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TextReadability } from "@lunarisapp/readability";
|
|
2
|
+
import { documentText } from "../../shared/text/document.js";
|
|
3
|
+
const MAX_SCORE = 12;
|
|
4
|
+
function rounded(score) {
|
|
5
|
+
return Math.round(score * 100) / 100;
|
|
6
|
+
}
|
|
7
|
+
const rule = (context) => {
|
|
8
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
9
|
+
const readability = new TextReadability({ lang: "en_US" });
|
|
10
|
+
return {
|
|
11
|
+
[Syntax.Document](node) {
|
|
12
|
+
const text = documentText(node);
|
|
13
|
+
if (text.length === 0) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const score = readability.gunningFog(text);
|
|
17
|
+
if (score <= MAX_SCORE) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
report(node, new RuleError(`Gunning Fog is ${rounded(score)}. Keep it at ${MAX_SCORE} or lower.`, {
|
|
21
|
+
padding: locator.at(0)
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export default rule;
|
|
27
|
+
//# sourceMappingURL=gunning-fog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gunning-fog.js","sourceRoot":"","sources":["../../../src/families/metrics/gunning-fog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC;AAED,MAAM,IAAI,GAAuB,CAAC,OAAO,EAAE,EAAE;IAC3C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACvD,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAE3D,OAAO;QACL,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAqB;YACrC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;gBACvB,OAAO;YACT,CAAC;YAED,MAAM,CACJ,IAAI,EACJ,IAAI,SAAS,CACX,kBAAkB,OAAO,CAAC,KAAK,CAAC,gBAAgB,SAAS,YAAY,EACrE;gBACE,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;aACvB,CACF,CACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { allParagraphs } from "../../shared/text/sections.js";
|
|
2
|
+
import { splitSentences } from "../../shared/text/sentences.js";
|
|
3
|
+
const MAX_SENTENCES = 6;
|
|
4
|
+
const rule = (context) => {
|
|
5
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
6
|
+
return {
|
|
7
|
+
[Syntax.Document](node) {
|
|
8
|
+
for (const item of allParagraphs(node)) {
|
|
9
|
+
const sentenceCount = splitSentences(item.text).length;
|
|
10
|
+
if (sentenceCount <= MAX_SENTENCES) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
report(item.paragraph, new RuleError(`Paragraph has ${sentenceCount} sentences. Keep paragraphs to ${MAX_SENTENCES} sentences or fewer.`, {
|
|
14
|
+
padding: locator.range([0, item.source.text.length])
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export default rule;
|
|
21
|
+
//# sourceMappingURL=paragraph-length.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paragraph-length.js","sourceRoot":"","sources":["../../../src/families/metrics/paragraph-length.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,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,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;gBAEvD,IAAI,aAAa,IAAI,aAAa,EAAE,CAAC;oBACnC,SAAS;gBACX,CAAC;gBAED,MAAM,CACJ,IAAI,CAAC,SAAS,EACd,IAAI,SAAS,CACX,iBAAiB,aAAa,kCAAkC,aAAa,sBAAsB,EACnG;oBACE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;iBACrD,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { allParagraphs } from "../../shared/text/sections.js";
|
|
2
|
+
import { wordTokens } from "../../shared/text/tokens.js";
|
|
3
|
+
const MAX_REPETITION = 5;
|
|
4
|
+
const EXCLUDED_WORDS = new Set([
|
|
5
|
+
"the",
|
|
6
|
+
"a",
|
|
7
|
+
"an",
|
|
8
|
+
"is",
|
|
9
|
+
"in",
|
|
10
|
+
"to",
|
|
11
|
+
"and",
|
|
12
|
+
"of",
|
|
13
|
+
"for",
|
|
14
|
+
"that"
|
|
15
|
+
]);
|
|
16
|
+
function repeatedWords(text) {
|
|
17
|
+
const counts = new Map();
|
|
18
|
+
for (const token of wordTokens(text)) {
|
|
19
|
+
const word = token.normalized;
|
|
20
|
+
counts.set(word, (counts.get(word) ?? 0) + 1);
|
|
21
|
+
}
|
|
22
|
+
return [...counts]
|
|
23
|
+
.filter(([word, count]) => {
|
|
24
|
+
return (word.length >= 4 && !EXCLUDED_WORDS.has(word) && count > MAX_REPETITION);
|
|
25
|
+
})
|
|
26
|
+
.sort(([left], [right]) => left.localeCompare(right));
|
|
27
|
+
}
|
|
28
|
+
const rule = (context) => {
|
|
29
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
30
|
+
return {
|
|
31
|
+
[Syntax.Document](node) {
|
|
32
|
+
for (const item of allParagraphs(node)) {
|
|
33
|
+
if (item.source.text.trimStart().startsWith("<")) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
for (const [word, count] of repeatedWords(item.text)) {
|
|
37
|
+
report(item.paragraph, new RuleError(`Word repeated ${count} times in one paragraph: "${word}". Keep repeated words to ${MAX_REPETITION} or fewer.`, {
|
|
38
|
+
padding: locator.range([0, item.source.text.length])
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export default rule;
|
|
46
|
+
//# sourceMappingURL=word-repetition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"word-repetition.js","sourceRoot":"","sources":["../../../src/families/metrics/word-repetition.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,KAAK;IACL,GAAG;IACH,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,KAAK;IACL,MAAM;CACP,CAAC,CAAC;AAEH,SAAS,aAAa,CACpB,IAAY;IAEZ,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzC,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC;QAC9B,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,CAAC,GAAG,MAAM,CAAC;SACf,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;QACxB,OAAO,CACL,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,cAAc,CACxE,CAAC;IACJ,CAAC,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,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,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACjD,SAAS;gBACX,CAAC;gBAED,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrD,MAAM,CACJ,IAAI,CAAC,SAAS,EACd,IAAI,SAAS,CACX,iBAAiB,KAAK,6BAA6B,IAAI,6BAA6B,cAAc,YAAY,EAC9G;wBACE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;qBACrD,CACF,CACF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { RuleHelper } from "textlint-rule-helper";
|
|
2
|
+
import { sourceText } from "../../shared/text/traverse.js";
|
|
3
|
+
import { countWhitespaceSeparatedWords } from "../../shared/text/whitespace.js";
|
|
4
|
+
const MAX_DRAMATIC_AFTER_COLON_WORDS = 5;
|
|
5
|
+
function firstNonWhitespaceIndex(text) {
|
|
6
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
7
|
+
if (text[index]?.trim() !== "") {
|
|
8
|
+
return index;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
function trimEndIndex(text) {
|
|
14
|
+
for (let index = text.length; index > 0; index -= 1) {
|
|
15
|
+
if (text[index - 1]?.trim() !== "") {
|
|
16
|
+
return index;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
function containsComma(text) {
|
|
22
|
+
for (const character of text) {
|
|
23
|
+
if (character === ",") {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
function isMeridiemInnerPeriod(text, index) {
|
|
30
|
+
const previous = text[index - 1]?.toLocaleLowerCase();
|
|
31
|
+
const next = text[index + 1]?.toLocaleLowerCase();
|
|
32
|
+
return (previous === "a" || previous === "p") && next === "m";
|
|
33
|
+
}
|
|
34
|
+
function sentenceEndWithClosingQuotes(text, index) {
|
|
35
|
+
let end = index + 1;
|
|
36
|
+
while (text[end] === '"' ||
|
|
37
|
+
text[end] === "\u201D" ||
|
|
38
|
+
text[end] === "\u2019") {
|
|
39
|
+
end += 1;
|
|
40
|
+
}
|
|
41
|
+
return end;
|
|
42
|
+
}
|
|
43
|
+
function sentenceEndAfter(text, start) {
|
|
44
|
+
for (let index = start; index < text.length; index += 1) {
|
|
45
|
+
const character = text[index];
|
|
46
|
+
if (character === "." && isMeridiemInnerPeriod(text, index)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (character === "." || character === "?" || character === "!") {
|
|
50
|
+
return sentenceEndWithClosingQuotes(text, index);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return text.length;
|
|
54
|
+
}
|
|
55
|
+
function dramaticColonAt(text, colonIndex) {
|
|
56
|
+
const end = sentenceEndAfter(text, colonIndex + 1);
|
|
57
|
+
const afterColon = text.slice(colonIndex + 1, end);
|
|
58
|
+
const trimStart = firstNonWhitespaceIndex(afterColon);
|
|
59
|
+
if (trimStart === undefined) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
const trimEnd = trimEndIndex(afterColon);
|
|
63
|
+
const trimmed = afterColon.slice(trimStart, trimEnd);
|
|
64
|
+
if (containsComma(trimmed)) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
if (countWhitespaceSeparatedWords(trimmed) > MAX_DRAMATIC_AFTER_COLON_WORDS) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
end: colonIndex + 1 + trimEnd,
|
|
72
|
+
start: colonIndex + 1 + trimStart,
|
|
73
|
+
text: trimmed
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function findDramaticColonMatches(text) {
|
|
77
|
+
const matches = [];
|
|
78
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
79
|
+
if (text[index] !== ":") {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const match = dramaticColonAt(text, index);
|
|
83
|
+
if (match === undefined) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
matches.push(match);
|
|
87
|
+
}
|
|
88
|
+
return matches;
|
|
89
|
+
}
|
|
90
|
+
const rule = (context) => {
|
|
91
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
92
|
+
const helper = new RuleHelper(context);
|
|
93
|
+
const ignoredParents = [
|
|
94
|
+
Syntax.List,
|
|
95
|
+
Syntax.ListItem,
|
|
96
|
+
Syntax.Table,
|
|
97
|
+
Syntax.TableCell
|
|
98
|
+
];
|
|
99
|
+
return {
|
|
100
|
+
[Syntax.Paragraph](node) {
|
|
101
|
+
if (helper.isChildNode(node, ignoredParents)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const source = sourceText(node);
|
|
105
|
+
for (const match of findDramaticColonMatches(source.text)) {
|
|
106
|
+
report(node, new RuleError(`Dramatic colon found: "${match.text}". Rewrite without the short reveal after the colon.`, {
|
|
107
|
+
padding: locator.range([
|
|
108
|
+
source.originalStartFor(match.start),
|
|
109
|
+
source.originalEndFor(match.end)
|
|
110
|
+
])
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
export default rule;
|
|
117
|
+
//# sourceMappingURL=colon-dramatic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colon-dramatic.js","sourceRoot":"","sources":["../../../src/families/orthography/colon-dramatic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { RuleHelper } from "textlint-rule-helper";
|
|
2
|
+
import { sourceText } from "../../shared/text/traverse.js";
|
|
3
|
+
import { isWhitespace } from "../../shared/text/whitespace.js";
|
|
4
|
+
const CLOSED_EM_DASH = "\u2014";
|
|
5
|
+
function isClosedEmDash(text, index) {
|
|
6
|
+
if (text[index] !== CLOSED_EM_DASH) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
return !isWhitespace(text[index - 1]) && !isWhitespace(text[index + 1]);
|
|
10
|
+
}
|
|
11
|
+
const rule = (context) => {
|
|
12
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
13
|
+
const helper = new RuleHelper(context);
|
|
14
|
+
const ignoredParents = [
|
|
15
|
+
Syntax.List,
|
|
16
|
+
Syntax.ListItem,
|
|
17
|
+
Syntax.Table,
|
|
18
|
+
Syntax.TableCell
|
|
19
|
+
];
|
|
20
|
+
return {
|
|
21
|
+
[Syntax.Paragraph](node) {
|
|
22
|
+
if (helper.isChildNode(node, ignoredParents)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const source = sourceText(node);
|
|
26
|
+
for (let index = 0; index < source.text.length; index += 1) {
|
|
27
|
+
if (!isClosedEmDash(source.text, index)) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
report(node, new RuleError("Closed em dash found. Replace it with a comma, colon, parenthesis, or spaced dash.", {
|
|
31
|
+
padding: locator.range([
|
|
32
|
+
source.originalStartFor(index),
|
|
33
|
+
source.originalEndFor(index + CLOSED_EM_DASH.length)
|
|
34
|
+
])
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export default rule;
|
|
41
|
+
//# sourceMappingURL=em-dashes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"em-dashes.js","sourceRoot":"","sources":["../../../src/families/orthography/em-dashes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAE/D,MAAM,cAAc,GAAG,QAAQ,CAAC;AAEhC,SAAS,cAAc,CAAC,IAAY,EAAE,KAAa;IACjD,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,cAAc,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,IAAI,GAAuB,CAAC,OAAO,EAAE,EAAE;IAC3C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,cAAc,GAAG;QACrB,MAAM,CAAC,IAAI;QACX,MAAM,CAAC,QAAQ;QACf,MAAM,CAAC,KAAK;QACZ,MAAM,CAAC,SAAS;KACjB,CAAC;IAEF,OAAO;QACL,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAmB;YACpC,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,CAAC;gBAC7C,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;YAEhC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBAC3D,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;oBACxC,SAAS;gBACX,CAAC;gBAED,MAAM,CACJ,IAAI,EACJ,IAAI,SAAS,CACX,oFAAoF,EACpF;oBACE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC;wBACrB,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC;wBAC9B,MAAM,CAAC,cAAc,CAAC,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC;qBACrD,CAAC;iBACH,CACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { RuleHelper } from "textlint-rule-helper";
|
|
2
|
+
import { sourceText } from "../../shared/text/traverse.js";
|
|
3
|
+
const MAX_EXCLAMATIONS_PER_PARAGRAPH = 1;
|
|
4
|
+
function countExclamations(text) {
|
|
5
|
+
let count = 0;
|
|
6
|
+
for (const character of text) {
|
|
7
|
+
if (character === "!") {
|
|
8
|
+
count += 1;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return count;
|
|
12
|
+
}
|
|
13
|
+
function firstExclamationIndex(text) {
|
|
14
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
15
|
+
if (text[index] === "!") {
|
|
16
|
+
return index;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const rule = (context) => {
|
|
22
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
23
|
+
const helper = new RuleHelper(context);
|
|
24
|
+
const ignoredParents = [
|
|
25
|
+
Syntax.List,
|
|
26
|
+
Syntax.ListItem,
|
|
27
|
+
Syntax.Table,
|
|
28
|
+
Syntax.TableCell
|
|
29
|
+
];
|
|
30
|
+
return {
|
|
31
|
+
[Syntax.Paragraph](node) {
|
|
32
|
+
if (helper.isChildNode(node, ignoredParents)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const source = sourceText(node);
|
|
36
|
+
const count = countExclamations(source.text);
|
|
37
|
+
if (count <= MAX_EXCLAMATIONS_PER_PARAGRAPH) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const index = firstExclamationIndex(source.text) ?? 0;
|
|
41
|
+
report(node, new RuleError(`Paragraph has ${count} exclamation marks. Keep at most ${MAX_EXCLAMATIONS_PER_PARAGRAPH}.`, {
|
|
42
|
+
padding: locator.range([
|
|
43
|
+
source.originalStartFor(index),
|
|
44
|
+
source.originalEndFor(index + 1)
|
|
45
|
+
])
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export default rule;
|
|
51
|
+
//# sourceMappingURL=exclamation-density.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exclamation-density.js","sourceRoot":"","sources":["../../../src/families/orthography/exclamation-density.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,MAAM,8BAA8B,GAAG,CAAC,CAAC;AAEzC,SAAS,iBAAiB,CAAC,IAAY;IACrC,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;YACtB,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY;IACzC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,IAAI,GAAuB,CAAC,OAAO,EAAE,EAAE;IAC3C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACvD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,cAAc,GAAG;QACrB,MAAM,CAAC,IAAI;QACX,MAAM,CAAC,QAAQ;QACf,MAAM,CAAC,KAAK;QACZ,MAAM,CAAC,SAAS;KACjB,CAAC;IAEF,OAAO;QACL,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAmB;YACpC,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,CAAC;gBAC7C,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,KAAK,GAAG,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAE7C,IAAI,KAAK,IAAI,8BAA8B,EAAE,CAAC;gBAC5C,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,qBAAqB,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEtD,MAAM,CACJ,IAAI,EACJ,IAAI,SAAS,CACX,iBAAiB,KAAK,oCAAoC,8BAA8B,GAAG,EAC3F;gBACE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC;oBACrB,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC;oBAC9B,MAAM,CAAC,cAAc,CAAC,KAAK,GAAG,CAAC,CAAC;iBACjC,CAAC;aACH,CACF,CACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { RuleHelper } from "textlint-rule-helper";
|
|
2
|
+
import { splitSentences } from "../../shared/text/sentences.js";
|
|
3
|
+
import { sourceText } from "../../shared/text/traverse.js";
|
|
4
|
+
function isAsciiDigit(character) {
|
|
5
|
+
return character !== undefined && character >= "0" && character <= "9";
|
|
6
|
+
}
|
|
7
|
+
function isPeriodMarker(first, second) {
|
|
8
|
+
if (first === undefined || second === undefined) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
const normalizedFirst = first.toUpperCase();
|
|
12
|
+
return ((normalizedFirst === "A" || normalizedFirst === "P") &&
|
|
13
|
+
second.toUpperCase() === "M");
|
|
14
|
+
}
|
|
15
|
+
function findTimestampMatches(text) {
|
|
16
|
+
const matches = [];
|
|
17
|
+
let index = 0;
|
|
18
|
+
while (index < text.length) {
|
|
19
|
+
if (!isAsciiDigit(text[index])) {
|
|
20
|
+
index += 1;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const start = index;
|
|
24
|
+
while (isAsciiDigit(text[index])) {
|
|
25
|
+
index += 1;
|
|
26
|
+
}
|
|
27
|
+
if (text[index] !== ":") {
|
|
28
|
+
index = start + 1;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
index += 1;
|
|
32
|
+
const minuteStart = index;
|
|
33
|
+
while (isAsciiDigit(text[index])) {
|
|
34
|
+
index += 1;
|
|
35
|
+
}
|
|
36
|
+
if (index === minuteStart) {
|
|
37
|
+
index = start + 1;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (text[index] === " ") {
|
|
41
|
+
index += 1;
|
|
42
|
+
}
|
|
43
|
+
if (!isPeriodMarker(text[index], text[index + 1])) {
|
|
44
|
+
index = start + 1;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const end = index + 2;
|
|
48
|
+
matches.push({
|
|
49
|
+
end,
|
|
50
|
+
start,
|
|
51
|
+
text: text.slice(start, end)
|
|
52
|
+
});
|
|
53
|
+
index = end;
|
|
54
|
+
}
|
|
55
|
+
return matches;
|
|
56
|
+
}
|
|
57
|
+
function findSentenceTimestampMatches(text) {
|
|
58
|
+
const matches = [];
|
|
59
|
+
for (const sentence of splitSentences(text)) {
|
|
60
|
+
const timestampMatches = findTimestampMatches(sentence.text);
|
|
61
|
+
if (timestampMatches.length === 0) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const first = timestampMatches[0];
|
|
65
|
+
if (first === undefined) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
matches.push({
|
|
69
|
+
end: sentence.start + first.end,
|
|
70
|
+
start: sentence.start + first.start,
|
|
71
|
+
text: first.text
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return matches;
|
|
75
|
+
}
|
|
76
|
+
const rule = (context) => {
|
|
77
|
+
const { Syntax, RuleError, locator, report } = context;
|
|
78
|
+
const helper = new RuleHelper(context);
|
|
79
|
+
const ignoredParents = [
|
|
80
|
+
Syntax.List,
|
|
81
|
+
Syntax.ListItem,
|
|
82
|
+
Syntax.Table,
|
|
83
|
+
Syntax.TableCell
|
|
84
|
+
];
|
|
85
|
+
return {
|
|
86
|
+
[Syntax.Paragraph](node) {
|
|
87
|
+
if (helper.isChildNode(node, ignoredParents)) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const source = sourceText(node);
|
|
91
|
+
for (const match of findSentenceTimestampMatches(source.text)) {
|
|
92
|
+
report(node, new RuleError(`Fake timestamp found: "${match.text}". Remove fabricated clock specificity.`, {
|
|
93
|
+
padding: locator.range([
|
|
94
|
+
source.originalStartFor(match.start),
|
|
95
|
+
source.originalEndFor(match.end)
|
|
96
|
+
])
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
export default rule;
|
|
103
|
+
//# sourceMappingURL=fake-timestamps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-timestamps.js","sourceRoot":"","sources":["../../../src/families/orthography/fake-timestamps.ts"],"names":[],"mappings":"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"}
|