gurkencheck 0.0.4

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 (259) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +327 -0
  3. package/dist/config-parser.d.ts +21 -0
  4. package/dist/config-parser.d.ts.map +1 -0
  5. package/dist/config-parser.js +171 -0
  6. package/dist/config-parser.js.map +1 -0
  7. package/dist/config-verifier.d.ts +4 -0
  8. package/dist/config-verifier.d.ts.map +1 -0
  9. package/dist/config-verifier.js +81 -0
  10. package/dist/config-verifier.js.map +1 -0
  11. package/dist/feature-finder.d.ts +18 -0
  12. package/dist/feature-finder.d.ts.map +1 -0
  13. package/dist/feature-finder.js +70 -0
  14. package/dist/feature-finder.js.map +1 -0
  15. package/dist/formatters/index.d.ts +23 -0
  16. package/dist/formatters/index.d.ts.map +1 -0
  17. package/dist/formatters/index.js +79 -0
  18. package/dist/formatters/index.js.map +1 -0
  19. package/dist/formatters/json.d.ts +31 -0
  20. package/dist/formatters/json.d.ts.map +1 -0
  21. package/dist/formatters/json.js +31 -0
  22. package/dist/formatters/json.js.map +1 -0
  23. package/dist/formatters/junit.d.ts +17 -0
  24. package/dist/formatters/junit.d.ts.map +1 -0
  25. package/dist/formatters/junit.js +61 -0
  26. package/dist/formatters/junit.js.map +1 -0
  27. package/dist/formatters/sarif.d.ts +6 -0
  28. package/dist/formatters/sarif.d.ts.map +1 -0
  29. package/dist/formatters/sarif.js +81 -0
  30. package/dist/formatters/sarif.js.map +1 -0
  31. package/dist/formatters/stylish.d.ts +9 -0
  32. package/dist/formatters/stylish.d.ts.map +1 -0
  33. package/dist/formatters/stylish.js +66 -0
  34. package/dist/formatters/stylish.js.map +1 -0
  35. package/dist/formatters/tap.d.ts +14 -0
  36. package/dist/formatters/tap.d.ts.map +1 -0
  37. package/dist/formatters/tap.js +45 -0
  38. package/dist/formatters/tap.js.map +1 -0
  39. package/dist/gherkin/dialects.d.ts +31 -0
  40. package/dist/gherkin/dialects.d.ts.map +1 -0
  41. package/dist/gherkin/dialects.js +40 -0
  42. package/dist/gherkin/dialects.js.map +1 -0
  43. package/dist/gherkin/keywords.d.ts +21 -0
  44. package/dist/gherkin/keywords.d.ts.map +1 -0
  45. package/dist/gherkin/keywords.js +53 -0
  46. package/dist/gherkin/keywords.js.map +1 -0
  47. package/dist/gherkin/parse.d.ts +32 -0
  48. package/dist/gherkin/parse.d.ts.map +1 -0
  49. package/dist/gherkin/parse.js +236 -0
  50. package/dist/gherkin/parse.js.map +1 -0
  51. package/dist/gherkin/traverse.d.ts +45 -0
  52. package/dist/gherkin/traverse.d.ts.map +1 -0
  53. package/dist/gherkin/traverse.js +89 -0
  54. package/dist/gherkin/traverse.js.map +1 -0
  55. package/dist/gherkin/variables.d.ts +26 -0
  56. package/dist/gherkin/variables.d.ts.map +1 -0
  57. package/dist/gherkin/variables.js +51 -0
  58. package/dist/gherkin/variables.js.map +1 -0
  59. package/dist/index.d.ts +39 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +31 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/linter.d.ts +23 -0
  64. package/dist/linter.d.ts.map +1 -0
  65. package/dist/linter.js +57 -0
  66. package/dist/linter.js.map +1 -0
  67. package/dist/logger.d.ts +16 -0
  68. package/dist/logger.d.ts.map +1 -0
  69. package/dist/logger.js +28 -0
  70. package/dist/logger.js.map +1 -0
  71. package/dist/main.d.ts +3 -0
  72. package/dist/main.d.ts.map +1 -0
  73. package/dist/main.js +144 -0
  74. package/dist/main.js.map +1 -0
  75. package/dist/presets.d.ts +19 -0
  76. package/dist/presets.d.ts.map +1 -0
  77. package/dist/presets.js +24 -0
  78. package/dist/presets.js.map +1 -0
  79. package/dist/rules/allowed-tags.d.ts +4 -0
  80. package/dist/rules/allowed-tags.d.ts.map +1 -0
  81. package/dist/rules/allowed-tags.js +34 -0
  82. package/dist/rules/allowed-tags.js.map +1 -0
  83. package/dist/rules/file-name.d.ts +4 -0
  84. package/dist/rules/file-name.d.ts.map +1 -0
  85. package/dist/rules/file-name.js +41 -0
  86. package/dist/rules/file-name.js.map +1 -0
  87. package/dist/rules/indentation.d.ts +4 -0
  88. package/dist/rules/indentation.d.ts.map +1 -0
  89. package/dist/rules/indentation.js +153 -0
  90. package/dist/rules/indentation.js.map +1 -0
  91. package/dist/rules/index.d.ts +13 -0
  92. package/dist/rules/index.d.ts.map +1 -0
  93. package/dist/rules/index.js +70 -0
  94. package/dist/rules/index.js.map +1 -0
  95. package/dist/rules/keywords-in-logical-order.d.ts +4 -0
  96. package/dist/rules/keywords-in-logical-order.d.ts.map +1 -0
  97. package/dist/rules/keywords-in-logical-order.js +37 -0
  98. package/dist/rules/keywords-in-logical-order.js.map +1 -0
  99. package/dist/rules/max-scenarios-per-file.d.ts +4 -0
  100. package/dist/rules/max-scenarios-per-file.d.ts.map +1 -0
  101. package/dist/rules/max-scenarios-per-file.js +42 -0
  102. package/dist/rules/max-scenarios-per-file.js.map +1 -0
  103. package/dist/rules/name-length.d.ts +4 -0
  104. package/dist/rules/name-length.d.ts.map +1 -0
  105. package/dist/rules/name-length.js +50 -0
  106. package/dist/rules/name-length.js.map +1 -0
  107. package/dist/rules/new-line-at-eof.d.ts +4 -0
  108. package/dist/rules/new-line-at-eof.d.ts.map +1 -0
  109. package/dist/rules/new-line-at-eof.js +30 -0
  110. package/dist/rules/new-line-at-eof.js.map +1 -0
  111. package/dist/rules/no-background-only-scenario.d.ts +4 -0
  112. package/dist/rules/no-background-only-scenario.d.ts.map +1 -0
  113. package/dist/rules/no-background-only-scenario.js +43 -0
  114. package/dist/rules/no-background-only-scenario.js.map +1 -0
  115. package/dist/rules/no-dupe-feature-names.d.ts +4 -0
  116. package/dist/rules/no-dupe-feature-names.d.ts.map +1 -0
  117. package/dist/rules/no-dupe-feature-names.js +25 -0
  118. package/dist/rules/no-dupe-feature-names.js.map +1 -0
  119. package/dist/rules/no-dupe-file-names.d.ts +4 -0
  120. package/dist/rules/no-dupe-file-names.d.ts.map +1 -0
  121. package/dist/rules/no-dupe-file-names.js +28 -0
  122. package/dist/rules/no-dupe-file-names.js.map +1 -0
  123. package/dist/rules/no-dupe-scenario-names.d.ts +4 -0
  124. package/dist/rules/no-dupe-scenario-names.d.ts.map +1 -0
  125. package/dist/rules/no-dupe-scenario-names.js +41 -0
  126. package/dist/rules/no-dupe-scenario-names.js.map +1 -0
  127. package/dist/rules/no-duplicate-tags.d.ts +4 -0
  128. package/dist/rules/no-duplicate-tags.d.ts.map +1 -0
  129. package/dist/rules/no-duplicate-tags.js +38 -0
  130. package/dist/rules/no-duplicate-tags.js.map +1 -0
  131. package/dist/rules/no-empty-background.d.ts +4 -0
  132. package/dist/rules/no-empty-background.d.ts.map +1 -0
  133. package/dist/rules/no-empty-background.js +24 -0
  134. package/dist/rules/no-empty-background.js.map +1 -0
  135. package/dist/rules/no-empty-file.d.ts +4 -0
  136. package/dist/rules/no-empty-file.d.ts.map +1 -0
  137. package/dist/rules/no-empty-file.js +12 -0
  138. package/dist/rules/no-empty-file.js.map +1 -0
  139. package/dist/rules/no-examples-in-scenarios.d.ts +4 -0
  140. package/dist/rules/no-examples-in-scenarios.d.ts.map +1 -0
  141. package/dist/rules/no-examples-in-scenarios.js +25 -0
  142. package/dist/rules/no-examples-in-scenarios.js.map +1 -0
  143. package/dist/rules/no-files-without-scenarios.d.ts +4 -0
  144. package/dist/rules/no-files-without-scenarios.d.ts.map +1 -0
  145. package/dist/rules/no-files-without-scenarios.js +18 -0
  146. package/dist/rules/no-files-without-scenarios.js.map +1 -0
  147. package/dist/rules/no-homogenous-tags.d.ts +4 -0
  148. package/dist/rules/no-homogenous-tags.d.ts.map +1 -0
  149. package/dist/rules/no-homogenous-tags.js +54 -0
  150. package/dist/rules/no-homogenous-tags.js.map +1 -0
  151. package/dist/rules/no-multiple-empty-lines.d.ts +4 -0
  152. package/dist/rules/no-multiple-empty-lines.d.ts.map +1 -0
  153. package/dist/rules/no-multiple-empty-lines.js +44 -0
  154. package/dist/rules/no-multiple-empty-lines.js.map +1 -0
  155. package/dist/rules/no-partially-commented-tag-lines.d.ts +4 -0
  156. package/dist/rules/no-partially-commented-tag-lines.d.ts.map +1 -0
  157. package/dist/rules/no-partially-commented-tag-lines.js +44 -0
  158. package/dist/rules/no-partially-commented-tag-lines.js.map +1 -0
  159. package/dist/rules/no-restricted-patterns.d.ts +4 -0
  160. package/dist/rules/no-restricted-patterns.d.ts.map +1 -0
  161. package/dist/rules/no-restricted-patterns.js +101 -0
  162. package/dist/rules/no-restricted-patterns.js.map +1 -0
  163. package/dist/rules/no-restricted-tags.d.ts +4 -0
  164. package/dist/rules/no-restricted-tags.d.ts.map +1 -0
  165. package/dist/rules/no-restricted-tags.js +35 -0
  166. package/dist/rules/no-restricted-tags.js.map +1 -0
  167. package/dist/rules/no-scenario-outlines-without-examples.d.ts +4 -0
  168. package/dist/rules/no-scenario-outlines-without-examples.d.ts.map +1 -0
  169. package/dist/rules/no-scenario-outlines-without-examples.js +29 -0
  170. package/dist/rules/no-scenario-outlines-without-examples.js.map +1 -0
  171. package/dist/rules/no-superfluous-tags.d.ts +4 -0
  172. package/dist/rules/no-superfluous-tags.d.ts.map +1 -0
  173. package/dist/rules/no-superfluous-tags.js +40 -0
  174. package/dist/rules/no-superfluous-tags.js.map +1 -0
  175. package/dist/rules/no-trailing-spaces.d.ts +4 -0
  176. package/dist/rules/no-trailing-spaces.d.ts.map +1 -0
  177. package/dist/rules/no-trailing-spaces.js +24 -0
  178. package/dist/rules/no-trailing-spaces.js.map +1 -0
  179. package/dist/rules/no-undeclared-variables.d.ts +4 -0
  180. package/dist/rules/no-undeclared-variables.d.ts.map +1 -0
  181. package/dist/rules/no-undeclared-variables.js +35 -0
  182. package/dist/rules/no-undeclared-variables.js.map +1 -0
  183. package/dist/rules/no-unnamed-features.d.ts +4 -0
  184. package/dist/rules/no-unnamed-features.d.ts.map +1 -0
  185. package/dist/rules/no-unnamed-features.js +19 -0
  186. package/dist/rules/no-unnamed-features.js.map +1 -0
  187. package/dist/rules/no-unnamed-scenarios.d.ts +4 -0
  188. package/dist/rules/no-unnamed-scenarios.d.ts.map +1 -0
  189. package/dist/rules/no-unnamed-scenarios.js +24 -0
  190. package/dist/rules/no-unnamed-scenarios.js.map +1 -0
  191. package/dist/rules/no-unused-variables.d.ts +4 -0
  192. package/dist/rules/no-unused-variables.d.ts.map +1 -0
  193. package/dist/rules/no-unused-variables.js +36 -0
  194. package/dist/rules/no-unused-variables.js.map +1 -0
  195. package/dist/rules/one-space-between-tags.d.ts +4 -0
  196. package/dist/rules/one-space-between-tags.d.ts.map +1 -0
  197. package/dist/rules/one-space-between-tags.js +36 -0
  198. package/dist/rules/one-space-between-tags.js.map +1 -0
  199. package/dist/rules/only-one-when.d.ts +4 -0
  200. package/dist/rules/only-one-when.d.ts.map +1 -0
  201. package/dist/rules/only-one-when.js +59 -0
  202. package/dist/rules/only-one-when.js.map +1 -0
  203. package/dist/rules/required-tags.d.ts +4 -0
  204. package/dist/rules/required-tags.d.ts.map +1 -0
  205. package/dist/rules/required-tags.js +36 -0
  206. package/dist/rules/required-tags.js.map +1 -0
  207. package/dist/rules/scenario-size.d.ts +4 -0
  208. package/dist/rules/scenario-size.d.ts.map +1 -0
  209. package/dist/rules/scenario-size.js +37 -0
  210. package/dist/rules/scenario-size.js.map +1 -0
  211. package/dist/rules/use-and.d.ts +4 -0
  212. package/dist/rules/use-and.d.ts.map +1 -0
  213. package/dist/rules/use-and.js +33 -0
  214. package/dist/rules/use-and.js.map +1 -0
  215. package/dist/rules.d.ts +24 -0
  216. package/dist/rules.d.ts.map +1 -0
  217. package/dist/rules.js +109 -0
  218. package/dist/rules.js.map +1 -0
  219. package/dist/suppressions.d.ts +33 -0
  220. package/dist/suppressions.d.ts.map +1 -0
  221. package/dist/suppressions.js +84 -0
  222. package/dist/suppressions.js.map +1 -0
  223. package/dist/types.d.ts +81 -0
  224. package/dist/types.d.ts.map +1 -0
  225. package/dist/types.js +2 -0
  226. package/dist/types.js.map +1 -0
  227. package/dist/util/case.d.ts +21 -0
  228. package/dist/util/case.d.ts.map +1 -0
  229. package/dist/util/case.js +42 -0
  230. package/dist/util/case.js.map +1 -0
  231. package/dist/util/collections.d.ts +30 -0
  232. package/dist/util/collections.d.ts.map +1 -0
  233. package/dist/util/collections.js +87 -0
  234. package/dist/util/collections.js.map +1 -0
  235. package/dist/util/glob.d.ts +20 -0
  236. package/dist/util/glob.d.ts.map +1 -0
  237. package/dist/util/glob.js +203 -0
  238. package/dist/util/glob.js.map +1 -0
  239. package/dist/util/json.d.ts +14 -0
  240. package/dist/util/json.d.ts.map +1 -0
  241. package/dist/util/json.js +63 -0
  242. package/dist/util/json.js.map +1 -0
  243. package/dist/util/lines.d.ts +24 -0
  244. package/dist/util/lines.d.ts.map +1 -0
  245. package/dist/util/lines.js +45 -0
  246. package/dist/util/lines.js.map +1 -0
  247. package/dist/util/location.d.ts +15 -0
  248. package/dist/util/location.d.ts.map +1 -0
  249. package/dist/util/location.js +11 -0
  250. package/dist/util/location.js.map +1 -0
  251. package/dist/util/xml.d.ts +16 -0
  252. package/dist/util/xml.d.ts.map +1 -0
  253. package/dist/util/xml.js +36 -0
  254. package/dist/util/xml.js.map +1 -0
  255. package/dist/version.d.ts +3 -0
  256. package/dist/version.d.ts.map +1 -0
  257. package/dist/version.js +24 -0
  258. package/dist/version.js.map +1 -0
  259. package/package.json +61 -0
