gurkencheck 0.0.10 → 0.1.0

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 (334) hide show
  1. package/README.md +30 -11
  2. package/dist/config-parser.d.ts +15 -1
  3. package/dist/config-parser.js +58 -12
  4. package/dist/config-verifier.d.ts +0 -1
  5. package/dist/config-verifier.js +71 -3
  6. package/dist/diagnostics.d.ts +0 -1
  7. package/dist/diagnostics.js +0 -1
  8. package/dist/exit-codes.d.ts +0 -1
  9. package/dist/exit-codes.js +0 -1
  10. package/dist/feature-finder.d.ts +0 -1
  11. package/dist/feature-finder.js +29 -11
  12. package/dist/formatters/index.d.ts +0 -1
  13. package/dist/formatters/index.js +2 -3
  14. package/dist/formatters/json.d.ts +0 -1
  15. package/dist/formatters/json.js +0 -1
  16. package/dist/formatters/junit.d.ts +1 -13
  17. package/dist/formatters/junit.js +36 -11
  18. package/dist/formatters/sarif.d.ts +0 -1
  19. package/dist/formatters/sarif.js +25 -7
  20. package/dist/formatters/stylish.d.ts +0 -1
  21. package/dist/formatters/stylish.js +0 -1
  22. package/dist/formatters/tap.d.ts +0 -1
  23. package/dist/formatters/tap.js +37 -5
  24. package/dist/gherkin/dialects.d.ts +0 -1
  25. package/dist/gherkin/dialects.js +0 -1
  26. package/dist/gherkin/keywords.d.ts +6 -3
  27. package/dist/gherkin/keywords.js +10 -4
  28. package/dist/gherkin/parse.d.ts +0 -1
  29. package/dist/gherkin/parse.js +19 -7
  30. package/dist/gherkin/traverse.d.ts +0 -1
  31. package/dist/gherkin/traverse.js +0 -1
  32. package/dist/gherkin/variables.d.ts +12 -1
  33. package/dist/gherkin/variables.js +24 -6
  34. package/dist/index.d.ts +1 -2
  35. package/dist/index.js +1 -2
  36. package/dist/linter.d.ts +0 -1
  37. package/dist/linter.js +1 -2
  38. package/dist/logger.d.ts +0 -1
  39. package/dist/logger.js +0 -1
  40. package/dist/main.d.ts +0 -1
  41. package/dist/main.js +78 -27
  42. package/dist/presets.d.ts +2 -2
  43. package/dist/presets.js +0 -5
  44. package/dist/rules/allowed-tags.d.ts +0 -1
  45. package/dist/rules/allowed-tags.js +2 -1
  46. package/dist/rules/background-setup-only.d.ts +0 -1
  47. package/dist/rules/background-setup-only.js +0 -1
  48. package/dist/rules/file-name.d.ts +0 -1
  49. package/dist/rules/file-name.js +10 -1
  50. package/dist/rules/indentation.d.ts +0 -1
  51. package/dist/rules/indentation.js +24 -10
  52. package/dist/rules/index.d.ts +0 -1
  53. package/dist/rules/index.js +0 -1
  54. package/dist/rules/keywords-in-logical-order.d.ts +0 -1
  55. package/dist/rules/keywords-in-logical-order.js +0 -1
  56. package/dist/rules/max-scenarios-per-file.d.ts +0 -1
  57. package/dist/rules/max-scenarios-per-file.js +0 -1
  58. package/dist/rules/name-length.d.ts +0 -1
  59. package/dist/rules/name-length.js +5 -3
  60. package/dist/rules/new-line-at-eof.d.ts +0 -1
  61. package/dist/rules/new-line-at-eof.js +10 -2
  62. package/dist/rules/no-background-only-scenario.d.ts +0 -1
  63. package/dist/rules/no-background-only-scenario.js +0 -1
  64. package/dist/rules/no-dupe-feature-names.d.ts +0 -1
  65. package/dist/rules/no-dupe-feature-names.js +5 -1
  66. package/dist/rules/no-dupe-file-names.d.ts +0 -1
  67. package/dist/rules/no-dupe-file-names.js +0 -1
  68. package/dist/rules/no-dupe-scenario-names.d.ts +0 -1
  69. package/dist/rules/no-dupe-scenario-names.js +4 -1
  70. package/dist/rules/no-duplicate-tags.d.ts +0 -1
  71. package/dist/rules/no-duplicate-tags.js +0 -1
  72. package/dist/rules/no-empty-background.d.ts +0 -1
  73. package/dist/rules/no-empty-background.js +0 -1
  74. package/dist/rules/no-empty-file.d.ts +0 -1
  75. package/dist/rules/no-empty-file.js +0 -1
  76. package/dist/rules/no-examples-in-scenarios.d.ts +0 -1
  77. package/dist/rules/no-examples-in-scenarios.js +0 -1
  78. package/dist/rules/no-files-without-scenarios.d.ts +0 -1
  79. package/dist/rules/no-files-without-scenarios.js +0 -1
  80. package/dist/rules/no-homogenous-tags.d.ts +0 -1
  81. package/dist/rules/no-homogenous-tags.js +0 -1
  82. package/dist/rules/no-multiple-empty-lines.d.ts +0 -1
  83. package/dist/rules/no-multiple-empty-lines.js +2 -3
  84. package/dist/rules/no-partially-commented-tag-lines.d.ts +0 -1
  85. package/dist/rules/no-partially-commented-tag-lines.js +7 -5
  86. package/dist/rules/no-restricted-patterns.d.ts +0 -1
  87. package/dist/rules/no-restricted-patterns.js +64 -19
  88. package/dist/rules/no-restricted-tags.d.ts +0 -1
  89. package/dist/rules/no-restricted-tags.js +2 -1
  90. package/dist/rules/no-scenario-outlines-without-examples.d.ts +0 -1
  91. package/dist/rules/no-scenario-outlines-without-examples.js +0 -1
  92. package/dist/rules/no-scenarios-without-then.d.ts +0 -1
  93. package/dist/rules/no-scenarios-without-then.js +0 -1
  94. package/dist/rules/no-scenarios-without-when.d.ts +0 -1
  95. package/dist/rules/no-scenarios-without-when.js +0 -1
  96. package/dist/rules/no-superfluous-tags.d.ts +0 -1
  97. package/dist/rules/no-superfluous-tags.js +0 -1
  98. package/dist/rules/no-trailing-spaces.d.ts +0 -1
  99. package/dist/rules/no-trailing-spaces.js +13 -4
  100. package/dist/rules/no-undeclared-variables.d.ts +0 -1
  101. package/dist/rules/no-undeclared-variables.js +12 -11
  102. package/dist/rules/no-unnamed-features.d.ts +0 -1
  103. package/dist/rules/no-unnamed-features.js +0 -1
  104. package/dist/rules/no-unnamed-scenarios.d.ts +0 -1
  105. package/dist/rules/no-unnamed-scenarios.js +0 -1
  106. package/dist/rules/no-unused-variables.d.ts +0 -1
  107. package/dist/rules/no-unused-variables.js +0 -1
  108. package/dist/rules/one-space-between-tags.d.ts +0 -1
  109. package/dist/rules/one-space-between-tags.js +3 -2
  110. package/dist/rules/only-one-when.d.ts +0 -1
  111. package/dist/rules/only-one-when.js +5 -5
  112. package/dist/rules/required-tags.d.ts +0 -1
  113. package/dist/rules/required-tags.js +13 -3
  114. package/dist/rules/scenario-size.d.ts +0 -1
  115. package/dist/rules/scenario-size.js +0 -1
  116. package/dist/rules/use-and.d.ts +0 -1
  117. package/dist/rules/use-and.js +2 -2
  118. package/dist/rules.d.ts +0 -1
  119. package/dist/rules.js +49 -4
  120. package/dist/stats/collect.d.ts +0 -1
  121. package/dist/stats/collect.js +0 -1
  122. package/dist/stats/command.d.ts +0 -1
  123. package/dist/stats/command.js +24 -7
  124. package/dist/stats/format/index.d.ts +0 -1
  125. package/dist/stats/format/index.js +0 -1
  126. package/dist/stats/format/json.d.ts +0 -1
  127. package/dist/stats/format/json.js +0 -1
  128. package/dist/stats/format/markdown.d.ts +0 -1
  129. package/dist/stats/format/markdown.js +24 -6
  130. package/dist/stats/format/shared.d.ts +0 -1
  131. package/dist/stats/format/shared.js +0 -1
  132. package/dist/stats/format/text.d.ts +0 -1
  133. package/dist/stats/format/text.js +0 -1
  134. package/dist/stats/index.d.ts +0 -1
  135. package/dist/stats/index.js +0 -1
  136. package/dist/stats/normalise.d.ts +0 -1
  137. package/dist/stats/normalise.js +27 -14
  138. package/dist/stats/similar.d.ts +0 -1
  139. package/dist/stats/similar.js +0 -1
  140. package/dist/stats/types.d.ts +0 -1
  141. package/dist/stats/types.js +0 -1
  142. package/dist/suppressions.d.ts +6 -3
  143. package/dist/suppressions.js +36 -30
  144. package/dist/types.d.ts +7 -1
  145. package/dist/types.js +0 -1
  146. package/dist/util/case.d.ts +2 -2
  147. package/dist/util/case.js +17 -3
  148. package/dist/util/collections.d.ts +0 -1
  149. package/dist/util/collections.js +0 -1
  150. package/dist/util/glob.d.ts +9 -3
  151. package/dist/util/glob.js +115 -27
  152. package/dist/util/json.d.ts +0 -1
  153. package/dist/util/json.js +0 -1
  154. package/dist/util/lines.d.ts +6 -4
  155. package/dist/util/lines.js +22 -4
  156. package/dist/util/location.d.ts +8 -1
  157. package/dist/util/location.js +10 -1
  158. package/dist/util/patterns.d.ts +9 -0
  159. package/dist/util/patterns.js +21 -0
  160. package/dist/util/resolve.d.ts +6 -0
  161. package/dist/util/resolve.js +101 -0
  162. package/dist/util/stream.d.ts +0 -1
  163. package/dist/util/stream.js +3 -2
  164. package/dist/util/xml.d.ts +0 -1
  165. package/dist/util/xml.js +17 -3
  166. package/dist/version.d.ts +0 -1
  167. package/dist/version.js +0 -1
  168. package/dist/watch.d.ts +11 -1
  169. package/dist/watch.js +38 -3
  170. package/package.json +2 -2
  171. package/dist/config-parser.d.ts.map +0 -1
  172. package/dist/config-parser.js.map +0 -1
  173. package/dist/config-verifier.d.ts.map +0 -1
  174. package/dist/config-verifier.js.map +0 -1
  175. package/dist/diagnostics.d.ts.map +0 -1
  176. package/dist/diagnostics.js.map +0 -1
  177. package/dist/exit-codes.d.ts.map +0 -1
  178. package/dist/exit-codes.js.map +0 -1
  179. package/dist/feature-finder.d.ts.map +0 -1
  180. package/dist/feature-finder.js.map +0 -1
  181. package/dist/formatters/index.d.ts.map +0 -1
  182. package/dist/formatters/index.js.map +0 -1
  183. package/dist/formatters/json.d.ts.map +0 -1
  184. package/dist/formatters/json.js.map +0 -1
  185. package/dist/formatters/junit.d.ts.map +0 -1
  186. package/dist/formatters/junit.js.map +0 -1
  187. package/dist/formatters/sarif.d.ts.map +0 -1
  188. package/dist/formatters/sarif.js.map +0 -1
  189. package/dist/formatters/stylish.d.ts.map +0 -1
  190. package/dist/formatters/stylish.js.map +0 -1
  191. package/dist/formatters/tap.d.ts.map +0 -1
  192. package/dist/formatters/tap.js.map +0 -1
  193. package/dist/gherkin/dialects.d.ts.map +0 -1
  194. package/dist/gherkin/dialects.js.map +0 -1
  195. package/dist/gherkin/keywords.d.ts.map +0 -1
  196. package/dist/gherkin/keywords.js.map +0 -1
  197. package/dist/gherkin/parse.d.ts.map +0 -1
  198. package/dist/gherkin/parse.js.map +0 -1
  199. package/dist/gherkin/traverse.d.ts.map +0 -1
  200. package/dist/gherkin/traverse.js.map +0 -1
  201. package/dist/gherkin/variables.d.ts.map +0 -1
  202. package/dist/gherkin/variables.js.map +0 -1
  203. package/dist/index.d.ts.map +0 -1
  204. package/dist/index.js.map +0 -1
  205. package/dist/linter.d.ts.map +0 -1
  206. package/dist/linter.js.map +0 -1
  207. package/dist/logger.d.ts.map +0 -1
  208. package/dist/logger.js.map +0 -1
  209. package/dist/main.d.ts.map +0 -1
  210. package/dist/main.js.map +0 -1
  211. package/dist/presets.d.ts.map +0 -1
  212. package/dist/presets.js.map +0 -1
  213. package/dist/rules/allowed-tags.d.ts.map +0 -1
  214. package/dist/rules/allowed-tags.js.map +0 -1
  215. package/dist/rules/background-setup-only.d.ts.map +0 -1
  216. package/dist/rules/background-setup-only.js.map +0 -1
  217. package/dist/rules/file-name.d.ts.map +0 -1
  218. package/dist/rules/file-name.js.map +0 -1
  219. package/dist/rules/indentation.d.ts.map +0 -1
  220. package/dist/rules/indentation.js.map +0 -1
  221. package/dist/rules/index.d.ts.map +0 -1
  222. package/dist/rules/index.js.map +0 -1
  223. package/dist/rules/keywords-in-logical-order.d.ts.map +0 -1
  224. package/dist/rules/keywords-in-logical-order.js.map +0 -1
  225. package/dist/rules/max-scenarios-per-file.d.ts.map +0 -1
  226. package/dist/rules/max-scenarios-per-file.js.map +0 -1
  227. package/dist/rules/name-length.d.ts.map +0 -1
  228. package/dist/rules/name-length.js.map +0 -1
  229. package/dist/rules/new-line-at-eof.d.ts.map +0 -1
  230. package/dist/rules/new-line-at-eof.js.map +0 -1
  231. package/dist/rules/no-background-only-scenario.d.ts.map +0 -1
  232. package/dist/rules/no-background-only-scenario.js.map +0 -1
  233. package/dist/rules/no-dupe-feature-names.d.ts.map +0 -1
  234. package/dist/rules/no-dupe-feature-names.js.map +0 -1
  235. package/dist/rules/no-dupe-file-names.d.ts.map +0 -1
  236. package/dist/rules/no-dupe-file-names.js.map +0 -1
  237. package/dist/rules/no-dupe-scenario-names.d.ts.map +0 -1
  238. package/dist/rules/no-dupe-scenario-names.js.map +0 -1
  239. package/dist/rules/no-duplicate-tags.d.ts.map +0 -1
  240. package/dist/rules/no-duplicate-tags.js.map +0 -1
  241. package/dist/rules/no-empty-background.d.ts.map +0 -1
  242. package/dist/rules/no-empty-background.js.map +0 -1
  243. package/dist/rules/no-empty-file.d.ts.map +0 -1
  244. package/dist/rules/no-empty-file.js.map +0 -1
  245. package/dist/rules/no-examples-in-scenarios.d.ts.map +0 -1
  246. package/dist/rules/no-examples-in-scenarios.js.map +0 -1
  247. package/dist/rules/no-files-without-scenarios.d.ts.map +0 -1
  248. package/dist/rules/no-files-without-scenarios.js.map +0 -1
  249. package/dist/rules/no-homogenous-tags.d.ts.map +0 -1
  250. package/dist/rules/no-homogenous-tags.js.map +0 -1
  251. package/dist/rules/no-multiple-empty-lines.d.ts.map +0 -1
  252. package/dist/rules/no-multiple-empty-lines.js.map +0 -1
  253. package/dist/rules/no-partially-commented-tag-lines.d.ts.map +0 -1
  254. package/dist/rules/no-partially-commented-tag-lines.js.map +0 -1
  255. package/dist/rules/no-restricted-patterns.d.ts.map +0 -1
  256. package/dist/rules/no-restricted-patterns.js.map +0 -1
  257. package/dist/rules/no-restricted-tags.d.ts.map +0 -1
  258. package/dist/rules/no-restricted-tags.js.map +0 -1
  259. package/dist/rules/no-scenario-outlines-without-examples.d.ts.map +0 -1
  260. package/dist/rules/no-scenario-outlines-without-examples.js.map +0 -1
  261. package/dist/rules/no-scenarios-without-then.d.ts.map +0 -1
  262. package/dist/rules/no-scenarios-without-then.js.map +0 -1
  263. package/dist/rules/no-scenarios-without-when.d.ts.map +0 -1
  264. package/dist/rules/no-scenarios-without-when.js.map +0 -1
  265. package/dist/rules/no-superfluous-tags.d.ts.map +0 -1
  266. package/dist/rules/no-superfluous-tags.js.map +0 -1
  267. package/dist/rules/no-trailing-spaces.d.ts.map +0 -1
  268. package/dist/rules/no-trailing-spaces.js.map +0 -1
  269. package/dist/rules/no-undeclared-variables.d.ts.map +0 -1
  270. package/dist/rules/no-undeclared-variables.js.map +0 -1
  271. package/dist/rules/no-unnamed-features.d.ts.map +0 -1
  272. package/dist/rules/no-unnamed-features.js.map +0 -1
  273. package/dist/rules/no-unnamed-scenarios.d.ts.map +0 -1
  274. package/dist/rules/no-unnamed-scenarios.js.map +0 -1
  275. package/dist/rules/no-unused-variables.d.ts.map +0 -1
  276. package/dist/rules/no-unused-variables.js.map +0 -1
  277. package/dist/rules/one-space-between-tags.d.ts.map +0 -1
  278. package/dist/rules/one-space-between-tags.js.map +0 -1
  279. package/dist/rules/only-one-when.d.ts.map +0 -1
  280. package/dist/rules/only-one-when.js.map +0 -1
  281. package/dist/rules/required-tags.d.ts.map +0 -1
  282. package/dist/rules/required-tags.js.map +0 -1
  283. package/dist/rules/scenario-size.d.ts.map +0 -1
  284. package/dist/rules/scenario-size.js.map +0 -1
  285. package/dist/rules/use-and.d.ts.map +0 -1
  286. package/dist/rules/use-and.js.map +0 -1
  287. package/dist/rules.d.ts.map +0 -1
  288. package/dist/rules.js.map +0 -1
  289. package/dist/stats/collect.d.ts.map +0 -1
  290. package/dist/stats/collect.js.map +0 -1
  291. package/dist/stats/command.d.ts.map +0 -1
  292. package/dist/stats/command.js.map +0 -1
  293. package/dist/stats/format/index.d.ts.map +0 -1
  294. package/dist/stats/format/index.js.map +0 -1
  295. package/dist/stats/format/json.d.ts.map +0 -1
  296. package/dist/stats/format/json.js.map +0 -1
  297. package/dist/stats/format/markdown.d.ts.map +0 -1
  298. package/dist/stats/format/markdown.js.map +0 -1
  299. package/dist/stats/format/shared.d.ts.map +0 -1
  300. package/dist/stats/format/shared.js.map +0 -1
  301. package/dist/stats/format/text.d.ts.map +0 -1
  302. package/dist/stats/format/text.js.map +0 -1
  303. package/dist/stats/index.d.ts.map +0 -1
  304. package/dist/stats/index.js.map +0 -1
  305. package/dist/stats/normalise.d.ts.map +0 -1
  306. package/dist/stats/normalise.js.map +0 -1
  307. package/dist/stats/similar.d.ts.map +0 -1
  308. package/dist/stats/similar.js.map +0 -1
  309. package/dist/stats/types.d.ts.map +0 -1
  310. package/dist/stats/types.js.map +0 -1
  311. package/dist/suppressions.d.ts.map +0 -1
  312. package/dist/suppressions.js.map +0 -1
  313. package/dist/types.d.ts.map +0 -1
  314. package/dist/types.js.map +0 -1
  315. package/dist/util/case.d.ts.map +0 -1
  316. package/dist/util/case.js.map +0 -1
  317. package/dist/util/collections.d.ts.map +0 -1
  318. package/dist/util/collections.js.map +0 -1
  319. package/dist/util/glob.d.ts.map +0 -1
  320. package/dist/util/glob.js.map +0 -1
  321. package/dist/util/json.d.ts.map +0 -1
  322. package/dist/util/json.js.map +0 -1
  323. package/dist/util/lines.d.ts.map +0 -1
  324. package/dist/util/lines.js.map +0 -1
  325. package/dist/util/location.d.ts.map +0 -1
  326. package/dist/util/location.js.map +0 -1
  327. package/dist/util/stream.d.ts.map +0 -1
  328. package/dist/util/stream.js.map +0 -1
  329. package/dist/util/xml.d.ts.map +0 -1
  330. package/dist/util/xml.js.map +0 -1
  331. package/dist/version.d.ts.map +0 -1
  332. package/dist/version.js.map +0 -1
  333. package/dist/watch.d.ts.map +0 -1
  334. package/dist/watch.js.map +0 -1
