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.
- package/LICENSE +13 -0
- package/README.md +327 -0
- package/dist/config-parser.d.ts +21 -0
- package/dist/config-parser.d.ts.map +1 -0
- package/dist/config-parser.js +171 -0
- package/dist/config-parser.js.map +1 -0
- package/dist/config-verifier.d.ts +4 -0
- package/dist/config-verifier.d.ts.map +1 -0
- package/dist/config-verifier.js +81 -0
- package/dist/config-verifier.js.map +1 -0
- package/dist/feature-finder.d.ts +18 -0
- package/dist/feature-finder.d.ts.map +1 -0
- package/dist/feature-finder.js +70 -0
- package/dist/feature-finder.js.map +1 -0
- package/dist/formatters/index.d.ts +23 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +79 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/json.d.ts +31 -0
- package/dist/formatters/json.d.ts.map +1 -0
- package/dist/formatters/json.js +31 -0
- package/dist/formatters/json.js.map +1 -0
- package/dist/formatters/junit.d.ts +17 -0
- package/dist/formatters/junit.d.ts.map +1 -0
- package/dist/formatters/junit.js +61 -0
- package/dist/formatters/junit.js.map +1 -0
- package/dist/formatters/sarif.d.ts +6 -0
- package/dist/formatters/sarif.d.ts.map +1 -0
- package/dist/formatters/sarif.js +81 -0
- package/dist/formatters/sarif.js.map +1 -0
- package/dist/formatters/stylish.d.ts +9 -0
- package/dist/formatters/stylish.d.ts.map +1 -0
- package/dist/formatters/stylish.js +66 -0
- package/dist/formatters/stylish.js.map +1 -0
- package/dist/formatters/tap.d.ts +14 -0
- package/dist/formatters/tap.d.ts.map +1 -0
- package/dist/formatters/tap.js +45 -0
- package/dist/formatters/tap.js.map +1 -0
- package/dist/gherkin/dialects.d.ts +31 -0
- package/dist/gherkin/dialects.d.ts.map +1 -0
- package/dist/gherkin/dialects.js +40 -0
- package/dist/gherkin/dialects.js.map +1 -0
- package/dist/gherkin/keywords.d.ts +21 -0
- package/dist/gherkin/keywords.d.ts.map +1 -0
- package/dist/gherkin/keywords.js +53 -0
- package/dist/gherkin/keywords.js.map +1 -0
- package/dist/gherkin/parse.d.ts +32 -0
- package/dist/gherkin/parse.d.ts.map +1 -0
- package/dist/gherkin/parse.js +236 -0
- package/dist/gherkin/parse.js.map +1 -0
- package/dist/gherkin/traverse.d.ts +45 -0
- package/dist/gherkin/traverse.d.ts.map +1 -0
- package/dist/gherkin/traverse.js +89 -0
- package/dist/gherkin/traverse.js.map +1 -0
- package/dist/gherkin/variables.d.ts +26 -0
- package/dist/gherkin/variables.d.ts.map +1 -0
- package/dist/gherkin/variables.js +51 -0
- package/dist/gherkin/variables.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/linter.d.ts +23 -0
- package/dist/linter.d.ts.map +1 -0
- package/dist/linter.js +57 -0
- package/dist/linter.js.map +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +28 -0
- package/dist/logger.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +144 -0
- package/dist/main.js.map +1 -0
- package/dist/presets.d.ts +19 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +24 -0
- package/dist/presets.js.map +1 -0
- package/dist/rules/allowed-tags.d.ts +4 -0
- package/dist/rules/allowed-tags.d.ts.map +1 -0
- package/dist/rules/allowed-tags.js +34 -0
- package/dist/rules/allowed-tags.js.map +1 -0
- package/dist/rules/file-name.d.ts +4 -0
- package/dist/rules/file-name.d.ts.map +1 -0
- package/dist/rules/file-name.js +41 -0
- package/dist/rules/file-name.js.map +1 -0
- package/dist/rules/indentation.d.ts +4 -0
- package/dist/rules/indentation.d.ts.map +1 -0
- package/dist/rules/indentation.js +153 -0
- package/dist/rules/indentation.js.map +1 -0
- package/dist/rules/index.d.ts +13 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +70 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/keywords-in-logical-order.d.ts +4 -0
- package/dist/rules/keywords-in-logical-order.d.ts.map +1 -0
- package/dist/rules/keywords-in-logical-order.js +37 -0
- package/dist/rules/keywords-in-logical-order.js.map +1 -0
- package/dist/rules/max-scenarios-per-file.d.ts +4 -0
- package/dist/rules/max-scenarios-per-file.d.ts.map +1 -0
- package/dist/rules/max-scenarios-per-file.js +42 -0
- package/dist/rules/max-scenarios-per-file.js.map +1 -0
- package/dist/rules/name-length.d.ts +4 -0
- package/dist/rules/name-length.d.ts.map +1 -0
- package/dist/rules/name-length.js +50 -0
- package/dist/rules/name-length.js.map +1 -0
- package/dist/rules/new-line-at-eof.d.ts +4 -0
- package/dist/rules/new-line-at-eof.d.ts.map +1 -0
- package/dist/rules/new-line-at-eof.js +30 -0
- package/dist/rules/new-line-at-eof.js.map +1 -0
- package/dist/rules/no-background-only-scenario.d.ts +4 -0
- package/dist/rules/no-background-only-scenario.d.ts.map +1 -0
- package/dist/rules/no-background-only-scenario.js +43 -0
- package/dist/rules/no-background-only-scenario.js.map +1 -0
- package/dist/rules/no-dupe-feature-names.d.ts +4 -0
- package/dist/rules/no-dupe-feature-names.d.ts.map +1 -0
- package/dist/rules/no-dupe-feature-names.js +25 -0
- package/dist/rules/no-dupe-feature-names.js.map +1 -0
- package/dist/rules/no-dupe-file-names.d.ts +4 -0
- package/dist/rules/no-dupe-file-names.d.ts.map +1 -0
- package/dist/rules/no-dupe-file-names.js +28 -0
- package/dist/rules/no-dupe-file-names.js.map +1 -0
- package/dist/rules/no-dupe-scenario-names.d.ts +4 -0
- package/dist/rules/no-dupe-scenario-names.d.ts.map +1 -0
- package/dist/rules/no-dupe-scenario-names.js +41 -0
- package/dist/rules/no-dupe-scenario-names.js.map +1 -0
- package/dist/rules/no-duplicate-tags.d.ts +4 -0
- package/dist/rules/no-duplicate-tags.d.ts.map +1 -0
- package/dist/rules/no-duplicate-tags.js +38 -0
- package/dist/rules/no-duplicate-tags.js.map +1 -0
- package/dist/rules/no-empty-background.d.ts +4 -0
- package/dist/rules/no-empty-background.d.ts.map +1 -0
- package/dist/rules/no-empty-background.js +24 -0
- package/dist/rules/no-empty-background.js.map +1 -0
- package/dist/rules/no-empty-file.d.ts +4 -0
- package/dist/rules/no-empty-file.d.ts.map +1 -0
- package/dist/rules/no-empty-file.js +12 -0
- package/dist/rules/no-empty-file.js.map +1 -0
- package/dist/rules/no-examples-in-scenarios.d.ts +4 -0
- package/dist/rules/no-examples-in-scenarios.d.ts.map +1 -0
- package/dist/rules/no-examples-in-scenarios.js +25 -0
- package/dist/rules/no-examples-in-scenarios.js.map +1 -0
- package/dist/rules/no-files-without-scenarios.d.ts +4 -0
- package/dist/rules/no-files-without-scenarios.d.ts.map +1 -0
- package/dist/rules/no-files-without-scenarios.js +18 -0
- package/dist/rules/no-files-without-scenarios.js.map +1 -0
- package/dist/rules/no-homogenous-tags.d.ts +4 -0
- package/dist/rules/no-homogenous-tags.d.ts.map +1 -0
- package/dist/rules/no-homogenous-tags.js +54 -0
- package/dist/rules/no-homogenous-tags.js.map +1 -0
- package/dist/rules/no-multiple-empty-lines.d.ts +4 -0
- package/dist/rules/no-multiple-empty-lines.d.ts.map +1 -0
- package/dist/rules/no-multiple-empty-lines.js +44 -0
- package/dist/rules/no-multiple-empty-lines.js.map +1 -0
- package/dist/rules/no-partially-commented-tag-lines.d.ts +4 -0
- package/dist/rules/no-partially-commented-tag-lines.d.ts.map +1 -0
- package/dist/rules/no-partially-commented-tag-lines.js +44 -0
- package/dist/rules/no-partially-commented-tag-lines.js.map +1 -0
- package/dist/rules/no-restricted-patterns.d.ts +4 -0
- package/dist/rules/no-restricted-patterns.d.ts.map +1 -0
- package/dist/rules/no-restricted-patterns.js +101 -0
- package/dist/rules/no-restricted-patterns.js.map +1 -0
- package/dist/rules/no-restricted-tags.d.ts +4 -0
- package/dist/rules/no-restricted-tags.d.ts.map +1 -0
- package/dist/rules/no-restricted-tags.js +35 -0
- package/dist/rules/no-restricted-tags.js.map +1 -0
- package/dist/rules/no-scenario-outlines-without-examples.d.ts +4 -0
- package/dist/rules/no-scenario-outlines-without-examples.d.ts.map +1 -0
- package/dist/rules/no-scenario-outlines-without-examples.js +29 -0
- package/dist/rules/no-scenario-outlines-without-examples.js.map +1 -0
- package/dist/rules/no-superfluous-tags.d.ts +4 -0
- package/dist/rules/no-superfluous-tags.d.ts.map +1 -0
- package/dist/rules/no-superfluous-tags.js +40 -0
- package/dist/rules/no-superfluous-tags.js.map +1 -0
- package/dist/rules/no-trailing-spaces.d.ts +4 -0
- package/dist/rules/no-trailing-spaces.d.ts.map +1 -0
- package/dist/rules/no-trailing-spaces.js +24 -0
- package/dist/rules/no-trailing-spaces.js.map +1 -0
- package/dist/rules/no-undeclared-variables.d.ts +4 -0
- package/dist/rules/no-undeclared-variables.d.ts.map +1 -0
- package/dist/rules/no-undeclared-variables.js +35 -0
- package/dist/rules/no-undeclared-variables.js.map +1 -0
- package/dist/rules/no-unnamed-features.d.ts +4 -0
- package/dist/rules/no-unnamed-features.d.ts.map +1 -0
- package/dist/rules/no-unnamed-features.js +19 -0
- package/dist/rules/no-unnamed-features.js.map +1 -0
- package/dist/rules/no-unnamed-scenarios.d.ts +4 -0
- package/dist/rules/no-unnamed-scenarios.d.ts.map +1 -0
- package/dist/rules/no-unnamed-scenarios.js +24 -0
- package/dist/rules/no-unnamed-scenarios.js.map +1 -0
- package/dist/rules/no-unused-variables.d.ts +4 -0
- package/dist/rules/no-unused-variables.d.ts.map +1 -0
- package/dist/rules/no-unused-variables.js +36 -0
- package/dist/rules/no-unused-variables.js.map +1 -0
- package/dist/rules/one-space-between-tags.d.ts +4 -0
- package/dist/rules/one-space-between-tags.d.ts.map +1 -0
- package/dist/rules/one-space-between-tags.js +36 -0
- package/dist/rules/one-space-between-tags.js.map +1 -0
- package/dist/rules/only-one-when.d.ts +4 -0
- package/dist/rules/only-one-when.d.ts.map +1 -0
- package/dist/rules/only-one-when.js +59 -0
- package/dist/rules/only-one-when.js.map +1 -0
- package/dist/rules/required-tags.d.ts +4 -0
- package/dist/rules/required-tags.d.ts.map +1 -0
- package/dist/rules/required-tags.js +36 -0
- package/dist/rules/required-tags.js.map +1 -0
- package/dist/rules/scenario-size.d.ts +4 -0
- package/dist/rules/scenario-size.d.ts.map +1 -0
- package/dist/rules/scenario-size.js +37 -0
- package/dist/rules/scenario-size.js.map +1 -0
- package/dist/rules/use-and.d.ts +4 -0
- package/dist/rules/use-and.d.ts.map +1 -0
- package/dist/rules/use-and.js +33 -0
- package/dist/rules/use-and.js.map +1 -0
- package/dist/rules.d.ts +24 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +109 -0
- package/dist/rules.js.map +1 -0
- package/dist/suppressions.d.ts +33 -0
- package/dist/suppressions.d.ts.map +1 -0
- package/dist/suppressions.js +84 -0
- package/dist/suppressions.js.map +1 -0
- package/dist/types.d.ts +81 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/util/case.d.ts +21 -0
- package/dist/util/case.d.ts.map +1 -0
- package/dist/util/case.js +42 -0
- package/dist/util/case.js.map +1 -0
- package/dist/util/collections.d.ts +30 -0
- package/dist/util/collections.d.ts.map +1 -0
- package/dist/util/collections.js +87 -0
- package/dist/util/collections.js.map +1 -0
- package/dist/util/glob.d.ts +20 -0
- package/dist/util/glob.d.ts.map +1 -0
- package/dist/util/glob.js +203 -0
- package/dist/util/glob.js.map +1 -0
- package/dist/util/json.d.ts +14 -0
- package/dist/util/json.d.ts.map +1 -0
- package/dist/util/json.js +63 -0
- package/dist/util/json.js.map +1 -0
- package/dist/util/lines.d.ts +24 -0
- package/dist/util/lines.d.ts.map +1 -0
- package/dist/util/lines.js +45 -0
- package/dist/util/lines.js.map +1 -0
- package/dist/util/location.d.ts +15 -0
- package/dist/util/location.d.ts.map +1 -0
- package/dist/util/location.js +11 -0
- package/dist/util/location.js.map +1 -0
- package/dist/util/xml.d.ts +16 -0
- package/dist/util/xml.d.ts.map +1 -0
- package/dist/util/xml.js +36 -0
- package/dist/util/xml.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +24 -0
- package/dist/version.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { getNeutralKeyword } from '../gherkin/keywords.js';
|
|
2
|
+
import { groupBy, mergeDefaults, sortBy } from '../util/collections.js';
|
|
3
|
+
import { at } from '../util/location.js';
|
|
4
|
+
const name = 'indentation';
|
|
5
|
+
/** The indentation, in spaces, expected for each kind of line. */
|
|
6
|
+
const defaultConfig = {
|
|
7
|
+
Feature: 0,
|
|
8
|
+
Background: 0,
|
|
9
|
+
Rule: 0,
|
|
10
|
+
Scenario: 0,
|
|
11
|
+
Step: 2,
|
|
12
|
+
Examples: 0,
|
|
13
|
+
example: 2,
|
|
14
|
+
given: 2,
|
|
15
|
+
when: 2,
|
|
16
|
+
then: 2,
|
|
17
|
+
and: 2,
|
|
18
|
+
but: 2,
|
|
19
|
+
};
|
|
20
|
+
/** What counts as the wrong character for each setting. */
|
|
21
|
+
const WRONG_CHARACTER = {
|
|
22
|
+
space: /\t/,
|
|
23
|
+
tab: / /,
|
|
24
|
+
};
|
|
25
|
+
const availableConfigs = {
|
|
26
|
+
...defaultConfig,
|
|
27
|
+
// These fall back to the node they belong to rather than to a fixed
|
|
28
|
+
// number, so they have no default of their own.
|
|
29
|
+
'feature tag': -1,
|
|
30
|
+
'rule tag': -1,
|
|
31
|
+
'scenario tag': -1,
|
|
32
|
+
docstring: -1,
|
|
33
|
+
/** One of "any", "space" or "tab". */
|
|
34
|
+
character: 'any',
|
|
35
|
+
};
|
|
36
|
+
function resolveConfig(configuration) {
|
|
37
|
+
const merged = mergeDefaults(defaultConfig, configuration);
|
|
38
|
+
merged['feature tag'] =
|
|
39
|
+
typeof configuration['feature tag'] === 'number' ? configuration['feature tag'] : merged.Feature;
|
|
40
|
+
merged['rule tag'] =
|
|
41
|
+
typeof configuration['rule tag'] === 'number' ? configuration['rule tag'] : merged.Rule;
|
|
42
|
+
merged['scenario tag'] =
|
|
43
|
+
typeof configuration['scenario tag'] === 'number'
|
|
44
|
+
? configuration['scenario tag']
|
|
45
|
+
: 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;
|
|
52
|
+
merged.character =
|
|
53
|
+
configuration['character'] === 'space' || configuration['character'] === 'tab'
|
|
54
|
+
? configuration['character']
|
|
55
|
+
: 'any';
|
|
56
|
+
return merged;
|
|
57
|
+
}
|
|
58
|
+
const rule = {
|
|
59
|
+
name,
|
|
60
|
+
availableConfigs,
|
|
61
|
+
run(feature, file, configuration) {
|
|
62
|
+
if (feature === undefined) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
const raw = (configuration ?? {});
|
|
66
|
+
const config = resolveConfig(raw);
|
|
67
|
+
const errors = [];
|
|
68
|
+
// A line can be tested more than once - a tag line groups several tags -
|
|
69
|
+
// so the character check reports each line at most once.
|
|
70
|
+
const characterChecked = new Set();
|
|
71
|
+
const testCharacter = (location, type) => {
|
|
72
|
+
if (config.character === 'any' || characterChecked.has(location.line)) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
characterChecked.add(location.line);
|
|
76
|
+
const leading = /^[\t ]*/.exec(file.lines[location.line - 1] ?? '')?.[0] ?? '';
|
|
77
|
+
if (WRONG_CHARACTER[config.character].test(leading)) {
|
|
78
|
+
errors.push({
|
|
79
|
+
message: `Wrong indentation character for "${type}", expected ${config.character}s`,
|
|
80
|
+
rule: name,
|
|
81
|
+
...at(location),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const test = (location, type) => {
|
|
86
|
+
testCharacter(location, type);
|
|
87
|
+
// Columns are 1-based, indentation is counted from 0.
|
|
88
|
+
const actual = (location.column ?? 1) - 1;
|
|
89
|
+
const expected = config[type];
|
|
90
|
+
if (actual !== expected) {
|
|
91
|
+
errors.push({
|
|
92
|
+
message: `Wrong indentation for "${type}", expected indentation level of ${expected}, but got ${actual}`,
|
|
93
|
+
rule: name,
|
|
94
|
+
...at(location),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const testStep = (step) => {
|
|
99
|
+
const keyword = getNeutralKeyword(step, feature.language);
|
|
100
|
+
// A step only uses its own keyword's setting when the user set one.
|
|
101
|
+
const type = keyword !== '' && keyword in raw ? keyword : 'Step';
|
|
102
|
+
test(step.location, type);
|
|
103
|
+
if (step.docString !== undefined) {
|
|
104
|
+
test(step.docString.location, 'docstring');
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const testTags = (tags, type) => {
|
|
108
|
+
for (const [, tagsOnLine] of groupBy(tags, (tag) => tag.location.line)) {
|
|
109
|
+
const first = sortBy(tagsOnLine, (tag) => tag.location.column ?? 0)[0];
|
|
110
|
+
if (first !== undefined) {
|
|
111
|
+
test(first.location, type);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
// Backgrounds and Scenarios appear both directly under the Feature and
|
|
116
|
+
// inside a Rule, and are indented against the same settings either way.
|
|
117
|
+
const testChild = (child) => {
|
|
118
|
+
if (child.background !== undefined) {
|
|
119
|
+
test(child.background.location, 'Background');
|
|
120
|
+
child.background.steps.forEach(testStep);
|
|
121
|
+
}
|
|
122
|
+
else if (child.scenario !== undefined) {
|
|
123
|
+
test(child.scenario.location, 'Scenario');
|
|
124
|
+
testTags(child.scenario.tags, 'scenario tag');
|
|
125
|
+
child.scenario.steps.forEach(testStep);
|
|
126
|
+
for (const examples of child.scenario.examples) {
|
|
127
|
+
test(examples.location, 'Examples');
|
|
128
|
+
if (examples.tableHeader !== undefined) {
|
|
129
|
+
test(examples.tableHeader.location, 'example');
|
|
130
|
+
for (const row of examples.tableBody) {
|
|
131
|
+
test(row.location, 'example');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
test(feature.location, 'Feature');
|
|
138
|
+
testTags(feature.tags, 'feature tag');
|
|
139
|
+
for (const child of feature.children) {
|
|
140
|
+
if (child.rule !== undefined) {
|
|
141
|
+
test(child.rule.location, 'Rule');
|
|
142
|
+
testTags(child.rule.tags, 'rule tag');
|
|
143
|
+
child.rule.children.forEach(testChild);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
testChild(child);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return errors;
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
export default rule;
|
|
153
|
+
//# sourceMappingURL=indentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indentation.js","sourceRoot":"","sources":["../../src/rules/indentation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The built-in rules.
|
|
3
|
+
*
|
|
4
|
+
* Imported statically rather than discovered on disk, so that the compiled
|
|
5
|
+
* package is self-contained and every rule is type-checked.
|
|
6
|
+
*
|
|
7
|
+
* This file is generated by `npm run generate:rules`; add a rule module to
|
|
8
|
+
* src/rules and run that rather than editing this list.
|
|
9
|
+
*/
|
|
10
|
+
import type { LintRule } from '../types.ts';
|
|
11
|
+
/** Every rule shipped with gurkencheck, in alphabetical order. */
|
|
12
|
+
export declare const BUILT_IN_RULES: readonly LintRule[];
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAmC1C,kEAAkE;AAClE,eAAO,MAAM,cAAc,EAAE,SAAS,QAAQ,EAkC7C,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import allowedTags from './allowed-tags.js';
|
|
2
|
+
import fileName from './file-name.js';
|
|
3
|
+
import indentation from './indentation.js';
|
|
4
|
+
import keywordsInLogicalOrder from './keywords-in-logical-order.js';
|
|
5
|
+
import maxScenariosPerFile from './max-scenarios-per-file.js';
|
|
6
|
+
import nameLength from './name-length.js';
|
|
7
|
+
import newLineAtEof from './new-line-at-eof.js';
|
|
8
|
+
import noBackgroundOnlyScenario from './no-background-only-scenario.js';
|
|
9
|
+
import noDupeFeatureNames from './no-dupe-feature-names.js';
|
|
10
|
+
import noDupeFileNames from './no-dupe-file-names.js';
|
|
11
|
+
import noDupeScenarioNames from './no-dupe-scenario-names.js';
|
|
12
|
+
import noDuplicateTags from './no-duplicate-tags.js';
|
|
13
|
+
import noEmptyBackground from './no-empty-background.js';
|
|
14
|
+
import noEmptyFile from './no-empty-file.js';
|
|
15
|
+
import noExamplesInScenarios from './no-examples-in-scenarios.js';
|
|
16
|
+
import noFilesWithoutScenarios from './no-files-without-scenarios.js';
|
|
17
|
+
import noHomogenousTags from './no-homogenous-tags.js';
|
|
18
|
+
import noMultipleEmptyLines from './no-multiple-empty-lines.js';
|
|
19
|
+
import noPartiallyCommentedTagLines from './no-partially-commented-tag-lines.js';
|
|
20
|
+
import noRestrictedPatterns from './no-restricted-patterns.js';
|
|
21
|
+
import noRestrictedTags from './no-restricted-tags.js';
|
|
22
|
+
import noScenarioOutlinesWithoutExamples from './no-scenario-outlines-without-examples.js';
|
|
23
|
+
import noSuperfluousTags from './no-superfluous-tags.js';
|
|
24
|
+
import noTrailingSpaces from './no-trailing-spaces.js';
|
|
25
|
+
import noUndeclaredVariables from './no-undeclared-variables.js';
|
|
26
|
+
import noUnnamedFeatures from './no-unnamed-features.js';
|
|
27
|
+
import noUnnamedScenarios from './no-unnamed-scenarios.js';
|
|
28
|
+
import noUnusedVariables from './no-unused-variables.js';
|
|
29
|
+
import oneSpaceBetweenTags from './one-space-between-tags.js';
|
|
30
|
+
import onlyOneWhen from './only-one-when.js';
|
|
31
|
+
import requiredTags from './required-tags.js';
|
|
32
|
+
import scenarioSize from './scenario-size.js';
|
|
33
|
+
import useAnd from './use-and.js';
|
|
34
|
+
/** Every rule shipped with gurkencheck, in alphabetical order. */
|
|
35
|
+
export const BUILT_IN_RULES = [
|
|
36
|
+
allowedTags,
|
|
37
|
+
fileName,
|
|
38
|
+
indentation,
|
|
39
|
+
keywordsInLogicalOrder,
|
|
40
|
+
maxScenariosPerFile,
|
|
41
|
+
nameLength,
|
|
42
|
+
newLineAtEof,
|
|
43
|
+
noBackgroundOnlyScenario,
|
|
44
|
+
noDupeFeatureNames,
|
|
45
|
+
noDupeFileNames,
|
|
46
|
+
noDupeScenarioNames,
|
|
47
|
+
noDuplicateTags,
|
|
48
|
+
noEmptyBackground,
|
|
49
|
+
noEmptyFile,
|
|
50
|
+
noExamplesInScenarios,
|
|
51
|
+
noFilesWithoutScenarios,
|
|
52
|
+
noHomogenousTags,
|
|
53
|
+
noMultipleEmptyLines,
|
|
54
|
+
noPartiallyCommentedTagLines,
|
|
55
|
+
noRestrictedPatterns,
|
|
56
|
+
noRestrictedTags,
|
|
57
|
+
noScenarioOutlinesWithoutExamples,
|
|
58
|
+
noSuperfluousTags,
|
|
59
|
+
noTrailingSpaces,
|
|
60
|
+
noUndeclaredVariables,
|
|
61
|
+
noUnnamedFeatures,
|
|
62
|
+
noUnnamedScenarios,
|
|
63
|
+
noUnusedVariables,
|
|
64
|
+
oneSpaceBetweenTags,
|
|
65
|
+
onlyOneWhen,
|
|
66
|
+
requiredTags,
|
|
67
|
+
scenarioSize,
|
|
68
|
+
useAnd,
|
|
69
|
+
];
|
|
70
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAUA,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAC5C,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,WAAW,MAAM,kBAAkB,CAAC;AAC3C,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,mBAAmB,MAAM,6BAA6B,CAAC;AAC9D,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAC1C,OAAO,YAAY,MAAM,sBAAsB,CAAC;AAChD,OAAO,wBAAwB,MAAM,kCAAkC,CAAC;AACxE,OAAO,kBAAkB,MAAM,4BAA4B,CAAC;AAC5D,OAAO,eAAe,MAAM,yBAAyB,CAAC;AACtD,OAAO,mBAAmB,MAAM,6BAA6B,CAAC;AAC9D,OAAO,eAAe,MAAM,wBAAwB,CAAC;AACrD,OAAO,iBAAiB,MAAM,0BAA0B,CAAC;AACzD,OAAO,WAAW,MAAM,oBAAoB,CAAC;AAC7C,OAAO,qBAAqB,MAAM,+BAA+B,CAAC;AAClE,OAAO,uBAAuB,MAAM,iCAAiC,CAAC;AACtE,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AACvD,OAAO,oBAAoB,MAAM,8BAA8B,CAAC;AAChE,OAAO,4BAA4B,MAAM,uCAAuC,CAAC;AACjF,OAAO,oBAAoB,MAAM,6BAA6B,CAAC;AAC/D,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AACvD,OAAO,iCAAiC,MAAM,4CAA4C,CAAC;AAC3F,OAAO,iBAAiB,MAAM,0BAA0B,CAAC;AACzD,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AACvD,OAAO,qBAAqB,MAAM,8BAA8B,CAAC;AACjE,OAAO,iBAAiB,MAAM,0BAA0B,CAAC;AACzD,OAAO,kBAAkB,MAAM,2BAA2B,CAAC;AAC3D,OAAO,iBAAiB,MAAM,0BAA0B,CAAC;AACzD,OAAO,mBAAmB,MAAM,6BAA6B,CAAC;AAC9D,OAAO,WAAW,MAAM,oBAAoB,CAAC;AAC7C,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC,kEAAkE;AAClE,MAAM,CAAC,MAAM,cAAc,GAAwB;IACjD,WAAW;IACX,QAAQ;IACR,WAAW;IACX,sBAAsB;IACtB,mBAAmB;IACnB,UAAU;IACV,YAAY;IACZ,wBAAwB;IACxB,kBAAkB;IAClB,eAAe;IACf,mBAAmB;IACnB,eAAe;IACf,iBAAiB;IACjB,WAAW;IACX,qBAAqB;IACrB,uBAAuB;IACvB,gBAAgB;IAChB,oBAAoB;IACpB,4BAA4B;IAC5B,oBAAoB;IACpB,gBAAgB;IAChB,iCAAiC;IACjC,iBAAiB;IACjB,gBAAgB;IAChB,qBAAqB;IACrB,iBAAiB;IACjB,kBAAkB;IAClB,iBAAiB;IACjB,mBAAmB;IACnB,WAAW;IACX,YAAY;IACZ,YAAY;IACZ,MAAM;CACP,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keywords-in-logical-order.d.ts","sourceRoot":"","sources":["../../src/rules/keywords-in-logical-order.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,QAAQ,EAAY,MAAM,aAAa,CAAC;AAQrD,QAAA,MAAM,IAAI,EAAE,QAiCX,CAAC;eAEa,IAAI"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { getNeutralKeyword } from '../gherkin/keywords.js';
|
|
2
|
+
import { stepContainersOf } from '../gherkin/traverse.js';
|
|
3
|
+
import { at } from '../util/location.js';
|
|
4
|
+
const name = 'keywords-in-logical-order';
|
|
5
|
+
/** Given sets the scene, When acts, Then checks - in that order. */
|
|
6
|
+
const ORDER = ['given', 'when', 'then'];
|
|
7
|
+
const rule = {
|
|
8
|
+
name,
|
|
9
|
+
run(feature) {
|
|
10
|
+
if (feature === undefined) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
const errors = [];
|
|
14
|
+
for (const { node } of stepContainersOf(feature)) {
|
|
15
|
+
let furthest = -1;
|
|
16
|
+
for (const step of node.steps) {
|
|
17
|
+
const keyword = getNeutralKeyword(step, feature.language);
|
|
18
|
+
const position = ORDER.indexOf(keyword);
|
|
19
|
+
if (position === -1) {
|
|
20
|
+
// And, But and * carry on from whatever came before them.
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (position < furthest) {
|
|
24
|
+
errors.push({
|
|
25
|
+
message: `Step "${step.keyword}${step.text}" should not appear after step using keyword ${ORDER[furthest]}`,
|
|
26
|
+
rule: name,
|
|
27
|
+
...at(step.location),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
furthest = Math.max(furthest, position);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return errors;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
export default rule;
|
|
37
|
+
//# sourceMappingURL=keywords-in-logical-order.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keywords-in-logical-order.js","sourceRoot":"","sources":["../../src/rules/keywords-in-logical-order.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,iBAAiB,EAAC,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAAC,EAAE,EAAC,MAAM,qBAAqB,CAAC;AAEvC,MAAM,IAAI,GAAG,2BAA2B,CAAC;AAEzC,oEAAoE;AACpE,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAEjD,MAAM,IAAI,GAAa;IACrB,IAAI;IACJ,GAAG,CAAC,OAAO;QACT,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,KAAK,MAAM,EAAC,IAAI,EAAC,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/C,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;YAElB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC9B,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,OAAiC,CAAC,CAAC;gBAClE,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;oBACpB,0DAA0D;oBAC1D,SAAS;gBACX,CAAC;gBAED,IAAI,QAAQ,GAAG,QAAQ,EAAE,CAAC;oBACxB,MAAM,CAAC,IAAI,CAAC;wBACV,OAAO,EAAE,SAAS,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,gDAAgD,KAAK,CAAC,QAAQ,CAAC,EAAE;wBAC3G,IAAI,EAAE,IAAI;wBACV,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;qBACrB,CAAC,CAAC;gBACL,CAAC;gBACD,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"max-scenarios-per-file.d.ts","sourceRoot":"","sources":["../../src/rules/max-scenarios-per-file.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAY1C,QAAA,MAAM,IAAI,EAAE,QAgCX,CAAC;eAEa,IAAI"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { scenariosOf } from '../gherkin/traverse.js';
|
|
2
|
+
import { mergeDefaults } from '../util/collections.js';
|
|
3
|
+
const name = 'max-scenarios-per-file';
|
|
4
|
+
const availableConfigs = {
|
|
5
|
+
/** How many Scenarios a single file may contain. */
|
|
6
|
+
maxScenarios: 10,
|
|
7
|
+
/** Whether each row of an Examples table counts as its own Scenario. */
|
|
8
|
+
countOutlineExamples: true,
|
|
9
|
+
};
|
|
10
|
+
const rule = {
|
|
11
|
+
name,
|
|
12
|
+
availableConfigs,
|
|
13
|
+
run(feature, _file, configuration) {
|
|
14
|
+
if (feature === undefined) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
const config = mergeDefaults(availableConfigs, configuration);
|
|
18
|
+
let count = 0;
|
|
19
|
+
for (const { scenario } of scenariosOf(feature)) {
|
|
20
|
+
if (config.countOutlineExamples && scenario.examples.length > 0) {
|
|
21
|
+
for (const examples of scenario.examples) {
|
|
22
|
+
count += examples.tableBody.length;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
count += 1;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (count <= config.maxScenarios) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
return [
|
|
33
|
+
{
|
|
34
|
+
message: `Number of scenarios exceeds maximum: ${count}/${config.maxScenarios}`,
|
|
35
|
+
rule: name,
|
|
36
|
+
line: 0,
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
export default rule;
|
|
42
|
+
//# sourceMappingURL=max-scenarios-per-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"max-scenarios-per-file.js","sourceRoot":"","sources":["../../src/rules/max-scenarios-per-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAErD,MAAM,IAAI,GAAG,wBAAwB,CAAC;AAEtC,MAAM,gBAAgB,GAAG;IACvB,oDAAoD;IACpD,YAAY,EAAE,EAAE;IAChB,wEAAwE;IACxE,oBAAoB,EAAE,IAAI;CAC3B,CAAC;AAEF,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,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,KAAK,MAAM,EAAC,QAAQ,EAAC,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9C,IAAI,MAAM,CAAC,oBAAoB,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChE,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;oBACzC,KAAK,IAAI,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC;gBACrC,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,KAAK,IAAI,CAAC,CAAC;YACb,CAAC;QACH,CAAC;QAED,IAAI,KAAK,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO;YACL;gBACE,OAAO,EAAE,wCAAwC,KAAK,IAAI,MAAM,CAAC,YAAY,EAAE;gBAC/E,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,CAAC;aACR;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name-length.d.ts","sourceRoot":"","sources":["../../src/rules/name-length.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,QAAQ,EAAY,MAAM,aAAa,CAAC;AAgBrD,QAAA,MAAM,IAAI,EAAE,QA0CX,CAAC;eAEa,IAAI"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { rulesOf, stepContainersOf } from '../gherkin/traverse.js';
|
|
2
|
+
import { mergeDefaults } from '../util/collections.js';
|
|
3
|
+
import { at } from '../util/location.js';
|
|
4
|
+
const name = 'name-length';
|
|
5
|
+
/** Maximum number of characters allowed in each kind of name; 0 means no limit. */
|
|
6
|
+
const availableConfigs = {
|
|
7
|
+
Feature: 70,
|
|
8
|
+
Rule: 70,
|
|
9
|
+
Step: 70,
|
|
10
|
+
Scenario: 70,
|
|
11
|
+
};
|
|
12
|
+
const rule = {
|
|
13
|
+
name,
|
|
14
|
+
availableConfigs,
|
|
15
|
+
run(feature, _file, configuration) {
|
|
16
|
+
if (feature === undefined) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const config = mergeDefaults(availableConfigs, configuration);
|
|
20
|
+
const errors = [];
|
|
21
|
+
const test = (text, location, type) => {
|
|
22
|
+
const maximum = config[type];
|
|
23
|
+
// A limit of 0 turns the check off for that kind of name, for teams that
|
|
24
|
+
// want a limit on scenario names but not on step text, or the reverse.
|
|
25
|
+
if (maximum > 0 && text !== '' && text.length > maximum) {
|
|
26
|
+
errors.push({
|
|
27
|
+
message: `${type} name is too long. Length of ${text.length} is longer than the maximum allowed: ${maximum}`,
|
|
28
|
+
rule: name,
|
|
29
|
+
...at(location),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
test(feature.name, feature.location, 'Feature');
|
|
34
|
+
for (const featureRule of rulesOf(feature)) {
|
|
35
|
+
test(featureRule.name, featureRule.location, 'Rule');
|
|
36
|
+
}
|
|
37
|
+
for (const { node } of stepContainersOf(feature)) {
|
|
38
|
+
// Only Scenarios have a name worth checking; Backgrounds rarely have one.
|
|
39
|
+
if ('examples' in node) {
|
|
40
|
+
test(node.name, node.location, 'Scenario');
|
|
41
|
+
}
|
|
42
|
+
for (const step of node.steps) {
|
|
43
|
+
test(step.text, step.location, 'Step');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return errors;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
export default rule;
|
|
50
|
+
//# sourceMappingURL=name-length.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name-length.js","sourceRoot":"","sources":["../../src/rules/name-length.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,OAAO,EAAE,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAC,EAAE,EAAC,MAAM,qBAAqB,CAAC;AAEvC,MAAM,IAAI,GAAG,aAAa,CAAC;AAE3B,mFAAmF;AACnF,MAAM,gBAAgB,GAAG;IACvB,OAAO,EAAE,EAAE;IACX,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,EAAE;IACR,QAAQ,EAAE,EAAE;CACb,CAAC;AAIF,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,MAAM,GAAgB,EAAE,CAAC;QAE/B,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,QAAkB,EAAE,IAA4B,EAAQ,EAAE;YACpF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YAC7B,yEAAyE;YACzE,uEAAuE;YACvE,IAAI,OAAO,GAAG,CAAC,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;gBACxD,MAAM,CAAC,IAAI,CAAC;oBACV,OAAO,EAAE,GAAG,IAAI,gCAAgC,IAAI,CAAC,MAAM,wCAAwC,OAAO,EAAE;oBAC5G,IAAI,EAAE,IAAI;oBACV,GAAG,EAAE,CAAC,QAAQ,CAAC;iBAChB,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC;QAEF,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAEhD,KAAK,MAAM,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACvD,CAAC;QAED,KAAK,MAAM,EAAC,IAAI,EAAC,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/C,0EAA0E;YAC1E,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YAC7C,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"new-line-at-eof.d.ts","sourceRoot":"","sources":["../../src/rules/new-line-at-eof.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAe1C,QAAA,MAAM,IAAI,EAAE,QAqBX,CAAC;eAEa,IAAI"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const name = 'new-line-at-eof';
|
|
2
|
+
/** Whether a trailing new line is required (`yes`) or forbidden (`no`). */
|
|
3
|
+
const availableConfigs = ['yes', 'no'];
|
|
4
|
+
const DEFAULT_SETTING = 'yes';
|
|
5
|
+
function toSetting(configuration) {
|
|
6
|
+
return configuration === 'no' || configuration === 'yes' ? configuration : DEFAULT_SETTING;
|
|
7
|
+
}
|
|
8
|
+
const rule = {
|
|
9
|
+
name,
|
|
10
|
+
availableConfigs,
|
|
11
|
+
run(_feature, file, configuration) {
|
|
12
|
+
const setting = toSetting(configuration);
|
|
13
|
+
// Splitting on line breaks leaves a trailing empty entry when the file
|
|
14
|
+
// ends with one.
|
|
15
|
+
const hasNewLineAtEof = file.lines.at(-1) === '';
|
|
16
|
+
let message = '';
|
|
17
|
+
if (hasNewLineAtEof && setting === 'no') {
|
|
18
|
+
message = 'New line at EOF(end of file) is not allowed';
|
|
19
|
+
}
|
|
20
|
+
else if (!hasNewLineAtEof && setting === 'yes') {
|
|
21
|
+
message = 'New line at EOF(end of file) is required';
|
|
22
|
+
}
|
|
23
|
+
if (message === '') {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
return [{ message, rule: name, line: file.lines.length }];
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
export default rule;
|
|
30
|
+
//# sourceMappingURL=new-line-at-eof.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"new-line-at-eof.js","sourceRoot":"","sources":["../../src/rules/new-line-at-eof.ts"],"names":[],"mappings":"AAEA,MAAM,IAAI,GAAG,iBAAiB,CAAC;AAE/B,2EAA2E;AAC3E,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,IAAI,CAAU,CAAC;AAIhD,MAAM,eAAe,GAAmB,KAAK,CAAC;AAE9C,SAAS,SAAS,CAAC,aAAsB;IACvC,OAAO,aAAa,KAAK,IAAI,IAAI,aAAa,KAAK,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC;AAC7F,CAAC;AAED,MAAM,IAAI,GAAa;IACrB,IAAI;IACJ,gBAAgB;IAChB,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,aAAa;QAC/B,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;QACzC,uEAAuE;QACvE,iBAAiB;QACjB,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;QAEjD,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,eAAe,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACxC,OAAO,GAAG,6CAA6C,CAAC;QAC1D,CAAC;aAAM,IAAI,CAAC,eAAe,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;YACjD,OAAO,GAAG,0CAA0C,CAAC;QACvD,CAAC;QAED,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;YACnB,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAC,CAAC,CAAC;IAC1D,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-background-only-scenario.d.ts","sourceRoot":"","sources":["../../src/rules/no-background-only-scenario.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,QAAQ,EAAY,MAAM,aAAa,CAAC;AAsBrD,QAAA,MAAM,IAAI,EAAE,QAwBX,CAAC;eAEa,IAAI"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { backgroundsOf, scenariosOf } from '../gherkin/traverse.js';
|
|
2
|
+
import { at } from '../util/location.js';
|
|
3
|
+
const name = 'no-background-only-scenario';
|
|
4
|
+
/**
|
|
5
|
+
* How many scenarios a Background applies to.
|
|
6
|
+
*
|
|
7
|
+
* A Background written inside a Rule covers that Rule's scenarios. One
|
|
8
|
+
* written at Feature level covers every scenario in the file, including
|
|
9
|
+
* those inside Rules.
|
|
10
|
+
*/
|
|
11
|
+
function scenariosCovered(feature, containingRule) {
|
|
12
|
+
let count = 0;
|
|
13
|
+
for (const { rule } of scenariosOf(feature)) {
|
|
14
|
+
if (containingRule === undefined || rule === containingRule) {
|
|
15
|
+
count++;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return count;
|
|
19
|
+
}
|
|
20
|
+
const rule = {
|
|
21
|
+
name,
|
|
22
|
+
run(feature) {
|
|
23
|
+
if (feature === undefined) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
const errors = [];
|
|
27
|
+
for (const { background, rule: containingRule } of backgroundsOf(feature)) {
|
|
28
|
+
// A Background exists to share setup between scenarios. With exactly one
|
|
29
|
+
// there is nothing to share. With none at all there is nothing to report
|
|
30
|
+
// here either - that is what no-files-without-scenarios is for.
|
|
31
|
+
if (scenariosCovered(feature, containingRule) === 1) {
|
|
32
|
+
errors.push({
|
|
33
|
+
message: 'Backgrounds are not allowed when there is just one scenario.',
|
|
34
|
+
rule: name,
|
|
35
|
+
...at(background.location),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return errors;
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
export default rule;
|
|
43
|
+
//# sourceMappingURL=no-background-only-scenario.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-background-only-scenario.js","sourceRoot":"","sources":["../../src/rules/no-background-only-scenario.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,aAAa,EAAE,WAAW,EAAC,MAAM,wBAAwB,CAAC;AAElE,OAAO,EAAC,EAAE,EAAC,MAAM,qBAAqB,CAAC;AAEvC,MAAM,IAAI,GAAG,6BAA6B,CAAC;AAE3C;;;;;;GAMG;AACH,SAAS,gBAAgB,CAAC,OAAgB,EAAE,cAAuC;IACjF,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,EAAC,IAAI,EAAC,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1C,IAAI,cAAc,KAAK,SAAS,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;YAC5D,KAAK,EAAE,CAAC;QACV,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,IAAI,GAAa;IACrB,IAAI;IACJ,GAAG,CAAC,OAAO;QACT,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,KAAK,MAAM,EAAC,UAAU,EAAE,IAAI,EAAE,cAAc,EAAC,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;YACxE,yEAAyE;YACzE,yEAAyE;YACzE,gEAAgE;YAChE,IAAI,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpD,MAAM,CAAC,IAAI,CAAC;oBACV,OAAO,EAAE,8DAA8D;oBACvE,IAAI,EAAE,IAAI;oBACV,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;iBAC3B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-dupe-feature-names.d.ts","sourceRoot":"","sources":["../../src/rules/no-dupe-feature-names.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAQ1C,QAAA,MAAM,IAAI,EAAE,QAoBX,CAAC;eAEa,IAAI"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { at } from '../util/location.js';
|
|
2
|
+
const name = 'no-dupe-feature-names';
|
|
3
|
+
/** Feature name -> the files it has already been seen in. */
|
|
4
|
+
const seen = new Map();
|
|
5
|
+
const rule = {
|
|
6
|
+
name,
|
|
7
|
+
reset() {
|
|
8
|
+
seen.clear();
|
|
9
|
+
},
|
|
10
|
+
run(feature, file) {
|
|
11
|
+
if (feature === undefined) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const previous = seen.get(feature.name);
|
|
15
|
+
if (previous === undefined) {
|
|
16
|
+
seen.set(feature.name, [file.relativePath]);
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const message = `Feature name is already used in: ${previous.join(', ')}`;
|
|
20
|
+
previous.push(file.relativePath);
|
|
21
|
+
return [{ message, rule: name, ...at(feature.location) }];
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
export default rule;
|
|
25
|
+
//# sourceMappingURL=no-dupe-feature-names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-dupe-feature-names.js","sourceRoot":"","sources":["../../src/rules/no-dupe-feature-names.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,EAAE,EAAC,MAAM,qBAAqB,CAAC;AAEvC,MAAM,IAAI,GAAG,uBAAuB,CAAC;AAErC,6DAA6D;AAC7D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAoB,CAAC;AAEzC,MAAM,IAAI,GAAa;IACrB,IAAI;IACJ,KAAK;QACH,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IACD,GAAG,CAAC,OAAO,EAAE,IAAI;QACf,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;YAC5C,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,OAAO,GAAG,oCAAoC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1E,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACjC,OAAO,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAC,CAAC,CAAC;IAC1D,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-dupe-file-names.d.ts","sourceRoot":"","sources":["../../src/rules/no-dupe-file-names.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAa1C,QAAA,MAAM,IAAI,EAAE,QAkBX,CAAC;eAEa,IAAI"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
const name = 'no-dupe-file-names';
|
|
3
|
+
/**
|
|
4
|
+
* Two feature files with the same name in different folders are easy to
|
|
5
|
+
* confuse, and tools that write one report per feature - naming it after the
|
|
6
|
+
* file - quietly overwrite one with the other.
|
|
7
|
+
*/
|
|
8
|
+
/** File name without its extension -> the paths it has already been seen at. */
|
|
9
|
+
const seen = new Map();
|
|
10
|
+
const rule = {
|
|
11
|
+
name,
|
|
12
|
+
reset() {
|
|
13
|
+
seen.clear();
|
|
14
|
+
},
|
|
15
|
+
run(_feature, file) {
|
|
16
|
+
const fileName = path.basename(file.relativePath, path.extname(file.relativePath));
|
|
17
|
+
const previous = seen.get(fileName);
|
|
18
|
+
if (previous === undefined) {
|
|
19
|
+
seen.set(fileName, [file.relativePath]);
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
const message = `File name is already used in: ${previous.join(', ')}`;
|
|
23
|
+
previous.push(file.relativePath);
|
|
24
|
+
return [{ message, rule: name, line: 0 }];
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
export default rule;
|
|
28
|
+
//# sourceMappingURL=no-dupe-file-names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-dupe-file-names.js","sourceRoot":"","sources":["../../src/rules/no-dupe-file-names.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,IAAI,GAAG,oBAAoB,CAAC;AAElC;;;;GAIG;AAEH,gFAAgF;AAChF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAoB,CAAC;AAEzC,MAAM,IAAI,GAAa;IACrB,IAAI;IACJ,KAAK;QACH,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IACD,GAAG,CAAC,QAAQ,EAAE,IAAI;QAChB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;QACnF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEpC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;YACxC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,OAAO,GAAG,iCAAiC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACvE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACjC,OAAO,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAC,CAAC,CAAC;IAC1C,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-dupe-scenario-names.d.ts","sourceRoot":"","sources":["../../src/rules/no-dupe-scenario-names.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAY,MAAM,aAAa,CAAC;AAgBrD,QAAA,MAAM,IAAI,EAAE,QAoCX,CAAC;eAEa,IAAI"}
|