vitest-cucumber-plugin 0.1.3

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 (73) hide show
  1. package/CONTRIBUTING.md +42 -0
  2. package/LICENSE +21 -0
  3. package/README.md +113 -0
  4. package/RELEASE_NOTES.md +9 -0
  5. package/package.json +34 -0
  6. package/rollup-nearley.js +10 -0
  7. package/run-tests +8 -0
  8. package/src/generate/example.js +20 -0
  9. package/src/generate/examples.js +47 -0
  10. package/src/generate/feature.js +45 -0
  11. package/src/generate/index.js +13 -0
  12. package/src/generate/scenarioOutline.js +18 -0
  13. package/src/generate/tests.js +23 -0
  14. package/src/generate/util.js +10 -0
  15. package/src/gherkin.js +171 -0
  16. package/src/gherkin.ne +130 -0
  17. package/src/gherkin.umd.js +118 -0
  18. package/src/index.js +65 -0
  19. package/src/logger.js +7 -0
  20. package/src/parameterize.js +7 -0
  21. package/src/parse.js +21 -0
  22. package/src/steps.js +42 -0
  23. package/tests/background/features/background.feature +25 -0
  24. package/tests/background/features/step_definitions/steps.js +30 -0
  25. package/tests/background/package-lock.json +1967 -0
  26. package/tests/background/package.json +11 -0
  27. package/tests/background/vite.config.js +9 -0
  28. package/tests/comments/features/is-it-friday.feature +10 -0
  29. package/tests/comments/features/step_definitions/stepdefs.js +15 -0
  30. package/tests/comments/package-lock.json +1967 -0
  31. package/tests/comments/package.json +11 -0
  32. package/tests/comments/vite.config.js +9 -0
  33. package/tests/data-tables/features/data-tables.feature +25 -0
  34. package/tests/data-tables/features/step_definitions/data-tables.js +21 -0
  35. package/tests/data-tables/package-lock.json +1967 -0
  36. package/tests/data-tables/package.json +11 -0
  37. package/tests/data-tables/vite.config.js +9 -0
  38. package/tests/data-tables/vite.config.js.timestamp-1682359000824-3876ac2e9095b.mjs +13 -0
  39. package/tests/is-it-friday/features/is-it-friday.feature +7 -0
  40. package/tests/is-it-friday/features/step_definitions/stepdefs.js +15 -0
  41. package/tests/is-it-friday/package-lock.json +1967 -0
  42. package/tests/is-it-friday/package.json +11 -0
  43. package/tests/is-it-friday/vite.config.js +9 -0
  44. package/tests/is-it-friday-scenario-outline/features/is-it-friday.feature +13 -0
  45. package/tests/is-it-friday-scenario-outline/features/step_definitions/stepdefs.js +15 -0
  46. package/tests/is-it-friday-scenario-outline/package-lock.json +1967 -0
  47. package/tests/is-it-friday-scenario-outline/package.json +11 -0
  48. package/tests/is-it-friday-scenario-outline/vite.config.js +9 -0
  49. package/tests/is-it-friday-two-scenarios/features/is-it-friday.feature +12 -0
  50. package/tests/is-it-friday-two-scenarios/features/step_definitions/stepdefs.js +19 -0
  51. package/tests/is-it-friday-two-scenarios/package-lock.json +1967 -0
  52. package/tests/is-it-friday-two-scenarios/package.json +11 -0
  53. package/tests/is-it-friday-two-scenarios/vite.config.js +9 -0
  54. package/tests/is-it-friday-two-scenarios-multiple-feature-files/features/friday.feature +7 -0
  55. package/tests/is-it-friday-two-scenarios-multiple-feature-files/features/step_definitions/stepdefs.js +19 -0
  56. package/tests/is-it-friday-two-scenarios-multiple-feature-files/features/sunday.feature +8 -0
  57. package/tests/is-it-friday-two-scenarios-multiple-feature-files/package-lock.json +1967 -0
  58. package/tests/is-it-friday-two-scenarios-multiple-feature-files/package.json +11 -0
  59. package/tests/is-it-friday-two-scenarios-multiple-feature-files/vite.config.js +9 -0
  60. package/tests/keyword-aliases/features/scenario-outline.feature +20 -0
  61. package/tests/keyword-aliases/features/scenario.feature +14 -0
  62. package/tests/keyword-aliases/features/step_definitions/steps.js +30 -0
  63. package/tests/keyword-aliases/features/steps.feature +28 -0
  64. package/tests/keyword-aliases/package-lock.json +1967 -0
  65. package/tests/keyword-aliases/package.json +11 -0
  66. package/tests/keyword-aliases/vite.config.js +9 -0
  67. package/tests/tags/features/skip.feature +9 -0
  68. package/tests/tags/features/step_definitions/steps.js +30 -0
  69. package/tests/tags/features/tags-scenario-outline.feature +30 -0
  70. package/tests/tags/features/tags.feature +26 -0
  71. package/tests/tags/package-lock.json +1967 -0
  72. package/tests/tags/package.json +11 -0
  73. package/tests/tags/vite.config.js +12 -0