package/dist/presets.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export const RECOMMENDED = {
2
- 'new-line-at-eof': ['on', 'yes'],
3
2
  'no-dupe-feature-names': 'on',
4
3
  'no-dupe-scenario-names': 'on',
5
4
  'no-duplicate-tags': 'on',
@@ -7,18 +6,14 @@ export const RECOMMENDED = {
7
6
  'no-empty-file': 'on',
8
7
  'no-examples-in-scenarios': 'on',
9
8
  'no-files-without-scenarios': 'on',
10
- 'no-multiple-empty-lines': 'on',
11
9
  'no-partially-commented-tag-lines': 'on',
12
10
  'no-scenario-outlines-without-examples': 'on',
13
- 'no-trailing-spaces': 'on',
14
11
  'no-undeclared-variables': 'on',
15
12
  'no-unnamed-features': 'on',
16
13
  'no-unnamed-scenarios': 'on',
17
14
  'no-unused-variables': 'on',
18
- 'one-space-between-tags': 'on',
19
15
  };
20
16
  /** The presets that can be named in a configuration file. */
21
17
  export const PRESETS = {
22
18
  'gurkencheck:recommended': RECOMMENDED,
23
19
  };
24
- //# sourceMappingURL=presets.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=allowed-tags.d.ts.map
@@ -2,11 +2,13 @@ import { getNodeType } from '../gherkin/keywords.js';
2
2
  import { taggedNodesOf } from '../gherkin/traverse.js';
3
3
  import { mergeDefaults } from '../util/collections.js';
4
4
  import { at } from '../util/location.js';
5
+ import { invalidPatterns } from '../util/patterns.js';
5
6
  const name = 'allowed-tags';
6
7
  const availableConfigs = { tags: [], patterns: [] };
7
8
  const rule = {
8
9
  name,
9
10
  availableConfigs,
11
+ verifySettings: (settings) => invalidPatterns('patterns', settings['patterns']),
10
12
  run(feature, _file, configuration) {
11
13
  if (feature === undefined) {
12
14
  return [];
@@ -31,4 +33,3 @@ const rule = {
31
33
  },
32
34
  };
33
35
  export default rule;
34
- //# sourceMappingURL=allowed-tags.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=background-setup-only.d.ts.map
@@ -29,4 +29,3 @@ const rule = {
29
29
  },
30
30
  };
31
31
  export default rule;
32
- //# sourceMappingURL=background-setup-only.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=file-name.d.ts.map
@@ -16,6 +16,16 @@ const availableConfigs = {
16
16
  const rule = {
17
17
  name,
18
18
  availableConfigs,
19
+ verifySettings(settings) {
20
+ const style = settings['style'];
21
+ return style === undefined || Object.hasOwn(STYLES, style)
22
+ ? []
23
+ : [
24
+ `"style" should be one of ${Object.keys(STYLES)
25
+ .map((known) => `"${known}"`)
26
+ .join(', ')}, not ${JSON.stringify(style)}`,
27
+ ];
28
+ },
19
29
  run(_feature, file, configuration) {
20
30
  const { style } = mergeDefaults(availableConfigs, configuration);
21
31
  const convert = STYLES[style];
@@ -38,4 +48,3 @@ const rule = {
38
48
  },
39
49
  };
40
50
  export default rule;
41
- //# sourceMappingURL=file-name.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=indentation.d.ts.map
@@ -29,7 +29,9 @@ const availableConfigs = {
29
29
  'feature tag': -1,
30
30
  'rule tag': -1,
31
31
  'scenario tag': -1,
32
+ 'examples tag': -1,
32
33
  docstring: -1,
34
+ datatable: -1,
33
35
  /** One of "any", "space" or "tab". */
34
36
  character: 'any',
35
37
  };
@@ -43,12 +45,15 @@ function resolveConfig(configuration) {
43
45
  typeof configuration['scenario tag'] === 'number'
44
46
  ? configuration['scenario tag']
45
47
  : merged.Scenario;
46
- // A doc string belongs to its step and is conventionally indented one level
47
- // further in, so it follows the Step setting unless it is set on its own.
48
- merged.docstring =
49
- typeof configuration['docstring'] === 'number'
50
- ? configuration['docstring']
51
- : merged.Step + 2;
48
+ merged['examples tag'] =
49
+ typeof configuration['examples tag'] === 'number'
50
+ ? configuration['examples tag']
51
+ : merged.Examples;
52
+ // A doc string or a data table belongs to its step and is conventionally
53
+ // indented one level further in, so unless it is set on its own it follows
54
+ // the step it belongs to; -1 stands for that here.
55
+ merged.docstring = typeof configuration['docstring'] === 'number' ? configuration['docstring'] : -1;
56
+ merged.datatable = typeof configuration['datatable'] === 'number' ? configuration['datatable'] : -1;
52
57
  merged.character =
53
58
  configuration['character'] === 'space' || configuration['character'] === 'tab'
54
59
  ? configuration['character']
@@ -58,6 +63,12 @@ function resolveConfig(configuration) {
58
63
  const rule = {
59
64
  name,
60
65
  availableConfigs,
66
+ verifySettings(settings) {
67
+ const character = settings['character'];
68
+ return character === undefined || ['any', 'space', 'tab'].includes(character)
69
+ ? []
70
+ : [`"character" should be "any", "space" or "tab", not ${JSON.stringify(character)}`];
71
+ },
61
72
  run(feature, file, configuration) {
62
73
  if (feature === undefined) {
63
74
  return [];
@@ -82,11 +93,10 @@ const rule = {
82
93
  });
83
94
  }
84
95
  };
85
- const test = (location, type) => {
96
+ const test = (location, type, expected = config[type]) => {
86
97
  testCharacter(location, type);
87
98
  // Columns are 1-based, indentation is counted from 0.
88
99
  const actual = (location.column ?? 1) - 1;
89
- const expected = config[type];
90
100
  if (actual !== expected) {
91
101
  errors.push({
92
102
  message: `Wrong indentation for "${type}", expected indentation level of ${expected}, but got ${actual}`,
@@ -100,8 +110,12 @@ const rule = {
100
110
  // A step only uses its own keyword's setting when the user set one.
101
111
  const type = keyword !== '' && keyword in raw ? keyword : 'Step';
102
112
  test(step.location, type);
113
+ const underStep = config[type] + 2;
103
114
  if (step.docString !== undefined) {
104
- test(step.docString.location, 'docstring');
115
+ test(step.docString.location, 'docstring', config.docstring === -1 ? underStep : config.docstring);
116
+ }
117
+ for (const row of step.dataTable?.rows ?? []) {
118
+ test(row.location, 'datatable', config.datatable === -1 ? underStep : config.datatable);
105
119
  }
106
120
  };
107
121
  const testTags = (tags, type) => {
@@ -125,6 +139,7 @@ const rule = {
125
139
  child.scenario.steps.forEach(testStep);
126
140
  for (const examples of child.scenario.examples) {
127
141
  test(examples.location, 'Examples');
142
+ testTags(examples.tags, 'examples tag');
128
143
  if (examples.tableHeader !== undefined) {
129
144
  test(examples.tableHeader.location, 'example');
130
145
  for (const row of examples.tableBody) {
@@ -150,4 +165,3 @@ const rule = {
150
165
  },
151
166
  };
152
167
  export default rule;
153
- //# sourceMappingURL=indentation.js.map
@@ -10,4 +10,3 @@
10
10
  import type { LintRule } from '../types.ts';
11
11
  /** Every rule shipped with gurkencheck, in alphabetical order. */
12
12
  export declare const BUILT_IN_RULES: readonly LintRule[];
13
- //# sourceMappingURL=index.d.ts.map
@@ -73,4 +73,3 @@ export const BUILT_IN_RULES = [
73
73
  scenarioSize,
74
74
  useAnd,
75
75
  ];
76
- //# sourceMappingURL=index.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=keywords-in-logical-order.d.ts.map
@@ -34,4 +34,3 @@ const rule = {
34
34
  },
35
35
  };
36
36
  export default rule;
37
- //# sourceMappingURL=keywords-in-logical-order.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=max-scenarios-per-file.d.ts.map
@@ -39,4 +39,3 @@ const rule = {
39
39
  },
40
40
  };
41
41
  export default rule;
42
- //# sourceMappingURL=max-scenarios-per-file.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=name-length.d.ts.map
@@ -20,11 +20,14 @@ const rule = {
20
20
  const errors = [];
21
21
  const test = (text, location, type) => {
22
22
  const maximum = config[type];
23
+ // Characters, not the UTF-16 units .length counts: an emoji is one
24
+ // character to the person reading the name, not two.
25
+ const length = [...text].length;
23
26
  // A limit of 0 turns the check off for that kind of name, for teams that
24
27
  // want a limit on scenario names but not on step text, or the reverse.
25
- if (maximum > 0 && text !== '' && text.length > maximum) {
28
+ if (maximum > 0 && text !== '' && length > maximum) {
26
29
  errors.push({
27
- message: `${type} name is too long. Length of ${text.length} is longer than the maximum allowed: ${maximum}`,
30
+ message: `${type} name is too long. Length of ${length} is longer than the maximum allowed: ${maximum}`,
28
31
  rule: name,
29
32
  ...at(location),
30
33
  });
@@ -47,4 +50,3 @@ const rule = {
47
50
  },
48
51
  };
49
52
  export default rule;
50
- //# sourceMappingURL=name-length.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=new-line-at-eof.d.ts.map
@@ -1,3 +1,4 @@
1
+ import { contentLines } from '../util/lines.js';
1
2
  const name = 'new-line-at-eof';
2
3
  /** Whether a trailing new line is required (`yes`) or forbidden (`no`). */
3
4
  const availableConfigs = ['yes', 'no'];
@@ -10,6 +11,12 @@ const rule = {
10
11
  availableConfigs,
11
12
  run(_feature, file, configuration) {
12
13
  const setting = toSetting(configuration);
14
+ // An empty file has no line for a new line to end, so there is nothing to
15
+ // require or forbid. Splitting it gives a single empty entry, which would
16
+ // otherwise read as a new line at the end.
17
+ if (file.lines.length === 1 && file.lines[0] === '') {
18
+ return [];
19
+ }
13
20
  // Splitting on line breaks leaves a trailing empty entry when the file
14
21
  // ends with one.
15
22
  const hasNewLineAtEof = file.lines.at(-1) === '';
@@ -23,8 +30,9 @@ const rule = {
23
30
  if (message === '') {
24
31
  return [];
25
32
  }
26
- return [{ message, rule: name, line: file.lines.length }];
33
+ // The last line of the file: the one the new line ends, or the one
34
+ // missing it. contentLines leaves out the empty entry after a new line.
35
+ return [{ message, rule: name, line: contentLines(file).length }];
27
36
  },
28
37
  };
29
38
  export default rule;
30
- //# sourceMappingURL=new-line-at-eof.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-background-only-scenario.d.ts.map
@@ -40,4 +40,3 @@ const rule = {
40
40
  },
41
41
  };
42
42
  export default rule;
43
- //# sourceMappingURL=no-background-only-scenario.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-dupe-feature-names.d.ts.map
@@ -6,6 +6,11 @@ const rule = {
6
6
  if (feature === undefined) {
7
7
  return [];
8
8
  }
9
+ // A feature with no name is no-unnamed-features' finding, not a clash
10
+ // between every file that forgot one.
11
+ if (feature.name.trim() === '') {
12
+ return [];
13
+ }
9
14
  const seen = context.state(() => new Map());
10
15
  const sightings = seen.get(feature.name) ?? [];
11
16
  sightings.push({ filePath: file.relativePath, at: at(feature.location) });
@@ -35,4 +40,3 @@ const rule = {
35
40
  },
36
41
  };
37
42
  export default rule;
38
- //# sourceMappingURL=no-dupe-feature-names.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-dupe-file-names.d.ts.map
@@ -40,4 +40,3 @@ const rule = {
40
40
  },
41
41
  };
42
42
  export default rule;
43
- //# sourceMappingURL=no-dupe-file-names.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-dupe-scenario-names.d.ts.map
@@ -13,6 +13,10 @@ const rule = {
13
13
  const seen = context.state(() => new Map());
14
14
  const withinOneFile = configuration === 'in-feature';
15
15
  for (const { scenario } of scenariosOf(feature)) {
16
+ // A scenario with no name is no-unnamed-scenarios' finding, not a clash.
17
+ if (scenario.name.trim() === '') {
18
+ continue;
19
+ }
16
20
  // Told to look within each file, a name only clashes with the same name
17
21
  // in the same file - so which file it is in is part of what makes a
18
22
  // name that name. A newline cannot appear in either half, so the two
@@ -50,4 +54,3 @@ const rule = {
50
54
  },
51
55
  };
52
56
  export default rule;
53
- //# sourceMappingURL=no-dupe-scenario-names.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-duplicate-tags.d.ts.map
@@ -35,4 +35,3 @@ const rule = {
35
35
  },
36
36
  };
37
37
  export default rule;
38
- //# sourceMappingURL=no-duplicate-tags.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-empty-background.d.ts.map
@@ -21,4 +21,3 @@ const rule = {
21
21
  },
22
22
  };
23
23
  export default rule;
24
- //# sourceMappingURL=no-empty-background.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-empty-file.d.ts.map
@@ -9,4 +9,3 @@ const rule = {
9
9
  },
10
10
  };
11
11
  export default rule;
12
- //# sourceMappingURL=no-empty-file.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-examples-in-scenarios.d.ts.map
@@ -22,4 +22,3 @@ const rule = {
22
22
  },
23
23
  };
24
24
  export default rule;
25
- //# sourceMappingURL=no-examples-in-scenarios.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-files-without-scenarios.d.ts.map
@@ -15,4 +15,3 @@ const rule = {
15
15
  },
16
16
  };
17
17
  export default rule;
18
- //# sourceMappingURL=no-files-without-scenarios.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-homogenous-tags.d.ts.map
@@ -51,4 +51,3 @@ const rule = {
51
51
  },
52
52
  };
53
53
  export default rule;
54
- //# sourceMappingURL=no-homogenous-tags.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-multiple-empty-lines.d.ts.map
@@ -13,10 +13,10 @@ function messageFor(max) {
13
13
  const rule = {
14
14
  name,
15
15
  availableConfigs,
16
- run(_feature, file, configuration) {
16
+ run(feature, file, configuration) {
17
17
  const { max } = mergeDefaults(availableConfigs, configuration);
18
18
  const lines = contentLines(file);
19
- const inDocString = markDocStrings(lines);
19
+ const inDocString = markDocStrings(lines, feature);
20
20
  const message = messageFor(max);
21
21
  const errors = [];
22
22
  let blanksInARow = 0;
@@ -41,4 +41,3 @@ const rule = {
41
41
  },
42
42
  };
43
43
  export default rule;
44
- //# sourceMappingURL=no-multiple-empty-lines.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-partially-commented-tag-lines.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { taggedNodesOf } from '../gherkin/traverse.js';
2
- import { atLineColumn } from '../util/location.js';
2
+ import { atLineColumn, columnOf } from '../util/location.js';
3
3
  const name = 'no-partially-commented-tag-lines';
4
4
  /**
5
5
  * A `#` on a tag line comments out everything after it. That is easy to do by
@@ -27,13 +27,16 @@ const rule = {
27
27
  }
28
28
  const errors = [];
29
29
  for (const line of [...tagLines].sort((a, b) => a - b)) {
30
- const comment = file.lines[line - 1]?.indexOf('#') ?? -1;
31
- if (comment !== -1) {
30
+ // As in Gherkin itself, only a # after whitespace starts a comment;
31
+ // one inside a tag, as in @issue#123, is part of the tag.
32
+ const text = file.lines[line - 1] ?? '';
33
+ const comment = /\s#/u.exec(text);
34
+ if (comment !== null) {
32
35
  errors.push({
33
36
  message: 'Partially commented tag lines not allowed',
34
37
  rule: name,
35
38
  // Point at the '#' itself: that is the character to remove.
36
- ...atLineColumn(line, comment + 1),
39
+ ...atLineColumn(line, columnOf(text, comment.index + 1)),
37
40
  });
38
41
  }
39
42
  }
@@ -41,4 +44,3 @@ const rule = {
41
44
  },
42
45
  };
43
46
  export default rule;
44
- //# sourceMappingURL=no-partially-commented-tag-lines.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-restricted-patterns.d.ts.map
@@ -2,6 +2,7 @@ import { getNeutralKeyword, getNodeType } from '../gherkin/keywords.js';
2
2
  import { rulesOf, stepContainersOf } from '../gherkin/traverse.js';
3
3
  import { mergeDefaults } from '../util/collections.js';
4
4
  import { at } from '../util/location.js';
5
+ import { invalidPatterns } from '../util/patterns.js';
5
6
  const name = 'no-restricted-patterns';
6
7
  /**
7
8
  * Patterns are grouped by where they apply. `Global` applies everywhere; the
@@ -51,51 +52,95 @@ function toCheckableStrings(property, value) {
51
52
  const rule = {
52
53
  name,
53
54
  availableConfigs,
54
- run(feature, _file, configuration) {
55
+ verifySettings: (settings) => Object.entries(settings).flatMap(([key, patterns]) => invalidPatterns(key, patterns, 'i')),
56
+ run(feature, file, configuration) {
55
57
  if (feature === undefined) {
56
58
  return [];
57
59
  }
58
60
  const patterns = compilePatterns(mergeDefaults(availableConfigs, configuration));
59
61
  const language = feature.language;
60
62
  const errors = [];
61
- const check = (node, property, value, applicable) => {
63
+ /** Reports every pattern the text matches, at the given position. */
64
+ const report = (type, property, text, applicable, position) => {
65
+ for (const pattern of applicable) {
66
+ if (pattern.test(text)) {
67
+ errors.push({
68
+ message: `${type} ${property}: "${text}" matches restricted pattern "${pattern}"`,
69
+ rule: name,
70
+ ...position,
71
+ });
72
+ }
73
+ }
74
+ };
75
+ const check = (node, property, value, applicable, location = node.location) => {
62
76
  if (value === undefined || value === '') {
63
77
  return;
64
78
  }
79
+ // Names may be padded with whitespace; steps are not.
80
+ report(getNodeType(node, language), property, value.trim(), applicable, at(location));
81
+ };
82
+ /**
83
+ * A description, line by line, each reported on the line it is written
84
+ * on. The description starts below the keyword line, and a comment
85
+ * between its lines is left out of it, so each line is looked for in the
86
+ * file rather than counted.
87
+ */
88
+ const checkDescription = (node, applicable) => {
89
+ if (node.description === undefined || node.description === '') {
90
+ return;
91
+ }
65
92
  const type = getNodeType(node, language);
66
- for (const pattern of applicable) {
67
- for (const candidate of toCheckableStrings(property, value)) {
68
- // Names and descriptions may be padded with whitespace; steps are not.
69
- const text = candidate.trim();
70
- if (pattern.test(text)) {
71
- errors.push({
72
- message: `${type} ${property}: "${text}" matches restricted pattern "${pattern}"`,
73
- rule: name,
74
- ...at(node.location),
75
- });
76
- }
77
- }
93
+ let searchFrom = node.location.line;
94
+ for (const candidate of toCheckableStrings('description', node.description)) {
95
+ const text = candidate.trim();
96
+ if (text === '')
97
+ continue;
98
+ const index = file.lines.findIndex((line, lineIndex) => lineIndex >= searchFrom && line.trim() === text);
99
+ const line = index === -1 ? node.location.line : index + 1;
100
+ if (index !== -1)
101
+ searchFrom = index + 1;
102
+ report(type, 'description', text, applicable, { line });
78
103
  }
79
104
  };
80
105
  const patternsFor = (node) => patterns.get(getNeutralKeyword(node, language)) ?? [];
81
106
  check(feature, 'name', feature.name, patternsFor(feature));
82
- check(feature, 'description', feature.description, patternsFor(feature));
107
+ checkDescription(feature, patternsFor(feature));
83
108
  for (const featureRule of rulesOf(feature)) {
84
109
  const applicable = patternsFor(featureRule);
85
110
  check(featureRule, 'name', featureRule.name, applicable);
86
- check(featureRule, 'description', featureRule.description, applicable);
111
+ checkDescription(featureRule, applicable);
87
112
  }
88
113
  for (const { node } of stepContainersOf(feature)) {
89
114
  const applicable = patternsFor(node);
90
115
  check(node, 'name', node.name, applicable);
91
- check(node, 'description', node.description, applicable);
92
- // Steps are checked against the patterns of the block they sit in.
116
+ checkDescription(node, applicable);
117
+ // Steps, and what they carry, are checked against the patterns of the
118
+ // block they sit in.
93
119
  for (const step of node.steps) {
94
120
  check(step, 'text', step.text, applicable);
121
+ for (const row of step.dataTable?.rows ?? []) {
122
+ for (const cell of row.cells) {
123
+ if (cell.value.trim() !== '') {
124
+ report('Step', 'data table', cell.value.trim(), applicable, at(cell.location));
125
+ }
126
+ }
127
+ }
128
+ if (step.docString !== undefined) {
129
+ const { content, location } = step.docString;
130
+ content.split('\n').forEach((line, index) => {
131
+ if (line.trim() !== '') {
132
+ report('Step', 'doc string', line.trim(), applicable, { line: location.line + 1 + index });
133
+ }
134
+ });
135
+ }
136
+ }
137
+ // An outline's Examples belong to it, and take its patterns.
138
+ for (const examples of 'examples' in node ? node.examples : []) {
139
+ check(examples, 'name', examples.name, applicable);
140
+ checkDescription(examples, applicable);
95
141
  }
96
142
  }
97
143
  return errors;
98
144
  },
99
145
  };
100
146
  export default rule;
101
- //# sourceMappingURL=no-restricted-patterns.js.map
@@ -1,4 +1,3 @@
1
1
  import type { LintRule } from '../types.ts';
2
2
  declare const rule: LintRule;
3
3
  export default rule;
4
- //# sourceMappingURL=no-restricted-tags.d.ts.map