@mark1russell7/ste-lint 0.0.0-stage → 0.1.2
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 +246 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +9 -0
- package/dist/cli.js.map +1 -0
- package/dist/config-core.d.ts +92 -0
- package/dist/config-core.d.ts.map +1 -0
- package/dist/config-core.js +198 -0
- package/dist/config-core.js.map +1 -0
- package/dist/config.d.ts +29 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +68 -0
- package/dist/config.js.map +1 -0
- package/dist/core.d.ts +16 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +16 -0
- package/dist/core.js.map +1 -0
- package/dist/dictionary-core.d.ts +72 -0
- package/dist/dictionary-core.d.ts.map +1 -0
- package/dist/dictionary-core.js +150 -0
- package/dist/dictionary-core.js.map +1 -0
- package/dist/dictionary.d.ts +9 -0
- package/dist/dictionary.d.ts.map +1 -0
- package/dist/dictionary.js +26 -0
- package/dist/dictionary.js.map +1 -0
- package/dist/engine.d.ts +44 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +122 -0
- package/dist/engine.js.map +1 -0
- package/dist/files.d.ts +35 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +181 -0
- package/dist/files.js.map +1 -0
- package/dist/format.d.ts +21 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +61 -0
- package/dist/format.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/lexicon.d.ts +33 -0
- package/dist/lexicon.d.ts.map +1 -0
- package/dist/lexicon.js +71 -0
- package/dist/lexicon.js.map +1 -0
- package/dist/lint.d.ts +18 -0
- package/dist/lint.d.ts.map +1 -0
- package/dist/lint.js +23 -0
- package/dist/lint.js.map +1 -0
- package/dist/rules/about-quantity.d.ts +3 -0
- package/dist/rules/about-quantity.d.ts.map +1 -0
- package/dist/rules/about-quantity.js +34 -0
- package/dist/rules/about-quantity.js.map +1 -0
- package/dist/rules/index.d.ts +8 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +35 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/ing-verb.d.ts +9 -0
- package/dist/rules/ing-verb.d.ts.map +1 -0
- package/dist/rules/ing-verb.js +60 -0
- package/dist/rules/ing-verb.js.map +1 -0
- package/dist/rules/latin-abbreviation.d.ts +3 -0
- package/dist/rules/latin-abbreviation.d.ts.map +1 -0
- package/dist/rules/latin-abbreviation.js +48 -0
- package/dist/rules/latin-abbreviation.js.map +1 -0
- package/dist/rules/missing-subject.d.ts +16 -0
- package/dist/rules/missing-subject.d.ts.map +1 -0
- package/dist/rules/missing-subject.js +138 -0
- package/dist/rules/missing-subject.js.map +1 -0
- package/dist/rules/modal-verb.d.ts +3 -0
- package/dist/rules/modal-verb.d.ts.map +1 -0
- package/dist/rules/modal-verb.js +72 -0
- package/dist/rules/modal-verb.js.map +1 -0
- package/dist/rules/noun-cluster.d.ts +17 -0
- package/dist/rules/noun-cluster.d.ts.map +1 -0
- package/dist/rules/noun-cluster.js +83 -0
- package/dist/rules/noun-cluster.js.map +1 -0
- package/dist/rules/paragraph-length.d.ts +3 -0
- package/dist/rules/paragraph-length.d.ts.map +1 -0
- package/dist/rules/paragraph-length.js +19 -0
- package/dist/rules/paragraph-length.js.map +1 -0
- package/dist/rules/passive-instruction.d.ts +15 -0
- package/dist/rules/passive-instruction.d.ts.map +1 -0
- package/dist/rules/passive-instruction.js +38 -0
- package/dist/rules/passive-instruction.js.map +1 -0
- package/dist/rules/pronouns.d.ts +4 -0
- package/dist/rules/pronouns.d.ts.map +1 -0
- package/dist/rules/pronouns.js +57 -0
- package/dist/rules/pronouns.js.map +1 -0
- package/dist/rules/rule.d.ts +46 -0
- package/dist/rules/rule.d.ts.map +1 -0
- package/dist/rules/rule.js +31 -0
- package/dist/rules/rule.js.map +1 -0
- package/dist/rules/semicolon.d.ts +3 -0
- package/dist/rules/semicolon.d.ts.map +1 -0
- package/dist/rules/semicolon.js +20 -0
- package/dist/rules/semicolon.js.map +1 -0
- package/dist/rules/sentence-length.d.ts +3 -0
- package/dist/rules/sentence-length.d.ts.map +1 -0
- package/dist/rules/sentence-length.js +31 -0
- package/dist/rules/sentence-length.js.map +1 -0
- package/dist/rules/unknown-word.d.ts +9 -0
- package/dist/rules/unknown-word.d.ts.map +1 -0
- package/dist/rules/unknown-word.js +49 -0
- package/dist/rules/unknown-word.js.map +1 -0
- package/dist/rules/word-list-matcher.d.ts +25 -0
- package/dist/rules/word-list-matcher.d.ts.map +1 -0
- package/dist/rules/word-list-matcher.js +60 -0
- package/dist/rules/word-list-matcher.js.map +1 -0
- package/dist/rules/word-list.d.ts +3 -0
- package/dist/rules/word-list.d.ts.map +1 -0
- package/dist/rules/word-list.js +26 -0
- package/dist/rules/word-list.js.map +1 -0
- package/dist/run-cli.d.ts +27 -0
- package/dist/run-cli.d.ts.map +1 -0
- package/dist/run-cli.js +176 -0
- package/dist/run-cli.js.map +1 -0
- package/dist/source/blocks.d.ts +55 -0
- package/dist/source/blocks.d.ts.map +1 -0
- package/dist/source/blocks.js +464 -0
- package/dist/source/blocks.js.map +1 -0
- package/dist/source/code.d.ts +9 -0
- package/dist/source/code.d.ts.map +1 -0
- package/dist/source/code.js +16 -0
- package/dist/source/code.js.map +1 -0
- package/dist/source/inline.d.ts +42 -0
- package/dist/source/inline.d.ts.map +1 -0
- package/dist/source/inline.js +396 -0
- package/dist/source/inline.js.map +1 -0
- package/dist/source/jsx.d.ts +18 -0
- package/dist/source/jsx.d.ts.map +1 -0
- package/dist/source/jsx.js +137 -0
- package/dist/source/jsx.js.map +1 -0
- package/dist/source/lines.d.ts +34 -0
- package/dist/source/lines.d.ts.map +1 -0
- package/dist/source/lines.js +83 -0
- package/dist/source/lines.js.map +1 -0
- package/dist/source/markdown.d.ts +23 -0
- package/dist/source/markdown.d.ts.map +1 -0
- package/dist/source/markdown.js +42 -0
- package/dist/source/markdown.js.map +1 -0
- package/dist/source/suppressions.d.ts +38 -0
- package/dist/source/suppressions.d.ts.map +1 -0
- package/dist/source/suppressions.js +69 -0
- package/dist/source/suppressions.js.map +1 -0
- package/dist/source/tsdoc.d.ts +40 -0
- package/dist/source/tsdoc.d.ts.map +1 -0
- package/dist/source/tsdoc.js +176 -0
- package/dist/source/tsdoc.js.map +1 -0
- package/dist/text/grammar.d.ts +91 -0
- package/dist/text/grammar.d.ts.map +1 -0
- package/dist/text/grammar.js +289 -0
- package/dist/text/grammar.js.map +1 -0
- package/dist/text/phrases.d.ts +30 -0
- package/dist/text/phrases.d.ts.map +1 -0
- package/dist/text/phrases.js +65 -0
- package/dist/text/phrases.js.map +1 -0
- package/dist/text/sentences.d.ts +45 -0
- package/dist/text/sentences.d.ts.map +1 -0
- package/dist/text/sentences.js +141 -0
- package/dist/text/sentences.js.map +1 -0
- package/dist/text/tokens.d.ts +35 -0
- package/dist/text/tokens.d.ts.map +1 -0
- package/dist/text/tokens.js +113 -0
- package/dist/text/tokens.js.map +1 -0
- package/dist/text/words.d.ts +58 -0
- package/dist/text/words.d.ts.map +1 -0
- package/dist/text/words.js +159 -0
- package/dist/text/words.js.map +1 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/dist/units.d.ts +47 -0
- package/dist/units.d.ts.map +1 -0
- package/dist/units.js +42 -0
- package/dist/units.js.map +1 -0
- package/dist/word-list.d.ts +34 -0
- package/dist/word-list.d.ts.map +1 -0
- package/dist/word-list.js +90 -0
- package/dist/word-list.js.map +1 -0
- package/package.json +54 -3
- package/src/cli.ts +9 -0
- package/src/config-core.ts +258 -0
- package/src/config.test.ts +188 -0
- package/src/config.ts +83 -0
- package/src/core.test.ts +87 -0
- package/src/core.ts +32 -0
- package/src/dictionary-core.ts +158 -0
- package/src/dictionary.test.ts +82 -0
- package/src/dictionary.ts +26 -0
- package/src/engine.ts +138 -0
- package/src/files.test.ts +107 -0
- package/src/files.ts +191 -0
- package/src/format.ts +78 -0
- package/src/index.test.ts +28 -0
- package/src/index.ts +38 -0
- package/src/lexicon.ts +92 -0
- package/src/lint.test.ts +182 -0
- package/src/lint.ts +30 -0
- package/src/rules/about-quantity.ts +33 -0
- package/src/rules/index.ts +40 -0
- package/src/rules/ing-verb.test.ts +48 -0
- package/src/rules/ing-verb.ts +54 -0
- package/src/rules/latin-abbreviation.ts +46 -0
- package/src/rules/missing-subject.test.ts +53 -0
- package/src/rules/missing-subject.ts +129 -0
- package/src/rules/modal-verb.test.ts +45 -0
- package/src/rules/modal-verb.ts +72 -0
- package/src/rules/noun-cluster.test.ts +49 -0
- package/src/rules/noun-cluster.ts +82 -0
- package/src/rules/paragraph-length.test.ts +30 -0
- package/src/rules/paragraph-length.ts +19 -0
- package/src/rules/passive-instruction.test.ts +38 -0
- package/src/rules/passive-instruction.ts +37 -0
- package/src/rules/pronouns.test.ts +38 -0
- package/src/rules/pronouns.ts +54 -0
- package/src/rules/punctuation.test.ts +59 -0
- package/src/rules/rule.ts +73 -0
- package/src/rules/semicolon.ts +19 -0
- package/src/rules/sentence-length.test.ts +52 -0
- package/src/rules/sentence-length.ts +32 -0
- package/src/rules/unknown-word.test.ts +81 -0
- package/src/rules/unknown-word.ts +43 -0
- package/src/rules/word-list-matcher.ts +68 -0
- package/src/rules/word-list.test.ts +110 -0
- package/src/rules/word-list.ts +25 -0
- package/src/run-cli.test.ts +189 -0
- package/src/run-cli.ts +193 -0
- package/src/source/blocks.ts +534 -0
- package/src/source/code.ts +17 -0
- package/src/source/inline.test.ts +92 -0
- package/src/source/inline.ts +416 -0
- package/src/source/jsx.test.ts +46 -0
- package/src/source/jsx.ts +147 -0
- package/src/source/lines.test.ts +51 -0
- package/src/source/lines.ts +91 -0
- package/src/source/markdown.test.ts +210 -0
- package/src/source/markdown.ts +49 -0
- package/src/source/suppressions.ts +79 -0
- package/src/source/tsdoc.test.ts +137 -0
- package/src/source/tsdoc.ts +189 -0
- package/src/text/grammar.ts +304 -0
- package/src/text/phrases.ts +72 -0
- package/src/text/sentences.ts +148 -0
- package/src/text/text.test.ts +262 -0
- package/src/text/tokens.ts +135 -0
- package/src/text/words.ts +183 -0
- package/src/types.ts +39 -0
- package/src/units.ts +86 -0
- package/src/word-list.ts +128 -0
- package/ste.config.schema.json +87 -0
package/dist/lexicon.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The word sets that the rules use: the project glossary from the
|
|
3
|
+
* configuration, the built-in word lists, and the local dictionary when
|
|
4
|
+
* there is one.
|
|
5
|
+
*/
|
|
6
|
+
import { hasLemmaIn } from "./text/grammar.js";
|
|
7
|
+
import { PhraseMatcher, splitPhrase } from "./text/phrases.js";
|
|
8
|
+
import { COMMON_NOUNS, COMMON_VERBS } from "./text/words.js";
|
|
9
|
+
function words(terms) {
|
|
10
|
+
const single = new Set();
|
|
11
|
+
const phrases = [];
|
|
12
|
+
for (const term of terms) {
|
|
13
|
+
const parts = splitPhrase(term);
|
|
14
|
+
if (parts.length === 1)
|
|
15
|
+
single.add(parts[0]);
|
|
16
|
+
else if (parts.length > 1)
|
|
17
|
+
phrases.push(parts.join(" "));
|
|
18
|
+
}
|
|
19
|
+
return { single, phrases };
|
|
20
|
+
}
|
|
21
|
+
/** This function makes the lexicon for a configuration and an optional dictionary. */
|
|
22
|
+
export function buildLexicon(config, dictionary = null) {
|
|
23
|
+
const nouns = words(config.technicalNouns);
|
|
24
|
+
const verbs = words(config.technicalVerbs);
|
|
25
|
+
const proper = words(config.properNouns);
|
|
26
|
+
const allowed = words(config.allowedWords);
|
|
27
|
+
const glossaryPhrases = new PhraseMatcher();
|
|
28
|
+
const technicalNounPhrases = new PhraseMatcher();
|
|
29
|
+
// A name counts as one word only with its own capital letters: "Event Timing", but not "event timing".
|
|
30
|
+
const properNounPhrases = new PhraseMatcher({ caseSensitive: true });
|
|
31
|
+
for (const phrase of nouns.phrases) {
|
|
32
|
+
glossaryPhrases.add(phrase, true);
|
|
33
|
+
technicalNounPhrases.add(phrase, true);
|
|
34
|
+
}
|
|
35
|
+
for (const phrase of verbs.phrases)
|
|
36
|
+
glossaryPhrases.add(phrase, true);
|
|
37
|
+
for (const phrase of proper.phrases)
|
|
38
|
+
glossaryPhrases.add(phrase, true);
|
|
39
|
+
for (const name of config.properNouns) {
|
|
40
|
+
if (name.trim().split(/\s+/).length > 1)
|
|
41
|
+
properNounPhrases.add(name.trim(), true);
|
|
42
|
+
}
|
|
43
|
+
const verbSet = new Set([...COMMON_VERBS, ...verbs.single, ...(dictionary?.verbs ?? [])]);
|
|
44
|
+
// A word that is often a verb counts as a noun only when the glossary or the dictionary says that it is a noun.
|
|
45
|
+
const nounSet = new Set();
|
|
46
|
+
for (const noun of COMMON_NOUNS)
|
|
47
|
+
if (!verbSet.has(noun))
|
|
48
|
+
nounSet.add(noun);
|
|
49
|
+
for (const noun of [...nouns.single, ...proper.single, ...(dictionary?.nouns ?? [])])
|
|
50
|
+
nounSet.add(noun);
|
|
51
|
+
return {
|
|
52
|
+
technicalNouns: nouns.single,
|
|
53
|
+
technicalVerbs: verbs.single,
|
|
54
|
+
properNouns: proper.single,
|
|
55
|
+
allowedWords: allowed.single,
|
|
56
|
+
glossaryPhrases,
|
|
57
|
+
technicalNounPhrases,
|
|
58
|
+
properNounPhrases,
|
|
59
|
+
nouns: nounSet,
|
|
60
|
+
verbs: verbSet,
|
|
61
|
+
dictionary,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** True when the glossary permits the word: a technical noun or verb in any form, a proper noun, or a word of `allowedWords`. */
|
|
65
|
+
export function isGlossaryWord(word, lexicon) {
|
|
66
|
+
return lexicon.properNouns.has(word)
|
|
67
|
+
|| lexicon.allowedWords.has(word)
|
|
68
|
+
|| hasLemmaIn(word, lexicon.technicalNouns)
|
|
69
|
+
|| hasLemmaIn(word, lexicon.technicalVerbs);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=lexicon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lexicon.js","sourceRoot":"","sources":["../src/lexicon.ts"],"names":[],"mappings":"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"}
|
package/dist/lint.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The linter for files: the engine of `engine.ts`, with the extractor of
|
|
3
|
+
* TypeScript doc comments and the file system.
|
|
4
|
+
*/
|
|
5
|
+
import type { ResolvedConfig } from "./config.js";
|
|
6
|
+
import { ProseLinter } from "./engine.js";
|
|
7
|
+
import type { Lexicon } from "./lexicon.js";
|
|
8
|
+
import type { Finding } from "./types.js";
|
|
9
|
+
export { fileKind, type FileKind } from "./engine.js";
|
|
10
|
+
/** A linter for one configuration. It makes the lexicon and the word list matcher one time. */
|
|
11
|
+
export declare class Linter extends ProseLinter {
|
|
12
|
+
constructor(config: ResolvedConfig, lexicon?: Lexicon);
|
|
13
|
+
/** The findings in a file on disk. `displayPath` is the file name in the findings. */
|
|
14
|
+
lintFile(path: string, displayPath?: string): Finding[];
|
|
15
|
+
}
|
|
16
|
+
/** The findings in `text`, with a new linter. To lint many files, make one `Linter` and use it again. */
|
|
17
|
+
export declare function lintText(text: string, path: string, config: ResolvedConfig, lexicon?: Lexicon): Finding[];
|
|
18
|
+
//# sourceMappingURL=lint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,+FAA+F;AAC/F,qBAAa,MAAO,SAAQ,WAAW;gBACvB,MAAM,EAAG,cAAc,EAAE,OAAO,CAAC,EAAG,OAAO;IAIvD,sFAAsF;IACtF,QAAQ,CAAC,IAAI,EAAG,MAAM,EAAE,WAAW,GAAG,MAAa,GAAI,OAAO,EAAE;CAGnE;AAED,yGAAyG;AACzG,wBAAgB,QAAQ,CAAC,IAAI,EAAG,MAAM,EAAE,IAAI,EAAG,MAAM,EAAE,MAAM,EAAG,cAAc,EAAE,OAAO,CAAC,EAAG,OAAO,GAAI,OAAO,EAAE,CAE9G"}
|
package/dist/lint.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The linter for files: the engine of `engine.ts`, with the extractor of
|
|
3
|
+
* TypeScript doc comments and the file system.
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
6
|
+
import { ProseLinter } from "./engine.js";
|
|
7
|
+
import { extractCode } from "./source/code.js";
|
|
8
|
+
export { fileKind } from "./engine.js";
|
|
9
|
+
/** A linter for one configuration. It makes the lexicon and the word list matcher one time. */
|
|
10
|
+
export class Linter extends ProseLinter {
|
|
11
|
+
constructor(config, lexicon) {
|
|
12
|
+
super(config, lexicon, { extractCode });
|
|
13
|
+
}
|
|
14
|
+
/** The findings in a file on disk. `displayPath` is the file name in the findings. */
|
|
15
|
+
lintFile(path, displayPath = path) {
|
|
16
|
+
return this.lintText(readFileSync(path, "utf8"), displayPath);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** The findings in `text`, with a new linter. To lint many files, make one `Linter` and use it again. */
|
|
20
|
+
export function lintText(text, path, config, lexicon) {
|
|
21
|
+
return new Linter(config, lexicon).lintText(text, path);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=lint.js.map
|
package/dist/lint.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.js","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,QAAQ,EAAiB,MAAM,aAAa,CAAC;AAEtD,+FAA+F;AAC/F,MAAM,OAAO,MAAO,SAAQ,WAAW;IACnC,YAAY,MAAuB,EAAE,OAAkB;QACnD,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,sFAAsF;IACtF,QAAQ,CAAC,IAAa,EAAE,cAAuB,IAAI;QAC/C,OAAO,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC;IAClE,CAAC;CACJ;AAED,yGAAyG;AACzG,MAAM,UAAU,QAAQ,CAAC,IAAa,EAAE,IAAa,EAAE,MAAuB,EAAE,OAAkB;IAC9F,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"about-quantity.d.ts","sourceRoot":"","sources":["../../src/rules/about-quantity.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4B,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAOhE,eAAO,MAAM,aAAa,EAAG,IAuB5B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { isNumber, isWord } from "../text/tokens.js";
|
|
2
|
+
import { UNITS } from "../text/words.js";
|
|
3
|
+
import { forEachToken, tokenRange } from "./rule.js";
|
|
4
|
+
/** Words after "about a" or "about an" that make a quantity: "about a second", "about an hour". */
|
|
5
|
+
const QUANTITY_AFTER_ARTICLE = new Set([
|
|
6
|
+
"dozen", "few", "hundred", "thousand", "million", "billion", "third", "quarter", "half", "factor", "tenth",
|
|
7
|
+
]);
|
|
8
|
+
export const aboutQuantity = {
|
|
9
|
+
id: "about-quantity",
|
|
10
|
+
description: "Find \"about\" before a number or a quantity, where the word means \"approximately\".",
|
|
11
|
+
ste: "1.3, 9.2",
|
|
12
|
+
defaultSeverity: "error",
|
|
13
|
+
scope: "word",
|
|
14
|
+
check(unit, context) {
|
|
15
|
+
forEachToken(unit, (tokens, i) => {
|
|
16
|
+
const token = tokens[i];
|
|
17
|
+
if (!isWord(token) || token.lower !== "about")
|
|
18
|
+
return;
|
|
19
|
+
const next = tokens[i + 1];
|
|
20
|
+
const after = tokens[i + 2];
|
|
21
|
+
const quantity = isNumber(next)
|
|
22
|
+
|| (next !== undefined && next.text === "~")
|
|
23
|
+
|| (isWord(next) && /^\d/.test(next.text))
|
|
24
|
+
|| (isWord(next) && (next.lower === "a" || next.lower === "an") && isWord(after) && (QUANTITY_AFTER_ARTICLE.has(after.lower) || UNITS.has(after.lower)));
|
|
25
|
+
if (!quantity)
|
|
26
|
+
return;
|
|
27
|
+
context.report({
|
|
28
|
+
...tokenRange(tokens, i, i + 1),
|
|
29
|
+
message: "Do not use \"about\" for a quantity. Write \"approximately\". Use \"about\" only for a topic, for example \"about the monitor\".",
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=about-quantity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"about-quantity.js","sourceRoot":"","sources":["../../src/rules/about-quantity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAa,MAAM,WAAW,CAAC;AAEhE,mGAAmG;AACnG,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACnC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO;CAC7G,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,aAAa,GAAU;IAChC,EAAE,EAAG,gBAAgB;IACrB,WAAW,EAAG,uFAAuF;IACrG,GAAG,EAAG,UAAU;IAChB,eAAe,EAAG,OAAO;IACzB,KAAK,EAAG,MAAM;IACd,KAAK,CAAC,IAAI,EAAE,OAAO;QACf,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO;gBAAE,OAAO;YACtD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5B,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;mBACxB,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC;mBACzC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;mBACvC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC7J,IAAI,CAAC,QAAQ;gBAAE,OAAO;YACtB,OAAO,CAAC,MAAM,CAAC;gBACX,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;gBAC/B,OAAO,EAAG,kIAAkI;aAC/I,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;CACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RuleId } from "../types.js";
|
|
2
|
+
import type { Rule } from "./rule.js";
|
|
3
|
+
/** All rules, in the order of the documentation. */
|
|
4
|
+
export declare const RULES: readonly Rule[];
|
|
5
|
+
/** The rule with the ID `id`. */
|
|
6
|
+
export declare function getRule(id: RuleId): Rule;
|
|
7
|
+
export type { Report, Rule, RuleContext, RuleScope } from "./rule.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAU1C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAMtC,oDAAoD;AACpD,eAAO,MAAM,KAAK,EAAG,SAAS,IAAI,EAejC,CAAC;AAEF,iCAAiC;AACjC,wBAAgB,OAAO,CAAC,EAAE,EAAG,MAAM,GAAI,IAAI,CAE1C;AAED,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { aboutQuantity } from "./about-quantity.js";
|
|
2
|
+
import { ingVerb } from "./ing-verb.js";
|
|
3
|
+
import { latinAbbreviation } from "./latin-abbreviation.js";
|
|
4
|
+
import { missingSubjectRule } from "./missing-subject.js";
|
|
5
|
+
import { modalVerb } from "./modal-verb.js";
|
|
6
|
+
import { nounCluster } from "./noun-cluster.js";
|
|
7
|
+
import { paragraphLength } from "./paragraph-length.js";
|
|
8
|
+
import { passiveInstruction } from "./passive-instruction.js";
|
|
9
|
+
import { firstPerson, genderedPronoun } from "./pronouns.js";
|
|
10
|
+
import { semicolon } from "./semicolon.js";
|
|
11
|
+
import { sentenceLength } from "./sentence-length.js";
|
|
12
|
+
import { unknownWord } from "./unknown-word.js";
|
|
13
|
+
import { wordList } from "./word-list.js";
|
|
14
|
+
/** All rules, in the order of the documentation. */
|
|
15
|
+
export const RULES = [
|
|
16
|
+
sentenceLength,
|
|
17
|
+
paragraphLength,
|
|
18
|
+
modalVerb,
|
|
19
|
+
semicolon,
|
|
20
|
+
latinAbbreviation,
|
|
21
|
+
aboutQuantity,
|
|
22
|
+
wordList,
|
|
23
|
+
genderedPronoun,
|
|
24
|
+
firstPerson,
|
|
25
|
+
passiveInstruction,
|
|
26
|
+
nounCluster,
|
|
27
|
+
missingSubjectRule,
|
|
28
|
+
ingVerb,
|
|
29
|
+
unknownWord,
|
|
30
|
+
];
|
|
31
|
+
/** The rule with the ID `id`. */
|
|
32
|
+
export function getRule(id) {
|
|
33
|
+
return RULES.find((rule) => rule.id === id);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE7D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,oDAAoD;AACpD,MAAM,CAAC,MAAM,KAAK,GAAqB;IACnC,cAAc;IACd,eAAe;IACf,SAAS;IACT,SAAS;IACT,iBAAiB;IACjB,aAAa;IACb,QAAQ;IACR,eAAe;IACf,WAAW;IACX,kBAAkB;IAClB,WAAW;IACX,kBAAkB;IAClB,OAAO;IACP,WAAW;CACd,CAAC;AAEF,iCAAiC;AACjC,MAAM,UAAU,OAAO,CAAC,EAAW;IAC/B,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAE,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PhraseMatcher } from "../text/phrases.js";
|
|
2
|
+
import { type Token } from "../text/tokens.js";
|
|
3
|
+
import { type Rule } from "./rule.js";
|
|
4
|
+
/** The token indices that a multi-word glossary phrase covers. */
|
|
5
|
+
export declare function coveredByPhrases(tokens: readonly Token[], phrases: PhraseMatcher): Set<number>;
|
|
6
|
+
/** The base form of an -ing word when it is a known verb ("running" gives "run"), or null. */
|
|
7
|
+
export declare function baseForm(word: string, verbs: ReadonlySet<string>): string | null;
|
|
8
|
+
export declare const ingVerb: Rule;
|
|
9
|
+
//# sourceMappingURL=ing-verb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ing-verb.d.ts","sourceRoot":"","sources":["../../src/rules/ing-verb.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAqB,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAA4B,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAEhE,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,MAAM,EAAG,SAAS,KAAK,EAAE,EAAE,OAAO,EAAG,aAAa,GAAI,GAAG,CAAC,MAAM,CAAC,CAQjG;AAED,8FAA8F;AAC9F,wBAAgB,QAAQ,CAAC,IAAI,EAAG,MAAM,EAAE,KAAK,EAAG,WAAW,CAAC,MAAM,CAAC,GAAI,MAAM,GAAG,IAAI,CAEnF;AAED,eAAO,MAAM,OAAO,EAAG,IA+BtB,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { isIngVerbUse, lemmas } from "../text/grammar.js";
|
|
2
|
+
import { isCounted, isWord } from "../text/tokens.js";
|
|
3
|
+
import { NON_VERB_ING } from "../text/words.js";
|
|
4
|
+
import { forEachToken, tokenRange } from "./rule.js";
|
|
5
|
+
/** The token indices that a multi-word glossary phrase covers. */
|
|
6
|
+
export function coveredByPhrases(tokens, phrases) {
|
|
7
|
+
const covered = new Set();
|
|
8
|
+
if (phrases.empty)
|
|
9
|
+
return covered;
|
|
10
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
11
|
+
const length = phrases.longestMatch(tokens, i);
|
|
12
|
+
if (length > 1)
|
|
13
|
+
for (let k = i; k < i + length; k++)
|
|
14
|
+
covered.add(k);
|
|
15
|
+
}
|
|
16
|
+
return covered;
|
|
17
|
+
}
|
|
18
|
+
/** The base form of an -ing word when it is a known verb ("running" gives "run"), or null. */
|
|
19
|
+
export function baseForm(word, verbs) {
|
|
20
|
+
return lemmas(word).find((form) => form !== word && verbs.has(form)) ?? null;
|
|
21
|
+
}
|
|
22
|
+
export const ingVerb = {
|
|
23
|
+
id: "ing-verb",
|
|
24
|
+
description: "Find -ing forms used as verbs. Headings, technical nouns and allowed words are not examined.",
|
|
25
|
+
ste: "3.2, 3.5",
|
|
26
|
+
defaultSeverity: "warning",
|
|
27
|
+
scope: "word",
|
|
28
|
+
check(unit, context) {
|
|
29
|
+
if (unit.kind === "heading")
|
|
30
|
+
return;
|
|
31
|
+
const { lexicon, wordList } = context;
|
|
32
|
+
let covered = new Set();
|
|
33
|
+
let current = null;
|
|
34
|
+
forEachToken(unit, (tokens, i) => {
|
|
35
|
+
if (tokens !== current) {
|
|
36
|
+
current = tokens;
|
|
37
|
+
covered = coveredByPhrases(tokens, lexicon.technicalNounPhrases);
|
|
38
|
+
}
|
|
39
|
+
const token = tokens[i];
|
|
40
|
+
if (!isWord(token) || !isCounted(token))
|
|
41
|
+
return;
|
|
42
|
+
const lower = token.lower;
|
|
43
|
+
if (lower.length < 5 || !/^[a-z]+ing$/.test(lower))
|
|
44
|
+
return;
|
|
45
|
+
if (NON_VERB_ING.has(lower) || lexicon.technicalNouns.has(lower) || lexicon.properNouns.has(lower) || lexicon.allowedWords.has(lower))
|
|
46
|
+
return;
|
|
47
|
+
if (wordList.words.has(lower) || covered.has(i))
|
|
48
|
+
return;
|
|
49
|
+
if (!isIngVerbUse(tokens, i))
|
|
50
|
+
return;
|
|
51
|
+
const base = baseForm(lower, lexicon.verbs);
|
|
52
|
+
const example = base === null ? "" : `, for example "when you ${base} ..." or "to ${base} ..."`;
|
|
53
|
+
context.report({
|
|
54
|
+
...tokenRange(tokens, i, i + 1),
|
|
55
|
+
message: `Do not use "${token.text}" as a verb. Use a simple tense, the infinitive or a noun${example}. If "${lower}" is a technical noun, add it to technicalNouns.`,
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=ing-verb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ing-verb.js","sourceRoot":"","sources":["../../src/rules/ing-verb.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latin-abbreviation.d.ts","sourceRoot":"","sources":["../../src/rules/latin-abbreviation.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAiBhE,eAAO,MAAM,iBAAiB,EAAG,IA2BhC,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { isWord } from "../text/tokens.js";
|
|
2
|
+
import { forEachToken, tokenRange } from "./rule.js";
|
|
3
|
+
// A map, not an object literal, so that a word such as "constructor" does not find an Object property.
|
|
4
|
+
const HELP = new Map([
|
|
5
|
+
["e.g", { name: "e.g.", help: "Write \"for example\"." }],
|
|
6
|
+
["eg", { name: "eg.", help: "Write \"for example\"." }],
|
|
7
|
+
["i.e", { name: "i.e.", help: "Write \"that is\", or write a separate sentence." }],
|
|
8
|
+
["ie", { name: "ie.", help: "Write \"that is\", or write a separate sentence." }],
|
|
9
|
+
["etc", { name: "etc.", help: "Give all the items, or write \"for example\" before the items." }],
|
|
10
|
+
["vs", { name: "vs.", help: "Write \"compared to\", \"and\" or \"or\"." }],
|
|
11
|
+
["viz", { name: "viz.", help: "Write \"that is\" or \"for example\"." }],
|
|
12
|
+
["cf", { name: "cf.", help: "Write \"compare with\" or \"refer to\"." }],
|
|
13
|
+
]);
|
|
14
|
+
/** Abbreviations that are a problem only with a period after them, because the letters alone can be another word. */
|
|
15
|
+
const NEEDS_PERIOD = new Set(["eg", "ie", "cf"]);
|
|
16
|
+
export const latinAbbreviation = {
|
|
17
|
+
id: "latin-abbreviation",
|
|
18
|
+
description: "Find Latin abbreviations: e.g., i.e., etc., vs., viz., cf. and et al.",
|
|
19
|
+
ste: "GR-6",
|
|
20
|
+
defaultSeverity: "error",
|
|
21
|
+
scope: "word",
|
|
22
|
+
check(unit, context) {
|
|
23
|
+
forEachToken(unit, (tokens, i) => {
|
|
24
|
+
const token = tokens[i];
|
|
25
|
+
if (!isWord(token))
|
|
26
|
+
return;
|
|
27
|
+
const next = tokens[i + 1];
|
|
28
|
+
const period = next !== undefined && next.kind === "punct" && next.text === "." && !next.spaceBefore;
|
|
29
|
+
const end = period ? i + 2 : i + 1;
|
|
30
|
+
if (token.lower === "et" && isWord(next) && next.lower === "al") {
|
|
31
|
+
const after = tokens[i + 2];
|
|
32
|
+
const withPeriod = after !== undefined && after.text === "." && !after.spaceBefore;
|
|
33
|
+
context.report({ ...tokenRange(tokens, i, withPeriod ? i + 3 : i + 2), message: "Do not use \"et al.\". Write \"and others\", or give the names." });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const entry = HELP.get(token.lower);
|
|
37
|
+
if (entry === undefined)
|
|
38
|
+
return;
|
|
39
|
+
// "VS" in capital letters is a name (for example "VS Code"), not "versus".
|
|
40
|
+
if (token.lower === "vs" && token.text === "VS")
|
|
41
|
+
return;
|
|
42
|
+
if (NEEDS_PERIOD.has(token.lower) && (!period || token.text !== token.lower))
|
|
43
|
+
return;
|
|
44
|
+
context.report({ ...tokenRange(tokens, i, end), message: `Do not use the Latin abbreviation "${entry.name}". ${entry.help}` });
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=latin-abbreviation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latin-abbreviation.js","sourceRoot":"","sources":["../../src/rules/latin-abbreviation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Lexicon } from "../lexicon.js";
|
|
2
|
+
import { type Token } from "../text/tokens.js";
|
|
3
|
+
import { type Rule } from "./rule.js";
|
|
4
|
+
/** The message when the sentence at `tokens` starts without a subject, or null. */
|
|
5
|
+
export declare function missingSubject(tokens: readonly Token[], lexicon: Lexicon): {
|
|
6
|
+
index: number;
|
|
7
|
+
message: string;
|
|
8
|
+
} | null;
|
|
9
|
+
/**
|
|
10
|
+
* The rule examines the summary and the `@remarks` text of doc comments.
|
|
11
|
+
* For example, "Returns the value." and "Called when the page is hidden."
|
|
12
|
+
* omit the subject. Text after `@param` and `@returns`, and list items, can
|
|
13
|
+
* be fragments, so the rule does not examine them.
|
|
14
|
+
*/
|
|
15
|
+
export declare const missingSubjectRule: Rule;
|
|
16
|
+
//# sourceMappingURL=missing-subject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-subject.d.ts","sourceRoot":"","sources":["../../src/rules/missing-subject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAoC,KAAK,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEjF,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AA6ElD,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,MAAM,EAAG,SAAS,KAAK,EAAE,EAAE,OAAO,EAAG,OAAO,GAAI;IAAE,KAAK,EAAG,MAAM,CAAC;IAAC,OAAO,EAAG,MAAM,CAAA;CAAE,GAAG,IAAI,CAuBzH;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAG,IAejC,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { isParticiple, nextCounted, startsObject } from "../text/grammar.js";
|
|
2
|
+
import { isCapitalized, isCounted, isWord } from "../text/tokens.js";
|
|
3
|
+
import { BE_FORMS, CONJUNCTIONS, DETERMINERS, HAVE_FORMS, MODALS, PREPOSITIONS, SUBJECT_PRONOUNS } from "../text/words.js";
|
|
4
|
+
import { tokenRange } from "./rule.js";
|
|
5
|
+
/** Auxiliary verbs that start a sentence without a subject: "Is true when ...", "Can be null.". */
|
|
6
|
+
const AUXILIARY_STARTS = new Set(["is", "are", "was", "were", "has", "have", "had", "does", "can", "cannot", "must", "will", "should", "may", "might", "would", "could"]);
|
|
7
|
+
/** Words that end in -s but are not verbs. */
|
|
8
|
+
const NOT_VERBS = new Set([
|
|
9
|
+
"this", "its", "always", "perhaps", "sometimes", "whereas", "unless", "plus", "thus", "yes", "less", "across",
|
|
10
|
+
"towards", "afterwards", "besides", "nevertheless", "regardless", "various", "numerous", "previous", "analysis",
|
|
11
|
+
"basis", "bias", "canvas", "status", "series", "species", "atlas", "alias", "chaos", "corpus", "focus", "bonus",
|
|
12
|
+
]);
|
|
13
|
+
/** Words after a participle that show a missing subject: "Called when ...", "Used by ...". */
|
|
14
|
+
const AFTER_PARTICIPLE = new Set([...PREPOSITIONS, "when", "if", "once", "only", "while", "as", "whenever", "unless"]);
|
|
15
|
+
function stems(word) {
|
|
16
|
+
const forms = [word.slice(0, -1)];
|
|
17
|
+
if (word.endsWith("es"))
|
|
18
|
+
forms.push(word.slice(0, -2));
|
|
19
|
+
if (word.endsWith("ies"))
|
|
20
|
+
forms.push(word.slice(0, -3) + "y");
|
|
21
|
+
return forms;
|
|
22
|
+
}
|
|
23
|
+
/** True when a comma comes later and a subject comes after it: "Based on X, the monitor ...". */
|
|
24
|
+
function hasLaterSubject(tokens, from) {
|
|
25
|
+
for (let i = from; i < tokens.length; i++) {
|
|
26
|
+
const token = tokens[i];
|
|
27
|
+
if (token.kind !== "punct" || token.text !== ",")
|
|
28
|
+
continue;
|
|
29
|
+
const next = tokens[nextCounted(tokens, i + 1)];
|
|
30
|
+
if (next === undefined)
|
|
31
|
+
return false;
|
|
32
|
+
return next.kind === "code" || isCapitalized(next) || (isWord(next) && (DETERMINERS.has(next.lower) || SUBJECT_PRONOUNS.has(next.lower)));
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const PLURAL_AUXILIARIES = new Set(["are", "were", "have", "do", "don't", "aren't", "weren't", "can", "cannot", "must", "will"]);
|
|
37
|
+
/**
|
|
38
|
+
* True when a verb for a plural subject comes later, after a noun:
|
|
39
|
+
* "Samples at or above this value wait ...", "Values below zero are ...".
|
|
40
|
+
* Then the first word is a plural noun, not a verb.
|
|
41
|
+
*/
|
|
42
|
+
function hasPluralVerbLater(tokens, from, lexicon) {
|
|
43
|
+
for (let i = from; i < tokens.length; i++) {
|
|
44
|
+
const token = tokens[i];
|
|
45
|
+
const previous = tokens[i - 1];
|
|
46
|
+
if (!isWord(token) || !isWord(previous))
|
|
47
|
+
continue;
|
|
48
|
+
if (DETERMINERS.has(previous.lower) || PREPOSITIONS.has(previous.lower) || MODALS.has(previous.lower) || previous.lower === "not")
|
|
49
|
+
continue;
|
|
50
|
+
if (PLURAL_AUXILIARIES.has(token.lower))
|
|
51
|
+
return true;
|
|
52
|
+
if (lexicon.verbs.has(token.lower) && !token.lower.endsWith("s"))
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
/** Relative pronouns. A word before one of them is a noun: "Tags whose content ...". */
|
|
58
|
+
const RELATIVE_PRONOUNS = new Set(["whose", "which", "who", "whom"]);
|
|
59
|
+
/**
|
|
60
|
+
* True when the words after the first word show that the first word is a
|
|
61
|
+
* plural noun, not a verb. These words show a noun:
|
|
62
|
+
*
|
|
63
|
+
* - An auxiliary verb, a conjunction or "of": "Values are ...", "Values of ..."
|
|
64
|
+
* - "per" or a relative pronoun: "Samples per round", "Tags whose ..."
|
|
65
|
+
* - A base form of a verb: "Monitors ask ..."
|
|
66
|
+
* - A participle and a preposition: "Handles returned by ...".
|
|
67
|
+
*/
|
|
68
|
+
function isNounSubject(tokens, index, lexicon) {
|
|
69
|
+
const next = tokens[index + 1];
|
|
70
|
+
if (!isWord(next))
|
|
71
|
+
return false;
|
|
72
|
+
const lower = next.lower;
|
|
73
|
+
if (BE_FORMS.has(lower) || MODALS.has(lower) || HAVE_FORMS.has(lower) || CONJUNCTIONS.has(lower) || lower === "of")
|
|
74
|
+
return true;
|
|
75
|
+
if (lower === "per" || RELATIVE_PRONOUNS.has(lower))
|
|
76
|
+
return true;
|
|
77
|
+
const after = tokens[index + 2];
|
|
78
|
+
const objectAfter = after === undefined || after.kind === "punct" || startsObject(after) || (isWord(after) && PREPOSITIONS.has(after.lower));
|
|
79
|
+
if (lexicon.verbs.has(lower) && !lower.endsWith("s") && !DETERMINERS.has(lower) && objectAfter)
|
|
80
|
+
return true;
|
|
81
|
+
return isParticiple(lower) && isWord(after) && PREPOSITIONS.has(after.lower);
|
|
82
|
+
}
|
|
83
|
+
/** The message when the sentence at `tokens` starts without a subject, or null. */
|
|
84
|
+
export function missingSubject(tokens, lexicon) {
|
|
85
|
+
const k = nextCounted(tokens, 0);
|
|
86
|
+
const first = tokens[k];
|
|
87
|
+
if (!isWord(first) || !isCapitalized(first))
|
|
88
|
+
return null;
|
|
89
|
+
const lower = first.lower;
|
|
90
|
+
const next = tokens[k + 1];
|
|
91
|
+
const last = [...tokens].reverse().find((token) => token.kind === "punct");
|
|
92
|
+
if (AUXILIARY_STARTS.has(lower)) {
|
|
93
|
+
if (last?.text === "?")
|
|
94
|
+
return null;
|
|
95
|
+
return { index: k, message: `This sentence has no subject. Write the subject before "${first.text}", for example "This value ${lower} ...".` };
|
|
96
|
+
}
|
|
97
|
+
if (/^[a-z]{3,}s$/.test(lower) && !/(ss|us|is|ous|ics|ness)$/.test(lower) && !NOT_VERBS.has(lower)) {
|
|
98
|
+
const knownVerb = stems(lower).some((stem) => lexicon.verbs.has(stem));
|
|
99
|
+
if (next?.text === "," || isNounSubject(tokens, k, lexicon))
|
|
100
|
+
return null;
|
|
101
|
+
if (!knownVerb && !startsObject(next))
|
|
102
|
+
return null;
|
|
103
|
+
if (isWord(next) && PREPOSITIONS.has(next.lower) && hasPluralVerbLater(tokens, k + 2, lexicon))
|
|
104
|
+
return null;
|
|
105
|
+
const example = lower === "returns" ? "This function gives ..." : `This function ${lower} ...`;
|
|
106
|
+
return { index: k, message: `"${first.text}" has no subject. Do not omit the subject. Write a full sentence, for example "${example}".` };
|
|
107
|
+
}
|
|
108
|
+
if (isParticiple(lower) && isWord(next) && AFTER_PARTICIPLE.has(next.lower) && !hasLaterSubject(tokens, k + 1)) {
|
|
109
|
+
return { index: k, message: `"${first.text}" starts a sentence that has no subject. Write a full sentence with a subject in the active voice, for example "The monitor uses this value when ...".` };
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The rule examines the summary and the `@remarks` text of doc comments.
|
|
115
|
+
* For example, "Returns the value." and "Called when the page is hidden."
|
|
116
|
+
* omit the subject. Text after `@param` and `@returns`, and list items, can
|
|
117
|
+
* be fragments, so the rule does not examine them.
|
|
118
|
+
*/
|
|
119
|
+
export const missingSubjectRule = {
|
|
120
|
+
id: "missing-subject",
|
|
121
|
+
description: "Find doc comment sentences that have no subject, for example \"Returns the value.\".",
|
|
122
|
+
ste: "4.2",
|
|
123
|
+
defaultSeverity: "error",
|
|
124
|
+
scope: "sentence",
|
|
125
|
+
check(unit, context) {
|
|
126
|
+
if (unit.origin.source !== "tsdoc" || unit.origin.tsdocSection === "tag" || unit.list !== null)
|
|
127
|
+
return;
|
|
128
|
+
for (const sentence of unit.sentences) {
|
|
129
|
+
if (!sentence.tokens.some(isCounted))
|
|
130
|
+
continue;
|
|
131
|
+
const found = missingSubject(sentence.tokens, context.lexicon);
|
|
132
|
+
if (found === null)
|
|
133
|
+
continue;
|
|
134
|
+
context.report({ ...tokenRange(sentence.tokens, found.index, found.index + 1), message: found.message });
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
//# sourceMappingURL=missing-subject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-subject.js","sourceRoot":"","sources":["../../src/rules/missing-subject.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modal-verb.d.ts","sourceRoot":"","sources":["../../src/rules/modal-verb.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqC,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AA0CzE,eAAO,MAAM,SAAS,EAAG,IA0BxB,CAAC"}
|