@@ -0,0 +1,42 @@
1
+ # Contributing Guide
2
+
3
+ ## Testing
4
+
5
+ ```
6
+ $ npm test
7
+ ```
8
+
9
+ Running this does a "npm install" followed by a "npm test" in each of the directories found in the [tests](tests)
10
+ directory. The test suite fails if either of these commands returns with a non-zero exit code.
11
+
12
+ ## Gherkin parser
13
+
14
+ This plugin uses [nearley](https://nearley.js.org/) with [moo](https://github.com/no-context/moo) to create it's
15
+ Gherkin parser.
16
+
17
+ Before you can run the parser generation script, you must install nearly globally:
18
+ ```
19
+ $ npm install -g nearly
20
+ ```
21
+
22
+ The parser nearley file is [src/gherkin.ne](src/gherkin.ne). If you modify this file, you must
23
+ regenerate the generated parser JS file via:
24
+ ```
25
+ $ npm run nearley
26
+ ```
27
+
28
+ In addition to running nearley, this script also runs rollup in order to convert the generated parser into an
29
+ ECMAScript module.
30
+
31
+ ## Branching
32
+
33
+ This repo uses [git flow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow) as it's
34
+ branching model. The 'main' branch the release branch and is only pushed to during the release process. The
35
+ 'develop' branch is the cutting edge branch which is pushed to whenever a feature branch is finished.
36
+
37
+ ## Doing a release
38
+
39
+ 1. git flow release start <version>
40
+ 1. Update version number in package.json
41
+ 1. Add the release notes to [RELEASE_NOTES.md](RELEASE_NOTES.md).
42
+ 1. git flow release finish <version>
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 SamZiegler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # vitest-cucumber-plugin
2
+
3
+ Plugin for [Vitest](https://vitest.dev/) to allow tests to be written in [Cucumber](https://cucumber.io/) format.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ $ npm install --save-dev SamZiegler/vitest-cucumber-plugin
9
+ ```
10
+
11
+ ## Usage
12
+
13
+
14
+ ### vite.config.js
15
+
16
+ Import the plugin then add it to the plugins array. Change test.inclue to look for .feature files.
17
+
18
+ ```
19
+ import { defineConfig } from 'vitest/config'
20
+ import vitestCucumberPlugin from 'vitest-cucumber-plugin';
21
+
22
+ export default defineConfig({
23
+ plugins: [vitestCucumberPlugin()],
24
+ test: {
25
+ include : [ '**/*.feature' ]
26
+ },
27
+ })
28
+ ```
29
+
30
+ ### Writing tests
31
+
32
+ Put feature files into the 'features/' directory and step definitions into the 'features/step_definitions/' directory.
33
+
34
+ See below for the differences between tests written for Cucumber and for this plugin.
35
+
36
+ ## Examples
37
+
38
+ Look in the [tests directory](tests) for examples on how to use the plugin.
39
+
40
+ ## Differences between this plugin and Cucumber
41
+
42
+ The goal of this plugin is to fully implement Cucumber's Gherkin syntax for feature files, but
43
+ there are a few differences in how step definitions are written.
44
+
45
+ ### Changes to Given/When/Then
46
+
47
+ The function signatures for Given, When and Then callbacks have been modified in order to make the step definitions
48
+ more friendly for functional programming. Specifically, the callback functions differ in that they
49
+ now have two parameters, a state object and array of parameters. The callback functions then return a new state
50
+ object which is passed to the next step definition in the chain.
51
+
52
+ For example, here is how you'd write step definitions in Cucumber:
53
+ ```
54
+ const assert = require('assert');
55
+ const { Given, When, Then } = require('@cucumber/cucumber');
56
+
57
+ function isItFriday(today) {
58
+ if (today === "Friday") {
59
+ return "TGIF";
60
+ } else {
61
+ return "Nope";
62
+ }
63
+ }
64
+
65
+ Given('today is {string}', function (givenDay) {
66
+ this.today = givenDay;
67
+ });
68
+
69
+ When('I ask whether it\'s Friday yet', function () {
70
+ this.actualAnswer = isItFriday(this.today);
71
+ });
72
+
73
+ Then('I should be told {string}', function (expectedAnswer) {
74
+ assert.strictEqual(this.actualAnswer, expectedAnswer);
75
+ });
76
+ ```
77
+
78
+ Here is how you'd write the same step functions in this plugin:
79
+ ```
80
+ import { Given, When, Then } from 'vitest-cucumber-plugin';
81
+ import _ from 'lodash/fp.js';
82
+ import { expect } from 'vitest'
83
+
84
+ Given('today is Sunday', function () {
85
+ return { today : 'Sunday' };
86
+ });
87
+
88
+ Given('today is Friday', function () {
89
+ return { today : 'Friday' };
90
+ });
91
+
92
+ When('I ask whether it\'s Friday yet', function (state) {
93
+ return _.set('answer',(state.today === 'Friday') ? 'TGIF' : 'Nope',state);
94
+ });
95
+
96
+ Then('I should be told {string}', function (state,[ answer ]) {
97
+ expect(state.answer).toBe(answer);
98
+ });
99
+ ```
100
+
101
+ ### Step definitions must be ECMAScript modules
102
+
103
+ Currently, all step definition files must be in ECMAScript module format. CommonJS files might
104
+ work, but this configuration isn't tested.
105
+
106
+
107
+ ### Not yet implemented
108
+
109
+ This plugin is not yet feature complete. Here is the list of features from Cucumber which aren't yet implemented:
110
+ * Rule keyword
111
+ * Doc strings
112
+ * Data Table escape characters
113
+ * Boolean expression support for tags
@@ -0,0 +1,9 @@
1
+ * v0.1.3 : Import modules from generated code to make sure they are processed correctly
2
+ * v0.1.2 : Set default log level to warn and make it configurable
3
+ * v0.1.1 : Use root dir from the config to find step_definitions dir
4
+ * v0.1.0 : Added basic support for tags.
5
+ * v0.0.5 : Implemented keyword aliases and comments
6
+ * v0.0.4 : Implemented Data Tables
7
+ * v0.0.3 : Implemented Scenario Outline
8
+ * v0.0.2 : Updated README
9
+ * v0.0.1 : Initial release
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "vitest-cucumber-plugin",
3
+ "version": "0.1.3",
4
+ "description": "Plugin for Vitest which allows for tests to be written in Cucumber format.",
5
+ "keywords": [
6
+ "vite",
7
+ "vitest",
8
+ "cucumber"
9
+ ],
10
+ "homepage": "https://github.com/SamZiegler/vitest-cucumber-plugin#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/SamZiegler/vitest-cucumber-plugin/issues"
13
+ },
14
+ "license": "MIT",
15
+ "main": "src/index.js",
16
+ "type": "module",
17
+ "scripts": {
18
+ "nearley": "nearleyc src/gherkin.ne -o src/gherkin.umd.js && rollup -c rollup-nearley.js",
19
+ "test": "./run-tests"
20
+ },
21
+ "dependencies": {
22
+ "@cucumber/cucumber-expressions": "^16.1.2",
23
+ "lodash": "^4.17.21",
24
+ "moo": "^0.5.2",
25
+ "nearley": "^2.20.1",
26
+ "pino": "^8.11.0"
27
+ },
28
+ "devDependencies": {
29
+ "@rollup/plugin-commonjs": "^24.1.0",
30
+ "@types/lodash": "^4.14.194",
31
+ "rollup": "^3.20.7"
32
+ },
33
+ "repository" : "https://github.com/SamZiegler/vitest-cucumber-plugin.git"
34
+ }
@@ -0,0 +1,10 @@
1
+ import commonjs from "@rollup/plugin-commonjs";
2
+
3
+ export default {
4
+ input: "src/gherkin.umd.js",
5
+ output: {
6
+ file: "src/gherkin.js",
7
+ format: "es",
8
+ },
9
+ plugins: [commonjs()],
10
+ };
package/run-tests ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/bash
2
+
3
+ for i in `ls tests`; do
4
+ pushd tests/$i
5
+ npm install || exit
6
+ npm test || exit
7
+ popd
8
+ done
@@ -0,0 +1,20 @@
1
+ import { escape, shouldSkip } from './util.js';
2
+ import { generateTests } from './tests.js';
3
+ import _ from 'lodash/fp.js';
4
+ import { log } from '../logger.js';
5
+
6
+ export const generateExample = (config,example) => {
7
+ log.debug('generateExample config: '+JSON.stringify(config)+' example: '+JSON.stringify(example));
8
+ var tests = '';
9
+
10
+ const steps = _.has('background.steps',example) ? _.concat(example.background.steps,example.steps) : example.steps;
11
+
12
+ tests += generateTests(steps);
13
+
14
+ const skip = shouldSkip(config,example.tags) ? '.skip' : '';
15
+
16
+ const code = ` describe${skip}('${escape(example.type.name)}: ${escape(example.name)}', () => {${tests}
17
+ });
18
+ `;
19
+ return code;
20
+ }
@@ -0,0 +1,47 @@
1
+ import { escape, shouldSkip } from './util.js';
2
+ import { generateTests } from './tests.js';
3
+ import _ from 'lodash/fp.js';
4
+ import { log } from '../logger.js';
5
+
6
+ const createParameterMap = (parameters,values) => {
7
+ const parameterMap = _.reduce((parameterMap,value) => {
8
+ return {
9
+ map : _.set(parameters[parameterMap.index],value,parameterMap.map),
10
+ index : parameterMap.index + 1
11
+ };
12
+ },{ map : {}, index : 0 })(values);
13
+
14
+ return parameterMap.map;
15
+ }
16
+
17
+ const generateAllTests = (steps,parameters,parameterValues) => {
18
+ const allTests = _.reduce((allTests,values) => {
19
+ const parameterMap = createParameterMap(parameters,values);
20
+ log.debug('parameterMap : '+JSON.stringify(parameterMap));
21
+
22
+ const tests = generateTests(steps,parameterMap,' ');
23
+
24
+ return { tests : allTests.tests + `
25
+ describe('${allTests.index}',() => {${tests}
26
+ });`, index : allTests.index + 1 };
27
+ },{ tests : '', index : 0})(parameterValues);
28
+
29
+ return allTests.tests;
30
+ }
31
+
32
+ export const generateExamples = (config,steps,examplesStatement) => {
33
+ log.debug('generateExamples steps:'+JSON.stringify(steps)+' examples: '+JSON.stringify(examplesStatement));
34
+
35
+ const parameters = _.head(examplesStatement.dataTable);
36
+ const parameterValues = _.tail(examplesStatement.dataTable);
37
+
38
+ log.debug('generateExamples parameters:'+JSON.stringify(parameters)+' parameterValues: '+
39
+ JSON.stringify(parameterValues));
40
+
41
+ const skip = shouldSkip(config,examplesStatement.tags) ? '.skip' : '';
42
+
43
+ const allTests = generateAllTests(steps,parameters,parameterValues);
44
+ const code = ` describe${skip}('${escape(examplesStatement.type.name)}: ${escape(examplesStatement.name)}', () => {${allTests}
45
+ });`;
46
+ return code;
47
+ }
@@ -0,0 +1,45 @@
1
+ import _ from 'lodash/fp.js';
2
+ import { log } from '../logger.js';
3
+ import { generateExample, generateScenarioOutline } from './index.js';
4
+ import { escape, shouldSkip } from './util.js';
5
+
6
+ export const generateFeature = (config,feature) => {
7
+ const name = feature.name;
8
+ const statements = feature.statements;
9
+
10
+ const testStatements = _.reduce((testStatements,statement) => {
11
+ if (feature.background) {
12
+ statement = _.set('background',feature.background,statement);
13
+ }
14
+ if (statement.type.type === 'example') {
15
+ return testStatements + generateExample(config,statement);
16
+ } else if (statement.type.type === 'scenarioOutline') {
17
+ return testStatements + generateScenarioOutline(config,statement);
18
+ }
19
+ },'')(statements);
20
+
21
+ const skip = shouldSkip(config,feature.tags) ? '.skip' : '';
22
+ const configStr = JSON.stringify(config);
23
+
24
+ const code = `import { expect, test, describe } from 'vitest';
25
+ import { Test } from 'vitest-cucumber-plugin';
26
+ import { readdir } from 'node:fs/promises';
27
+
28
+ const importStepDefinitions = async (config) => {
29
+ const stepDefinitionDirectory = config.root+'/features/step_definitions';
30
+ const files = await readdir(stepDefinitionDirectory);
31
+ for (const file of files) {
32
+ const stepDefinition = stepDefinitionDirectory+'/'+file;
33
+ await import(stepDefinition);
34
+ }
35
+ };
36
+
37
+ await importStepDefinitions(${configStr});
38
+
39
+ describe${skip}('${escape(feature.type.name)}: ${escape(name)}', () => {
40
+ ${testStatements}});
41
+ `;
42
+ log.debug(code);
43
+
44
+ return code;
45
+ }
@@ -0,0 +1,13 @@
1
+ import { generateTests } from './tests.js';
2
+ import { generateExample } from './example.js';
3
+ import { generateExamples } from './examples.js';
4
+ import { generateScenarioOutline } from './scenarioOutline.js';
5
+ import { generateFeature } from './feature.js';
6
+
7
+ export {
8
+ generateTests,
9
+ generateExample,
10
+ generateExamples,
11
+ generateScenarioOutline,
12
+ generateFeature
13
+ };
@@ -0,0 +1,18 @@
1
+ import _ from 'lodash/fp.js';
2
+ import { generateExamples } from './examples.js';
3
+ import { escape, shouldSkip } from './util.js';
4
+
5
+ export const generateScenarioOutline = (config,scenarioOutline) => {
6
+ const examplesStatements = _.reduce((examplesStatements,examplesStatement) => {
7
+ return examplesStatements + generateExamples(config,scenarioOutline.steps,examplesStatement);
8
+ },'')(scenarioOutline.examples);
9
+
10
+ const skip = shouldSkip(config,scenarioOutline.tags) ? '.skip' : '';
11
+
12
+ const code = ` describe${skip}('${escape(scenarioOutline.type.name)}: ${escape(scenarioOutline.name)}', () => {
13
+ ${examplesStatements}
14
+ });
15
+ `;
16
+
17
+ return code;
18
+ }
@@ -0,0 +1,23 @@
1
+ import _ from 'lodash/fp.js';
2
+ import { escape } from './util.js';
3
+ import { parameterizeText } from '../parameterize.js';
4
+ import { log } from '../logger.js';
5
+
6
+ export const generateTests = (steps,parameterMap,extraIndent) => {
7
+ log.debug('generateTests steps : '+JSON.stringify(steps));
8
+ const indent = extraIndent ? extraIndent : '';
9
+ let tests = `
10
+ ${indent} var state = {};`;
11
+
12
+ _.forEach((step) => {
13
+ const parameterizedText = ( parameterMap ? parameterizeText(step.text,parameterMap) : step.text);
14
+ const name = parameterizedText;
15
+ const parameterizedStep = _.set('text',parameterizedText,step);
16
+
17
+ const stepString = JSON.stringify(parameterizedStep);
18
+ tests = tests+`
19
+ ${indent} test('${escape(step.type.name)} ${escape(name)}', () => { state = Test(state,${stepString}); });`;
20
+ },steps);
21
+
22
+ return tests;
23
+ };
@@ -0,0 +1,10 @@
1
+ import _ from 'lodash/fp.js';
2
+ import { log } from '../logger.js';
3
+
4
+ export const escape = (str) => str.replace(/'/g,"\\'");
5
+ export const shouldSkip = (config,tags) => {
6
+ const exclude = _.getOr([],'tags.exclude',config);
7
+ const intersection = _.intersection(exclude,tags);
8
+ log.debug('shouldSkip config: '+JSON.stringify(config)+' tags: '+JSON.stringify(tags)+' intersection: '+JSON.stringify(intersection));
9
+ return intersection.length > 0;
10
+ }
package/src/gherkin.js ADDED
@@ -0,0 +1,171 @@
1
+ import require$$0 from 'lodash/fp.js';
2
+ import require$$1 from 'moo';
3
+ import pino from 'pino';
4
+
5
+ function getDefaultExportFromCjs (x) {
6
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
7
+ }
8
+
9
+ function getAugmentedNamespace(n) {
10
+ if (n.__esModule) return n;
11
+ var f = n.default;
12
+ if (typeof f == "function") {
13
+ var a = function a () {
14
+ if (this instanceof a) {
15
+ var args = [null];
16
+ args.push.apply(args, arguments);
17
+ var Ctor = Function.bind.apply(f, args);
18
+ return new Ctor();
19
+ }
20
+ return f.apply(this, arguments);
21
+ };
22
+ a.prototype = f.prototype;
23
+ } else a = {};
24
+ Object.defineProperty(a, '__esModule', {value: true});
25
+ Object.keys(n).forEach(function (k) {
26
+ var d = Object.getOwnPropertyDescriptor(n, k);
27
+ Object.defineProperty(a, k, d.get ? d : {
28
+ enumerable: true,
29
+ get: function () {
30
+ return n[k];
31
+ }
32
+ });
33
+ });
34
+ return a;
35
+ }
36
+
37
+ var gherkin_umd$1 = {exports: {}};
38
+
39
+ const log = pino();
40
+
41
+ log.level = 'warn';
42
+
43
+ var logger = /*#__PURE__*/Object.freeze({
44
+ __proto__: null,
45
+ log: log
46
+ });
47
+
48
+ var require$$2 = /*@__PURE__*/getAugmentedNamespace(logger);
49
+
50
+ (function (module) {
51
+ // Generated automatically by nearley, version 2.20.1
52
+ // http://github.com/Hardmath123/nearley
53
+ (function () {
54
+
55
+ const fp = require$$0;
56
+ const moo = require$$1;
57
+ require$$2.log;
58
+ const lexer = moo.compile({
59
+ emptyLine : { match: /^[ \t]*(?:\#[^\n]+)?\n/, lineBreaks : true },
60
+ newline : { match : '\n', lineBreaks : true },
61
+ ws : /[ \t]+/,
62
+ at : '@',
63
+ colon : ':',
64
+ step : '*',
65
+ pipe : '|',
66
+ backSlash : '\\',
67
+ scenarioOutline : ['Scenario Outline','Scenario Template'],
68
+ word : {
69
+ match : /[^ \t\n:|\\]+/,
70
+ type : moo.keywords({
71
+ feature : 'Feature',
72
+ examples : ['Examples','Scenarios'],
73
+ step : ['Given','When','Then','And','But'],
74
+ example : ['Example','Scenario'],
75
+ background : 'Background',
76
+ }),
77
+ },
78
+ });
79
+ var grammar = {
80
+ Lexer: lexer,
81
+ ParserRules: [
82
+ {"name": "main", "symbols": ["emptyLines", "tags", "feature"], "postprocess": data => fp.set('tags',data[1],data[2])},
83
+ {"name": "feature", "symbols": ["featureStatement", "freeform", "background", "statements"], "postprocess":
84
+ (data) => fp.assign(data[0],{ description : data[1].trim(), background : data[2], statements : data[3] })
85
+ },
86
+ {"name": "featureStatement", "symbols": ["_", (lexer.has("feature") ? {type: "feature"} : feature), "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
87
+ (data) => { return { type : { type : 'feature', name : data[1].value.trim() }, name : data[4].trim() } }
88
+ },
89
+ {"name": "tags", "symbols": [], "postprocess": data => []},
90
+ {"name": "tags", "symbols": ["_", "tag", "tagList", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": data => fp.concat(data[1],data[2])},
91
+ {"name": "tagList", "symbols": [], "postprocess": data => []},
92
+ {"name": "tagList", "symbols": ["tagList", (lexer.has("ws") ? {type: "ws"} : ws), "tag"], "postprocess": data => fp.concat(data[0],data[2])},
93
+ {"name": "tag", "symbols": [(lexer.has("at") ? {type: "at"} : at), (lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[1].value.trim()},
94
+ {"name": "background", "symbols": [], "postprocess": data => null},
95
+ {"name": "background", "symbols": ["backgroundStatement", "freeform", "steps"], "postprocess":
96
+ data => fp.assign(data[0],{ description : data[1].trim(), steps : data[2] })
97
+ },
98
+ {"name": "backgroundStatement", "symbols": ["_", (lexer.has("background") ? {type: "background"} : background), "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
99
+ (data) => { return { type : { type : 'background', name : data[1].value }, name : data[4].trim() } }
100
+ },
101
+ {"name": "statement", "symbols": ["example"], "postprocess": data => data[0]},
102
+ {"name": "statement", "symbols": ["scenarioOutline"], "postprocess": data => data[0]},
103
+ {"name": "statements", "symbols": [], "postprocess": data => []},
104
+ {"name": "statements", "symbols": ["statements", "statement"], "postprocess": data => fp.concat(data[0],data[1])},
105
+ {"name": "example", "symbols": ["tags", "exampleStatement", "steps"], "postprocess": (data) => fp.assign(data[1],{ tags : data[0], steps : data[2] })},
106
+ {"name": "exampleStatement", "symbols": ["_", "exampleKeyword", "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
107
+ (data) => { return { type : { type : 'example', name : data[1] }, name : data[4].trim() } }
108
+ },
109
+ {"name": "exampleKeyword", "symbols": [(lexer.has("example") ? {type: "example"} : example)], "postprocess": data => data[0].value},
110
+ {"name": "scenarioOutline", "symbols": ["tags", "scenarioOutlineStatement", "steps", "examplesList"], "postprocess":
111
+ data => fp.assign(data[1],{ tags : data[0], steps : data[2], examples : data[3] })
112
+ },
113
+ {"name": "scenarioOutlineStatement", "symbols": ["_", "scenarioOutlineKeyword", "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
114
+ (data) => { return { type : { type : 'scenarioOutline', name : data[1] }, name : data[4].trim() } }
115
+ },
116
+ {"name": "scenarioOutlineKeyword", "symbols": [(lexer.has("scenarioOutline") ? {type: "scenarioOutline"} : scenarioOutline)], "postprocess": data => data[0].value},
117
+ {"name": "examplesList", "symbols": [], "postprocess": data => []},
118
+ {"name": "examplesList", "symbols": ["examplesList", "examples"], "postprocess": data => fp.concat(data[0],data[1])},
119
+ {"name": "examples", "symbols": ["tags", "examplesStatement", "dataTable", "emptyLines"], "postprocess":
120
+ data => fp.assign(data[1],{ tags : data[0], dataTable : data[2] })
121
+ },
122
+ {"name": "examplesStatement", "symbols": ["_", "examplesKeyword", "_", (lexer.has("colon") ? {type: "colon"} : colon), "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess":
123
+ (data) => { return { type : { type : 'examples', name : data[1] }, name : data[4] } }
124
+ },
125
+ {"name": "examplesKeyword", "symbols": [(lexer.has("examples") ? {type: "examples"} : examples)], "postprocess": data => data[0].value},
126
+ {"name": "dataTable", "symbols": [], "postprocess": data => []},
127
+ {"name": "dataTable", "symbols": ["dataTable", "dataTableRow"], "postprocess": data => fp.concat(data[0],[data[1]])},
128
+ {"name": "dataTableRow", "symbols": ["_", (lexer.has("pipe") ? {type: "pipe"} : pipe), "dataTableColumns", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": data => data[2]},
129
+ {"name": "dataTableColumns", "symbols": [], "postprocess": data => []},
130
+ {"name": "dataTableColumns", "symbols": ["dataTableColumns", "text", (lexer.has("pipe") ? {type: "pipe"} : pipe)], "postprocess": data => fp.concat(data[0],data[1].trim())},
131
+ {"name": "steps", "symbols": ["stepAndTable", "moreSteps"], "postprocess": data => fp.concat(data[0],data[1])},
132
+ {"name": "moreSteps", "symbols": [], "postprocess": data => []},
133
+ {"name": "moreSteps", "symbols": ["moreSteps", "stepAndTable"], "postprocess": data => fp.concat(data[0],data[1])},
134
+ {"name": "moreSteps", "symbols": ["moreSteps", (lexer.has("emptyLine") ? {type: "emptyLine"} : emptyLine)], "postprocess": data => data[0]},
135
+ {"name": "step", "symbols": ["_", "stepKeyword", "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": data => { return { type : data[1], text : data[2].trim() } }},
136
+ {"name": "stepAndTable", "symbols": ["step", "dataTable"], "postprocess": data => fp.set('dataTable',data[1],data[0])},
137
+ {"name": "stepKeyword", "symbols": [(lexer.has("step") ? {type: "step"} : step)], "postprocess": (data) => { return { type : 'step', name : data[0].value } }},
138
+ {"name": "text", "symbols": [], "postprocess": data => ''},
139
+ {"name": "text", "symbols": ["text", (lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[0]+data[1].value},
140
+ {"name": "text", "symbols": ["text", (lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": data => data[0]+data[1].value},
141
+ {"name": "text", "symbols": ["text", (lexer.has("step") ? {type: "step"} : step)], "postprocess": data => data[0]+data[1].value},
142
+ {"name": "text", "symbols": ["text", (lexer.has("colon") ? {type: "colon"} : colon)], "postprocess": data => data[0]+data[1].value},
143
+ {"name": "text", "symbols": ["text", (lexer.has("example") ? {type: "example"} : example)], "postprocess": data => data[0]+data[1].value},
144
+ {"name": "text", "symbols": ["text", (lexer.has("examples") ? {type: "examples"} : examples)], "postprocess": data => data[0]+data[1].value},
145
+ {"name": "text", "symbols": ["text", (lexer.has("scenarioOutline") ? {type: "scenarioOutline"} : scenarioOutline)], "postprocess": data => data[0]+data[1].value},
146
+ {"name": "text", "symbols": ["text", (lexer.has("background") ? {type: "background"} : background)], "postprocess": data => data[0]+data[1].value},
147
+ {"name": "bolText", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws), (lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[1].value},
148
+ {"name": "bolText", "symbols": [(lexer.has("word") ? {type: "word"} : word)], "postprocess": data => data[0].value},
149
+ {"name": "freeform", "symbols": [], "postprocess": data => ''},
150
+ {"name": "freeform", "symbols": ["freeform", "bolText", "text", (lexer.has("newline") ? {type: "newline"} : newline)], "postprocess": (data) => {
151
+ return data[0]+data[1]+data[2]+'\n'
152
+ }
153
+ },
154
+ {"name": "freeform", "symbols": ["freeform", (lexer.has("emptyLine") ? {type: "emptyLine"} : emptyLine)], "postprocess": data => data[0]+'\n'},
155
+ {"name": "_", "symbols": [], "postprocess": data => ''},
156
+ {"name": "_", "symbols": [(lexer.has("ws") ? {type: "ws"} : ws)], "postprocess": data => data[0].value},
157
+ {"name": "emptyLines", "symbols": [], "postprocess": data => ''},
158
+ {"name": "emptyLines", "symbols": ["emptyLines", (lexer.has("emptyLine") ? {type: "emptyLine"} : emptyLine)], "postprocess": data => data[0]+'\n'}
159
+ ]
160
+ , ParserStart: "main"
161
+ };
162
+ {
163
+ module.exports = grammar;
164
+ }
165
+ })();
166
+ } (gherkin_umd$1));
167
+
168
+ var gherkin_umdExports = gherkin_umd$1.exports;
169
+ var gherkin_umd = /*@__PURE__*/getDefaultExportFromCjs(gherkin_umdExports);
170
+
171
+ export { gherkin_umd as default };