@mark1russell7/ste-lint 0.0.0-bootstrap.0 → 0.1.1

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.
Files changed (227) hide show
  1. package/README.md +224 -1
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +9 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/config.d.ts +103 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +251 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/dictionary.d.ts +74 -0
  12. package/dist/dictionary.d.ts.map +1 -0
  13. package/dist/dictionary.js +169 -0
  14. package/dist/dictionary.js.map +1 -0
  15. package/dist/files.d.ts +35 -0
  16. package/dist/files.d.ts.map +1 -0
  17. package/dist/files.js +181 -0
  18. package/dist/files.js.map +1 -0
  19. package/dist/format.d.ts +21 -0
  20. package/dist/format.d.ts.map +1 -0
  21. package/dist/format.js +61 -0
  22. package/dist/format.js.map +1 -0
  23. package/dist/index.d.ts +17 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +17 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/lexicon.d.ts +33 -0
  28. package/dist/lexicon.d.ts.map +1 -0
  29. package/dist/lexicon.js +71 -0
  30. package/dist/lexicon.js.map +1 -0
  31. package/dist/lint.d.ts +28 -0
  32. package/dist/lint.d.ts.map +1 -0
  33. package/dist/lint.js +132 -0
  34. package/dist/lint.js.map +1 -0
  35. package/dist/rules/about-quantity.d.ts +3 -0
  36. package/dist/rules/about-quantity.d.ts.map +1 -0
  37. package/dist/rules/about-quantity.js +34 -0
  38. package/dist/rules/about-quantity.js.map +1 -0
  39. package/dist/rules/index.d.ts +8 -0
  40. package/dist/rules/index.d.ts.map +1 -0
  41. package/dist/rules/index.js +35 -0
  42. package/dist/rules/index.js.map +1 -0
  43. package/dist/rules/ing-verb.d.ts +9 -0
  44. package/dist/rules/ing-verb.d.ts.map +1 -0
  45. package/dist/rules/ing-verb.js +60 -0
  46. package/dist/rules/ing-verb.js.map +1 -0
  47. package/dist/rules/latin-abbreviation.d.ts +3 -0
  48. package/dist/rules/latin-abbreviation.d.ts.map +1 -0
  49. package/dist/rules/latin-abbreviation.js +48 -0
  50. package/dist/rules/latin-abbreviation.js.map +1 -0
  51. package/dist/rules/missing-subject.d.ts +16 -0
  52. package/dist/rules/missing-subject.d.ts.map +1 -0
  53. package/dist/rules/missing-subject.js +138 -0
  54. package/dist/rules/missing-subject.js.map +1 -0
  55. package/dist/rules/modal-verb.d.ts +3 -0
  56. package/dist/rules/modal-verb.d.ts.map +1 -0
  57. package/dist/rules/modal-verb.js +72 -0
  58. package/dist/rules/modal-verb.js.map +1 -0
  59. package/dist/rules/noun-cluster.d.ts +17 -0
  60. package/dist/rules/noun-cluster.d.ts.map +1 -0
  61. package/dist/rules/noun-cluster.js +83 -0
  62. package/dist/rules/noun-cluster.js.map +1 -0
  63. package/dist/rules/paragraph-length.d.ts +3 -0
  64. package/dist/rules/paragraph-length.d.ts.map +1 -0
  65. package/dist/rules/paragraph-length.js +19 -0
  66. package/dist/rules/paragraph-length.js.map +1 -0
  67. package/dist/rules/passive-instruction.d.ts +15 -0
  68. package/dist/rules/passive-instruction.d.ts.map +1 -0
  69. package/dist/rules/passive-instruction.js +38 -0
  70. package/dist/rules/passive-instruction.js.map +1 -0
  71. package/dist/rules/pronouns.d.ts +4 -0
  72. package/dist/rules/pronouns.d.ts.map +1 -0
  73. package/dist/rules/pronouns.js +57 -0
  74. package/dist/rules/pronouns.js.map +1 -0
  75. package/dist/rules/rule.d.ts +46 -0
  76. package/dist/rules/rule.d.ts.map +1 -0
  77. package/dist/rules/rule.js +31 -0
  78. package/dist/rules/rule.js.map +1 -0
  79. package/dist/rules/semicolon.d.ts +3 -0
  80. package/dist/rules/semicolon.d.ts.map +1 -0
  81. package/dist/rules/semicolon.js +20 -0
  82. package/dist/rules/semicolon.js.map +1 -0
  83. package/dist/rules/sentence-length.d.ts +3 -0
  84. package/dist/rules/sentence-length.d.ts.map +1 -0
  85. package/dist/rules/sentence-length.js +31 -0
  86. package/dist/rules/sentence-length.js.map +1 -0
  87. package/dist/rules/unknown-word.d.ts +9 -0
  88. package/dist/rules/unknown-word.d.ts.map +1 -0
  89. package/dist/rules/unknown-word.js +49 -0
  90. package/dist/rules/unknown-word.js.map +1 -0
  91. package/dist/rules/word-list-matcher.d.ts +25 -0
  92. package/dist/rules/word-list-matcher.d.ts.map +1 -0
  93. package/dist/rules/word-list-matcher.js +60 -0
  94. package/dist/rules/word-list-matcher.js.map +1 -0
  95. package/dist/rules/word-list.d.ts +3 -0
  96. package/dist/rules/word-list.d.ts.map +1 -0
  97. package/dist/rules/word-list.js +26 -0
  98. package/dist/rules/word-list.js.map +1 -0
  99. package/dist/run-cli.d.ts +27 -0
  100. package/dist/run-cli.d.ts.map +1 -0
  101. package/dist/run-cli.js +176 -0
  102. package/dist/run-cli.js.map +1 -0
  103. package/dist/source/blocks.d.ts +55 -0
  104. package/dist/source/blocks.d.ts.map +1 -0
  105. package/dist/source/blocks.js +464 -0
  106. package/dist/source/blocks.js.map +1 -0
  107. package/dist/source/inline.d.ts +42 -0
  108. package/dist/source/inline.d.ts.map +1 -0
  109. package/dist/source/inline.js +396 -0
  110. package/dist/source/inline.js.map +1 -0
  111. package/dist/source/jsx.d.ts +18 -0
  112. package/dist/source/jsx.d.ts.map +1 -0
  113. package/dist/source/jsx.js +137 -0
  114. package/dist/source/jsx.js.map +1 -0
  115. package/dist/source/lines.d.ts +34 -0
  116. package/dist/source/lines.d.ts.map +1 -0
  117. package/dist/source/lines.js +83 -0
  118. package/dist/source/lines.js.map +1 -0
  119. package/dist/source/markdown.d.ts +23 -0
  120. package/dist/source/markdown.d.ts.map +1 -0
  121. package/dist/source/markdown.js +42 -0
  122. package/dist/source/markdown.js.map +1 -0
  123. package/dist/source/suppressions.d.ts +38 -0
  124. package/dist/source/suppressions.d.ts.map +1 -0
  125. package/dist/source/suppressions.js +69 -0
  126. package/dist/source/suppressions.js.map +1 -0
  127. package/dist/source/tsdoc.d.ts +40 -0
  128. package/dist/source/tsdoc.d.ts.map +1 -0
  129. package/dist/source/tsdoc.js +176 -0
  130. package/dist/source/tsdoc.js.map +1 -0
  131. package/dist/text/grammar.d.ts +91 -0
  132. package/dist/text/grammar.d.ts.map +1 -0
  133. package/dist/text/grammar.js +289 -0
  134. package/dist/text/grammar.js.map +1 -0
  135. package/dist/text/phrases.d.ts +30 -0
  136. package/dist/text/phrases.d.ts.map +1 -0
  137. package/dist/text/phrases.js +65 -0
  138. package/dist/text/phrases.js.map +1 -0
  139. package/dist/text/sentences.d.ts +45 -0
  140. package/dist/text/sentences.d.ts.map +1 -0
  141. package/dist/text/sentences.js +141 -0
  142. package/dist/text/sentences.js.map +1 -0
  143. package/dist/text/tokens.d.ts +35 -0
  144. package/dist/text/tokens.d.ts.map +1 -0
  145. package/dist/text/tokens.js +113 -0
  146. package/dist/text/tokens.js.map +1 -0
  147. package/dist/text/words.d.ts +58 -0
  148. package/dist/text/words.d.ts.map +1 -0
  149. package/dist/text/words.js +159 -0
  150. package/dist/text/words.js.map +1 -0
  151. package/dist/types.d.ts +18 -0
  152. package/dist/types.d.ts.map +1 -0
  153. package/dist/types.js +20 -0
  154. package/dist/types.js.map +1 -0
  155. package/dist/units.d.ts +47 -0
  156. package/dist/units.d.ts.map +1 -0
  157. package/dist/units.js +42 -0
  158. package/dist/units.js.map +1 -0
  159. package/dist/word-list.d.ts +34 -0
  160. package/dist/word-list.d.ts.map +1 -0
  161. package/dist/word-list.js +90 -0
  162. package/dist/word-list.js.map +1 -0
  163. package/package.json +41 -4
  164. package/src/cli.ts +9 -0
  165. package/src/config.test.ts +188 -0
  166. package/src/config.ts +318 -0
  167. package/src/dictionary.test.ts +82 -0
  168. package/src/dictionary.ts +177 -0
  169. package/src/files.test.ts +107 -0
  170. package/src/files.ts +191 -0
  171. package/src/format.ts +78 -0
  172. package/src/index.test.ts +28 -0
  173. package/src/index.ts +34 -0
  174. package/src/lexicon.ts +92 -0
  175. package/src/lint.test.ts +182 -0
  176. package/src/lint.ts +135 -0
  177. package/src/rules/about-quantity.ts +33 -0
  178. package/src/rules/index.ts +40 -0
  179. package/src/rules/ing-verb.test.ts +48 -0
  180. package/src/rules/ing-verb.ts +54 -0
  181. package/src/rules/latin-abbreviation.ts +46 -0
  182. package/src/rules/missing-subject.test.ts +53 -0
  183. package/src/rules/missing-subject.ts +129 -0
  184. package/src/rules/modal-verb.test.ts +45 -0
  185. package/src/rules/modal-verb.ts +72 -0
  186. package/src/rules/noun-cluster.test.ts +49 -0
  187. package/src/rules/noun-cluster.ts +82 -0
  188. package/src/rules/paragraph-length.test.ts +30 -0
  189. package/src/rules/paragraph-length.ts +19 -0
  190. package/src/rules/passive-instruction.test.ts +38 -0
  191. package/src/rules/passive-instruction.ts +37 -0
  192. package/src/rules/pronouns.test.ts +38 -0
  193. package/src/rules/pronouns.ts +54 -0
  194. package/src/rules/punctuation.test.ts +59 -0
  195. package/src/rules/rule.ts +73 -0
  196. package/src/rules/semicolon.ts +19 -0
  197. package/src/rules/sentence-length.test.ts +52 -0
  198. package/src/rules/sentence-length.ts +32 -0
  199. package/src/rules/unknown-word.test.ts +81 -0
  200. package/src/rules/unknown-word.ts +43 -0
  201. package/src/rules/word-list-matcher.ts +68 -0
  202. package/src/rules/word-list.test.ts +110 -0
  203. package/src/rules/word-list.ts +25 -0
  204. package/src/run-cli.test.ts +189 -0
  205. package/src/run-cli.ts +193 -0
  206. package/src/source/blocks.ts +534 -0
  207. package/src/source/inline.test.ts +92 -0
  208. package/src/source/inline.ts +416 -0
  209. package/src/source/jsx.test.ts +46 -0
  210. package/src/source/jsx.ts +147 -0
  211. package/src/source/lines.test.ts +51 -0
  212. package/src/source/lines.ts +91 -0
  213. package/src/source/markdown.test.ts +210 -0
  214. package/src/source/markdown.ts +49 -0
  215. package/src/source/suppressions.ts +79 -0
  216. package/src/source/tsdoc.test.ts +137 -0
  217. package/src/source/tsdoc.ts +189 -0
  218. package/src/text/grammar.ts +304 -0
  219. package/src/text/phrases.ts +72 -0
  220. package/src/text/sentences.ts +148 -0
  221. package/src/text/text.test.ts +262 -0
  222. package/src/text/tokens.ts +135 -0
  223. package/src/text/words.ts +183 -0
  224. package/src/types.ts +39 -0
  225. package/src/units.ts +86 -0
  226. package/src/word-list.ts +128 -0
  227. package/ste.config.schema.json +87 -0
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Closed word classes and short word lists for the grammar heuristics.
3
+ *
4
+ * These lists are general English grammar. They do not come from the
5
+ * ASD-STE100 dictionary. The linter cannot tag parts of speech, so the
6
+ * heuristics look at the words near a word to guess how the text uses it.
7
+ */
8
+
9
+ const set = (words : string) : ReadonlySet<string> => new Set(words.trim().split(/\s+/));
10
+
11
+ export const DETERMINERS : ReadonlySet<string> = set(`
12
+ a an the this that these those each every all any some no its their your our my his her
13
+ another other either neither both many much more most few several such which whose what one
14
+ `);
15
+
16
+ export const SUBJECT_PRONOUNS : ReadonlySet<string> = set("i you we they he she it this that which who there");
17
+
18
+ export const OBJECT_PRONOUNS : ReadonlySet<string> = set("me you us them him her it itself themselves this these those");
19
+
20
+ /** Forms of "be", with the contractions that contain "is", "are" or "am". */
21
+ export const BE_FORMS : ReadonlySet<string> = set(`
22
+ am is are was were be been being isn't aren't wasn't weren't it's that's there's here's what's who's
23
+ he's she's they're we're you're i'm
24
+ `);
25
+
26
+ /** Words before a past participle that make a passive: forms of "be" and "get". */
27
+ export const PASSIVE_AUXILIARIES : ReadonlySet<string> = new Set([...BE_FORMS, "get", "gets", "got", "gotten", "getting"]);
28
+
29
+ export const HAVE_FORMS : ReadonlySet<string> = set("have has had having haven't hasn't hadn't");
30
+
31
+ export const DO_FORMS : ReadonlySet<string> = set("do does did don't doesn't didn't");
32
+
33
+ export const MODALS : ReadonlySet<string> = set(`
34
+ can cannot could may might must shall should will would can't couldn't mustn't shouldn't won't wouldn't
35
+ `);
36
+
37
+ export const PREPOSITIONS : ReadonlySet<string> = set(`
38
+ about above across after against along among around as at before behind below beneath beside between
39
+ beyond by despite down during except for from in inside into like near of off on onto out outside over
40
+ past per since through throughout to toward towards under until up upon via with within without
41
+ `);
42
+
43
+ export const CONJUNCTIONS : ReadonlySet<string> = set(`
44
+ and or but nor so yet if when while because although though unless until whether that where once than
45
+ `);
46
+
47
+ /** Words that start a condition or purpose clause before the main clause. */
48
+ export const CLAUSE_STARTERS : ReadonlySet<string> = set(`
49
+ if when whenever before after while until unless once to for in on at during because as since where
50
+ with without by from although though
51
+ `);
52
+
53
+ /** Words that can come before the verb of an imperative sentence. */
54
+ export const LEADING_ADVERBS : ReadonlySet<string> = set(`
55
+ then first next also finally optionally now please second third afterward afterwards alternatively
56
+ instead always only just simply again manually carefully immediately
57
+ `);
58
+
59
+ /** Adverbs that can come between an auxiliary verb and a participle. */
60
+ export const MIDDLE_ADVERBS : ReadonlySet<string> = set(`
61
+ not also always never only then still already often usually automatically immediately sometimes just
62
+ all both each first again correctly currently directly fully later normally now once possibly
63
+ probably quickly rarely really safely silently simply successfully typically
64
+ `);
65
+
66
+ /** Words that tell the reader that a clause is a condition, so a participle after "be" is a state. */
67
+ export const CONDITION_MARKERS : ReadonlySet<string> = set(`
68
+ if when whenever until unless while after before once whether sure that because since
69
+ `);
70
+
71
+ export const PARTICLES : ReadonlySet<string> = set("up out down off back over away");
72
+
73
+ export const NUMBER_WORDS : ReadonlySet<string> = set(`
74
+ zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen
75
+ seventeen eighteen nineteen twenty thirty forty fifty sixty seventy eighty ninety hundred hundreds
76
+ thousand thousands million millions billion billions dozen dozens half twice
77
+ `);
78
+
79
+ /** Units of measurement. A number and its unit count as one word (STE Rule 8.6). */
80
+ export const UNITS : ReadonlySet<string> = set(`
81
+ ns µs μs us ms s sec secs second seconds millisecond milliseconds microsecond microseconds nanosecond
82
+ nanoseconds min mins minute minutes h hr hrs hour hours day days week weeks month months year years
83
+ b byte bytes kb mb gb tb kib mib gib tib kilobyte kilobytes megabyte megabytes gigabyte gigabytes
84
+ % percent px pixel pixels hz khz mhz ghz fps °c °f degree degrees kg g mm cm m km kilogram kilograms
85
+ gram grams kilometer kilometers liter liters litre litres inch inches
86
+ `);
87
+
88
+ /**
89
+ * Words that end in "-ing" but are usually not verb forms: nouns, adjectives,
90
+ * prepositions, and base forms, for example "bring".
91
+ */
92
+ export const NON_VERB_ING : ReadonlySet<string> = set(`
93
+ thing things string strings ring rings spring springs king kings wing wings sing bring brings during
94
+ something anything everything nothing morning mornings evening evenings ceiling ceilings sibling
95
+ siblings duckling earring inkling offspring pudding sterling swing swings sling wring cling fling
96
+ sting
97
+ outstanding ongoing upcoming incoming outgoing missing remaining pending interesting confusing
98
+ misleading surprising promising demanding challenging exciting annoying boring willing worrying
99
+ overwhelming existing corresponding underlying trailing preceding notwithstanding
100
+ timing padding heading spacing wording warning beginning opening
101
+ `);
102
+
103
+ /** Irregular past participles. A participle after "be" makes a passive. */
104
+ export const IRREGULAR_PARTICIPLES : ReadonlySet<string> = set(`
105
+ arisen awoken begun bent bitten blown bound broken brought built bought caught chosen cut dealt done
106
+ drawn driven eaten fallen fed felt fought found flown forbidden forgotten forgiven frozen gotten given
107
+ gone grown hung heard hidden hit held hurt kept known laid led left lent let lost made meant met paid
108
+ put quit read rebuilt reset rerun ridden rung risen run said seen sought sold sent set shaken shown
109
+ shut sung sunk slept slid spoken spent spun split spread stood stolen stuck struck sworn swept taken
110
+ taught torn told thought thrown undone understood unset upset withdrawn woken worn won wound written
111
+ overridden rewritten overwritten bitten
112
+ `);
113
+
114
+ /** Words that end in "-ed" but are not past participles. */
115
+ export const NOT_PARTICIPLE_ED : ReadonlySet<string> = set(`
116
+ need needed bed red shed feed seed speed bleed breed deed embed exceed proceed succeed indeed hundred
117
+ kindred sacred naked wicked rugged ragged aged beloved learned
118
+ `);
119
+
120
+ /**
121
+ * Common verbs in their base form. The imperative heuristic and the
122
+ * missing-subject heuristic use this list. The project glossary adds
123
+ * technical verbs to it.
124
+ */
125
+ export const COMMON_VERBS : ReadonlySet<string> = set(`
126
+ accept access activate add adjust allow apply assign attach avoid begin bind block break bring build
127
+ calculate call cancel capture change check choose clean clear click clone close collect combine commit
128
+ compare compile complete compute configure confirm connect consider contain continue control convert
129
+ copy correct count cover create deactivate debug decide declare decrease define delay delete deliver
130
+ depend deploy describe destroy detach detect determine disable disconnect discard dispatch display
131
+ dispose do download drag drop emit enable end enforce enqueue ensure enter estimate examine exclude
132
+ execute exit expand expect explain export expose extend extract fail fetch fill filter find finish fire
133
+ fix flag flush follow force forward freeze generate get give go grant group handle hold ignore implement
134
+ import include increase indicate initialize insert inspect install invoke keep kill launch leave let
135
+ limit link list listen load lock log look make manage map mark match measure merge migrate mock modify
136
+ monitor mount move name navigate need note notify observe obtain omit open operate override parse pass
137
+ paste pause perform pick pin place point poll post prefer prepare press prevent print process produce
138
+ provide publish pull push put queue read rebuild reboot receive record reduce refer refresh register
139
+ reject release reload remember remove rename render repeat replace report request require reschedule
140
+ reset resize resolve respond restart restore resume retry return reuse review revert rotate run sample
141
+ save schedule scroll search select send serve set share show shut sign skip sleep sort specify split
142
+ start stay step stop store submit subscribe substitute supply support swap switch sync take tap tell
143
+ terminate test throttle throw tick toggle touch track transform trigger try turn type uncomment
144
+ uninstall unlock unpin unregister unsubscribe update upgrade upload use validate verify view visit wait
145
+ wake warn watch wrap write yield
146
+ agree appear arrive ask become belong come differ exist happen help know occur overlap reach remain
147
+ seem survive think want
148
+ `);
149
+
150
+ /**
151
+ * Nouns that software text often uses before another noun. The noun-cluster
152
+ * heuristic counts only these words, technical nouns, proper nouns,
153
+ * abbreviations and code. Words that are frequently verbs are not in this
154
+ * list, so the heuristic does not count a verb as a noun.
155
+ */
156
+ export const COMMON_NOUNS : ReadonlySet<string> = set(`
157
+ attribute browser buffer bucket byte cache callback channel chart clock collector column component config
158
+ configuration console constructor container context counter dashboard data database delay dependency
159
+ deployment device dialog directory document domain duration element endpoint entry environment error
160
+ event exception exporter factory field file folder frame framework function gauge handler hardware
161
+ header heap heartbeat histogram history host id identifier index input instance interface interval item
162
+ key keyboard label latency layer layout length level library lifecycle line listener logger loop
163
+ machine memory message meter method metric millisecond mode model module monitor mouse network node
164
+ number object observer offset option origin output owner package page pair parameter parser path
165
+ pattern payload percentile period permission phase pipeline platform plugin pointer policy pool port
166
+ position pressure priority problem procedure processor profile program project promise property protocol
167
+ provider proxy quantity query range rate ratio reader reason receiver recorder reference region registry
168
+ renderer repository resolution resource response router runtime scheduler schema scope screen script
169
+ second section selector sender sequence server service session setting signal size slot snapshot socket
170
+ source span stack stage standard state statement status storage stream string structure style
171
+ subscriber suite summary symbol syntax system tab table target task template terminal text thread
172
+ threshold time timeout timer timestamp title token tool topic trace transaction transport tree tuple
173
+ unit url usage user utility validator value variable vendor version viewport visibility warning window
174
+ worker workspace wrapper
175
+ `);
176
+
177
+ /** Abbreviations after which a period does not end a sentence. */
178
+ export const NO_BREAK_ABBREVIATIONS : ReadonlySet<string> = set(`
179
+ e.g i.e vs viz cf al approx mr mrs dr st jr sr inc ltd corp u.s a.m p.m
180
+ `);
181
+
182
+ /** Abbreviations that do not end a sentence when a number comes after them, for example "Fig. 3". */
183
+ export const NUMBER_ABBREVIATIONS : ReadonlySet<string> = set("fig figs eq eqs no nos ref vol ch pp p sec para");
package/src/types.ts ADDED
@@ -0,0 +1,39 @@
1
+ export type Severity = "error" | "warning";
2
+
3
+ /** The setting of a rule in `ste.config.json`. */
4
+ export type RuleSetting = Severity | "off";
5
+
6
+ export const RULE_IDS = [
7
+ "sentence-length",
8
+ "paragraph-length",
9
+ "modal-verb",
10
+ "semicolon",
11
+ "latin-abbreviation",
12
+ "about-quantity",
13
+ "word-list",
14
+ "gendered-pronoun",
15
+ "first-person",
16
+ "passive-instruction",
17
+ "noun-cluster",
18
+ "missing-subject",
19
+ "ing-verb",
20
+ "unknown-word",
21
+ ] as const;
22
+
23
+ export type RuleId = (typeof RULE_IDS)[number];
24
+
25
+ /** One problem that the linter found. Lines and columns start at 1. */
26
+ export type Finding = {
27
+ readonly file : string;
28
+ readonly line : number;
29
+ readonly column : number;
30
+ readonly endLine : number;
31
+ readonly endColumn : number;
32
+ readonly ruleId : RuleId;
33
+ readonly severity : Severity;
34
+ readonly message : string;
35
+ };
36
+
37
+ export function isRuleId(value : string) : value is RuleId {
38
+ return (RULE_IDS as readonly string[]).includes(value);
39
+ }
package/src/units.ts ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Prose units: the blocks of text that the rules examine, with their tokens
3
+ * and sentences.
4
+ */
5
+
6
+ import type { Lexicon } from "./lexicon.js";
7
+ import type { ListContext, ProseBlock } from "./source/blocks.js";
8
+ import { normalizeInline } from "./source/inline.js";
9
+ import { isInstruction } from "./text/grammar.js";
10
+ import { countWords, splitSentences } from "./text/sentences.js";
11
+ import { isCounted, tokenize, type Token } from "./text/tokens.js";
12
+
13
+ export type TsdocSection = "summary" | "remarks" | "tag";
14
+
15
+ /** Where a block comes from. */
16
+ export type BlockOrigin = {
17
+ readonly source : "markdown" | "mdx" | "tsdoc" | "jsx";
18
+ /** For a doc comment: the summary, the `@remarks` section, or the text of another block tag. */
19
+ readonly tsdocSection : TsdocSection | null;
20
+ /** For a doc comment: the block tag, for example `@param`, or null for the summary. */
21
+ readonly tsdocTag : string | null;
22
+ };
23
+
24
+ export type ExtractedBlock = {
25
+ readonly block : ProseBlock;
26
+ readonly origin : BlockOrigin;
27
+ };
28
+
29
+ export type Sentence = {
30
+ /** All tokens of the sentence, with the punctuation. */
31
+ readonly tokens : readonly Token[];
32
+ /** The STE word count. */
33
+ readonly words : number;
34
+ /** The tokens in each top-level parenthesis. Each one counts as a separate sentence. */
35
+ readonly parentheticals : readonly (readonly Token[])[];
36
+ /** True when the sentence is an instruction (imperative). */
37
+ readonly instruction : boolean;
38
+ readonly start : number;
39
+ readonly end : number;
40
+ };
41
+
42
+ export type UnitKind = ProseBlock["kind"];
43
+
44
+ export type ProseUnit = {
45
+ readonly kind : UnitKind;
46
+ readonly origin : BlockOrigin;
47
+ readonly list : ListContext | null;
48
+ readonly tokens : readonly Token[];
49
+ readonly sentences : readonly Sentence[];
50
+ readonly start : number;
51
+ readonly end : number;
52
+ };
53
+
54
+ /** This function makes a prose unit from a block. The result is null when the block has no words. */
55
+ export function buildUnit(extracted : ExtractedBlock, lexicon : Lexicon) : ProseUnit | null {
56
+ const { block, origin } = extracted;
57
+ const inline = normalizeInline(block.lines, { mdx : origin.source === "mdx" || origin.source === "jsx", tsdoc : origin.source === "tsdoc" });
58
+ return unitFromTokens(tokenize(inline), block, origin, lexicon);
59
+ }
60
+
61
+ /** This function makes a prose unit from the tokens of a block. */
62
+ export function unitFromTokens(tokens : readonly Token[], block : Pick<ProseBlock, "kind" | "list">, origin : BlockOrigin, lexicon : Lexicon) : ProseUnit | null {
63
+ if (!tokens.some(isCounted)) return null;
64
+ const ranges = block.kind === "paragraph" ? splitSentences(tokens) : [{ from : 0, to : tokens.length }];
65
+ const sentences : Sentence[] = ranges.map((range) => {
66
+ const sentenceTokens = tokens.slice(range.from, range.to);
67
+ const count = countWords(sentenceTokens, { properNouns : lexicon.properNounPhrases });
68
+ return {
69
+ tokens : sentenceTokens,
70
+ words : count.words,
71
+ parentheticals : count.parentheticals,
72
+ instruction : block.kind === "paragraph" && isInstruction(sentenceTokens, { verbs : lexicon.verbs }),
73
+ start : sentenceTokens[0]!.start,
74
+ end : sentenceTokens[sentenceTokens.length - 1]!.end,
75
+ };
76
+ });
77
+ return {
78
+ kind : block.kind,
79
+ origin,
80
+ list : block.list,
81
+ tokens,
82
+ sentences,
83
+ start : tokens[0]!.start,
84
+ end : tokens[tokens.length - 1]!.end,
85
+ };
86
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * The project word list: plain-language substitutions for the documentation
3
+ * of this repository. This list is the style guide of the project, written
4
+ * for it. It is not a copy of the ASD-STE100 dictionary. The local
5
+ * dictionary file (refer to `dictionary.ts`) does that job, and it is not
6
+ * part of the repository at any time.
7
+ *
8
+ * Each entry has the words or phrases to find, the words to write instead,
9
+ * and a severity. `ste.config.json` can add entries, change them, or set an
10
+ * entry to "off".
11
+ */
12
+
13
+ import type { Severity } from "./types.js";
14
+
15
+ export type WordListEntry = {
16
+ /** A short name of the entry. A configuration entry with the same ID changes this entry. */
17
+ readonly id : string;
18
+ /** The words and phrases to find. The match ignores case. */
19
+ readonly match : readonly string[];
20
+ /** The words to write instead, as the message shows them. Null when the fix is to remove the word. */
21
+ readonly suggest : string | null;
22
+ /** More help for the message, or null. */
23
+ readonly note : string | null;
24
+ readonly severity : Severity;
25
+ /**
26
+ * True when the word can be a noun too. Then the rule reports the word
27
+ * only when the words near it show a verb ("Run the tests", but not "a
28
+ * test run").
29
+ */
30
+ readonly verbOnly : boolean;
31
+ /** A special context: "reference" finds "see" only where it tells the reader to look at other text. */
32
+ readonly context : "reference" | null;
33
+ };
34
+
35
+ type EntryInput = {
36
+ readonly match : readonly string[];
37
+ readonly suggest? : string;
38
+ readonly note? : string;
39
+ readonly severity? : Severity;
40
+ readonly verbOnly? : boolean;
41
+ readonly context? : "reference";
42
+ readonly id? : string;
43
+ };
44
+
45
+ function entry(input : EntryInput) : WordListEntry {
46
+ return {
47
+ id : input.id ?? input.match[0]!,
48
+ match : input.match,
49
+ suggest : input.suggest ?? null,
50
+ note : input.note ?? null,
51
+ severity : input.severity ?? "error",
52
+ verbOnly : input.verbOnly ?? false,
53
+ context : input.context ?? null,
54
+ };
55
+ }
56
+
57
+ /** The default word list. */
58
+ export const DEFAULT_WORD_LIST : readonly WordListEntry[] = [
59
+ // Long or formal words that have a short, common equivalent.
60
+ entry({ match : ["utilize", "utilizes", "utilized", "utilizing", "utilization", "utilise", "utilises", "utilised", "utilising"], suggest : "\"use\"" }),
61
+ entry({ match : ["initiate", "initiates", "initiated", "initiating"], suggest : "\"start\"" }),
62
+ entry({ match : ["ensure", "ensures", "ensured", "ensuring"], suggest : "\"make sure\"", note : "Write \"that\" after it: \"make sure that ...\"." }),
63
+ entry({ match : ["via"], suggest : "\"through\" or \"with\"" }),
64
+ entry({ match : ["leverage", "leverages", "leveraged", "leveraging"], suggest : "\"use\"" }),
65
+ entry({ match : ["facilitate", "facilitates", "facilitated", "facilitating"], suggest : "\"help\" or \"make ... easier\"" }),
66
+ entry({ match : ["commence", "commences", "commenced", "commencing"], suggest : "\"start\"" }),
67
+ entry({ match : ["terminate", "terminates", "terminated", "terminating"], suggest : "\"stop\"" }),
68
+ entry({ match : ["obtain", "obtains", "obtained", "obtaining"], suggest : "\"get\"" }),
69
+ entry({ match : ["assist", "assists", "assisted", "assisting"], suggest : "\"help\"" }),
70
+ entry({ match : ["modify", "modifies", "modified", "modifying"], suggest : "\"change\"" }),
71
+ entry({ match : ["indicate", "indicates", "indicated", "indicating"], suggest : "\"show\"" }),
72
+ entry({ match : ["demonstrate", "demonstrates", "demonstrated", "demonstrating"], suggest : "\"show\"" }),
73
+ entry({ match : ["perform", "performs", "performed", "performing"], suggest : "\"do\"" }),
74
+ entry({ match : ["attempt", "attempts", "attempted", "attempting"], suggest : "\"try\"" }),
75
+ entry({ match : ["numerous"], suggest : "\"many\", or give the number" }),
76
+ entry({ match : ["additional"], suggest : "\"more\"" }),
77
+ entry({ match : ["additionally"], suggest : "\"also\"" }),
78
+ entry({ match : ["regarding"], suggest : "\"about\"" }),
79
+ entry({ match : ["hence"], suggest : "\"thus\"" }),
80
+
81
+ // Phrases that have a shorter equivalent.
82
+ entry({ match : ["prior to"], suggest : "\"before\"" }),
83
+ entry({ match : ["in order to"], suggest : "\"to\"" }),
84
+ entry({ match : ["due to the fact that"], suggest : "\"because\"" }),
85
+ entry({ match : ["due to"], suggest : "\"because of\"" }),
86
+ entry({ match : ["in the event that"], suggest : "\"if\"" }),
87
+ entry({ match : ["at this point in time"], suggest : "\"at this time\"" }),
88
+ entry({ match : ["in an effort to"], suggest : "\"to\"" }),
89
+ entry({ match : ["for the purpose of"], suggest : "\"to\" or \"for\"" }),
90
+ entry({ match : ["with respect to", "with regard to"], suggest : "\"about\" or \"for\"" }),
91
+ entry({ match : ["as well as"], suggest : "\"and\"" }),
92
+ entry({ match : ["a number of"], suggest : "\"some\", or give the number" }),
93
+ entry({ match : ["is able to", "are able to", "be able to"], suggest : "\"can\"" }),
94
+ entry({ match : ["such as"], suggest : "\"for example\"" }),
95
+ entry({ match : ["follow these steps", "follow the steps"], suggest : "\"do these steps\" or \"do the steps\"" }),
96
+
97
+ // Connecting words.
98
+ entry({ match : ["however"], suggest : "\"but\"", note : "Start a new sentence with \"But\" if necessary." }),
99
+ entry({ match : ["therefore"], suggest : "\"thus\" or \"as a result\"" }),
100
+ entry({ match : ["whether or not", "whether"], suggest : "\"if\"" }),
101
+
102
+ // Verbs that have a simpler equivalent.
103
+ entry({ match : ["allow", "allows", "allowed", "allowing"], suggest : "\"let\" or \"lets\"", note : "For an adjective, write \"permitted\"." }),
104
+ entry({ match : ["require", "requires", "required", "requiring"], suggest : "\"necessary\"", note : "For example, write \"X is necessary for Y\", or use the imperative." }),
105
+ entry({ match : ["provided that"], suggest : "\"if\"" }),
106
+ entry({ match : ["provide", "provides", "provided", "providing"], suggest : "\"give\" or \"gives\"" }),
107
+ entry({ match : ["execute", "executes", "executed", "executing"], suggest : "\"do\", \"does\" or \"start\"" }),
108
+ entry({ match : ["create", "creates", "created", "creating"], suggest : "\"make\" or \"makes\"" }),
109
+ entry({ match : ["kill", "kills", "killed", "killing"], suggest : "\"stop\"" }),
110
+ entry({ id : "displays", match : ["displayed", "displaying"], suggest : "\"show\" or \"shows\"", severity : "warning" }),
111
+ entry({ id : "display", match : ["display", "displays"], suggest : "\"show\" or \"shows\"", severity : "warning", verbOnly : true }),
112
+ entry({ id : "returns", match : ["returns", "returned", "returning"], suggest : "\"gives\"", severity : "warning", note : "For a function, write \"This function gives ...\"." }),
113
+ entry({ id : "return", match : ["return"], suggest : "\"give\" or \"gives\"", severity : "warning", verbOnly : true }),
114
+ entry({ id : "call", match : ["call", "calls", "called", "calling"], suggest : "\"use\" or \"start\"", severity : "warning", verbOnly : true, note : "This applies when the verb means to start a function." }),
115
+ entry({ id : "ran", match : ["ran"], suggest : "\"started\" or \"operated\"", severity : "warning" }),
116
+ entry({ id : "run", match : ["run", "runs", "running"], suggest : "\"start\", \"starts\" or \"operates\"", severity : "warning", verbOnly : true }),
117
+ entry({ id : "see", match : ["see"], suggest : "\"refer to\"", severity : "warning", context : "reference" }),
118
+
119
+ // Words that do not add information.
120
+ entry({ match : ["simple", "simply", "easily"], severity : "warning", note : "The word tells the reader what to think. Tell the reader what to do." }),
121
+ entry({ match : ["just"], suggest : "\"only\"", severity : "warning", note : "Or remove the word." }),
122
+ entry({ match : ["basically", "obviously", "of course"], severity : "warning", note : "The word does not add information." }),
123
+ entry({ match : ["please"], severity : "warning", note : "Write the instruction in the imperative." }),
124
+
125
+ // Time and negation.
126
+ entry({ match : ["currently", "now"], suggest : "\"at this time\"", note : "Or remove the word if the time is clear." }),
127
+ entry({ match : ["never"], suggest : "\"do not\"", note : "For a description, write \"not ... at any time\"." }),
128
+ ];
@@ -0,0 +1,87 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/mark1russell7/ste-lint/main/ste.config.schema.json",
4
+ "title": "ste-lint configuration",
5
+ "description": "The configuration of ste-lint. All properties are optional.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "$schema": { "type": "string" },
10
+ "include": {
11
+ "description": "Glob patterns of the files to examine, relative to this file.",
12
+ "type": "array",
13
+ "items": { "type": "string" }
14
+ },
15
+ "ignore": {
16
+ "description": "Glob patterns of the files not to examine, relative to this file.",
17
+ "type": "array",
18
+ "items": { "type": "string" }
19
+ },
20
+ "technicalNouns": {
21
+ "description": "Technical nouns of the project glossary. A term can have more than one word.",
22
+ "type": "array",
23
+ "items": { "type": "string" }
24
+ },
25
+ "technicalVerbs": {
26
+ "description": "Technical verbs of the project glossary, in the base form.",
27
+ "type": "array",
28
+ "items": { "type": "string" }
29
+ },
30
+ "properNouns": {
31
+ "description": "Names of products, organizations and standards. A name with more than one word counts as one word.",
32
+ "type": "array",
33
+ "items": { "type": "string" }
34
+ },
35
+ "allowedWords": {
36
+ "description": "Other words that the -ing rule and the unknown-word rule accept.",
37
+ "type": "array",
38
+ "items": { "type": "string" }
39
+ },
40
+ "rules": {
41
+ "description": "The severity of each rule.",
42
+ "type": "object",
43
+ "propertyNames": {
44
+ "enum": [
45
+ "sentence-length", "paragraph-length", "modal-verb", "semicolon", "latin-abbreviation", "about-quantity",
46
+ "word-list", "gendered-pronoun", "first-person", "passive-instruction", "noun-cluster", "missing-subject",
47
+ "ing-verb", "unknown-word"
48
+ ]
49
+ },
50
+ "additionalProperties": { "enum": ["error", "warning", "off"] }
51
+ },
52
+ "wordList": {
53
+ "description": "Entries to add to the project word list, or to change in it.",
54
+ "type": "array",
55
+ "items": {
56
+ "type": "object",
57
+ "additionalProperties": false,
58
+ "anyOf": [{ "required": ["id"] }, { "required": ["match"] }],
59
+ "properties": {
60
+ "id": { "description": "The ID of a default entry to change.", "type": "string" },
61
+ "match": {
62
+ "description": "The words or phrases to find.",
63
+ "anyOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" }, "minItems": 1 }]
64
+ },
65
+ "suggest": { "description": "The words to write instead, as the message shows them.", "type": ["string", "null"] },
66
+ "note": { "description": "More help for the message.", "type": ["string", "null"] },
67
+ "severity": { "enum": ["error", "warning", "off"] },
68
+ "verbOnly": { "description": "Find the words only where they are verbs.", "type": "boolean" }
69
+ }
70
+ }
71
+ },
72
+ "limits": {
73
+ "type": "object",
74
+ "additionalProperties": false,
75
+ "properties": {
76
+ "instructionWords": { "type": "integer", "minimum": 1, "default": 20 },
77
+ "descriptionWords": { "type": "integer", "minimum": 1, "default": 25 },
78
+ "paragraphSentences": { "type": "integer", "minimum": 1, "default": 6 },
79
+ "nounClusterNouns": { "type": "integer", "minimum": 1, "default": 3 }
80
+ }
81
+ },
82
+ "dictionaryPath": {
83
+ "description": "The path of a local dictionary file. Never commit a dictionary. The environment variable STE_DICTIONARY has priority.",
84
+ "type": ["string", "null"]
85
+ }
86
+ }
87
+ }