@mark1russell7/ste-lint 0.0.0-stage → 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 +225 -2
  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 +46 -3
  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
package/dist/files.js ADDED
@@ -0,0 +1,181 @@
1
+ /**
2
+ * File discovery: glob patterns to files.
3
+ *
4
+ * The glob syntax:
5
+ *
6
+ * - `*` matches characters in one path segment
7
+ * - `**` matches zero or more segments
8
+ * - `?` matches one character
9
+ * - `{a,b}` matches one of the alternatives
10
+ * - `[abc]` or `[!abc]` matches one character of a set.
11
+ *
12
+ * Patterns use `/` on all platforms. An absolute pattern is also correct.
13
+ */
14
+ import { existsSync, readdirSync, statSync } from "node:fs";
15
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
16
+ const GLOB_CHARS = /[*?[\]{}]/;
17
+ /** True when `pattern` has glob characters. */
18
+ export function isGlob(pattern) {
19
+ return GLOB_CHARS.test(pattern);
20
+ }
21
+ function escape(char) {
22
+ return /[.+^$()|\\[\]{}]/.test(char) ? `\\${char}` : char;
23
+ }
24
+ /** The index of the `}` that closes the `{` at `open`, or -1. */
25
+ function closingBrace(glob, open) {
26
+ let depth = 0;
27
+ for (let i = open; i < glob.length; i++) {
28
+ if (glob[i] === "{")
29
+ depth++;
30
+ if (glob[i] === "}" && --depth === 0)
31
+ return i;
32
+ }
33
+ return -1;
34
+ }
35
+ /** The alternatives of a `{...}` group. A comma in a nested group does not divide alternatives. */
36
+ function splitAlternatives(body) {
37
+ const parts = [];
38
+ let depth = 0;
39
+ let start = 0;
40
+ for (let i = 0; i < body.length; i++) {
41
+ if (body[i] === "{")
42
+ depth++;
43
+ if (body[i] === "}")
44
+ depth--;
45
+ if (body[i] === "," && depth === 0) {
46
+ parts.push(body.slice(start, i));
47
+ start = i + 1;
48
+ }
49
+ }
50
+ parts.push(body.slice(start));
51
+ return parts;
52
+ }
53
+ function globSource(glob) {
54
+ let source = "";
55
+ let i = 0;
56
+ while (i < glob.length) {
57
+ const char = glob[i];
58
+ if (char === "*") {
59
+ if (glob[i + 1] === "*") {
60
+ const atStart = i === 0 || glob[i - 1] === "/";
61
+ const atEnd = i + 2 === glob.length || glob[i + 2] === "/";
62
+ if (atStart && atEnd) {
63
+ if (glob[i + 2] === "/") {
64
+ source += "(?:.*/)?";
65
+ i += 3;
66
+ }
67
+ else {
68
+ source += ".*";
69
+ i += 2;
70
+ }
71
+ continue;
72
+ }
73
+ }
74
+ source += "[^/]*";
75
+ i++;
76
+ while (glob[i] === "*")
77
+ i++;
78
+ continue;
79
+ }
80
+ if (char === "?") {
81
+ source += "[^/]";
82
+ i++;
83
+ continue;
84
+ }
85
+ if (char === "[") {
86
+ const close = glob.indexOf("]", i + 1);
87
+ if (close !== -1) {
88
+ let set = glob.slice(i + 1, close);
89
+ if (set.startsWith("!"))
90
+ set = "^" + set.slice(1);
91
+ source += `[${set.replace(/\\/g, "\\\\")}]`;
92
+ i = close + 1;
93
+ continue;
94
+ }
95
+ }
96
+ if (char === "{") {
97
+ const close = closingBrace(glob, i);
98
+ if (close !== -1) {
99
+ source += `(?:${splitAlternatives(glob.slice(i + 1, close)).map(globSource).join("|")})`;
100
+ i = close + 1;
101
+ continue;
102
+ }
103
+ }
104
+ source += escape(char);
105
+ i++;
106
+ }
107
+ return source;
108
+ }
109
+ /** This function converts a glob pattern to a regular expression that matches a whole relative path. */
110
+ export function globToRegExp(glob) {
111
+ const normalized = glob.replace(/\\/g, "/").replace(/^\.\//, "");
112
+ return new RegExp(`^${globSource(normalized)}$`);
113
+ }
114
+ /** The part of a pattern before the first segment with glob characters. The walk starts in that directory. */
115
+ export function globBase(glob) {
116
+ const segments = glob.replace(/\\/g, "/").split("/");
117
+ const base = [];
118
+ for (const segment of segments.slice(0, -1)) {
119
+ if (isGlob(segment))
120
+ break;
121
+ base.push(segment);
122
+ }
123
+ return base.join("/");
124
+ }
125
+ function toPosix(path) {
126
+ return path.split(sep).join("/");
127
+ }
128
+ /** The pattern with `/`, relative to `root`. An absolute pattern becomes relative to `root`, so that it can match a relative path. */
129
+ function relativePattern(root, pattern) {
130
+ const normalized = pattern.replace(/\\/g, "/").replace(/^\.\//, "");
131
+ return isAbsolute(normalized) ? toPosix(relative(root, normalized)) : normalized;
132
+ }
133
+ /** Directories that the walk does not enter. */
134
+ const SKIPPED_DIRECTORIES = new Set(["node_modules", ".git"]);
135
+ /**
136
+ * This function finds the files that match the include patterns and no
137
+ * ignore pattern. A pattern without glob characters is a file name, and
138
+ * the ignore patterns do not apply to it. The result has absolute paths,
139
+ * in sorted order, without duplicates.
140
+ */
141
+ export function findFiles(options) {
142
+ const root = resolve(options.root);
143
+ const ignoreRoot = resolve(options.ignoreRoot ?? root);
144
+ const ignore = options.ignore.map((pattern) => globToRegExp(relativePattern(ignoreRoot, pattern)));
145
+ const isIgnored = (path, suffix = "") => {
146
+ const relativePath = toPosix(relative(ignoreRoot, path)) + suffix;
147
+ return ignore.some((pattern) => pattern.test(relativePath));
148
+ };
149
+ const found = new Set();
150
+ for (const pattern of options.include) {
151
+ const normalized = relativePattern(root, pattern);
152
+ if (!isGlob(normalized)) {
153
+ const path = resolve(root, normalized);
154
+ if (existsSync(path) && statSync(path).isFile())
155
+ found.add(path);
156
+ continue;
157
+ }
158
+ const matcher = globToRegExp(normalized);
159
+ const base = resolve(root, globBase(normalized));
160
+ if (!existsSync(base))
161
+ continue;
162
+ const walk = (directory) => {
163
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
164
+ const path = join(directory, entry.name);
165
+ const relativePath = toPosix(relative(root, path));
166
+ if (entry.isDirectory()) {
167
+ // A pattern such as "**/dist/**" matches the files in a directory, so test the directory with a "/" after it.
168
+ if (SKIPPED_DIRECTORIES.has(entry.name) || isIgnored(path) || isIgnored(path, "/"))
169
+ continue;
170
+ walk(path);
171
+ }
172
+ else if (entry.isFile() && matcher.test(relativePath) && !isIgnored(path)) {
173
+ found.add(path);
174
+ }
175
+ }
176
+ };
177
+ walk(base);
178
+ }
179
+ return [...found].sort();
180
+ }
181
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { type Finding, type RuleId } from "./types.js";
2
+ export type RuleCount = {
3
+ readonly errors: number;
4
+ readonly warnings: number;
5
+ };
6
+ export type Summary = {
7
+ /** The number of files that the linter examined. */
8
+ readonly files: number;
9
+ readonly filesWithFindings: number;
10
+ readonly errors: number;
11
+ readonly warnings: number;
12
+ /** The counts of each rule that has findings, in the order of the rule list. */
13
+ readonly byRule: Readonly<Partial<Record<RuleId, RuleCount>>>;
14
+ };
15
+ /** This function counts the findings, by severity and by rule. */
16
+ export declare function summarize(findings: readonly Finding[], files: number): Summary;
17
+ /** The findings as text: one group for each file, then a summary and the counts by rule. */
18
+ export declare function formatText(findings: readonly Finding[], summary: Summary): string;
19
+ /** The findings and the summary as JSON. */
20
+ export declare function formatJson(findings: readonly Finding[], summary: Summary): string;
21
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,MAAM,SAAS,GAAG;IACpB,QAAQ,CAAC,MAAM,EAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAG,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IAClB,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,iBAAiB,EAAG,MAAM,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAG,MAAM,CAAC;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;CAClE,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,QAAQ,EAAG,SAAS,OAAO,EAAE,EAAE,KAAK,EAAG,MAAM,GAAI,OAAO,CAiBjF;AAID,4FAA4F;AAC5F,wBAAgB,UAAU,CAAC,QAAQ,EAAG,SAAS,OAAO,EAAE,EAAE,OAAO,EAAG,OAAO,GAAI,MAAM,CAgCpF;AAED,4CAA4C;AAC5C,wBAAgB,UAAU,CAAC,QAAQ,EAAG,SAAS,OAAO,EAAE,EAAE,OAAO,EAAG,OAAO,GAAI,MAAM,CAEpF"}
package/dist/format.js ADDED
@@ -0,0 +1,61 @@
1
+ import { RULE_IDS } from "./types.js";
2
+ /** This function counts the findings, by severity and by rule. */
3
+ export function summarize(findings, files) {
4
+ const byRule = {};
5
+ for (const id of RULE_IDS) {
6
+ const own = findings.filter((finding) => finding.ruleId === id);
7
+ if (own.length === 0)
8
+ continue;
9
+ byRule[id] = {
10
+ errors: own.filter((finding) => finding.severity === "error").length,
11
+ warnings: own.filter((finding) => finding.severity === "warning").length,
12
+ };
13
+ }
14
+ return {
15
+ files,
16
+ filesWithFindings: new Set(findings.map((finding) => finding.file)).size,
17
+ errors: findings.filter((finding) => finding.severity === "error").length,
18
+ warnings: findings.filter((finding) => finding.severity === "warning").length,
19
+ byRule,
20
+ };
21
+ }
22
+ const plural = (count, word) => `${count} ${word}${count === 1 ? "" : "s"}`;
23
+ /** The findings as text: one group for each file, then a summary and the counts by rule. */
24
+ export function formatText(findings, summary) {
25
+ const lines = [];
26
+ const byFile = new Map();
27
+ for (const finding of findings) {
28
+ const list = byFile.get(finding.file) ?? [];
29
+ list.push(finding);
30
+ byFile.set(finding.file, list);
31
+ }
32
+ for (const [file, list] of byFile) {
33
+ lines.push(file);
34
+ const positions = list.map((finding) => `${finding.line}:${finding.column}`);
35
+ const width = Math.max(...positions.map((position) => position.length));
36
+ list.forEach((finding, index) => {
37
+ lines.push(` ${positions[index].padEnd(width)} ${finding.severity.padEnd(7)} ${finding.message} ${finding.ruleId}`);
38
+ });
39
+ lines.push("");
40
+ }
41
+ const total = summary.errors + summary.warnings;
42
+ if (total === 0) {
43
+ lines.push(`No problems found in ${plural(summary.files, "file")}.`);
44
+ return lines.join("\n") + "\n";
45
+ }
46
+ lines.push(`${plural(total, "problem")} (${plural(summary.errors, "error")}, ${plural(summary.warnings, "warning")}) in ${plural(summary.filesWithFindings, "file")} of ${summary.files}.`);
47
+ lines.push("");
48
+ lines.push("Findings by rule:");
49
+ const entries = Object.entries(summary.byRule);
50
+ const width = Math.max(...entries.map(([id]) => id.length));
51
+ for (const [id, count] of entries) {
52
+ const parts = [count.errors > 0 ? plural(count.errors, "error") : null, count.warnings > 0 ? plural(count.warnings, "warning") : null].filter((part) => part !== null);
53
+ lines.push(` ${id.padEnd(width)} ${String(count.errors + count.warnings).padStart(5)} (${parts.join(", ")})`);
54
+ }
55
+ return lines.join("\n") + "\n";
56
+ }
57
+ /** The findings and the summary as JSON. */
58
+ export function formatJson(findings, summary) {
59
+ return JSON.stringify({ tool: "ste-lint", summary, findings }, null, 2) + "\n";
60
+ }
61
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `@mark1russell7/ste-lint`: a linter for prose in Markdown, MDX and TypeScript doc
3
+ * comments. It is an automated approximation of the writing rules of
4
+ * ASD-STE100 Simplified Technical English. It does not certify that a text
5
+ * obeys the standard.
6
+ */
7
+ export { CONFIG_FILE_NAME, ConfigError, DEFAULT_IGNORE, DEFAULT_INCLUDE, DEFAULT_LIMITS, DICTIONARY_ENV, findConfigFile, loadConfig, mergeWordList, resolveConfig, validateConfig, type Limits, type LimitsConfig, type ResolvedConfig, type SteConfigFile, type WordListEntryConfig, } from "./config.js";
8
+ export { Dictionary, DICTIONARY_FORMAT, DictionaryError, loadDictionary, parseDictionary, type DictionaryEntry, type DictionaryLookup } from "./dictionary.js";
9
+ export { findFiles, globToRegExp } from "./files.js";
10
+ export { formatJson, formatText, summarize, type RuleCount, type Summary } from "./format.js";
11
+ export { buildLexicon, type Lexicon } from "./lexicon.js";
12
+ export { fileKind, Linter, lintText, type FileKind } from "./lint.js";
13
+ export { getRule, RULES, type Rule } from "./rules/index.js";
14
+ export { parseArgs, runCli, USAGE, type CliIo, type CliOptions } from "./run-cli.js";
15
+ export { isRuleId, RULE_IDS, type Finding, type RuleId, type RuleSetting, type Severity } from "./types.js";
16
+ export { DEFAULT_WORD_LIST, type WordListEntry } from "./word-list.js";
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACd,cAAc,EACd,cAAc,EACd,UAAU,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,mBAAmB,GAC3B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC/J,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC5G,OAAO,EAAE,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `@mark1russell7/ste-lint`: a linter for prose in Markdown, MDX and TypeScript doc
3
+ * comments. It is an automated approximation of the writing rules of
4
+ * ASD-STE100 Simplified Technical English. It does not certify that a text
5
+ * obeys the standard.
6
+ */
7
+ export { CONFIG_FILE_NAME, ConfigError, DEFAULT_IGNORE, DEFAULT_INCLUDE, DEFAULT_LIMITS, DICTIONARY_ENV, findConfigFile, loadConfig, mergeWordList, resolveConfig, validateConfig, } from "./config.js";
8
+ export { Dictionary, DICTIONARY_FORMAT, DictionaryError, loadDictionary, parseDictionary } from "./dictionary.js";
9
+ export { findFiles, globToRegExp } from "./files.js";
10
+ export { formatJson, formatText, summarize } from "./format.js";
11
+ export { buildLexicon } from "./lexicon.js";
12
+ export { fileKind, Linter, lintText } from "./lint.js";
13
+ export { getRule, RULES } from "./rules/index.js";
14
+ export { parseArgs, runCli, USAGE } from "./run-cli.js";
15
+ export { isRuleId, RULE_IDS } from "./types.js";
16
+ export { DEFAULT_WORD_LIST } from "./word-list.js";
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACd,cAAc,EACd,cAAc,EACd,UAAU,EACV,aAAa,EACb,aAAa,EACb,cAAc,GAMjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAA+C,MAAM,iBAAiB,CAAC;AAC/J,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAgC,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,YAAY,EAAgB,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAiB,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAa,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAA+B,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAA8D,MAAM,YAAY,CAAC;AAC5G,OAAO,EAAE,iBAAiB,EAAsB,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,33 @@
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 type { ResolvedConfig } from "./config.js";
7
+ import type { Dictionary } from "./dictionary.js";
8
+ import { PhraseMatcher } from "./text/phrases.js";
9
+ export type Lexicon = {
10
+ /** Single-word technical nouns, in lower case. */
11
+ readonly technicalNouns: ReadonlySet<string>;
12
+ /** Single-word technical verbs, in lower case. */
13
+ readonly technicalVerbs: ReadonlySet<string>;
14
+ /** Single-word proper nouns, in lower case. */
15
+ readonly properNouns: ReadonlySet<string>;
16
+ readonly allowedWords: ReadonlySet<string>;
17
+ /** All glossary terms, single words and phrases, for the unknown-word rule. */
18
+ readonly glossaryPhrases: PhraseMatcher;
19
+ /** Multi-word technical nouns. The noun-cluster rule counts each one as one noun. */
20
+ readonly technicalNounPhrases: PhraseMatcher;
21
+ /** Multi-word proper nouns. Each one counts as one word (STE Rule 8.6). */
22
+ readonly properNounPhrases: PhraseMatcher;
23
+ /** Nouns for the noun-cluster rule. */
24
+ readonly nouns: ReadonlySet<string>;
25
+ /** Base forms of verbs for the imperative and missing-subject heuristics. */
26
+ readonly verbs: ReadonlySet<string>;
27
+ readonly dictionary: Dictionary | null;
28
+ };
29
+ /** This function makes the lexicon for a configuration and an optional dictionary. */
30
+ export declare function buildLexicon(config: ResolvedConfig, dictionary?: Dictionary | null): Lexicon;
31
+ /** True when the glossary permits the word: a technical noun or verb in any form, a proper noun, or a word of `allowedWords`. */
32
+ export declare function isGlossaryWord(word: string, lexicon: Lexicon): boolean;
33
+ //# sourceMappingURL=lexicon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lexicon.d.ts","sourceRoot":"","sources":["../src/lexicon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAe,MAAM,mBAAmB,CAAC;AAG/D,MAAM,MAAM,OAAO,GAAG;IAClB,kDAAkD;IAClD,QAAQ,CAAC,cAAc,EAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9C,kDAAkD;IAClD,QAAQ,CAAC,cAAc,EAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9C,+CAA+C;IAC/C,QAAQ,CAAC,WAAW,EAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3C,QAAQ,CAAC,YAAY,EAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5C,+EAA+E;IAC/E,QAAQ,CAAC,eAAe,EAAG,aAAa,CAAC;IACzC,qFAAqF;IACrF,QAAQ,CAAC,oBAAoB,EAAG,aAAa,CAAC;IAC9C,2EAA2E;IAC3E,QAAQ,CAAC,iBAAiB,EAAG,aAAa,CAAC;IAC3C,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAG,UAAU,GAAG,IAAI,CAAC;CAC3C,CAAC;AAaF,sFAAsF;AACtF,wBAAgB,YAAY,CAAC,MAAM,EAAG,cAAc,EAAE,UAAU,GAAG,UAAU,GAAG,IAAW,GAAI,OAAO,CAsCrG;AAED,iIAAiI;AACjI,wBAAgB,cAAc,CAAC,IAAI,EAAG,MAAM,EAAE,OAAO,EAAG,OAAO,GAAI,OAAO,CAKzE"}
@@ -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,28 @@
1
+ /**
2
+ * The lint engine. It extracts the prose of a file, runs the rules on each
3
+ * prose unit, and gives the findings with their lines and columns.
4
+ */
5
+ import type { ResolvedConfig } from "./config.js";
6
+ import { type Lexicon } from "./lexicon.js";
7
+ import type { Finding } from "./types.js";
8
+ import { type ProseUnit } from "./units.js";
9
+ export type FileKind = "markdown" | "mdx" | "typescript";
10
+ /** The kind of a file, from its extension, or null when the linter cannot read it. */
11
+ export declare function fileKind(path: string): FileKind | null;
12
+ /** A linter for one configuration. It makes the lexicon and the word list matcher one time. */
13
+ export declare class Linter {
14
+ readonly config: ResolvedConfig;
15
+ readonly lexicon: Lexicon;
16
+ private readonly wordList;
17
+ private readonly rules;
18
+ constructor(config: ResolvedConfig, lexicon?: Lexicon);
19
+ /** The prose units of a file. */
20
+ units(text: string, path: string): ProseUnit[];
21
+ /** The findings in `text`. `path` gives the kind of file, and it is the file name in the findings. */
22
+ lintText(text: string, path: string): Finding[];
23
+ /** The findings in a file on disk. `displayPath` is the file name in the findings. */
24
+ lintFile(path: string, displayPath?: string): Finding[];
25
+ }
26
+ /** The findings in `text`, with a new linter. To lint many files, make one `Linter` and use it again. */
27
+ export declare function lintText(text: string, path: string, config: ResolvedConfig, lexicon?: Lexicon): Finding[];
28
+ //# 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,EAAgB,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAQ1D,OAAO,KAAK,EAAE,OAAO,EAAoB,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvD,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,KAAK,GAAG,YAAY,CAAC;AAEzD,sFAAsF;AACtF,wBAAgB,QAAQ,CAAC,IAAI,EAAG,MAAM,GAAI,QAAQ,GAAG,IAAI,CAMxD;AAED,+FAA+F;AAC/F,qBAAa,MAAM;IAKH,QAAQ,CAAC,MAAM,EAAG,cAAc;IAJ5C,QAAQ,CAAC,OAAO,EAAG,OAAO,CAAC;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgF;gBAEjF,MAAM,EAAG,cAAc,EAAE,OAAO,CAAC,EAAG,OAAO;IAWhE,iCAAiC;IACjC,KAAK,CAAC,IAAI,EAAG,MAAM,EAAE,IAAI,EAAG,MAAM,GAAI,SAAS,EAAE;IAIjD,sGAAsG;IACtG,QAAQ,CAAC,IAAI,EAAG,MAAM,EAAE,IAAI,EAAG,MAAM,GAAI,OAAO,EAAE;IAoDlD,sFAAsF;IACtF,QAAQ,CAAC,IAAI,EAAG,MAAM,EAAE,WAAW,GAAG,MAAa,GAAI,OAAO,EAAE;CAGnE;AAuBD,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,132 @@
1
+ /**
2
+ * The lint engine. It extracts the prose of a file, runs the rules on each
3
+ * prose unit, and gives the findings with their lines and columns.
4
+ */
5
+ import { readFileSync } from "node:fs";
6
+ import { buildLexicon } from "./lexicon.js";
7
+ import { RULES } from "./rules/index.js";
8
+ import { WordListMatcher } from "./rules/word-list-matcher.js";
9
+ import { LineIndex } from "./source/lines.js";
10
+ import { extractMarkdown } from "./source/markdown.js";
11
+ import { isSuppressed } from "./source/suppressions.js";
12
+ import { extractTsdoc } from "./source/tsdoc.js";
13
+ import { extractJsxText } from "./source/jsx.js";
14
+ import { buildUnit } from "./units.js";
15
+ /** The kind of a file, from its extension, or null when the linter cannot read it. */
16
+ export function fileKind(path) {
17
+ const lower = path.toLowerCase();
18
+ if (lower.endsWith(".mdx"))
19
+ return "mdx";
20
+ if (lower.endsWith(".md") || lower.endsWith(".markdown"))
21
+ return "markdown";
22
+ if (/\.(?:[mc]?ts|tsx|[mc]?js|jsx)$/.test(lower) && !lower.endsWith(".d.ts"))
23
+ return "typescript";
24
+ return null;
25
+ }
26
+ /** A linter for one configuration. It makes the lexicon and the word list matcher one time. */
27
+ export class Linter {
28
+ config;
29
+ lexicon;
30
+ wordList;
31
+ rules;
32
+ constructor(config, lexicon) {
33
+ this.config = config;
34
+ this.lexicon = lexicon ?? buildLexicon(config);
35
+ this.wordList = new WordListMatcher(config.wordList);
36
+ this.rules = RULES.flatMap((rule) => {
37
+ const setting = config.rules[rule.id];
38
+ if (setting === "off")
39
+ return [];
40
+ if (rule.id === "unknown-word" && this.lexicon.dictionary === null)
41
+ return [];
42
+ return [{ rule, override: setting ?? null }];
43
+ });
44
+ }
45
+ /** The prose units of a file. */
46
+ units(text, path) {
47
+ return extract(text, path).blocks.flatMap((block) => buildUnit(block, this.lexicon) ?? []);
48
+ }
49
+ /** The findings in `text`. `path` gives the kind of file, and it is the file name in the findings. */
50
+ lintText(text, path) {
51
+ const extraction = extract(text, path);
52
+ const lineIndex = new LineIndex(text);
53
+ const raw = [];
54
+ for (const block of extraction.blocks) {
55
+ const unit = buildUnit(block, this.lexicon);
56
+ if (unit === null)
57
+ continue;
58
+ const wordOnly = unit.kind !== "paragraph";
59
+ for (const { rule, override } of this.rules) {
60
+ if (wordOnly && rule.scope !== "word")
61
+ continue;
62
+ rule.check(unit, {
63
+ config: this.config,
64
+ lexicon: this.lexicon,
65
+ wordList: this.wordList,
66
+ report: (report) => {
67
+ raw.push({
68
+ ruleId: rule.id,
69
+ severity: override ?? report.severity ?? rule.defaultSeverity,
70
+ start: report.start,
71
+ end: report.end,
72
+ message: report.message,
73
+ eachWord: reportsEachWord(rule),
74
+ });
75
+ },
76
+ });
77
+ }
78
+ }
79
+ // An unknown word that another rule reports already gets no second finding. A finding for a
80
+ // sentence, a paragraph or a noun cluster does not report each word in it.
81
+ const others = raw.filter((finding) => finding.ruleId !== "unknown-word" && finding.eachWord);
82
+ const kept = raw.filter((finding) => finding.ruleId !== "unknown-word"
83
+ || !others.some((other) => other.start < finding.end && finding.start < other.end));
84
+ return kept
85
+ .filter((finding) => !isSuppressed(extraction.suppressions, finding.ruleId, finding.start))
86
+ .sort((a, b) => a.start - b.start || a.end - b.end || a.ruleId.localeCompare(b.ruleId))
87
+ .map((finding) => {
88
+ const start = lineIndex.position(finding.start);
89
+ const end = lineIndex.position(Math.max(finding.start, finding.end));
90
+ return {
91
+ file: path,
92
+ line: start.line,
93
+ column: start.column,
94
+ endLine: end.line,
95
+ endColumn: end.column,
96
+ ruleId: finding.ruleId,
97
+ severity: finding.severity,
98
+ message: finding.message,
99
+ };
100
+ });
101
+ }
102
+ /** The findings in a file on disk. `displayPath` is the file name in the findings. */
103
+ lintFile(path, displayPath = path) {
104
+ return this.lintText(readFileSync(path, "utf8"), displayPath);
105
+ }
106
+ }
107
+ /**
108
+ * True when a finding of the rule is about each word in its range. A word rule reports a word or a
109
+ * phrase, for example a modal verb or a word list phrase. The noun-cluster rule reports a group of
110
+ * nouns, and the sentence and paragraph rules report a full sentence or paragraph.
111
+ */
112
+ function reportsEachWord(rule) {
113
+ return rule.scope === "word" && rule.id !== "noun-cluster";
114
+ }
115
+ function extract(text, path) {
116
+ const kind = fileKind(path);
117
+ if (kind === "typescript") {
118
+ const comments = extractTsdoc(text, path);
119
+ if (!/\.[jt]sx$/i.test(path))
120
+ return comments;
121
+ // The text that the user interface shows
122
+ return { blocks: [...comments.blocks, ...extractJsxText(text, path).blocks], suppressions: comments.suppressions };
123
+ }
124
+ if (kind === null)
125
+ return { blocks: [], suppressions: [] };
126
+ return extractMarkdown(text, { mdx: kind === "mdx" });
127
+ }
128
+ /** The findings in `text`, with a new linter. To lint many files, make one `Linter` and use it again. */
129
+ export function lintText(text, path, config, lexicon) {
130
+ return new Linter(config, lexicon).lintText(text, path);
131
+ }
132
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../src/lint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type Rule } from "./rule.js";
2
+ export declare const aboutQuantity: Rule;
3
+ //# sourceMappingURL=about-quantity.d.ts.map
@@ -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"}