@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
@@ -0,0 +1,90 @@
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
+ function entry(input) {
13
+ return {
14
+ id: input.id ?? input.match[0],
15
+ match: input.match,
16
+ suggest: input.suggest ?? null,
17
+ note: input.note ?? null,
18
+ severity: input.severity ?? "error",
19
+ verbOnly: input.verbOnly ?? false,
20
+ context: input.context ?? null,
21
+ };
22
+ }
23
+ /** The default word list. */
24
+ export const DEFAULT_WORD_LIST = [
25
+ // Long or formal words that have a short, common equivalent.
26
+ entry({ match: ["utilize", "utilizes", "utilized", "utilizing", "utilization", "utilise", "utilises", "utilised", "utilising"], suggest: "\"use\"" }),
27
+ entry({ match: ["initiate", "initiates", "initiated", "initiating"], suggest: "\"start\"" }),
28
+ entry({ match: ["ensure", "ensures", "ensured", "ensuring"], suggest: "\"make sure\"", note: "Write \"that\" after it: \"make sure that ...\"." }),
29
+ entry({ match: ["via"], suggest: "\"through\" or \"with\"" }),
30
+ entry({ match: ["leverage", "leverages", "leveraged", "leveraging"], suggest: "\"use\"" }),
31
+ entry({ match: ["facilitate", "facilitates", "facilitated", "facilitating"], suggest: "\"help\" or \"make ... easier\"" }),
32
+ entry({ match: ["commence", "commences", "commenced", "commencing"], suggest: "\"start\"" }),
33
+ entry({ match: ["terminate", "terminates", "terminated", "terminating"], suggest: "\"stop\"" }),
34
+ entry({ match: ["obtain", "obtains", "obtained", "obtaining"], suggest: "\"get\"" }),
35
+ entry({ match: ["assist", "assists", "assisted", "assisting"], suggest: "\"help\"" }),
36
+ entry({ match: ["modify", "modifies", "modified", "modifying"], suggest: "\"change\"" }),
37
+ entry({ match: ["indicate", "indicates", "indicated", "indicating"], suggest: "\"show\"" }),
38
+ entry({ match: ["demonstrate", "demonstrates", "demonstrated", "demonstrating"], suggest: "\"show\"" }),
39
+ entry({ match: ["perform", "performs", "performed", "performing"], suggest: "\"do\"" }),
40
+ entry({ match: ["attempt", "attempts", "attempted", "attempting"], suggest: "\"try\"" }),
41
+ entry({ match: ["numerous"], suggest: "\"many\", or give the number" }),
42
+ entry({ match: ["additional"], suggest: "\"more\"" }),
43
+ entry({ match: ["additionally"], suggest: "\"also\"" }),
44
+ entry({ match: ["regarding"], suggest: "\"about\"" }),
45
+ entry({ match: ["hence"], suggest: "\"thus\"" }),
46
+ // Phrases that have a shorter equivalent.
47
+ entry({ match: ["prior to"], suggest: "\"before\"" }),
48
+ entry({ match: ["in order to"], suggest: "\"to\"" }),
49
+ entry({ match: ["due to the fact that"], suggest: "\"because\"" }),
50
+ entry({ match: ["due to"], suggest: "\"because of\"" }),
51
+ entry({ match: ["in the event that"], suggest: "\"if\"" }),
52
+ entry({ match: ["at this point in time"], suggest: "\"at this time\"" }),
53
+ entry({ match: ["in an effort to"], suggest: "\"to\"" }),
54
+ entry({ match: ["for the purpose of"], suggest: "\"to\" or \"for\"" }),
55
+ entry({ match: ["with respect to", "with regard to"], suggest: "\"about\" or \"for\"" }),
56
+ entry({ match: ["as well as"], suggest: "\"and\"" }),
57
+ entry({ match: ["a number of"], suggest: "\"some\", or give the number" }),
58
+ entry({ match: ["is able to", "are able to", "be able to"], suggest: "\"can\"" }),
59
+ entry({ match: ["such as"], suggest: "\"for example\"" }),
60
+ entry({ match: ["follow these steps", "follow the steps"], suggest: "\"do these steps\" or \"do the steps\"" }),
61
+ // Connecting words.
62
+ entry({ match: ["however"], suggest: "\"but\"", note: "Start a new sentence with \"But\" if necessary." }),
63
+ entry({ match: ["therefore"], suggest: "\"thus\" or \"as a result\"" }),
64
+ entry({ match: ["whether or not", "whether"], suggest: "\"if\"" }),
65
+ // Verbs that have a simpler equivalent.
66
+ entry({ match: ["allow", "allows", "allowed", "allowing"], suggest: "\"let\" or \"lets\"", note: "For an adjective, write \"permitted\"." }),
67
+ entry({ match: ["require", "requires", "required", "requiring"], suggest: "\"necessary\"", note: "For example, write \"X is necessary for Y\", or use the imperative." }),
68
+ entry({ match: ["provided that"], suggest: "\"if\"" }),
69
+ entry({ match: ["provide", "provides", "provided", "providing"], suggest: "\"give\" or \"gives\"" }),
70
+ entry({ match: ["execute", "executes", "executed", "executing"], suggest: "\"do\", \"does\" or \"start\"" }),
71
+ entry({ match: ["create", "creates", "created", "creating"], suggest: "\"make\" or \"makes\"" }),
72
+ entry({ match: ["kill", "kills", "killed", "killing"], suggest: "\"stop\"" }),
73
+ entry({ id: "displays", match: ["displayed", "displaying"], suggest: "\"show\" or \"shows\"", severity: "warning" }),
74
+ entry({ id: "display", match: ["display", "displays"], suggest: "\"show\" or \"shows\"", severity: "warning", verbOnly: true }),
75
+ entry({ id: "returns", match: ["returns", "returned", "returning"], suggest: "\"gives\"", severity: "warning", note: "For a function, write \"This function gives ...\"." }),
76
+ entry({ id: "return", match: ["return"], suggest: "\"give\" or \"gives\"", severity: "warning", verbOnly: true }),
77
+ 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." }),
78
+ entry({ id: "ran", match: ["ran"], suggest: "\"started\" or \"operated\"", severity: "warning" }),
79
+ entry({ id: "run", match: ["run", "runs", "running"], suggest: "\"start\", \"starts\" or \"operates\"", severity: "warning", verbOnly: true }),
80
+ entry({ id: "see", match: ["see"], suggest: "\"refer to\"", severity: "warning", context: "reference" }),
81
+ // Words that do not add information.
82
+ entry({ match: ["simple", "simply", "easily"], severity: "warning", note: "The word tells the reader what to think. Tell the reader what to do." }),
83
+ entry({ match: ["just"], suggest: "\"only\"", severity: "warning", note: "Or remove the word." }),
84
+ entry({ match: ["basically", "obviously", "of course"], severity: "warning", note: "The word does not add information." }),
85
+ entry({ match: ["please"], severity: "warning", note: "Write the instruction in the imperative." }),
86
+ // Time and negation.
87
+ entry({ match: ["currently", "now"], suggest: "\"at this time\"", note: "Or remove the word if the time is clear." }),
88
+ entry({ match: ["never"], suggest: "\"do not\"", note: "For a description, write \"not ... at any time\"." }),
89
+ ];
90
+ //# sourceMappingURL=word-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"word-list.js","sourceRoot":"","sources":["../src/word-list.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,49 @@
1
1
  {
2
+ "$schema": "https://json.schemastore.org/package",
2
3
  "name": "@mark1russell7/ste-lint",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
4
+ "version": "0.1.1",
5
+ "description": "A linter for the writing rules of ASD-STE100 Simplified Technical English in Markdown, MDX and TypeScript doc comments",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=22"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "./ste.config.schema.json": "./ste.config.schema.json"
18
+ },
19
+ "bin": {
20
+ "ste-lint": "./dist/cli.js"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "src",
25
+ "ste.config.schema.json"
26
+ ],
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/mark1russell7/ste-lint.git"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "dependencies": {
35
+ "typescript": "^6.0.3"
36
+ },
37
+ "devDependencies": {
38
+ "@mark1russell7/cue": "^1.0.2",
39
+ "@types/node": "^26.6.4",
40
+ "tsx": "^4.23.15",
41
+ "vitest": "^5.0.3"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc -b",
45
+ "typecheck": "tsc -p tsconfig.test.json",
46
+ "test": "vitest run",
47
+ "lint:ste": "tsx src/cli.ts"
48
+ }
6
49
  }