@@ -0,0 +1,51 @@
1
+ import { at } from '../util/location.js';
2
+ /** `<name>` placeholders, as used in Scenario Outlines. */
3
+ const VARIABLE = /<([^>]*)>/gu;
4
+ function note(variable, position, into) {
5
+ const seen = into.get(variable);
6
+ if (seen === undefined) {
7
+ into.set(variable, [position]);
8
+ return;
9
+ }
10
+ const already = seen.some((p) => p.line === position.line && p.column === position.column);
11
+ if (!already) {
12
+ seen.push(position);
13
+ }
14
+ }
15
+ /** Records every `<variable>` in `text` against the node holding it. */
16
+ function collect(text, position, into) {
17
+ if (text === undefined || text === '') {
18
+ return;
19
+ }
20
+ for (const match of text.matchAll(VARIABLE)) {
21
+ note(match[1], position, into);
22
+ }
23
+ }
24
+ /** Gathers the variables a Scenario Outline declares and the ones it uses. */
25
+ export function variablesOf(scenario) {
26
+ const declared = new Map();
27
+ const used = new Map();
28
+ for (const examples of scenario.examples) {
29
+ for (const cell of examples.tableHeader?.cells ?? []) {
30
+ if (cell.value !== '') {
31
+ note(cell.value, at(cell.location), declared);
32
+ }
33
+ }
34
+ }
35
+ collect(scenario.name, at(scenario.location), used);
36
+ for (const step of scenario.steps) {
37
+ collect(step.text, at(step.location), used);
38
+ // Steps can carry a data table or a doc string, and both may contain
39
+ // variables. See https://cucumber.io/docs/gherkin/reference/
40
+ for (const row of step.dataTable?.rows ?? []) {
41
+ for (const cell of row.cells) {
42
+ collect(cell.value, at(cell.location), used);
43
+ }
44
+ }
45
+ if (step.docString !== undefined) {
46
+ collect(step.docString.content, at(step.location), used);
47
+ }
48
+ }
49
+ return { declared, used };
50
+ }
51
+ //# sourceMappingURL=variables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variables.js","sourceRoot":"","sources":["../../src/gherkin/variables.ts"],"names":[],"mappings":"AASA,OAAO,EAAC,EAAE,EAAC,MAAM,qBAAqB,CAAC;AAEvC,2DAA2D;AAC3D,MAAM,QAAQ,GAAG,aAAa,CAAC;AAmB/B,SAAS,IAAI,CAAC,QAAgB,EAAE,QAAkB,EAAE,IAAe;IACjE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAChC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/B,OAAO;IACT,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3F,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,wEAAwE;AACxE,SAAS,OAAO,CAAC,IAAwB,EAAE,QAAkB,EAAE,IAAe;IAC5E,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QACtC,OAAO;IACT,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,WAAW,CAAC,QAAkB;IAC5C,MAAM,QAAQ,GAAc,IAAI,GAAG,EAAE,CAAC;IACtC,MAAM,IAAI,GAAc,IAAI,GAAG,EAAE,CAAC;IAElC,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACzC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE,EAAE,CAAC;YACrD,IAAI,IAAI,CAAC,KAAK,KAAK,EAAE,EAAE,CAAC;gBACtB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IAEpD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;QAE5C,qEAAqE;QACrE,6DAA6D;QAC7D,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;YAC7C,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;gBAC7B,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,OAAO,EAAC,QAAQ,EAAE,IAAI,EAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * gurkencheck as a library.
3
+ *
4
+ * ```ts
5
+ * import {findFeatureFiles, lint, loadRules, readConfiguration} from 'gurkencheck';
6
+ *
7
+ * const rules = await loadRules();
8
+ * const config = readConfiguration('.gurkencheckrc', rules);
9
+ * if (config.ok) {
10
+ * const {files} = findFeatureFiles(['features']);
11
+ * const results = await lint(files, config.configuration, rules);
12
+ * }
13
+ * ```
14
+ */
15
+ export { DEFAULT_CONFIG_FILE_NAME, readConfiguration } from './config-parser.ts';
16
+ export type { ConfigurationResult } from './config-parser.ts';
17
+ export { verifyConfiguration } from './config-verifier.ts';
18
+ export { PRESETS, RECOMMENDED } from './presets.ts';
19
+ export { DEFAULT_IGNORE_FILE_NAME, DEFAULT_IGNORED_PATTERNS, findFeatureFiles, readIgnorePatterns, } from './feature-finder.ts';
20
+ export type { FeatureSearch } from './feature-finder.ts';
21
+ export { DEFAULT_FORMAT, FORMATTERS, getFormatter, loadFormatter } from './formatters/index.ts';
22
+ export type { Formatter } from './formatters/index.ts';
23
+ export { toJson } from './formatters/json.ts';
24
+ export { toSarif } from './formatters/sarif.ts';
25
+ export { version } from './version.ts';
26
+ export type { JsonMessage, JsonResult } from './formatters/json.ts';
27
+ export { ALWAYS_ON_RULES, PARSER_RULES, parseFeature, readAndParseFile } from './gherkin/parse.ts';
28
+ export type { ParseResult } from './gherkin/parse.ts';
29
+ export { getNeutralKeyword, getNodeType } from './gherkin/keywords.ts';
30
+ export { DEFAULT_LANGUAGE, detectLanguage, getDialect, isKnownLanguage } from './gherkin/dialects.ts';
31
+ export { backgroundsOf, rulesOf, scenariosOf, stepContainersOf } from './gherkin/traverse.ts';
32
+ export { countBySeverity, hasErrors, lint } from './linter.ts';
33
+ export type { LintOptions } from './linter.ts';
34
+ export { readSuppressions } from './suppressions.ts';
35
+ export type { Suppressions } from './suppressions.ts';
36
+ export { getRuleSettings, getRuleSeverity, isRuleEnabled, loadRules, resetRules, runEnabledRules, } from './rules.ts';
37
+ export { BUILT_IN_RULES } from './rules/index.ts';
38
+ export type { Configuration, FeatureFile, FileResult, LintRule, RuleConfig, RuleError, RuleRegistry, RuleState, Severity, } from './types.ts';
39
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAC,wBAAwB,EAAE,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAC/E,YAAY,EAAC,mBAAmB,EAAC,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAC,mBAAmB,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,EAAE,WAAW,EAAC,MAAM,cAAc,CAAC;AAClD,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAC,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAC,MAAM,uBAAuB,CAAC;AAC9F,YAAY,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAC,MAAM,EAAC,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AACrC,YAAY,EAAC,WAAW,EAAE,UAAU,EAAC,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAC,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AACjG,YAAY,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAC,iBAAiB,EAAE,WAAW,EAAC,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAC,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAC,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAC,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EAAC,eAAe,EAAE,SAAS,EAAE,IAAI,EAAC,MAAM,aAAa,CAAC;AAC7D,YAAY,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAC,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AACnD,YAAY,EAAC,YAAY,EAAC,MAAM,mBAAmB,CAAC;AACpD,OAAO,EACL,eAAe,EACf,eAAe,EACf,aAAa,EACb,SAAS,EACT,UAAU,EACV,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,YAAY,EACV,aAAa,EACb,WAAW,EACX,UAAU,EACV,QAAQ,EACR,UAAU,EACV,SAAS,EACT,YAAY,EACZ,SAAS,EACT,QAAQ,GACT,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * gurkencheck as a library.
3
+ *
4
+ * ```ts
5
+ * import {findFeatureFiles, lint, loadRules, readConfiguration} from 'gurkencheck';
6
+ *
7
+ * const rules = await loadRules();
8
+ * const config = readConfiguration('.gurkencheckrc', rules);
9
+ * if (config.ok) {
10
+ * const {files} = findFeatureFiles(['features']);
11
+ * const results = await lint(files, config.configuration, rules);
12
+ * }
13
+ * ```
14
+ */
15
+ export { DEFAULT_CONFIG_FILE_NAME, readConfiguration } from './config-parser.js';
16
+ export { verifyConfiguration } from './config-verifier.js';
17
+ export { PRESETS, RECOMMENDED } from './presets.js';
18
+ export { DEFAULT_IGNORE_FILE_NAME, DEFAULT_IGNORED_PATTERNS, findFeatureFiles, readIgnorePatterns, } from './feature-finder.js';
19
+ export { DEFAULT_FORMAT, FORMATTERS, getFormatter, loadFormatter } from './formatters/index.js';
20
+ export { toJson } from './formatters/json.js';
21
+ export { toSarif } from './formatters/sarif.js';
22
+ export { version } from './version.js';
23
+ export { ALWAYS_ON_RULES, PARSER_RULES, parseFeature, readAndParseFile } from './gherkin/parse.js';
24
+ export { getNeutralKeyword, getNodeType } from './gherkin/keywords.js';
25
+ export { DEFAULT_LANGUAGE, detectLanguage, getDialect, isKnownLanguage } from './gherkin/dialects.js';
26
+ export { backgroundsOf, rulesOf, scenariosOf, stepContainersOf } from './gherkin/traverse.js';
27
+ export { countBySeverity, hasErrors, lint } from './linter.js';
28
+ export { readSuppressions } from './suppressions.js';
29
+ export { getRuleSettings, getRuleSeverity, isRuleEnabled, loadRules, resetRules, runEnabledRules, } from './rules.js';
30
+ export { BUILT_IN_RULES } from './rules/index.js';
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAC,wBAAwB,EAAE,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAE/E,OAAO,EAAC,mBAAmB,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,OAAO,EAAE,WAAW,EAAC,MAAM,cAAc,CAAC;AAClD,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAC,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAC,MAAM,uBAAuB,CAAC;AAE9F,OAAO,EAAC,MAAM,EAAC,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AAErC,OAAO,EAAC,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AAEjG,OAAO,EAAC,iBAAiB,EAAE,WAAW,EAAC,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAC,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAC,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAC,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EAAC,eAAe,EAAE,SAAS,EAAE,IAAI,EAAC,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAC,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,eAAe,EACf,eAAe,EACf,aAAa,EACb,SAAS,EACT,UAAU,EACV,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { Configuration, FileResult, RuleRegistry } from './types.ts';
2
+ export interface LintOptions {
3
+ /**
4
+ * The dialect to read a file in when it carries no `# language:` header,
5
+ * for projects written entirely in one language.
6
+ */
7
+ language?: string;
8
+ }
9
+ /**
10
+ * Lints every file and returns one result per file, in the order given.
11
+ *
12
+ * Files are read concurrently but checked one after another, because rules
13
+ * that look for duplicates across files need a predictable order.
14
+ */
15
+ export declare function lint(files: readonly string[], configuration: Configuration, rules: RuleRegistry, options?: LintOptions): Promise<FileResult[]>;
16
+ /** True when any file has a finding serious enough to fail the run. */
17
+ export declare function hasErrors(results: readonly FileResult[]): boolean;
18
+ /** How many findings there are of each severity. */
19
+ export declare function countBySeverity(results: readonly FileResult[]): {
20
+ errors: number;
21
+ warnings: number;
22
+ };
23
+ //# sourceMappingURL=linter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linter.d.ts","sourceRoot":"","sources":["../src/linter.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,aAAa,EAAE,UAAU,EAAE,YAAY,EAAC,MAAM,YAAY,CAAC;AAGxE,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,IAAI,CACxB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,aAAa,EAAE,aAAa,EAC5B,KAAK,EAAE,YAAY,EACnB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,EAAE,CAAC,CA4BvB;AAED,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAIjE;AAED,oDAAoD;AACpD,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAaA"}
package/dist/linter.js ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Running the rules over a set of feature files.
3
+ */
4
+ import path from 'node:path';
5
+ import { readAndParseFile } from './gherkin/parse.js';
6
+ import { resetRules, runEnabledRules } from './rules.js';
7
+ import { readSuppressions } from './suppressions.js';
8
+ import { sortBy } from './util/collections.js';
9
+ /**
10
+ * Lints every file and returns one result per file, in the order given.
11
+ *
12
+ * Files are read concurrently but checked one after another, because rules
13
+ * that look for duplicates across files need a predictable order.
14
+ */
15
+ export async function lint(files, configuration, rules, options = {}) {
16
+ resetRules(rules);
17
+ const parsed = await Promise.all(files.map((file) => readAndParseFile(file, options.language)));
18
+ const results = [];
19
+ for (const result of parsed) {
20
+ // Parse errors are not suppressible: the file could not be read, so
21
+ // hiding the message would leave nothing in its place.
22
+ let errors = result.errors;
23
+ if (errors.length === 0) {
24
+ errors = await runEnabledRules(result.feature, result.file, configuration, rules);
25
+ const suppressions = readSuppressions(result.file.lines);
26
+ if (!suppressions.isEmpty) {
27
+ errors = errors.filter((error) => !suppressions.isSuppressed(error));
28
+ }
29
+ }
30
+ results.push({
31
+ filePath: path.resolve(result.file.relativePath),
32
+ errors: sortBy(errors, (error) => error.line),
33
+ });
34
+ }
35
+ return results;
36
+ }
37
+ /** True when any file has a finding serious enough to fail the run. */
38
+ export function hasErrors(results) {
39
+ return results.some((result) => result.errors.some((error) => (error.severity ?? 'error') === 'error'));
40
+ }
41
+ /** How many findings there are of each severity. */
42
+ export function countBySeverity(results) {
43
+ let errors = 0;
44
+ let warnings = 0;
45
+ for (const result of results) {
46
+ for (const error of result.errors) {
47
+ if ((error.severity ?? 'error') === 'warning') {
48
+ warnings++;
49
+ }
50
+ else {
51
+ errors++;
52
+ }
53
+ }
54
+ }
55
+ return { errors, warnings };
56
+ }
57
+ //# sourceMappingURL=linter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linter.js","sourceRoot":"","sources":["../src/linter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAC,gBAAgB,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAC,UAAU,EAAE,eAAe,EAAC,MAAM,YAAY,CAAC;AACvD,OAAO,EAAC,gBAAgB,EAAC,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EAAC,MAAM,EAAC,MAAM,uBAAuB,CAAC;AAU7C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,KAAwB,EACxB,aAA4B,EAC5B,KAAmB,EACnB,OAAO,GAAgB,EAAE;IAEzB,UAAU,CAAC,KAAK,CAAC,CAAC;IAElB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAC9D,CAAC;IACF,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;QAC5B,oEAAoE;QACpE,uDAAuD;QACvD,IAAI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAE3B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;YAClF,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzD,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;gBAC1B,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;YACvE,CAAC;QACH,CAAC;QAED,OAAO,CAAC,IAAI,CAAC;YACX,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;YAChD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;SAC9C,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,SAAS,CAAC,OAA8B;IACtD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,OAAO,CAAC,KAAK,OAAO,CAAC,CACvE,CAAC;AACJ,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,eAAe,CAAC,OAA8B;IAI5D,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,OAAO,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC9C,QAAQ,EAAE,CAAC;YACb,CAAC;iBAAM,CAAC;gBACN,MAAM,EAAE,CAAC;YACX,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Console output. Colour is disabled when stderr is not a terminal, or when
3
+ * the NO_COLOR environment variable is set.
4
+ */
5
+ /** Writes a red message to stderr. */
6
+ export declare function error(message: string): void;
7
+ /** Writes a bold red message to stderr. */
8
+ export declare function boldError(message: string): void;
9
+ /** Text decorations used by the stylish formatter. */
10
+ export declare const style: {
11
+ gray: (text: string) => string;
12
+ underline: (text: string) => string;
13
+ /** Red for something that fails the run, yellow for something that does not. */
14
+ severity: (severity: string, text: string) => string;
15
+ };
16
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,sCAAsC;AACtC,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED,sDAAsD;AACtD,eAAO,MAAM,KAAK;IAChB,IAAI,SAAS,MAAM,KAAG,MAAM;IAC5B,SAAS,SAAS,MAAM,KAAG,MAAM;IACjC,gFAAgF;IAChF,QAAQ,aAAa,MAAM,QAAQ,MAAM,KAAG,MAAM;CAEnD,CAAC"}
package/dist/logger.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Console output. Colour is disabled when stderr is not a terminal, or when
3
+ * the NO_COLOR environment variable is set.
4
+ */
5
+ const ESC = '\u001B[';
6
+ const RESET = `${ESC}0m`;
7
+ function useColor() {
8
+ return process.stderr.isTTY === true && !process.env['NO_COLOR'];
9
+ }
10
+ function paint(codes, message) {
11
+ return useColor() ? `${codes}${message}${RESET}` : message;
12
+ }
13
+ /** Writes a red message to stderr. */
14
+ export function error(message) {
15
+ console.error(paint(`${ESC}31m`, message));
16
+ }
17
+ /** Writes a bold red message to stderr. */
18
+ export function boldError(message) {
19
+ console.error(paint(`${ESC}31m${ESC}1m`, message));
20
+ }
21
+ /** Text decorations used by the stylish formatter. */
22
+ export const style = {
23
+ gray: (text) => paint(`${ESC}38;5;243m`, text),
24
+ underline: (text) => (useColor() ? `${ESC}0;4m${text}${ESC}24m` : text),
25
+ /** Red for something that fails the run, yellow for something that does not. */
26
+ severity: (severity, text) => paint(severity === 'warning' ? `${ESC}33m` : `${ESC}31m`, text),
27
+ };
28
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,GAAG,GAAG,SAAS,CAAC;AACtB,MAAM,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC;AAEzB,SAAS,QAAQ;IACf,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,KAAK,CAAC,KAAa,EAAE,OAAe;IAC3C,OAAO,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AAC7D,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,KAAK,CAAC,OAAe;IACnC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,sDAAsD;AACtD,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,IAAI,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,WAAW,EAAE,IAAI,CAAC;IAC9D,SAAS,EAAE,CAAC,IAAY,EAAU,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,OAAO,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACvF,gFAAgF;IAChF,QAAQ,EAAE,CAAC,QAAgB,EAAE,IAAY,EAAU,EAAE,CACnD,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,EAAE,IAAI,CAAC;CAClE,CAAC"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare function run(argv: readonly string[]): Promise<number>;
3
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AA6CA,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqFlE"}
package/dist/main.js ADDED
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The gurkencheck command line interface.
4
+ */
5
+ import fs from 'node:fs';
6
+ import { pathToFileURL } from 'node:url';
7
+ import { parseArgs } from 'node:util';
8
+ import { DEFAULT_CONFIG_FILE_NAME, readConfiguration } from './config-parser.js';
9
+ import { DEFAULT_IGNORE_FILE_NAME, findFeatureFiles } from './feature-finder.js';
10
+ import { DEFAULT_FORMAT, FORMATTERS, loadFormatter } from './formatters/index.js';
11
+ import { isKnownLanguage } from './gherkin/dialects.js';
12
+ import { hasErrors, lint } from './linter.js';
13
+ import * as logger from './logger.js';
14
+ import { loadRules } from './rules.js';
15
+ import { version } from './version.js';
16
+ /** Nothing to report. */
17
+ const EXIT_OK = 0;
18
+ /** At least one finding serious enough to fail the run. Warnings alone do not. */
19
+ const EXIT_LINT_ERRORS = 1;
20
+ /** The linter could not run: bad arguments, missing or invalid config. */
21
+ const EXIT_USAGE = 2;
22
+ function usage() {
23
+ return [
24
+ 'Usage: gurkencheck [options] <feature-files>',
25
+ '',
26
+ 'Lints Gherkin feature files against the rules in your configuration file.',
27
+ '',
28
+ 'Options:',
29
+ ` -f, --format <format> output format: ${Object.keys(FORMATTERS).join(', ')},`,
30
+ ' or the path to a formatter of your own',
31
+ ` (default: ${DEFAULT_FORMAT})`,
32
+ ` -c, --config <path> configuration file (default: ${DEFAULT_CONFIG_FILE_NAME})`,
33
+ ` -i, --ignore <globs> comma separated globs to skip, overriding ${DEFAULT_IGNORE_FILE_NAME}`,
34
+ ' -r, --rulesdir <dir> directory of custom rules; may be given more than once',
35
+ ' -l, --language <code> dialect for files with no "# language:" header',
36
+ ' -h, --help show this message',
37
+ ' -v, --version show the version number',
38
+ '',
39
+ 'With no files given, the working directory is searched recursively.',
40
+ 'Documentation: https://sebs.github.io/gurkencheck/',
41
+ ].join('\n');
42
+ }
43
+ export async function run(argv) {
44
+ let parsed;
45
+ try {
46
+ parsed = parseArgs({
47
+ args: [...argv],
48
+ options: {
49
+ format: { type: 'string', short: 'f' },
50
+ config: { type: 'string', short: 'c' },
51
+ ignore: { type: 'string', short: 'i' },
52
+ rulesdir: { type: 'string', short: 'r', multiple: true },
53
+ language: { type: 'string', short: 'l' },
54
+ help: { type: 'boolean', short: 'h' },
55
+ version: { type: 'boolean', short: 'v' },
56
+ },
57
+ allowPositionals: true,
58
+ });
59
+ }
60
+ catch (thrown) {
61
+ logger.boldError(thrown instanceof Error ? thrown.message : String(thrown));
62
+ console.error(usage());
63
+ return EXIT_USAGE;
64
+ }
65
+ const { values, positionals } = parsed;
66
+ if (values.help === true) {
67
+ console.log(usage());
68
+ return EXIT_OK;
69
+ }
70
+ if (values.version === true) {
71
+ console.log(version());
72
+ return EXIT_OK;
73
+ }
74
+ const additionalRulesDirs = values.rulesdir ?? [];
75
+ let rules;
76
+ try {
77
+ rules = await loadRules(additionalRulesDirs);
78
+ }
79
+ catch (thrown) {
80
+ logger.boldError(thrown instanceof Error ? thrown.message : String(thrown));
81
+ return EXIT_USAGE;
82
+ }
83
+ const configuration = await readConfiguration(values.config, rules);
84
+ if (!configuration.ok) {
85
+ logger.boldError(configuration.message);
86
+ for (const detail of configuration.details) {
87
+ logger.error(`- ${detail}`);
88
+ }
89
+ return EXIT_USAGE;
90
+ }
91
+ const ignore = values.ignore?.split(',').map((pattern) => pattern.trim());
92
+ const { files, invalidPatterns } = findFeatureFiles(positionals, ignore);
93
+ if (invalidPatterns.length > 0) {
94
+ for (const pattern of invalidPatterns) {
95
+ logger.boldError(`Invalid format of the feature file path/pattern: "${pattern}".`);
96
+ }
97
+ logger.error('To run the linter please specify an existing feature file, directory or glob.');
98
+ return EXIT_USAGE;
99
+ }
100
+ let formatter;
101
+ try {
102
+ formatter = await loadFormatter(values.format);
103
+ }
104
+ catch (thrown) {
105
+ logger.boldError(thrown instanceof Error ? thrown.message : String(thrown));
106
+ return EXIT_USAGE;
107
+ }
108
+ const language = values.language ?? configuration.language;
109
+ if (language !== undefined && !isKnownLanguage(language)) {
110
+ logger.boldError(`Unknown language "${language}". Use a Gherkin language code, such as "fr".`);
111
+ return EXIT_USAGE;
112
+ }
113
+ const results = await lint(files, configuration.configuration, rules, { language });
114
+ // A formatter may print the output itself or hand it back as a string.
115
+ const output = await formatter(results);
116
+ if (typeof output === 'string' && output !== '') {
117
+ console.log(output);
118
+ }
119
+ return hasErrors(results) ? EXIT_LINT_ERRORS : EXIT_OK;
120
+ }
121
+ /**
122
+ * True when this file is the script node was asked to run.
123
+ *
124
+ * npm installs the command as a symlink in `node_modules/.bin`, and on some
125
+ * systems the temporary and home directories are symlinked too, so both sides
126
+ * have to be resolved before they can be compared.
127
+ */
128
+ function isMainModule() {
129
+ const entryPoint = process.argv[1];
130
+ if (entryPoint === undefined) {
131
+ return false;
132
+ }
133
+ try {
134
+ return import.meta.url === pathToFileURL(fs.realpathSync(entryPoint)).href;
135
+ }
136
+ catch {
137
+ return false;
138
+ }
139
+ }
140
+ // Only take over the process when run as a command, not when imported.
141
+ if (isMainModule()) {
142
+ process.exitCode = await run(process.argv.slice(2));
143
+ }
144
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Ready-made configurations.
3
+ *
4
+ * `recommended` is what you get when there is no configuration file. It holds
5
+ * the rules that catch a mistake rather than express a preference: an empty
6
+ * file, a scenario with no name, a variable that will never be substituted.
7
+ * Nothing in it depends on how a team likes to lay a file out, so it should be
8
+ * quiet on a codebase that has never been linted.
9
+ *
10
+ * Rules about style - indentation, name length, which tags go where, whether
11
+ * repeated keywords become And - are deliberately left out. They are worth
12
+ * switching on, but that is a decision for a team to make rather than a
13
+ * default to inherit.
14
+ */
15
+ import type { Configuration } from './types.ts';
16
+ export declare const RECOMMENDED: Configuration;
17
+ /** The presets that can be named in a configuration file. */
18
+ export declare const PRESETS: Record<string, Configuration>;
19
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,WAAW,EAAE,aAkBzB,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAEjD,CAAC"}
@@ -0,0 +1,24 @@
1
+ export const RECOMMENDED = {
2
+ 'new-line-at-eof': ['on', 'yes'],
3
+ 'no-dupe-feature-names': 'on',
4
+ 'no-dupe-scenario-names': 'on',
5
+ 'no-duplicate-tags': 'on',
6
+ 'no-empty-background': 'on',
7
+ 'no-empty-file': 'on',
8
+ 'no-examples-in-scenarios': 'on',
9
+ 'no-files-without-scenarios': 'on',
10
+ 'no-multiple-empty-lines': 'on',
11
+ 'no-partially-commented-tag-lines': 'on',
12
+ 'no-scenario-outlines-without-examples': 'on',
13
+ 'no-trailing-spaces': 'on',
14
+ 'no-undeclared-variables': 'on',
15
+ 'no-unnamed-features': 'on',
16
+ 'no-unnamed-scenarios': 'on',
17
+ 'no-unused-variables': 'on',
18
+ 'one-space-between-tags': 'on',
19
+ };
20
+ /** The presets that can be named in a configuration file. */
21
+ export const PRESETS = {
22
+ 'gurkencheck:recommended': RECOMMENDED,
23
+ };
24
+ //# sourceMappingURL=presets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAgBA,MAAM,CAAC,MAAM,WAAW,GAAkB;IACxC,iBAAiB,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC;IAChC,uBAAuB,EAAE,IAAI;IAC7B,wBAAwB,EAAE,IAAI;IAC9B,mBAAmB,EAAE,IAAI;IACzB,qBAAqB,EAAE,IAAI;IAC3B,eAAe,EAAE,IAAI;IACrB,0BAA0B,EAAE,IAAI;IAChC,4BAA4B,EAAE,IAAI;IAClC,yBAAyB,EAAE,IAAI;IAC/B,kCAAkC,EAAE,IAAI;IACxC,uCAAuC,EAAE,IAAI;IAC7C,oBAAoB,EAAE,IAAI;IAC1B,yBAAyB,EAAE,IAAI;IAC/B,qBAAqB,EAAE,IAAI;IAC3B,sBAAsB,EAAE,IAAI;IAC5B,qBAAqB,EAAE,IAAI;IAC3B,wBAAwB,EAAE,IAAI;CAC/B,CAAC;AAEF,6DAA6D;AAC7D,MAAM,CAAC,MAAM,OAAO,GAAkC;IACpD,yBAAyB,EAAE,WAAW;CACvC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { LintRule } from '../types.ts';
2
+ declare const rule: LintRule;
3
+ export default rule;
4
+ //# sourceMappingURL=allowed-tags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowed-tags.d.ts","sourceRoot":"","sources":["../../src/rules/allowed-tags.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,QAAQ,EAAY,MAAM,aAAa,CAAC;AAerD,QAAA,MAAM,IAAI,EAAE,QA4BX,CAAC;eAEa,IAAI"}
@@ -0,0 +1,34 @@
1
+ import { getNodeType } from '../gherkin/keywords.js';
2
+ import { taggedNodesOf } from '../gherkin/traverse.js';
3
+ import { mergeDefaults } from '../util/collections.js';
4
+ import { at } from '../util/location.js';
5
+ const name = 'allowed-tags';
6
+ const availableConfigs = { tags: [], patterns: [] };
7
+ const rule = {
8
+ name,
9
+ availableConfigs,
10
+ run(feature, _file, configuration) {
11
+ if (feature === undefined) {
12
+ return [];
13
+ }
14
+ const config = mergeDefaults(availableConfigs, configuration);
15
+ const allowedTags = new Set(config.tags);
16
+ const allowedPatterns = config.patterns.map((pattern) => new RegExp(pattern));
17
+ const errors = [];
18
+ for (const { node } of taggedNodesOf(feature)) {
19
+ for (const tag of node.tags) {
20
+ const allowed = allowedTags.has(tag.name) || allowedPatterns.some((pattern) => pattern.test(tag.name));
21
+ if (!allowed) {
22
+ errors.push({
23
+ message: `Not allowed tag ${tag.name} on ${getNodeType(node, feature.language)}`,
24
+ rule: name,
25
+ ...at(tag.location),
26
+ });
27
+ }
28
+ }
29
+ }
30
+ return errors;
31
+ },
32
+ };
33
+ export default rule;
34
+ //# sourceMappingURL=allowed-tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowed-tags.js","sourceRoot":"","sources":["../../src/rules/allowed-tags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAC,EAAE,EAAC,MAAM,qBAAqB,CAAC;AAEvC,MAAM,IAAI,GAAG,cAAc,CAAC;AAS5B,MAAM,gBAAgB,GAAsB,EAAC,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAC,CAAC;AAErE,MAAM,IAAI,GAAa;IACrB,IAAI;IACJ,gBAAgB;IAChB,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,aAAa;QAC/B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAG,aAAa,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;QAC9D,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9E,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,KAAK,MAAM,EAAC,IAAI,EAAC,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC5B,MAAM,OAAO,GACX,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;gBACzF,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,MAAM,CAAC,IAAI,CAAC;wBACV,OAAO,EAAE,mBAAmB,GAAG,CAAC,IAAI,OAAO,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;wBAChF,IAAI,EAAE,IAAI;wBACV,GAAG,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC;qBACpB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { LintRule } from '../types.ts';
2
+ declare const rule: LintRule;
3
+ export default rule;
4
+ //# sourceMappingURL=file-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-name.d.ts","sourceRoot":"","sources":["../../src/rules/file-name.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAqB1C,QAAA,MAAM,IAAI,EAAE,QA0BX,CAAC;eAEa,IAAI"}
@@ -0,0 +1,41 @@
1
+ import path from 'node:path';
2
+ import { camelCase, kebabCase, pascalCase, snakeCase, titleCase } from '../util/case.js';
3
+ import { mergeDefaults } from '../util/collections.js';
4
+ const name = 'file-name';
5
+ const STYLES = {
6
+ PascalCase: pascalCase,
7
+ 'Title Case': titleCase,
8
+ camelCase,
9
+ 'kebab-case': kebabCase,
10
+ snake_case: snakeCase,
11
+ };
12
+ const availableConfigs = {
13
+ /** One of PascalCase, Title Case, camelCase, kebab-case or snake_case. */
14
+ style: 'PascalCase',
15
+ };
16
+ const rule = {
17
+ name,
18
+ availableConfigs,
19
+ run(_feature, file, configuration) {
20
+ const { style } = mergeDefaults(availableConfigs, configuration);
21
+ const convert = STYLES[style];
22
+ if (convert === undefined) {
23
+ throw new Error(`style "${style}" is not supported by the ${name} rule. ` +
24
+ `Supported styles: ${Object.keys(STYLES).join(', ')}`);
25
+ }
26
+ const fileName = path.basename(file.relativePath, '.feature');
27
+ const expected = convert(fileName);
28
+ if (fileName === expected) {
29
+ return [];
30
+ }
31
+ return [
32
+ {
33
+ message: `File names should be written in ${style} e.g. "${expected}.feature"`,
34
+ rule: name,
35
+ line: 0,
36
+ },
37
+ ];
38
+ },
39
+ };
40
+ export default rule;
41
+ //# sourceMappingURL=file-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-name.js","sourceRoot":"","sources":["../../src/rules/file-name.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAC,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAC,MAAM,iBAAiB,CAAC;AACvF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAErD,MAAM,IAAI,GAAG,WAAW,CAAC;AAEzB,MAAM,MAAM,GAAG;IACb,UAAU,EAAE,UAAU;IACtB,YAAY,EAAE,SAAS;IACvB,SAAS;IACT,YAAY,EAAE,SAAS;IACvB,UAAU,EAAE,SAAS;CACtB,CAAC;AAIF,MAAM,gBAAgB,GAAG;IACvB,0EAA0E;IAC1E,KAAK,EAAE,YAAqB;CAC7B,CAAC;AAEF,MAAM,IAAI,GAAa;IACrB,IAAI;IACJ,gBAAgB;IAChB,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,aAAa;QAC/B,MAAM,EAAC,KAAK,EAAC,GAAG,aAAa,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,UAAU,KAAK,6BAA6B,IAAI,SAAS;gBACvD,qBAAqB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxD,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO;YACL;gBACE,OAAO,EAAE,mCAAmC,KAAK,UAAU,QAAQ,WAAW;gBAC9E,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,CAAC;aACR;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { LintRule } from '../types.ts';
2
+ declare const rule: LintRule;
3
+ export default rule;
4
+ //# sourceMappingURL=indentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indentation.d.ts","sourceRoot":"","sources":["../../src/rules/indentation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,QAAQ,EAAY,MAAM,aAAa,CAAC;AA0ErD,QAAA,MAAM,IAAI,EAAE,QAgHX,CAAC;eAEa,IAAI"}