package/src/cli.ts ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from "./run-cli.js";
3
+
4
+ process.exitCode = runCli(process.argv.slice(2), {
5
+ cwd : process.cwd(),
6
+ env : process.env,
7
+ stdout : (text) => process.stdout.write(text),
8
+ stderr : (text) => process.stderr.write(text),
9
+ });
@@ -0,0 +1,188 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { homedir, tmpdir } from "node:os";
3
+ import { join, resolve } from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import {
6
+ ConfigError,
7
+ DEFAULT_IGNORE,
8
+ DEFAULT_INCLUDE,
9
+ DEFAULT_LIMITS,
10
+ findConfigFile,
11
+ loadConfig,
12
+ mergeWordList,
13
+ resolveConfig,
14
+ resolvePath,
15
+ validateConfig,
16
+ } from "./config.js";
17
+ import { DEFAULT_WORD_LIST } from "./word-list.js";
18
+
19
+ let directory : string;
20
+
21
+ beforeEach(() => {
22
+ directory = mkdtempSync(join(tmpdir(), "ste-config-"));
23
+ });
24
+
25
+ afterEach(() => {
26
+ rmSync(directory, { recursive : true, force : true });
27
+ });
28
+
29
+ describe("validateConfig", () => {
30
+ it("accepts a full configuration", () => {
31
+ const file = {
32
+ $schema : "./schema.json",
33
+ include : ["README.md"],
34
+ ignore : ["**/dist/**"],
35
+ technicalNouns : ["monitor"],
36
+ technicalVerbs : ["flush"],
37
+ properNouns : ["Grafana"],
38
+ allowedWords : ["okay"],
39
+ rules : { "modal-verb" : "warning", "noun-cluster" : "off" },
40
+ wordList : [{ match : ["blazingly fast"], suggest : "\"fast\"", severity : "warning", verbOnly : false, note : null }, { id : "via", severity : "off" }],
41
+ limits : { instructionWords : 18 },
42
+ dictionaryPath : null,
43
+ };
44
+ expect(validateConfig(file, "ste.config.json")).toBe(file);
45
+ });
46
+
47
+ it("lists all problems in one error", () => {
48
+ const bad = {
49
+ unknown : 1,
50
+ include : "README.md",
51
+ rules : { "no-such-rule" : "error", "semicolon" : "fatal", "constructor" : "off" },
52
+ limits : { instructionWords : 0, constructor : 5, wordCount : 2 },
53
+ dictionaryPath : 3,
54
+ wordList : [{}, "x", { match : [], severity : "loud", verbOnly : "yes", id : 4, suggest : 5, extra : true }],
55
+ };
56
+ let message = "";
57
+ try {
58
+ validateConfig(bad, "ste.config.json");
59
+ } catch (error) {
60
+ expect(error).toBeInstanceOf(ConfigError);
61
+ message = (error as Error).message;
62
+ }
63
+ for (const part of [
64
+ "\"unknown\" is not a known property",
65
+ "\"include\" must be an array of strings",
66
+ "\"rules.no-such-rule\" is not a known rule",
67
+ "\"rules.semicolon\" must be \"error\", \"warning\" or \"off\"",
68
+ "\"rules.constructor\" is not a known rule",
69
+ "\"limits.instructionWords\" must be an integer of 1 or more",
70
+ "\"limits.constructor\" is not a known limit",
71
+ "\"limits.wordCount\" is not a known limit",
72
+ "\"dictionaryPath\" must be a string or null",
73
+ "\"wordList[0]\" must have \"id\" or \"match\"",
74
+ "\"wordList[1]\" must be an object",
75
+ "\"wordList[2].match\" must be a string or an array of strings",
76
+ "\"wordList[2].severity\"",
77
+ "\"wordList[2].verbOnly\" must be true or false",
78
+ "\"wordList[2].id\" must be a string",
79
+ "\"wordList[2].suggest\" must be a string or null",
80
+ "\"wordList[2].extra\" is not a known property",
81
+ ]) {
82
+ expect(message).toContain(part);
83
+ }
84
+ });
85
+
86
+ it("rejects values that are not objects", () => {
87
+ expect(() => validateConfig([], "x")).toThrow(ConfigError);
88
+ expect(() => validateConfig(null, "x")).toThrow("must be a JSON object");
89
+ expect(() => validateConfig({ rules : [] }, "x")).toThrow("\"rules\" must be an object");
90
+ expect(() => validateConfig({ limits : 3 }, "x")).toThrow("\"limits\" must be an object");
91
+ expect(() => validateConfig({ wordList : {} }, "x")).toThrow("\"wordList\" must be an array");
92
+ });
93
+ });
94
+
95
+ describe("resolveConfig", () => {
96
+ it("applies the defaults", () => {
97
+ const config = resolveConfig({}, { root : directory });
98
+ expect(config.include).toBe(DEFAULT_INCLUDE);
99
+ expect(config.ignore).toBe(DEFAULT_IGNORE);
100
+ expect(config.limits).toEqual(DEFAULT_LIMITS);
101
+ expect(config.wordList).toEqual(DEFAULT_WORD_LIST);
102
+ expect(config.dictionaryPath).toBeNull();
103
+ expect(config.dictionarySource).toBeNull();
104
+ expect(config.configFile).toBeNull();
105
+ });
106
+
107
+ it("keeps known rule settings and merges the limits", () => {
108
+ const config = resolveConfig({ rules : { "modal-verb" : "warning" }, limits : { paragraphSentences : 4 } }, { root : directory });
109
+ expect(config.rules).toEqual({ "modal-verb" : "warning" });
110
+ expect(config.limits).toEqual({ ...DEFAULT_LIMITS, paragraphSentences : 4 });
111
+ });
112
+
113
+ it("resolves the dictionary path from the configuration, relative to the root", () => {
114
+ const config = resolveConfig({ dictionaryPath : ".ste/dictionary.json" }, { root : directory });
115
+ expect(config.dictionaryPath).toBe(resolve(directory, ".ste/dictionary.json"));
116
+ expect(config.dictionarySource).toBe("config");
117
+ });
118
+
119
+ it("gives the environment variable priority, relative to the working directory", () => {
120
+ const config = resolveConfig({ dictionaryPath : "a.json" }, { root : directory, cwd : "/work", env : { STE_DICTIONARY : "b.json" } });
121
+ expect(config.dictionaryPath).toBe(resolve("/work", "b.json"));
122
+ expect(config.dictionarySource).toBe("env");
123
+ expect(resolveConfig({}, { root : directory, env : { STE_DICTIONARY : " " } }).dictionaryPath).toBeNull();
124
+ });
125
+
126
+ it("expands ~ to the home directory", () => {
127
+ expect(resolvePath("~/ste/dictionary.json", "/base")).toBe(join(homedir(), "ste/dictionary.json"));
128
+ expect(resolvePath("~", "/base")).toBe(homedir());
129
+ expect(resolvePath("/abs/file.json", "/base")).toBe(resolve("/abs/file.json"));
130
+ });
131
+ });
132
+
133
+ describe("mergeWordList", () => {
134
+ it("changes, adds and removes entries", () => {
135
+ const merged = mergeWordList(DEFAULT_WORD_LIST, [
136
+ { id : "via", suggest : "\"by\"", severity : "warning" },
137
+ { match : "blazingly fast", suggest : "\"fast\"" },
138
+ { id : "utilize", severity : "off" },
139
+ { match : ["easily"], severity : "off" },
140
+ ]);
141
+ const byId = new Map(merged.map((entry) => [entry.id, entry]));
142
+ expect(byId.get("via")).toMatchObject({ suggest : "\"by\"", severity : "warning", match : ["via"] });
143
+ expect(byId.get("blazingly fast")).toMatchObject({ match : ["blazingly fast"], suggest : "\"fast\"", severity : "error", verbOnly : false, note : null });
144
+ expect(byId.has("utilize")).toBe(false);
145
+ expect(byId.get("simple")!.match).toEqual(["simple", "simply"]);
146
+ });
147
+
148
+ it("removes an entry that has no words left", () => {
149
+ const merged = mergeWordList(DEFAULT_WORD_LIST, [{ match : ["numerous"], severity : "off" }]);
150
+ expect(merged.some((entry) => entry.id === "numerous")).toBe(false);
151
+ });
152
+
153
+ it("keeps the fields of a default entry that the override does not give", () => {
154
+ const merged = mergeWordList(DEFAULT_WORD_LIST, [{ id : "run", note : "Extra." }]);
155
+ expect(merged.find((entry) => entry.id === "run")).toMatchObject({ verbOnly : true, severity : "warning", note : "Extra." });
156
+ });
157
+ });
158
+
159
+ describe("loadConfig", () => {
160
+ it("finds ste.config.json in a parent directory and uses its directory as the root", () => {
161
+ writeFileSync(join(directory, "ste.config.json"), JSON.stringify({ technicalNouns : ["monitor"], dictionaryPath : "dict.json" }));
162
+ const nested = join(directory, "a", "b");
163
+ mkdirSync(nested, { recursive : true });
164
+ expect(findConfigFile(nested)).toBe(join(directory, "ste.config.json"));
165
+ const config = loadConfig({ cwd : nested });
166
+ expect(config.root).toBe(directory);
167
+ expect(config.technicalNouns).toEqual(["monitor"]);
168
+ expect(config.dictionaryPath).toBe(join(directory, "dict.json"));
169
+ });
170
+
171
+ it("uses the defaults without a configuration file", () => {
172
+ const config = loadConfig({ cwd : directory, env : {} });
173
+ expect(config.configFile === null || !config.configFile.startsWith(directory)).toBe(true);
174
+ });
175
+
176
+ it("reads an explicit configuration file", () => {
177
+ writeFileSync(join(directory, "custom.json"), JSON.stringify({ rules : { semicolon : "warning" } }));
178
+ expect(loadConfig({ cwd : directory, configPath : "custom.json" }).rules).toEqual({ semicolon : "warning" });
179
+ });
180
+
181
+ it("gives clear errors for a missing file, a file that is not JSON and a configuration that is not valid", () => {
182
+ expect(() => loadConfig({ cwd : directory, configPath : "missing.json" })).toThrow("Cannot read the configuration file");
183
+ writeFileSync(join(directory, "broken.json"), "{ nope");
184
+ expect(() => loadConfig({ cwd : directory, configPath : "broken.json" })).toThrow("is not valid JSON");
185
+ writeFileSync(join(directory, "invalid.json"), JSON.stringify({ rules : { nope : "error" } }));
186
+ expect(() => loadConfig({ cwd : directory, configPath : "invalid.json" })).toThrow("is not a known rule");
187
+ });
188
+ });