refactor: init cypress-cucumber-preprocessor install.
This commit is contained in:
10
node_modules/cucumber-expressions/.babelrc
generated
vendored
Normal file
10
node_modules/cucumber-expressions/.babelrc
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"presets": [
|
||||
["@babel/env", {
|
||||
"targets": {
|
||||
"node": "current"
|
||||
}
|
||||
}]
|
||||
],
|
||||
"plugins": ["@babel/plugin-transform-async-to-generator"]
|
||||
}
|
21
node_modules/cucumber-expressions/.eslintrc
generated
vendored
Normal file
21
node_modules/cucumber-expressions/.eslintrc
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 8
|
||||
},
|
||||
"plugins": [
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"prettier/prettier": [
|
||||
"error", {"trailingComma": "es5", "singleQuote": true, "semi": false}
|
||||
]
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"prettier"
|
||||
]
|
||||
}
|
5
node_modules/cucumber-expressions/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
5
node_modules/cucumber-expressions/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
PLEASE DO NOT CREATE ISSUES IN THIS REPO.
|
||||
THIS REPO IS A READ-ONLY MIRROR.
|
||||
|
||||
Create your issue in the Cucumber monorepo instead:
|
||||
https://github.com/cucumber/cucumber/issues
|
5
node_modules/cucumber-expressions/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
5
node_modules/cucumber-expressions/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
PLEASE DO NOT CREATE PULL REAUESTS IN THIS REPO.
|
||||
THIS REPO IS A READ-ONLY MIRROR.
|
||||
|
||||
Create your pull request in the Cucumber monorepo instead:
|
||||
https://github.com/cucumber/cucumber/pulls
|
14
node_modules/cucumber-expressions/.npmignore
generated
vendored
Normal file
14
node_modules/cucumber-expressions/.npmignore
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
.idea/
|
||||
.nyc_output/
|
||||
coverage/
|
||||
node_modules/
|
||||
yarn.lock
|
||||
npm-debug.log
|
||||
package-lock.json
|
||||
.deps
|
||||
.tested
|
||||
.eslinted
|
||||
.compared
|
||||
acceptance
|
||||
dist
|
||||
*-go/
|
4
node_modules/cucumber-expressions/.rsync
generated
vendored
Normal file
4
node_modules/cucumber-expressions/.rsync
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
../../LICENSE LICENSE
|
||||
../../.templates/github/ .github/
|
||||
../../.templates/javascript/ .
|
||||
../examples.txt examples.txt
|
1
node_modules/cucumber-expressions/.subrepo
generated
vendored
Normal file
1
node_modules/cucumber-expressions/.subrepo
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
cucumber/cucumber-expressions-javascript
|
24
node_modules/cucumber-expressions/.travis.yml
generated
vendored
Normal file
24
node_modules/cucumber-expressions/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- "10"
|
||||
- "9"
|
||||
- "8"
|
||||
- "6"
|
||||
|
||||
before_install:
|
||||
- npm i -g npm@latest
|
||||
script: make default
|
||||
jobs:
|
||||
include:
|
||||
- stage: deploy
|
||||
node_js: '10'
|
||||
deploy:
|
||||
skip_cleanup: true
|
||||
provider: npm
|
||||
email: cukebot@cucumber.io
|
||||
on:
|
||||
tags: true
|
||||
deploy:
|
||||
api_key:
|
||||
secure: bUmCug37qcNOAQnjNduP0katc7ETn3vmePjp+cYWlpA27pQTvhf7zxcgocgDJPstS1tooDuIxzyk802mXgkV6rwRo2hs0ul3P/lyRcodsWshiKsAR/4hA3VrJ3om3v+RSOW3Qdlh+e0m7h4a3IANWMxaaEKBmAhd+iHjrmqXYjQsvImEZydkfNddOubO7MBECDOazH4tEQ65ppyrSJIsABRDAs6OD5obRhDBbEnzW2oNBH/m48W/C33H+dSgM3DIisu9+qCscqM1iMb6c/vFhq8q2EHRWpzRnsTEz3yUiXnotmU9A3iX/0qwvM6vpAtrixd4kKG8ruocnK1zK1NEItrEESWSvJ5qbcVDQcwGE3wmUtJhHgRClWcTVxAL68PkIuBAfZYwFrDCfbb2Cx1ecJGZFJ/042D6JE5v4hWApXz7KMMt2pEPz1peQ9ytguolT5sO/xZLtHwaBxegK6AcIjVgJoke/yXRPJPfNHQHW+MGV+mATv0kba9DKDAmo+H57Lo2YPHGaQ2xghWPHn8CaykSleAgC8+17gNOr50JTIu82hNXpLZiFx6Rdy2MP6/TW2+s+iPvq1bmYSqfjZKdw7cONDnxYWZc0SeNxVuxrJgluEzegHstTHQ9Aq5v7qAnPEwPXx+CXP2KmxGt9DjW0zUCCIUz+77pcZuYponG7tg=
|
21
node_modules/cucumber-expressions/LICENSE
generated
vendored
Normal file
21
node_modules/cucumber-expressions/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Cucumber Ltd
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
4
node_modules/cucumber-expressions/Makefile
generated
vendored
Normal file
4
node_modules/cucumber-expressions/Makefile
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
include default.mk
|
||||
|
||||
.deps:
|
||||
touch $@
|
5
node_modules/cucumber-expressions/README.md
generated
vendored
Normal file
5
node_modules/cucumber-expressions/README.md
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Cucumber Expressions for JavaScript
|
||||
|
||||
[](https://travis-ci.org/cucumber/cucumber-expressions-javascript)
|
||||
|
||||
[The docs are here](https://docs.cucumber.io/cucumber/cucumber-expressions/).
|
43
node_modules/cucumber-expressions/default.mk
generated
vendored
Normal file
43
node_modules/cucumber-expressions/default.mk
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
SHELL := /usr/bin/env bash
|
||||
JAVASCRIPT_SOURCE_FILES = $(shell find . -name "*.js" -not -path "./node_modules/*")
|
||||
|
||||
ifdef TRAVIS_BRANCH
|
||||
LIBRARY_VERSION=$(TRAVIS_BRANCH)
|
||||
endif
|
||||
ifdef TRAVIS_TAG
|
||||
LIBRARY_VERSION=$(TRAVIS_TAG)
|
||||
endif
|
||||
ifndef LIBRARY_VERSION
|
||||
LIBRARY_VERSION=$(shell git rev-parse --abbrev-ref HEAD)
|
||||
endif
|
||||
|
||||
ASYNC_SUPPORTED := $(shell node --eval "async function foo(){}" 2> /dev/null; echo $$?)
|
||||
|
||||
.tested: package-lock.json .deps $(JAVASCRIPT_SOURCE_FILES)
|
||||
npm run build
|
||||
ifeq ($(ASYNC_SUPPORTED),0)
|
||||
npm run coverage
|
||||
else
|
||||
npm run build-test
|
||||
npm run mocha-built
|
||||
endif
|
||||
touch $@
|
||||
|
||||
default: .tested .eslinted
|
||||
.PHONY: default
|
||||
|
||||
.eslinted: $(JAVASCRIPT_SOURCE_FILES)
|
||||
npm run eslint-fix
|
||||
touch $@
|
||||
|
||||
package-lock.json: package.json
|
||||
npm install
|
||||
npm link
|
||||
touch $@
|
||||
|
||||
clean: clean-javascript
|
||||
.PHONY: clean
|
||||
|
||||
clean-javascript:
|
||||
rm -rf .deps package-lock.json node_modules coverage dist
|
||||
.PHONY: clean-javascript
|
42
node_modules/cucumber-expressions/dist/src/argument.js
generated
vendored
Normal file
42
node_modules/cucumber-expressions/dist/src/argument.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
CucumberExpressionError
|
||||
} = require('./errors');
|
||||
|
||||
class Argument {
|
||||
static build(treeRegexp, text, parameterTypes) {
|
||||
const group = treeRegexp.match(text);
|
||||
if (!group) return null;
|
||||
const argGroups = group.children;
|
||||
|
||||
if (argGroups.length !== parameterTypes.length) {
|
||||
throw new CucumberExpressionError(`Expression ${treeRegexp.regexp} has ${argGroups.length} capture groups (${argGroups.map(g => g.value)}), but there were ${parameterTypes.length} parameter types (${parameterTypes.map(p => p.name)})`);
|
||||
}
|
||||
|
||||
return parameterTypes.map((parameterType, i) => new Argument(argGroups[i], parameterType));
|
||||
}
|
||||
|
||||
constructor(group, parameterType) {
|
||||
this._group = group;
|
||||
this._parameterType = parameterType;
|
||||
}
|
||||
|
||||
get group() {
|
||||
return this._group;
|
||||
}
|
||||
/**
|
||||
* Get the value returned by the parameter type's transformer function.
|
||||
*
|
||||
* @param thisObj the object in which the transformer function is applied.
|
||||
*/
|
||||
|
||||
|
||||
getValue(thisObj) {
|
||||
let groupValues = this._group ? this._group.values : null;
|
||||
return this._parameterType.transform(thisObj, groupValues);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Argument;
|
48
node_modules/cucumber-expressions/dist/src/combinatorial_generated_expression_factory.js
generated
vendored
Normal file
48
node_modules/cucumber-expressions/dist/src/combinatorial_generated_expression_factory.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
"use strict";
|
||||
|
||||
const GeneratedExpression = require('./generated_expression'); // 256 generated expressions ought to be enough for anybody
|
||||
|
||||
|
||||
const MAX_EXPRESSIONS = 256;
|
||||
|
||||
class CombinatorialGeneratedExpressionFactory {
|
||||
constructor(expressionTemplate, parameterTypeCombinations) {
|
||||
this._expressionTemplate = expressionTemplate;
|
||||
this._parameterTypeCombinations = parameterTypeCombinations;
|
||||
}
|
||||
|
||||
generateExpressions() {
|
||||
const generatedExpressions = [];
|
||||
|
||||
this._generatePermutations(generatedExpressions, 0, []);
|
||||
|
||||
return generatedExpressions;
|
||||
}
|
||||
|
||||
_generatePermutations(generatedExpressions, depth, currentParameterTypes) {
|
||||
if (generatedExpressions.length >= MAX_EXPRESSIONS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (depth === this._parameterTypeCombinations.length) {
|
||||
generatedExpressions.push(new GeneratedExpression(this._expressionTemplate, currentParameterTypes));
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._parameterTypeCombinations[depth].length; ++i) {
|
||||
// Avoid recursion if no elements can be added.
|
||||
if (generatedExpressions.length >= MAX_EXPRESSIONS) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newCurrentParameterTypes = currentParameterTypes.slice(); // clone
|
||||
|
||||
newCurrentParameterTypes.push(this._parameterTypeCombinations[depth][i]);
|
||||
|
||||
this._generatePermutations(generatedExpressions, depth + 1, newCurrentParameterTypes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = CombinatorialGeneratedExpressionFactory;
|
125
node_modules/cucumber-expressions/dist/src/cucumber_expression.js
generated
vendored
Normal file
125
node_modules/cucumber-expressions/dist/src/cucumber_expression.js
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
"use strict";
|
||||
|
||||
const Argument = require('./argument');
|
||||
|
||||
const TreeRegexp = require('./tree_regexp');
|
||||
|
||||
const ParameterType = require('./parameter_type');
|
||||
|
||||
const {
|
||||
UndefinedParameterTypeError,
|
||||
CucumberExpressionError
|
||||
} = require('./errors'); // RegExps with the g flag are stateful in JavaScript. In order to be able
|
||||
// to reuse them we have to wrap them in a function.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test
|
||||
// Does not include (){} characters because they have special meaning
|
||||
|
||||
|
||||
const ESCAPE_REGEXP = () => /([\\^[$.|?*+])/g;
|
||||
|
||||
const PARAMETER_REGEXP = () => /(\\\\)?{([^}]*)}/g;
|
||||
|
||||
const OPTIONAL_REGEXP = () => /(\\\\)?\(([^)]+)\)/g;
|
||||
|
||||
const ALTERNATIVE_NON_WHITESPACE_TEXT_REGEXP = () => /([^\s^/]+)((\/[^\s^/]+)+)/g;
|
||||
|
||||
const DOUBLE_ESCAPE = '\\\\';
|
||||
const PARAMETER_TYPES_CANNOT_BE_ALTERNATIVE = 'Parameter types cannot be alternative: ';
|
||||
const PARAMETER_TYPES_CANNOT_BE_OPTIONAL = 'Parameter types cannot be optional: ';
|
||||
|
||||
class CucumberExpression {
|
||||
/**
|
||||
* @param expression
|
||||
* @param parameterTypeRegistry
|
||||
*/
|
||||
constructor(expression, parameterTypeRegistry) {
|
||||
this._expression = expression;
|
||||
this._parameterTypes = [];
|
||||
expression = this.processEscapes(expression);
|
||||
expression = this.processOptional(expression);
|
||||
expression = this.processAlternation(expression);
|
||||
expression = this.processParameters(expression, parameterTypeRegistry);
|
||||
expression = `^${expression}$`;
|
||||
this._treeRegexp = new TreeRegexp(expression);
|
||||
}
|
||||
|
||||
processEscapes(expression) {
|
||||
return expression.replace(ESCAPE_REGEXP(), '\\$1');
|
||||
}
|
||||
|
||||
processOptional(expression) {
|
||||
return expression.replace(OPTIONAL_REGEXP(), (match, p1, p2) => {
|
||||
if (p1 === DOUBLE_ESCAPE) {
|
||||
return `\\(${p2}\\)`;
|
||||
}
|
||||
|
||||
this._checkNoParameterType(p2, PARAMETER_TYPES_CANNOT_BE_OPTIONAL);
|
||||
|
||||
return `(?:${p2})?`;
|
||||
});
|
||||
}
|
||||
|
||||
processAlternation(expression) {
|
||||
return expression.replace(ALTERNATIVE_NON_WHITESPACE_TEXT_REGEXP(), match => {
|
||||
// replace \/ with /
|
||||
// replace / with |
|
||||
const replacement = match.replace(/\//g, '|').replace(/\\\|/g, '/');
|
||||
|
||||
if (replacement.indexOf('|') !== -1) {
|
||||
for (const part of replacement.split(/\|/)) {
|
||||
this._checkNoParameterType(part, PARAMETER_TYPES_CANNOT_BE_ALTERNATIVE);
|
||||
}
|
||||
|
||||
return `(?:${replacement})`;
|
||||
} else {
|
||||
return replacement;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
processParameters(expression, parameterTypeRegistry) {
|
||||
return expression.replace(PARAMETER_REGEXP(), (match, p1, p2) => {
|
||||
if (p1 === DOUBLE_ESCAPE) return `\\{${p2}\\}`;
|
||||
const typeName = p2;
|
||||
ParameterType.checkParameterTypeName(typeName);
|
||||
const parameterType = parameterTypeRegistry.lookupByTypeName(typeName);
|
||||
if (!parameterType) throw new UndefinedParameterTypeError(typeName);
|
||||
|
||||
this._parameterTypes.push(parameterType);
|
||||
|
||||
return buildCaptureRegexp(parameterType.regexps);
|
||||
});
|
||||
}
|
||||
|
||||
match(text) {
|
||||
return Argument.build(this._treeRegexp, text, this._parameterTypes);
|
||||
}
|
||||
|
||||
get regexp() {
|
||||
return this._treeRegexp.regexp;
|
||||
}
|
||||
|
||||
get source() {
|
||||
return this._expression;
|
||||
}
|
||||
|
||||
_checkNoParameterType(s, message) {
|
||||
if (s.match(PARAMETER_REGEXP())) {
|
||||
throw new CucumberExpressionError(message + this.source);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function buildCaptureRegexp(regexps) {
|
||||
if (regexps.length === 1) {
|
||||
return `(${regexps[0]})`;
|
||||
}
|
||||
|
||||
const captureGroups = regexps.map(group => {
|
||||
return `(?:${group})`;
|
||||
});
|
||||
return `(${captureGroups.join('|')})`;
|
||||
}
|
||||
|
||||
module.exports = CucumberExpression;
|
110
node_modules/cucumber-expressions/dist/src/cucumber_expression_generator.js
generated
vendored
Normal file
110
node_modules/cucumber-expressions/dist/src/cucumber_expression_generator.js
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
"use strict";
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const ParameterTypeMatcher = require('./parameter_type_matcher');
|
||||
|
||||
const ParameterType = require('./parameter_type');
|
||||
|
||||
const CombinatorialGeneratedExpressionFactory = require('./combinatorial_generated_expression_factory');
|
||||
|
||||
class CucumberExpressionGenerator {
|
||||
constructor(parameterTypeRegistry) {
|
||||
this._parameterTypeRegistry = parameterTypeRegistry;
|
||||
}
|
||||
|
||||
generateExpressions(text) {
|
||||
const parameterTypeCombinations = [];
|
||||
|
||||
const parameterTypeMatchers = this._createParameterTypeMatchers(text);
|
||||
|
||||
let expressionTemplate = '';
|
||||
let pos = 0; // eslint-disable-next-line no-constant-condition
|
||||
|
||||
while (true) {
|
||||
let matchingParameterTypeMatchers = [];
|
||||
|
||||
for (const parameterTypeMatcher of parameterTypeMatchers) {
|
||||
const advancedParameterTypeMatcher = parameterTypeMatcher.advanceTo(pos);
|
||||
|
||||
if (advancedParameterTypeMatcher.find) {
|
||||
matchingParameterTypeMatchers.push(advancedParameterTypeMatcher);
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingParameterTypeMatchers.length > 0) {
|
||||
matchingParameterTypeMatchers = matchingParameterTypeMatchers.sort(ParameterTypeMatcher.compare); // Find all the best parameter type matchers, they are all candidates.
|
||||
|
||||
const bestParameterTypeMatcher = matchingParameterTypeMatchers[0];
|
||||
const bestParameterTypeMatchers = matchingParameterTypeMatchers.filter(m => ParameterTypeMatcher.compare(m, bestParameterTypeMatcher) === 0); // Build a list of parameter types without duplicates. The reason there
|
||||
// might be duplicates is that some parameter types have more than one regexp,
|
||||
// which means multiple ParameterTypeMatcher objects will have a reference to the
|
||||
// same ParameterType.
|
||||
// We're sorting the list so preferential parameter types are listed first.
|
||||
// Users are most likely to want these, so they should be listed at the top.
|
||||
|
||||
let parameterTypes = [];
|
||||
|
||||
for (const parameterTypeMatcher of bestParameterTypeMatchers) {
|
||||
if (parameterTypes.indexOf(parameterTypeMatcher.parameterType) === -1) {
|
||||
parameterTypes.push(parameterTypeMatcher.parameterType);
|
||||
}
|
||||
}
|
||||
|
||||
parameterTypes = parameterTypes.sort(ParameterType.compare);
|
||||
parameterTypeCombinations.push(parameterTypes);
|
||||
expressionTemplate += escape(text.slice(pos, bestParameterTypeMatcher.start));
|
||||
expressionTemplate += '{%s}';
|
||||
pos = bestParameterTypeMatcher.start + bestParameterTypeMatcher.group.length;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if (pos >= text.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expressionTemplate += escape(text.slice(pos));
|
||||
return new CombinatorialGeneratedExpressionFactory(expressionTemplate, parameterTypeCombinations).generateExpressions();
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
|
||||
|
||||
generateExpression(text) {
|
||||
return util.deprecate(() => this.generateExpressions(text)[0], 'CucumberExpressionGenerator.generateExpression: Use CucumberExpressionGenerator.generateExpressions instead')();
|
||||
}
|
||||
|
||||
_createParameterTypeMatchers(text) {
|
||||
let parameterMatchers = [];
|
||||
|
||||
for (const parameterType of this._parameterTypeRegistry.parameterTypes) {
|
||||
if (parameterType.useForSnippets) {
|
||||
parameterMatchers = parameterMatchers.concat(this._createParameterTypeMatchers2(parameterType, text));
|
||||
}
|
||||
}
|
||||
|
||||
return parameterMatchers;
|
||||
}
|
||||
|
||||
_createParameterTypeMatchers2(parameterType, text) {
|
||||
// TODO: [].map
|
||||
const result = [];
|
||||
|
||||
for (const regexp of parameterType.regexps) {
|
||||
result.push(new ParameterTypeMatcher(parameterType, regexp, text));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function escape(s) {
|
||||
return s.replace(/%/g, '%%') // for util.format
|
||||
.replace(/\(/g, '\\(').replace(/{/g, '\\{').replace(/\//g, '\\/');
|
||||
}
|
||||
|
||||
module.exports = CucumberExpressionGenerator;
|
45
node_modules/cucumber-expressions/dist/src/errors.js
generated
vendored
Normal file
45
node_modules/cucumber-expressions/dist/src/errors.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
"use strict";
|
||||
|
||||
class CucumberExpressionError extends Error {}
|
||||
|
||||
class AmbiguousParameterTypeError extends CucumberExpressionError {
|
||||
static forConstructor(keyName, keyValue, parameterTypes, generatedExpressions) {
|
||||
return new this(`parameter type with ${keyName}=${keyValue} is used by several parameter types: ${parameterTypes}, ${generatedExpressions}`);
|
||||
}
|
||||
|
||||
static forRegExp(parameterTypeRegexp, expressionRegexp, parameterTypes, generatedExpressions) {
|
||||
return new this(`Your Regular Expression ${expressionRegexp}
|
||||
matches multiple parameter types with regexp ${parameterTypeRegexp}:
|
||||
${this._parameterTypeNames(parameterTypes)}
|
||||
|
||||
I couldn't decide which one to use. You have two options:
|
||||
|
||||
1) Use a Cucumber Expression instead of a Regular Expression. Try one of these:
|
||||
${this._expressions(generatedExpressions)}
|
||||
|
||||
2) Make one of the parameter types preferential and continue to use a Regular Expression.
|
||||
`);
|
||||
}
|
||||
|
||||
static _parameterTypeNames(parameterTypes) {
|
||||
return parameterTypes.map(p => `{${p.name}}`).join('\n ');
|
||||
}
|
||||
|
||||
static _expressions(generatedExpressions) {
|
||||
return generatedExpressions.map(e => e.source).join('\n ');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UndefinedParameterTypeError extends CucumberExpressionError {
|
||||
constructor(typeName) {
|
||||
super(`Undefined parameter type {${typeName}}`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
AmbiguousParameterTypeError,
|
||||
UndefinedParameterTypeError,
|
||||
CucumberExpressionError
|
||||
};
|
43
node_modules/cucumber-expressions/dist/src/generated_expression.js
generated
vendored
Normal file
43
node_modules/cucumber-expressions/dist/src/generated_expression.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
"use strict";
|
||||
|
||||
const util = require('util');
|
||||
|
||||
class GeneratedExpression {
|
||||
constructor(expressionTemplate, parameterTypes) {
|
||||
this._expressionTemplate = expressionTemplate;
|
||||
this._parameterTypes = parameterTypes;
|
||||
}
|
||||
|
||||
get source() {
|
||||
return util.format(this._expressionTemplate, ...this._parameterTypes.map(t => t.name));
|
||||
}
|
||||
/**
|
||||
* Returns an array of parameter names to use in generated function/method signatures
|
||||
*
|
||||
* @returns {Array.<String>}
|
||||
*/
|
||||
|
||||
|
||||
get parameterNames() {
|
||||
const usageByTypeName = {};
|
||||
return this._parameterTypes.map(t => getParameterName(t.name, usageByTypeName));
|
||||
}
|
||||
/**
|
||||
* @returns {Array.<ParameterType>}
|
||||
*/
|
||||
|
||||
|
||||
get parameterTypes() {
|
||||
return this._parameterTypes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getParameterName(typeName, usageByTypeName) {
|
||||
let count = usageByTypeName[typeName];
|
||||
count = count ? count + 1 : 1;
|
||||
usageByTypeName[typeName] = count;
|
||||
return count === 1 ? typeName : `${typeName}${count}`;
|
||||
}
|
||||
|
||||
module.exports = GeneratedExpression;
|
33
node_modules/cucumber-expressions/dist/src/group.js
generated
vendored
Normal file
33
node_modules/cucumber-expressions/dist/src/group.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
|
||||
class Group {
|
||||
constructor(value, start, end, children) {
|
||||
this._value = value;
|
||||
this._start = start;
|
||||
this._end = end;
|
||||
this._children = children;
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
get start() {
|
||||
return this._start;
|
||||
}
|
||||
|
||||
get end() {
|
||||
return this._end;
|
||||
}
|
||||
|
||||
get children() {
|
||||
return this._children;
|
||||
}
|
||||
|
||||
get values() {
|
||||
return (this.children.length === 0 ? [this] : this.children).map(g => g.value).filter(v => v !== undefined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Group;
|
41
node_modules/cucumber-expressions/dist/src/group_builder.js
generated
vendored
Normal file
41
node_modules/cucumber-expressions/dist/src/group_builder.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
"use strict";
|
||||
|
||||
const Group = require('./group');
|
||||
|
||||
class GroupBuilder {
|
||||
constructor() {
|
||||
this._groupBuilders = [];
|
||||
this._capturing = true;
|
||||
}
|
||||
|
||||
add(groupBuilder) {
|
||||
this._groupBuilders.push(groupBuilder);
|
||||
}
|
||||
|
||||
build(match, nextGroupIndex) {
|
||||
const groupIndex = nextGroupIndex();
|
||||
|
||||
const children = this._groupBuilders.map(gb => gb.build(match, nextGroupIndex));
|
||||
|
||||
return new Group(match[groupIndex], match.index[groupIndex], match.index[groupIndex] + (match[groupIndex] || '').length, children);
|
||||
}
|
||||
|
||||
setNonCapturing() {
|
||||
this._capturing = false;
|
||||
}
|
||||
|
||||
get capturing() {
|
||||
return this._capturing;
|
||||
}
|
||||
|
||||
get children() {
|
||||
return this._groupBuilders;
|
||||
}
|
||||
|
||||
moveChildrenTo(groupBuilder) {
|
||||
this._groupBuilders.forEach(child => groupBuilder.add(child));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = GroupBuilder;
|
19
node_modules/cucumber-expressions/dist/src/index.js
generated
vendored
Normal file
19
node_modules/cucumber-expressions/dist/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
const CucumberExpression = require('./cucumber_expression');
|
||||
|
||||
const RegularExpression = require('./regular_expression');
|
||||
|
||||
const CucumberExpressionGenerator = require('./cucumber_expression_generator');
|
||||
|
||||
const ParameterTypeRegistry = require('./parameter_type_registry');
|
||||
|
||||
const ParameterType = require('./parameter_type');
|
||||
|
||||
module.exports = {
|
||||
CucumberExpression,
|
||||
RegularExpression,
|
||||
CucumberExpressionGenerator,
|
||||
ParameterTypeRegistry,
|
||||
ParameterType
|
||||
};
|
106
node_modules/cucumber-expressions/dist/src/parameter_type.js
generated
vendored
Normal file
106
node_modules/cucumber-expressions/dist/src/parameter_type.js
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
CucumberExpressionError
|
||||
} = require('./errors');
|
||||
|
||||
const ILLEGAL_PARAMETER_NAME_PATTERN = /([[\]()$.|?*+])/;
|
||||
|
||||
const UNESCAPE_PATTERN = () => /(\\([[$.|?*+\]]))/g;
|
||||
|
||||
class ParameterType {
|
||||
static compare(pt1, pt2) {
|
||||
if (pt1.preferForRegexpMatch && !pt2.preferForRegexpMatch) return -1;
|
||||
if (pt2.preferForRegexpMatch && !pt1.preferForRegexpMatch) return 1;
|
||||
return pt1.name.localeCompare(pt2.name);
|
||||
}
|
||||
|
||||
static checkParameterTypeName(typeName) {
|
||||
const unescapedTypeName = typeName.replace(UNESCAPE_PATTERN(), '$2');
|
||||
const match = unescapedTypeName.match(ILLEGAL_PARAMETER_NAME_PATTERN);
|
||||
if (match) throw new CucumberExpressionError(`Illegal character '${match[1]}' in parameter name {${unescapedTypeName}}`);
|
||||
}
|
||||
/**
|
||||
* @param name {String} the name of the type
|
||||
* @param regexps {Array.<RegExp>,RegExp,Array.<String>,String} that matches the type
|
||||
* @param type {Function} the prototype (constructor) of the type. May be null.
|
||||
* @param transform {Function} function transforming string to another type. May be null.
|
||||
* @param useForSnippets {boolean} true if this should be used for snippets. Defaults to true.
|
||||
* @param preferForRegexpMatch {boolean} true if this is a preferential type. Defaults to false.
|
||||
*/
|
||||
|
||||
|
||||
constructor(name, regexps, type, transform, useForSnippets, preferForRegexpMatch) {
|
||||
if (transform === undefined) transform = s => s;
|
||||
if (useForSnippets === undefined) useForSnippets = true;
|
||||
if (preferForRegexpMatch === undefined) preferForRegexpMatch = false;
|
||||
if (name) ParameterType.checkParameterTypeName(name);
|
||||
this._name = name;
|
||||
this._regexps = stringArray(regexps);
|
||||
this._type = type;
|
||||
this._transform = transform;
|
||||
this._useForSnippets = useForSnippets;
|
||||
this._preferForRegexpMatch = preferForRegexpMatch;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get regexps() {
|
||||
return this._regexps;
|
||||
}
|
||||
|
||||
get type() {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
get preferForRegexpMatch() {
|
||||
return this._preferForRegexpMatch;
|
||||
}
|
||||
|
||||
get useForSnippets() {
|
||||
return this._useForSnippets;
|
||||
}
|
||||
|
||||
transform(thisObj, groupValues) {
|
||||
return this._transform.apply(thisObj, groupValues);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function stringArray(regexps) {
|
||||
const array = Array.isArray(regexps) ? regexps : [regexps];
|
||||
return array.map(r => typeof r === 'string' ? r : regexpSource(r));
|
||||
}
|
||||
|
||||
function regexpSource(regexp) {
|
||||
const flags = regexpFlags(regexp);
|
||||
|
||||
for (const flag of ['g', 'i', 'm', 'y']) {
|
||||
if (flags.indexOf(flag) !== -1) throw new CucumberExpressionError(`ParameterType Regexps can't use flag '${flag}'`);
|
||||
}
|
||||
|
||||
return regexp.source;
|
||||
} // Backport RegExp.flags for Node 4.x
|
||||
// https://github.com/nodejs/node/issues/8390
|
||||
//
|
||||
// For some strange reason this is not needed for
|
||||
// `./mocha dist/test`, but it is needed for
|
||||
// `./mocha dist/test/parameter_type_test.js`
|
||||
|
||||
|
||||
function regexpFlags(regexp) {
|
||||
let flags = regexp.flags;
|
||||
|
||||
if (flags === undefined) {
|
||||
flags = '';
|
||||
if (regexp.ignoreCase) flags += 'i';
|
||||
if (regexp.global) flags += 'g';
|
||||
if (regexp.multiline) flags += 'm';
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
module.exports = ParameterType;
|
51
node_modules/cucumber-expressions/dist/src/parameter_type_matcher.js
generated
vendored
Normal file
51
node_modules/cucumber-expressions/dist/src/parameter_type_matcher.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
|
||||
class ParameterTypeMatcher {
|
||||
constructor(parameter, regexp, text, matchPosition) {
|
||||
this._parameterType = parameter;
|
||||
this._treeRegexp = regexp;
|
||||
this._text = text;
|
||||
this._matchPosition = matchPosition || 0;
|
||||
const captureGroupRegexp = new RegExp(`(${regexp})`);
|
||||
this._match = captureGroupRegexp.exec(text.slice(this._matchPosition));
|
||||
}
|
||||
|
||||
get parameterType() {
|
||||
return this._parameterType;
|
||||
}
|
||||
|
||||
advanceTo(newMatchPosition) {
|
||||
for (let advancedPos = newMatchPosition; advancedPos < this._text.length; advancedPos++) {
|
||||
let matcher = new ParameterTypeMatcher(this._parameterType, this._treeRegexp, this._text, advancedPos);
|
||||
|
||||
if (matcher.find) {
|
||||
return matcher;
|
||||
}
|
||||
}
|
||||
|
||||
return new ParameterTypeMatcher(this._parameterType, this._treeRegexp, this._text, this._text.length);
|
||||
}
|
||||
|
||||
get find() {
|
||||
return this._match && this.group !== '';
|
||||
}
|
||||
|
||||
get start() {
|
||||
return this._matchPosition + this._match.index;
|
||||
}
|
||||
|
||||
get group() {
|
||||
return this._match[0];
|
||||
}
|
||||
|
||||
static compare(a, b) {
|
||||
const posComparison = a.start - b.start;
|
||||
if (posComparison !== 0) return posComparison;
|
||||
const lengthComparison = b.group.length - a.group.length;
|
||||
if (lengthComparison !== 0) return lengthComparison;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ParameterTypeMatcher;
|
83
node_modules/cucumber-expressions/dist/src/parameter_type_registry.js
generated
vendored
Normal file
83
node_modules/cucumber-expressions/dist/src/parameter_type_registry.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
"use strict";
|
||||
|
||||
const ParameterType = require('./parameter_type');
|
||||
|
||||
const CucumberExpressionGenerator = require('./cucumber_expression_generator.js');
|
||||
|
||||
const {
|
||||
CucumberExpressionError,
|
||||
AmbiguousParameterTypeError
|
||||
} = require('./errors');
|
||||
|
||||
const INTEGER_REGEXPS = [/-?\d+/, /\d+/];
|
||||
const FLOAT_REGEXP = /-?\d*\.\d+/;
|
||||
const WORD_REGEXP = /[^\s]+/;
|
||||
const STRING_REGEXP = /"([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'/;
|
||||
const ANONYMOUS_REGEXP = /.*/;
|
||||
|
||||
class ParameterTypeRegistry {
|
||||
constructor() {
|
||||
this._parameterTypeByName = new Map();
|
||||
this._parameterTypesByRegexp = new Map();
|
||||
this.defineParameterType(new ParameterType('int', INTEGER_REGEXPS, Number, s => s && parseInt(s), true, true));
|
||||
this.defineParameterType(new ParameterType('float', FLOAT_REGEXP, Number, s => s && parseFloat(s), true, false));
|
||||
this.defineParameterType(new ParameterType('word', WORD_REGEXP, String, s => s, false, false));
|
||||
this.defineParameterType(new ParameterType('string', STRING_REGEXP, String, s => s.replace(/\\"/g, '"').replace(/\\'/g, "'"), true, false));
|
||||
this.defineParameterType(new ParameterType('', ANONYMOUS_REGEXP, String, s => s, false, true));
|
||||
}
|
||||
|
||||
get parameterTypes() {
|
||||
return this._parameterTypeByName.values();
|
||||
}
|
||||
|
||||
lookupByTypeName(typeName) {
|
||||
return this._parameterTypeByName.get(typeName);
|
||||
}
|
||||
|
||||
lookupByRegexp(parameterTypeRegexp, expressionRegexp, text) {
|
||||
const parameterTypes = this._parameterTypesByRegexp.get(parameterTypeRegexp);
|
||||
|
||||
if (!parameterTypes) return null;
|
||||
|
||||
if (parameterTypes.length > 1 && !parameterTypes[0].preferForRegexpMatch) {
|
||||
// We don't do this check on insertion because we only want to restrict
|
||||
// ambiguiuty when we look up by Regexp. Users of CucumberExpression should
|
||||
// not be restricted.
|
||||
const generatedExpressions = new CucumberExpressionGenerator(this).generateExpressions(text);
|
||||
throw new AmbiguousParameterTypeError.forRegExp(parameterTypeRegexp, expressionRegexp, parameterTypes, generatedExpressions);
|
||||
}
|
||||
|
||||
return parameterTypes[0];
|
||||
}
|
||||
|
||||
defineParameterType(parameterType) {
|
||||
if (parameterType.name !== undefined) {
|
||||
if (this._parameterTypeByName.has(parameterType.name)) if (parameterType.name.length === 0) throw new Error(`The anonymous parameter type has already been defined`);else throw new Error(`There is already a parameter type with name ${parameterType.name}`);
|
||||
|
||||
this._parameterTypeByName.set(parameterType.name, parameterType);
|
||||
}
|
||||
|
||||
for (const parameterTypeRegexp of parameterType.regexps) {
|
||||
if (!this._parameterTypesByRegexp.has(parameterTypeRegexp)) {
|
||||
this._parameterTypesByRegexp.set(parameterTypeRegexp, []);
|
||||
}
|
||||
|
||||
const parameterTypes = this._parameterTypesByRegexp.get(parameterTypeRegexp);
|
||||
|
||||
const existingParameterType = parameterTypes[0];
|
||||
|
||||
if (parameterTypes.length > 0 && existingParameterType.preferForRegexpMatch && parameterType.preferForRegexpMatch) {
|
||||
throw new CucumberExpressionError('There can only be one preferential parameter type per regexp. ' + `The regexp /${parameterTypeRegexp}/ is used for two preferential parameter types, {${existingParameterType.name}} and {${parameterType.name}}`);
|
||||
}
|
||||
|
||||
if (parameterTypes.indexOf(parameterType) === -1) {
|
||||
parameterTypes.push(parameterType);
|
||||
|
||||
this._parameterTypesByRegexp.set(parameterTypeRegexp, parameterTypes.sort(ParameterType.compare));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ParameterTypeRegistry;
|
35
node_modules/cucumber-expressions/dist/src/regular_expression.js
generated
vendored
Normal file
35
node_modules/cucumber-expressions/dist/src/regular_expression.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
const Argument = require('./argument');
|
||||
|
||||
const TreeRegexp = require('./tree_regexp');
|
||||
|
||||
const ParameterType = require('./parameter_type');
|
||||
|
||||
class RegularExpression {
|
||||
constructor(expressionRegexp, parameterTypeRegistry) {
|
||||
this._expressionRegexp = expressionRegexp;
|
||||
this._parameterTypeRegistry = parameterTypeRegistry;
|
||||
this._treeRegexp = new TreeRegexp(expressionRegexp);
|
||||
}
|
||||
|
||||
match(text) {
|
||||
const parameterTypes = this._treeRegexp.groupBuilder.children.map(groupBuilder => {
|
||||
const parameterTypeRegexp = groupBuilder.source;
|
||||
return this._parameterTypeRegistry.lookupByRegexp(parameterTypeRegexp, this._treeRegexp, text) || new ParameterType(null, parameterTypeRegexp, String, s => s, false, false);
|
||||
});
|
||||
|
||||
return Argument.build(this._treeRegexp, text, parameterTypes);
|
||||
}
|
||||
|
||||
get regexp() {
|
||||
return this._expressionRegexp;
|
||||
}
|
||||
|
||||
get source() {
|
||||
return this._expressionRegexp.source;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = RegularExpression;
|
74
node_modules/cucumber-expressions/dist/src/tree_regexp.js
generated
vendored
Normal file
74
node_modules/cucumber-expressions/dist/src/tree_regexp.js
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
"use strict";
|
||||
|
||||
const Regex = require('becke-ch--regex--s0-0-v1--base--pl--lib');
|
||||
|
||||
const GroupBuilder = require('./group_builder');
|
||||
|
||||
class TreeRegexp {
|
||||
constructor(regexp) {
|
||||
this._re = 'string' === typeof regexp ? new RegExp(regexp) : regexp;
|
||||
this._regex = new Regex(this._re.source, this._re.flags);
|
||||
const stack = [new GroupBuilder()];
|
||||
const groupStartStack = [];
|
||||
let last = null;
|
||||
let escaping = false;
|
||||
let nonCapturingMaybe = false;
|
||||
let charClass = false;
|
||||
|
||||
this._re.source.split('').forEach((c, n) => {
|
||||
if (c == '[' && !escaping) {
|
||||
charClass = true;
|
||||
} else if (c == ']' && !escaping) {
|
||||
charClass = false;
|
||||
} else if (c === '(' && !escaping && !charClass) {
|
||||
stack.push(new GroupBuilder());
|
||||
groupStartStack.push(n + 1);
|
||||
nonCapturingMaybe = false;
|
||||
} else if (c === ')' && !escaping && !charClass) {
|
||||
const gb = stack.pop();
|
||||
const groupStart = groupStartStack.pop();
|
||||
|
||||
if (gb.capturing) {
|
||||
gb.source = this._re.source.substring(groupStart, n);
|
||||
stack[stack.length - 1].add(gb);
|
||||
} else {
|
||||
gb.moveChildrenTo(stack[stack.length - 1]);
|
||||
}
|
||||
|
||||
nonCapturingMaybe = false;
|
||||
} else if (c === '?' && last === '(') {
|
||||
nonCapturingMaybe = true;
|
||||
} else if (c === ':' && nonCapturingMaybe) {
|
||||
stack[stack.length - 1].setNonCapturing();
|
||||
nonCapturingMaybe = false;
|
||||
}
|
||||
|
||||
escaping = c === '\\' && !escaping;
|
||||
last = c;
|
||||
});
|
||||
|
||||
this._groupBuilder = stack.pop();
|
||||
}
|
||||
|
||||
get regexp() {
|
||||
return this._re;
|
||||
}
|
||||
|
||||
get groupBuilder() {
|
||||
return this._groupBuilder;
|
||||
}
|
||||
|
||||
match(s) {
|
||||
const match = this._regex.exec(s);
|
||||
|
||||
if (!match) return null;
|
||||
let groupIndex = 0;
|
||||
|
||||
const nextGroupIndex = () => groupIndex++;
|
||||
|
||||
return this._groupBuilder.build(match, nextGroupIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = TreeRegexp;
|
31
node_modules/cucumber-expressions/examples.txt
generated
vendored
Normal file
31
node_modules/cucumber-expressions/examples.txt
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
I have {int} cuke(s)
|
||||
I have 22 cukes
|
||||
[22]
|
||||
---
|
||||
I have {int} cuke(s) and some \[]^$.|?*+
|
||||
I have 1 cuke and some \[]^$.|?*+
|
||||
[1]
|
||||
---
|
||||
/I have (\d+) cukes? in my (\w+) now/
|
||||
I have 22 cukes in my belly now
|
||||
[22,"belly"]
|
||||
---
|
||||
/I have (-?\d+) cukes? in my (.*) now/
|
||||
I have 1 cuke in my belly now
|
||||
[1,"belly"]
|
||||
---
|
||||
/^Something( with an optional argument)?$/
|
||||
Something
|
||||
[null]
|
||||
---
|
||||
Привет, {word}!
|
||||
Привет, Мир!
|
||||
["Мир"]
|
||||
---
|
||||
/I have (.*) cukes? in my (.*) now/
|
||||
I have 22 cukes in my belly now
|
||||
["22","belly"]
|
||||
---
|
||||
I have {} cuke(s) in my {} now
|
||||
I have 22 cukes in my belly now
|
||||
["22","belly"]
|
2
node_modules/cucumber-expressions/mocha
generated
vendored
Executable file
2
node_modules/cucumber-expressions/mocha
generated
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
node_modules/.bin/mocha "$@"
|
79
node_modules/cucumber-expressions/package.json
generated
vendored
Normal file
79
node_modules/cucumber-expressions/package.json
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"_from": "cucumber-expressions@^6.0.1",
|
||||
"_id": "cucumber-expressions@6.6.2",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-WcFSVBiWNLJbIcAAC3t/ACU46vaOKfe1UIF5H3qveoq+Y4XQm9j3YwHurQNufRKBBg8nCnpU7Ttsx7egjS3hwA==",
|
||||
"_location": "/cucumber-expressions",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "range",
|
||||
"registry": true,
|
||||
"raw": "cucumber-expressions@^6.0.1",
|
||||
"name": "cucumber-expressions",
|
||||
"escapedName": "cucumber-expressions",
|
||||
"rawSpec": "^6.0.1",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "^6.0.1"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/cypress-cucumber-preprocessor"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-6.6.2.tgz",
|
||||
"_shasum": "d89640eccc72a78380b6c210eae36a64e7462b81",
|
||||
"_spec": "cucumber-expressions@^6.0.1",
|
||||
"_where": "/home/simon/Documents/lifen-autotest/node_modules/cypress-cucumber-preprocessor",
|
||||
"author": {
|
||||
"name": "Cucumber Limited",
|
||||
"email": "cukes@googlegroups.com"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/cucumber/cucumber-expressions-javascript/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {
|
||||
"becke-ch--regex--s0-0-v1--base--pl--lib": "^1.2.0"
|
||||
},
|
||||
"deprecated": false,
|
||||
"description": "Cucumber Expressions - a simpler alternative to Regular Expressions",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.0.0",
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/plugin-transform-async-to-generator": "^7.0.0",
|
||||
"@babel/polyfill": "^7.0.0",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"eslint": "^5.7.0",
|
||||
"eslint-config-eslint": "^5.0.1",
|
||||
"eslint-config-prettier": "^4.1.0",
|
||||
"eslint-plugin-prettier": "^3.0.0",
|
||||
"mocha": "^6.0.2",
|
||||
"nyc": "^13.1.0",
|
||||
"prettier": "^1.13.2"
|
||||
},
|
||||
"files": [
|
||||
"*"
|
||||
],
|
||||
"homepage": "https://github.com/cucumber/cucumber-expressions-javascript#readme",
|
||||
"keywords": [
|
||||
"cucumber",
|
||||
"steps",
|
||||
"regexp",
|
||||
"regex"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "dist/src/index.js",
|
||||
"name": "cucumber-expressions",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/cucumber/cucumber-expressions-javascript.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "babel src --out-dir dist/src",
|
||||
"build-test": "babel test --out-dir dist/test",
|
||||
"coverage": "nyc --reporter=html --reporter=text mocha",
|
||||
"eslint-fix": "eslint --fix src test",
|
||||
"mocha-built": "mocha dist/test",
|
||||
"prepublishOnly": "npm run build",
|
||||
"test": "mocha"
|
||||
},
|
||||
"version": "6.6.2"
|
||||
}
|
45
node_modules/cucumber-expressions/src/argument.js
generated
vendored
Normal file
45
node_modules/cucumber-expressions/src/argument.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
const { CucumberExpressionError } = require('./errors')
|
||||
|
||||
class Argument {
|
||||
static build(treeRegexp, text, parameterTypes) {
|
||||
const group = treeRegexp.match(text)
|
||||
if (!group) return null
|
||||
|
||||
const argGroups = group.children
|
||||
|
||||
if (argGroups.length !== parameterTypes.length) {
|
||||
throw new CucumberExpressionError(
|
||||
`Expression ${treeRegexp.regexp} has ${
|
||||
argGroups.length
|
||||
} capture groups (${argGroups.map(g => g.value)}), but there were ${
|
||||
parameterTypes.length
|
||||
} parameter types (${parameterTypes.map(p => p.name)})`
|
||||
)
|
||||
}
|
||||
|
||||
return parameterTypes.map(
|
||||
(parameterType, i) => new Argument(argGroups[i], parameterType)
|
||||
)
|
||||
}
|
||||
|
||||
constructor(group, parameterType) {
|
||||
this._group = group
|
||||
this._parameterType = parameterType
|
||||
}
|
||||
|
||||
get group() {
|
||||
return this._group
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value returned by the parameter type's transformer function.
|
||||
*
|
||||
* @param thisObj the object in which the transformer function is applied.
|
||||
*/
|
||||
getValue(thisObj) {
|
||||
let groupValues = this._group ? this._group.values : null
|
||||
return this._parameterType.transform(thisObj, groupValues)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Argument
|
47
node_modules/cucumber-expressions/src/combinatorial_generated_expression_factory.js
generated
vendored
Normal file
47
node_modules/cucumber-expressions/src/combinatorial_generated_expression_factory.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
const GeneratedExpression = require('./generated_expression')
|
||||
|
||||
// 256 generated expressions ought to be enough for anybody
|
||||
const MAX_EXPRESSIONS = 256
|
||||
|
||||
class CombinatorialGeneratedExpressionFactory {
|
||||
constructor(expressionTemplate, parameterTypeCombinations) {
|
||||
this._expressionTemplate = expressionTemplate
|
||||
this._parameterTypeCombinations = parameterTypeCombinations
|
||||
}
|
||||
|
||||
generateExpressions() {
|
||||
const generatedExpressions = []
|
||||
this._generatePermutations(generatedExpressions, 0, [])
|
||||
return generatedExpressions
|
||||
}
|
||||
|
||||
_generatePermutations(generatedExpressions, depth, currentParameterTypes) {
|
||||
if (generatedExpressions.length >= MAX_EXPRESSIONS) {
|
||||
return
|
||||
}
|
||||
|
||||
if (depth === this._parameterTypeCombinations.length) {
|
||||
generatedExpressions.push(
|
||||
new GeneratedExpression(this._expressionTemplate, currentParameterTypes)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._parameterTypeCombinations[depth].length; ++i) {
|
||||
// Avoid recursion if no elements can be added.
|
||||
if (generatedExpressions.length >= MAX_EXPRESSIONS) {
|
||||
return
|
||||
}
|
||||
|
||||
const newCurrentParameterTypes = currentParameterTypes.slice() // clone
|
||||
newCurrentParameterTypes.push(this._parameterTypeCombinations[depth][i])
|
||||
this._generatePermutations(
|
||||
generatedExpressions,
|
||||
depth + 1,
|
||||
newCurrentParameterTypes
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CombinatorialGeneratedExpressionFactory
|
122
node_modules/cucumber-expressions/src/cucumber_expression.js
generated
vendored
Normal file
122
node_modules/cucumber-expressions/src/cucumber_expression.js
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
const Argument = require('./argument')
|
||||
const TreeRegexp = require('./tree_regexp')
|
||||
const ParameterType = require('./parameter_type')
|
||||
const {
|
||||
UndefinedParameterTypeError,
|
||||
CucumberExpressionError,
|
||||
} = require('./errors')
|
||||
|
||||
// RegExps with the g flag are stateful in JavaScript. In order to be able
|
||||
// to reuse them we have to wrap them in a function.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test
|
||||
|
||||
// Does not include (){} characters because they have special meaning
|
||||
const ESCAPE_REGEXP = () => /([\\^[$.|?*+])/g
|
||||
const PARAMETER_REGEXP = () => /(\\\\)?{([^}]*)}/g
|
||||
const OPTIONAL_REGEXP = () => /(\\\\)?\(([^)]+)\)/g
|
||||
const ALTERNATIVE_NON_WHITESPACE_TEXT_REGEXP = () =>
|
||||
/([^\s^/]+)((\/[^\s^/]+)+)/g
|
||||
const DOUBLE_ESCAPE = '\\\\'
|
||||
const PARAMETER_TYPES_CANNOT_BE_ALTERNATIVE =
|
||||
'Parameter types cannot be alternative: '
|
||||
const PARAMETER_TYPES_CANNOT_BE_OPTIONAL =
|
||||
'Parameter types cannot be optional: '
|
||||
|
||||
class CucumberExpression {
|
||||
/**
|
||||
* @param expression
|
||||
* @param parameterTypeRegistry
|
||||
*/
|
||||
constructor(expression, parameterTypeRegistry) {
|
||||
this._expression = expression
|
||||
this._parameterTypes = []
|
||||
|
||||
expression = this.processEscapes(expression)
|
||||
expression = this.processOptional(expression)
|
||||
expression = this.processAlternation(expression)
|
||||
expression = this.processParameters(expression, parameterTypeRegistry)
|
||||
expression = `^${expression}$`
|
||||
|
||||
this._treeRegexp = new TreeRegexp(expression)
|
||||
}
|
||||
|
||||
processEscapes(expression) {
|
||||
return expression.replace(ESCAPE_REGEXP(), '\\$1')
|
||||
}
|
||||
|
||||
processOptional(expression) {
|
||||
return expression.replace(OPTIONAL_REGEXP(), (match, p1, p2) => {
|
||||
if (p1 === DOUBLE_ESCAPE) {
|
||||
return `\\(${p2}\\)`
|
||||
}
|
||||
this._checkNoParameterType(p2, PARAMETER_TYPES_CANNOT_BE_OPTIONAL)
|
||||
return `(?:${p2})?`
|
||||
})
|
||||
}
|
||||
|
||||
processAlternation(expression) {
|
||||
return expression.replace(
|
||||
ALTERNATIVE_NON_WHITESPACE_TEXT_REGEXP(),
|
||||
match => {
|
||||
// replace \/ with /
|
||||
// replace / with |
|
||||
const replacement = match.replace(/\//g, '|').replace(/\\\|/g, '/')
|
||||
if (replacement.indexOf('|') !== -1) {
|
||||
for (const part of replacement.split(/\|/)) {
|
||||
this._checkNoParameterType(
|
||||
part,
|
||||
PARAMETER_TYPES_CANNOT_BE_ALTERNATIVE
|
||||
)
|
||||
}
|
||||
return `(?:${replacement})`
|
||||
} else {
|
||||
return replacement
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
processParameters(expression, parameterTypeRegistry) {
|
||||
return expression.replace(PARAMETER_REGEXP(), (match, p1, p2) => {
|
||||
if (p1 === DOUBLE_ESCAPE) return `\\{${p2}\\}`
|
||||
|
||||
const typeName = p2
|
||||
ParameterType.checkParameterTypeName(typeName)
|
||||
const parameterType = parameterTypeRegistry.lookupByTypeName(typeName)
|
||||
if (!parameterType) throw new UndefinedParameterTypeError(typeName)
|
||||
this._parameterTypes.push(parameterType)
|
||||
return buildCaptureRegexp(parameterType.regexps)
|
||||
})
|
||||
}
|
||||
|
||||
match(text) {
|
||||
return Argument.build(this._treeRegexp, text, this._parameterTypes)
|
||||
}
|
||||
|
||||
get regexp() {
|
||||
return this._treeRegexp.regexp
|
||||
}
|
||||
|
||||
get source() {
|
||||
return this._expression
|
||||
}
|
||||
|
||||
_checkNoParameterType(s, message) {
|
||||
if (s.match(PARAMETER_REGEXP())) {
|
||||
throw new CucumberExpressionError(message + this.source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildCaptureRegexp(regexps) {
|
||||
if (regexps.length === 1) {
|
||||
return `(${regexps[0]})`
|
||||
}
|
||||
|
||||
const captureGroups = regexps.map(group => {
|
||||
return `(?:${group})`
|
||||
})
|
||||
|
||||
return `(${captureGroups.join('|')})`
|
||||
}
|
||||
module.exports = CucumberExpression
|
120
node_modules/cucumber-expressions/src/cucumber_expression_generator.js
generated
vendored
Normal file
120
node_modules/cucumber-expressions/src/cucumber_expression_generator.js
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
const util = require('util')
|
||||
const ParameterTypeMatcher = require('./parameter_type_matcher')
|
||||
const ParameterType = require('./parameter_type')
|
||||
const CombinatorialGeneratedExpressionFactory = require('./combinatorial_generated_expression_factory')
|
||||
|
||||
class CucumberExpressionGenerator {
|
||||
constructor(parameterTypeRegistry) {
|
||||
this._parameterTypeRegistry = parameterTypeRegistry
|
||||
}
|
||||
|
||||
generateExpressions(text) {
|
||||
const parameterTypeCombinations = []
|
||||
const parameterTypeMatchers = this._createParameterTypeMatchers(text)
|
||||
let expressionTemplate = ''
|
||||
let pos = 0
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
let matchingParameterTypeMatchers = []
|
||||
|
||||
for (const parameterTypeMatcher of parameterTypeMatchers) {
|
||||
const advancedParameterTypeMatcher = parameterTypeMatcher.advanceTo(pos)
|
||||
if (advancedParameterTypeMatcher.find) {
|
||||
matchingParameterTypeMatchers.push(advancedParameterTypeMatcher)
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingParameterTypeMatchers.length > 0) {
|
||||
matchingParameterTypeMatchers = matchingParameterTypeMatchers.sort(
|
||||
ParameterTypeMatcher.compare
|
||||
)
|
||||
|
||||
// Find all the best parameter type matchers, they are all candidates.
|
||||
const bestParameterTypeMatcher = matchingParameterTypeMatchers[0]
|
||||
const bestParameterTypeMatchers = matchingParameterTypeMatchers.filter(
|
||||
m => ParameterTypeMatcher.compare(m, bestParameterTypeMatcher) === 0
|
||||
)
|
||||
|
||||
// Build a list of parameter types without duplicates. The reason there
|
||||
// might be duplicates is that some parameter types have more than one regexp,
|
||||
// which means multiple ParameterTypeMatcher objects will have a reference to the
|
||||
// same ParameterType.
|
||||
// We're sorting the list so preferential parameter types are listed first.
|
||||
// Users are most likely to want these, so they should be listed at the top.
|
||||
let parameterTypes = []
|
||||
for (const parameterTypeMatcher of bestParameterTypeMatchers) {
|
||||
if (
|
||||
parameterTypes.indexOf(parameterTypeMatcher.parameterType) === -1
|
||||
) {
|
||||
parameterTypes.push(parameterTypeMatcher.parameterType)
|
||||
}
|
||||
}
|
||||
parameterTypes = parameterTypes.sort(ParameterType.compare)
|
||||
|
||||
parameterTypeCombinations.push(parameterTypes)
|
||||
|
||||
expressionTemplate += escape(
|
||||
text.slice(pos, bestParameterTypeMatcher.start)
|
||||
)
|
||||
expressionTemplate += '{%s}'
|
||||
|
||||
pos =
|
||||
bestParameterTypeMatcher.start + bestParameterTypeMatcher.group.length
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if (pos >= text.length) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
expressionTemplate += escape(text.slice(pos))
|
||||
return new CombinatorialGeneratedExpressionFactory(
|
||||
expressionTemplate,
|
||||
parameterTypeCombinations
|
||||
).generateExpressions()
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
generateExpression(text) {
|
||||
return util.deprecate(
|
||||
() => this.generateExpressions(text)[0],
|
||||
'CucumberExpressionGenerator.generateExpression: Use CucumberExpressionGenerator.generateExpressions instead'
|
||||
)()
|
||||
}
|
||||
|
||||
_createParameterTypeMatchers(text) {
|
||||
let parameterMatchers = []
|
||||
for (const parameterType of this._parameterTypeRegistry.parameterTypes) {
|
||||
if (parameterType.useForSnippets) {
|
||||
parameterMatchers = parameterMatchers.concat(
|
||||
this._createParameterTypeMatchers2(parameterType, text)
|
||||
)
|
||||
}
|
||||
}
|
||||
return parameterMatchers
|
||||
}
|
||||
|
||||
_createParameterTypeMatchers2(parameterType, text) {
|
||||
// TODO: [].map
|
||||
const result = []
|
||||
for (const regexp of parameterType.regexps) {
|
||||
result.push(new ParameterTypeMatcher(parameterType, regexp, text))
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
function escape(s) {
|
||||
return s
|
||||
.replace(/%/g, '%%') // for util.format
|
||||
.replace(/\(/g, '\\(')
|
||||
.replace(/{/g, '\\{')
|
||||
.replace(/\//g, '\\/')
|
||||
}
|
||||
|
||||
module.exports = CucumberExpressionGenerator
|
55
node_modules/cucumber-expressions/src/errors.js
generated
vendored
Normal file
55
node_modules/cucumber-expressions/src/errors.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
class CucumberExpressionError extends Error {}
|
||||
|
||||
class AmbiguousParameterTypeError extends CucumberExpressionError {
|
||||
static forConstructor(
|
||||
keyName,
|
||||
keyValue,
|
||||
parameterTypes,
|
||||
generatedExpressions
|
||||
) {
|
||||
return new this(
|
||||
`parameter type with ${keyName}=${keyValue} is used by several parameter types: ${parameterTypes}, ${generatedExpressions}`
|
||||
)
|
||||
}
|
||||
|
||||
static forRegExp(
|
||||
parameterTypeRegexp,
|
||||
expressionRegexp,
|
||||
parameterTypes,
|
||||
generatedExpressions
|
||||
) {
|
||||
return new this(
|
||||
`Your Regular Expression ${expressionRegexp}
|
||||
matches multiple parameter types with regexp ${parameterTypeRegexp}:
|
||||
${this._parameterTypeNames(parameterTypes)}
|
||||
|
||||
I couldn't decide which one to use. You have two options:
|
||||
|
||||
1) Use a Cucumber Expression instead of a Regular Expression. Try one of these:
|
||||
${this._expressions(generatedExpressions)}
|
||||
|
||||
2) Make one of the parameter types preferential and continue to use a Regular Expression.
|
||||
`
|
||||
)
|
||||
}
|
||||
|
||||
static _parameterTypeNames(parameterTypes) {
|
||||
return parameterTypes.map(p => `{${p.name}}`).join('\n ')
|
||||
}
|
||||
|
||||
static _expressions(generatedExpressions) {
|
||||
return generatedExpressions.map(e => e.source).join('\n ')
|
||||
}
|
||||
}
|
||||
|
||||
class UndefinedParameterTypeError extends CucumberExpressionError {
|
||||
constructor(typeName) {
|
||||
super(`Undefined parameter type {${typeName}}`)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
AmbiguousParameterTypeError,
|
||||
UndefinedParameterTypeError,
|
||||
CucumberExpressionError,
|
||||
}
|
44
node_modules/cucumber-expressions/src/generated_expression.js
generated
vendored
Normal file
44
node_modules/cucumber-expressions/src/generated_expression.js
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
const util = require('util')
|
||||
|
||||
class GeneratedExpression {
|
||||
constructor(expressionTemplate, parameterTypes) {
|
||||
this._expressionTemplate = expressionTemplate
|
||||
this._parameterTypes = parameterTypes
|
||||
}
|
||||
|
||||
get source() {
|
||||
return util.format(
|
||||
this._expressionTemplate,
|
||||
...this._parameterTypes.map(t => t.name)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of parameter names to use in generated function/method signatures
|
||||
*
|
||||
* @returns {Array.<String>}
|
||||
*/
|
||||
get parameterNames() {
|
||||
const usageByTypeName = {}
|
||||
return this._parameterTypes.map(t =>
|
||||
getParameterName(t.name, usageByTypeName)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Array.<ParameterType>}
|
||||
*/
|
||||
get parameterTypes() {
|
||||
return this._parameterTypes
|
||||
}
|
||||
}
|
||||
|
||||
function getParameterName(typeName, usageByTypeName) {
|
||||
let count = usageByTypeName[typeName]
|
||||
count = count ? count + 1 : 1
|
||||
usageByTypeName[typeName] = count
|
||||
|
||||
return count === 1 ? typeName : `${typeName}${count}`
|
||||
}
|
||||
|
||||
module.exports = GeneratedExpression
|
32
node_modules/cucumber-expressions/src/group.js
generated
vendored
Normal file
32
node_modules/cucumber-expressions/src/group.js
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
class Group {
|
||||
constructor(value, start, end, children) {
|
||||
this._value = value
|
||||
this._start = start
|
||||
this._end = end
|
||||
this._children = children
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this._value
|
||||
}
|
||||
|
||||
get start() {
|
||||
return this._start
|
||||
}
|
||||
|
||||
get end() {
|
||||
return this._end
|
||||
}
|
||||
|
||||
get children() {
|
||||
return this._children
|
||||
}
|
||||
|
||||
get values() {
|
||||
return (this.children.length === 0 ? [this] : this.children)
|
||||
.map(g => g.value)
|
||||
.filter(v => v !== undefined)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Group
|
43
node_modules/cucumber-expressions/src/group_builder.js
generated
vendored
Normal file
43
node_modules/cucumber-expressions/src/group_builder.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
const Group = require('./group')
|
||||
|
||||
class GroupBuilder {
|
||||
constructor() {
|
||||
this._groupBuilders = []
|
||||
this._capturing = true
|
||||
}
|
||||
|
||||
add(groupBuilder) {
|
||||
this._groupBuilders.push(groupBuilder)
|
||||
}
|
||||
|
||||
build(match, nextGroupIndex) {
|
||||
const groupIndex = nextGroupIndex()
|
||||
const children = this._groupBuilders.map(gb =>
|
||||
gb.build(match, nextGroupIndex)
|
||||
)
|
||||
return new Group(
|
||||
match[groupIndex],
|
||||
match.index[groupIndex],
|
||||
match.index[groupIndex] + (match[groupIndex] || '').length,
|
||||
children
|
||||
)
|
||||
}
|
||||
|
||||
setNonCapturing() {
|
||||
this._capturing = false
|
||||
}
|
||||
|
||||
get capturing() {
|
||||
return this._capturing
|
||||
}
|
||||
|
||||
get children() {
|
||||
return this._groupBuilders
|
||||
}
|
||||
|
||||
moveChildrenTo(groupBuilder) {
|
||||
this._groupBuilders.forEach(child => groupBuilder.add(child))
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GroupBuilder
|
13
node_modules/cucumber-expressions/src/index.js
generated
vendored
Normal file
13
node_modules/cucumber-expressions/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
const CucumberExpression = require('./cucumber_expression')
|
||||
const RegularExpression = require('./regular_expression')
|
||||
const CucumberExpressionGenerator = require('./cucumber_expression_generator')
|
||||
const ParameterTypeRegistry = require('./parameter_type_registry')
|
||||
const ParameterType = require('./parameter_type')
|
||||
|
||||
module.exports = {
|
||||
CucumberExpression,
|
||||
RegularExpression,
|
||||
CucumberExpressionGenerator,
|
||||
ParameterTypeRegistry,
|
||||
ParameterType,
|
||||
}
|
113
node_modules/cucumber-expressions/src/parameter_type.js
generated
vendored
Normal file
113
node_modules/cucumber-expressions/src/parameter_type.js
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
const { CucumberExpressionError } = require('./errors')
|
||||
|
||||
const ILLEGAL_PARAMETER_NAME_PATTERN = /([[\]()$.|?*+])/
|
||||
const UNESCAPE_PATTERN = () => /(\\([[$.|?*+\]]))/g
|
||||
|
||||
class ParameterType {
|
||||
static compare(pt1, pt2) {
|
||||
if (pt1.preferForRegexpMatch && !pt2.preferForRegexpMatch) return -1
|
||||
if (pt2.preferForRegexpMatch && !pt1.preferForRegexpMatch) return 1
|
||||
return pt1.name.localeCompare(pt2.name)
|
||||
}
|
||||
|
||||
static checkParameterTypeName(typeName) {
|
||||
const unescapedTypeName = typeName.replace(UNESCAPE_PATTERN(), '$2')
|
||||
const match = unescapedTypeName.match(ILLEGAL_PARAMETER_NAME_PATTERN)
|
||||
if (match)
|
||||
throw new CucumberExpressionError(
|
||||
`Illegal character '${
|
||||
match[1]
|
||||
}' in parameter name {${unescapedTypeName}}`
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name {String} the name of the type
|
||||
* @param regexps {Array.<RegExp>,RegExp,Array.<String>,String} that matches the type
|
||||
* @param type {Function} the prototype (constructor) of the type. May be null.
|
||||
* @param transform {Function} function transforming string to another type. May be null.
|
||||
* @param useForSnippets {boolean} true if this should be used for snippets. Defaults to true.
|
||||
* @param preferForRegexpMatch {boolean} true if this is a preferential type. Defaults to false.
|
||||
*/
|
||||
constructor(
|
||||
name,
|
||||
regexps,
|
||||
type,
|
||||
transform,
|
||||
useForSnippets,
|
||||
preferForRegexpMatch
|
||||
) {
|
||||
if (transform === undefined) transform = s => s
|
||||
if (useForSnippets === undefined) useForSnippets = true
|
||||
if (preferForRegexpMatch === undefined) preferForRegexpMatch = false
|
||||
|
||||
if (name) ParameterType.checkParameterTypeName(name)
|
||||
|
||||
this._name = name
|
||||
this._regexps = stringArray(regexps)
|
||||
this._type = type
|
||||
this._transform = transform
|
||||
this._useForSnippets = useForSnippets
|
||||
this._preferForRegexpMatch = preferForRegexpMatch
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._name
|
||||
}
|
||||
|
||||
get regexps() {
|
||||
return this._regexps
|
||||
}
|
||||
|
||||
get type() {
|
||||
return this._type
|
||||
}
|
||||
|
||||
get preferForRegexpMatch() {
|
||||
return this._preferForRegexpMatch
|
||||
}
|
||||
|
||||
get useForSnippets() {
|
||||
return this._useForSnippets
|
||||
}
|
||||
|
||||
transform(thisObj, groupValues) {
|
||||
return this._transform.apply(thisObj, groupValues)
|
||||
}
|
||||
}
|
||||
|
||||
function stringArray(regexps) {
|
||||
const array = Array.isArray(regexps) ? regexps : [regexps]
|
||||
return array.map(r => (typeof r === 'string' ? r : regexpSource(r)))
|
||||
}
|
||||
|
||||
function regexpSource(regexp) {
|
||||
const flags = regexpFlags(regexp)
|
||||
|
||||
for (const flag of ['g', 'i', 'm', 'y']) {
|
||||
if (flags.indexOf(flag) !== -1)
|
||||
throw new CucumberExpressionError(
|
||||
`ParameterType Regexps can't use flag '${flag}'`
|
||||
)
|
||||
}
|
||||
return regexp.source
|
||||
}
|
||||
|
||||
// Backport RegExp.flags for Node 4.x
|
||||
// https://github.com/nodejs/node/issues/8390
|
||||
//
|
||||
// For some strange reason this is not needed for
|
||||
// `./mocha dist/test`, but it is needed for
|
||||
// `./mocha dist/test/parameter_type_test.js`
|
||||
function regexpFlags(regexp) {
|
||||
let flags = regexp.flags
|
||||
if (flags === undefined) {
|
||||
flags = ''
|
||||
if (regexp.ignoreCase) flags += 'i'
|
||||
if (regexp.global) flags += 'g'
|
||||
if (regexp.multiline) flags += 'm'
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
module.exports = ParameterType
|
63
node_modules/cucumber-expressions/src/parameter_type_matcher.js
generated
vendored
Normal file
63
node_modules/cucumber-expressions/src/parameter_type_matcher.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
class ParameterTypeMatcher {
|
||||
constructor(parameter, regexp, text, matchPosition) {
|
||||
this._parameterType = parameter
|
||||
this._treeRegexp = regexp
|
||||
this._text = text
|
||||
this._matchPosition = matchPosition || 0
|
||||
|
||||
const captureGroupRegexp = new RegExp(`(${regexp})`)
|
||||
this._match = captureGroupRegexp.exec(text.slice(this._matchPosition))
|
||||
}
|
||||
|
||||
get parameterType() {
|
||||
return this._parameterType
|
||||
}
|
||||
|
||||
advanceTo(newMatchPosition) {
|
||||
for (
|
||||
let advancedPos = newMatchPosition;
|
||||
advancedPos < this._text.length;
|
||||
advancedPos++
|
||||
) {
|
||||
let matcher = new ParameterTypeMatcher(
|
||||
this._parameterType,
|
||||
this._treeRegexp,
|
||||
this._text,
|
||||
advancedPos
|
||||
)
|
||||
|
||||
if (matcher.find) {
|
||||
return matcher
|
||||
}
|
||||
}
|
||||
|
||||
return new ParameterTypeMatcher(
|
||||
this._parameterType,
|
||||
this._treeRegexp,
|
||||
this._text,
|
||||
this._text.length
|
||||
)
|
||||
}
|
||||
|
||||
get find() {
|
||||
return this._match && this.group !== ''
|
||||
}
|
||||
|
||||
get start() {
|
||||
return this._matchPosition + this._match.index
|
||||
}
|
||||
|
||||
get group() {
|
||||
return this._match[0]
|
||||
}
|
||||
|
||||
static compare(a, b) {
|
||||
const posComparison = a.start - b.start
|
||||
if (posComparison !== 0) return posComparison
|
||||
const lengthComparison = b.group.length - a.group.length
|
||||
if (lengthComparison !== 0) return lengthComparison
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ParameterTypeMatcher
|
130
node_modules/cucumber-expressions/src/parameter_type_registry.js
generated
vendored
Normal file
130
node_modules/cucumber-expressions/src/parameter_type_registry.js
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
const ParameterType = require('./parameter_type')
|
||||
const CucumberExpressionGenerator = require('./cucumber_expression_generator.js')
|
||||
const {
|
||||
CucumberExpressionError,
|
||||
AmbiguousParameterTypeError,
|
||||
} = require('./errors')
|
||||
|
||||
const INTEGER_REGEXPS = [/-?\d+/, /\d+/]
|
||||
const FLOAT_REGEXP = /-?\d*\.\d+/
|
||||
const WORD_REGEXP = /[^\s]+/
|
||||
const STRING_REGEXP = /"([^"\\]*(\\.[^"\\]*)*)"|'([^'\\]*(\\.[^'\\]*)*)'/
|
||||
const ANONYMOUS_REGEXP = /.*/
|
||||
|
||||
class ParameterTypeRegistry {
|
||||
constructor() {
|
||||
this._parameterTypeByName = new Map()
|
||||
this._parameterTypesByRegexp = new Map()
|
||||
|
||||
this.defineParameterType(
|
||||
new ParameterType(
|
||||
'int',
|
||||
INTEGER_REGEXPS,
|
||||
Number,
|
||||
s => s && parseInt(s),
|
||||
true,
|
||||
true
|
||||
)
|
||||
)
|
||||
this.defineParameterType(
|
||||
new ParameterType(
|
||||
'float',
|
||||
FLOAT_REGEXP,
|
||||
Number,
|
||||
s => s && parseFloat(s),
|
||||
true,
|
||||
false
|
||||
)
|
||||
)
|
||||
this.defineParameterType(
|
||||
new ParameterType('word', WORD_REGEXP, String, s => s, false, false)
|
||||
)
|
||||
this.defineParameterType(
|
||||
new ParameterType(
|
||||
'string',
|
||||
STRING_REGEXP,
|
||||
String,
|
||||
s => s.replace(/\\"/g, '"').replace(/\\'/g, "'"),
|
||||
true,
|
||||
false
|
||||
)
|
||||
)
|
||||
this.defineParameterType(
|
||||
new ParameterType('', ANONYMOUS_REGEXP, String, s => s, false, true)
|
||||
)
|
||||
}
|
||||
|
||||
get parameterTypes() {
|
||||
return this._parameterTypeByName.values()
|
||||
}
|
||||
|
||||
lookupByTypeName(typeName) {
|
||||
return this._parameterTypeByName.get(typeName)
|
||||
}
|
||||
|
||||
lookupByRegexp(parameterTypeRegexp, expressionRegexp, text) {
|
||||
const parameterTypes = this._parameterTypesByRegexp.get(parameterTypeRegexp)
|
||||
if (!parameterTypes) return null
|
||||
if (parameterTypes.length > 1 && !parameterTypes[0].preferForRegexpMatch) {
|
||||
// We don't do this check on insertion because we only want to restrict
|
||||
// ambiguiuty when we look up by Regexp. Users of CucumberExpression should
|
||||
// not be restricted.
|
||||
const generatedExpressions = new CucumberExpressionGenerator(
|
||||
this
|
||||
).generateExpressions(text)
|
||||
throw new AmbiguousParameterTypeError.forRegExp(
|
||||
parameterTypeRegexp,
|
||||
expressionRegexp,
|
||||
parameterTypes,
|
||||
generatedExpressions
|
||||
)
|
||||
}
|
||||
return parameterTypes[0]
|
||||
}
|
||||
|
||||
defineParameterType(parameterType) {
|
||||
if (parameterType.name !== undefined) {
|
||||
if (this._parameterTypeByName.has(parameterType.name))
|
||||
if (parameterType.name.length === 0)
|
||||
throw new Error(
|
||||
`The anonymous parameter type has already been defined`
|
||||
)
|
||||
else
|
||||
throw new Error(
|
||||
`There is already a parameter type with name ${parameterType.name}`
|
||||
)
|
||||
this._parameterTypeByName.set(parameterType.name, parameterType)
|
||||
}
|
||||
|
||||
for (const parameterTypeRegexp of parameterType.regexps) {
|
||||
if (!this._parameterTypesByRegexp.has(parameterTypeRegexp)) {
|
||||
this._parameterTypesByRegexp.set(parameterTypeRegexp, [])
|
||||
}
|
||||
const parameterTypes = this._parameterTypesByRegexp.get(
|
||||
parameterTypeRegexp
|
||||
)
|
||||
const existingParameterType = parameterTypes[0]
|
||||
if (
|
||||
parameterTypes.length > 0 &&
|
||||
existingParameterType.preferForRegexpMatch &&
|
||||
parameterType.preferForRegexpMatch
|
||||
) {
|
||||
throw new CucumberExpressionError(
|
||||
'There can only be one preferential parameter type per regexp. ' +
|
||||
`The regexp /${parameterTypeRegexp}/ is used for two preferential parameter types, {${
|
||||
existingParameterType.name
|
||||
}} and {${parameterType.name}}`
|
||||
)
|
||||
}
|
||||
if (parameterTypes.indexOf(parameterType) === -1) {
|
||||
parameterTypes.push(parameterType)
|
||||
this._parameterTypesByRegexp.set(
|
||||
parameterTypeRegexp,
|
||||
parameterTypes.sort(ParameterType.compare)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ParameterTypeRegistry
|
47
node_modules/cucumber-expressions/src/regular_expression.js
generated
vendored
Normal file
47
node_modules/cucumber-expressions/src/regular_expression.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
const Argument = require('./argument')
|
||||
const TreeRegexp = require('./tree_regexp')
|
||||
const ParameterType = require('./parameter_type')
|
||||
|
||||
class RegularExpression {
|
||||
constructor(expressionRegexp, parameterTypeRegistry) {
|
||||
this._expressionRegexp = expressionRegexp
|
||||
this._parameterTypeRegistry = parameterTypeRegistry
|
||||
this._treeRegexp = new TreeRegexp(expressionRegexp)
|
||||
}
|
||||
|
||||
match(text) {
|
||||
const parameterTypes = this._treeRegexp.groupBuilder.children.map(
|
||||
groupBuilder => {
|
||||
const parameterTypeRegexp = groupBuilder.source
|
||||
|
||||
return (
|
||||
this._parameterTypeRegistry.lookupByRegexp(
|
||||
parameterTypeRegexp,
|
||||
this._treeRegexp,
|
||||
text
|
||||
) ||
|
||||
new ParameterType(
|
||||
null,
|
||||
parameterTypeRegexp,
|
||||
String,
|
||||
s => s,
|
||||
false,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
return Argument.build(this._treeRegexp, text, parameterTypes)
|
||||
}
|
||||
|
||||
get regexp() {
|
||||
return this._expressionRegexp
|
||||
}
|
||||
|
||||
get source() {
|
||||
return this._expressionRegexp.source
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RegularExpression
|
63
node_modules/cucumber-expressions/src/tree_regexp.js
generated
vendored
Normal file
63
node_modules/cucumber-expressions/src/tree_regexp.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
const Regex = require('becke-ch--regex--s0-0-v1--base--pl--lib')
|
||||
const GroupBuilder = require('./group_builder')
|
||||
|
||||
class TreeRegexp {
|
||||
constructor(regexp) {
|
||||
this._re = 'string' === typeof regexp ? new RegExp(regexp) : regexp
|
||||
this._regex = new Regex(this._re.source, this._re.flags)
|
||||
|
||||
const stack = [new GroupBuilder()]
|
||||
const groupStartStack = []
|
||||
let last = null
|
||||
let escaping = false
|
||||
let nonCapturingMaybe = false
|
||||
let charClass = false
|
||||
this._re.source.split('').forEach((c, n) => {
|
||||
if (c == '[' && !escaping) {
|
||||
charClass = true
|
||||
} else if (c == ']' && !escaping) {
|
||||
charClass = false
|
||||
} else if (c === '(' && !escaping && !charClass) {
|
||||
stack.push(new GroupBuilder())
|
||||
groupStartStack.push(n + 1)
|
||||
nonCapturingMaybe = false
|
||||
} else if (c === ')' && !escaping && !charClass) {
|
||||
const gb = stack.pop()
|
||||
const groupStart = groupStartStack.pop()
|
||||
if (gb.capturing) {
|
||||
gb.source = this._re.source.substring(groupStart, n)
|
||||
stack[stack.length - 1].add(gb)
|
||||
} else {
|
||||
gb.moveChildrenTo(stack[stack.length - 1])
|
||||
}
|
||||
nonCapturingMaybe = false
|
||||
} else if (c === '?' && last === '(') {
|
||||
nonCapturingMaybe = true
|
||||
} else if (c === ':' && nonCapturingMaybe) {
|
||||
stack[stack.length - 1].setNonCapturing()
|
||||
nonCapturingMaybe = false
|
||||
}
|
||||
escaping = c === '\\' && !escaping
|
||||
last = c
|
||||
})
|
||||
this._groupBuilder = stack.pop()
|
||||
}
|
||||
|
||||
get regexp() {
|
||||
return this._re
|
||||
}
|
||||
|
||||
get groupBuilder() {
|
||||
return this._groupBuilder
|
||||
}
|
||||
|
||||
match(s) {
|
||||
const match = this._regex.exec(s)
|
||||
if (!match) return null
|
||||
let groupIndex = 0
|
||||
const nextGroupIndex = () => groupIndex++
|
||||
return this._groupBuilder.build(match, nextGroupIndex)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TreeRegexp
|
7
node_modules/cucumber-expressions/test/assert_throws.js
generated
vendored
Normal file
7
node_modules/cucumber-expressions/test/assert_throws.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
const assert = require('assert')
|
||||
|
||||
// A better assert.error that allows an exact error message
|
||||
module.exports = (fn, message) => {
|
||||
const regexp = new RegExp(message.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&'))
|
||||
assert.throws(fn, regexp)
|
||||
}
|
69
node_modules/cucumber-expressions/test/combinatorial_generated_expression_factory_test.js
generated
vendored
Normal file
69
node_modules/cucumber-expressions/test/combinatorial_generated_expression_factory_test.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/* eslint-env mocha */
|
||||
const assert = require('assert')
|
||||
const ParameterType = require('../src/parameter_type')
|
||||
const CombinatorialGeneratedExpressionFactory = require('../src/combinatorial_generated_expression_factory')
|
||||
|
||||
describe('CucumberExpressionGenerator', () => {
|
||||
it('generates multiple expressions', () => {
|
||||
const parameterTypeCombinations = [
|
||||
[
|
||||
new ParameterType(
|
||||
'color',
|
||||
/red|blue|yellow/,
|
||||
null,
|
||||
s => s,
|
||||
false,
|
||||
true
|
||||
),
|
||||
new ParameterType(
|
||||
'csscolor',
|
||||
/red|blue|yellow/,
|
||||
null,
|
||||
s => s,
|
||||
false,
|
||||
true
|
||||
),
|
||||
],
|
||||
[
|
||||
new ParameterType(
|
||||
'date',
|
||||
/\d{4}-\d{2}-\d{2}/,
|
||||
null,
|
||||
s => s,
|
||||
false,
|
||||
true
|
||||
),
|
||||
new ParameterType(
|
||||
'datetime',
|
||||
/\d{4}-\d{2}-\d{2}/,
|
||||
null,
|
||||
s => s,
|
||||
false,
|
||||
true
|
||||
),
|
||||
new ParameterType(
|
||||
'timestamp',
|
||||
/\d{4}-\d{2}-\d{2}/,
|
||||
null,
|
||||
s => s,
|
||||
false,
|
||||
true
|
||||
),
|
||||
],
|
||||
]
|
||||
|
||||
const factory = new CombinatorialGeneratedExpressionFactory(
|
||||
'I bought a {%s} ball on {%s}',
|
||||
parameterTypeCombinations
|
||||
)
|
||||
const expressions = factory.generateExpressions().map(ge => ge.source)
|
||||
assert.deepEqual(expressions, [
|
||||
'I bought a {color} ball on {date}',
|
||||
'I bought a {color} ball on {datetime}',
|
||||
'I bought a {color} ball on {timestamp}',
|
||||
'I bought a {csscolor} ball on {date}',
|
||||
'I bought a {csscolor} ball on {datetime}',
|
||||
'I bought a {csscolor} ball on {timestamp}',
|
||||
])
|
||||
})
|
||||
})
|
248
node_modules/cucumber-expressions/test/cucumber_expression_generator_test.js
generated
vendored
Normal file
248
node_modules/cucumber-expressions/test/cucumber_expression_generator_test.js
generated
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
/* eslint-env mocha */
|
||||
const assert = require('assert')
|
||||
const CucumberExpressionGenerator = require('../src/cucumber_expression_generator')
|
||||
const CucumberExpression = require('../src/cucumber_expression')
|
||||
const ParameterType = require('../src/parameter_type')
|
||||
const ParameterTypeRegistry = require('../src/parameter_type_registry')
|
||||
|
||||
class Currency {}
|
||||
|
||||
describe('CucumberExpressionGenerator', () => {
|
||||
let parameterTypeRegistry, generator
|
||||
|
||||
function assertExpression(expectedExpression, expectedArgumentNames, text) {
|
||||
const generatedExpression = generator.generateExpressions(text)[0]
|
||||
assert.deepEqual(generatedExpression.parameterNames, expectedArgumentNames)
|
||||
assert.equal(generatedExpression.source, expectedExpression)
|
||||
|
||||
const cucumberExpression = new CucumberExpression(
|
||||
generatedExpression.source,
|
||||
parameterTypeRegistry
|
||||
)
|
||||
const match = cucumberExpression.match(text)
|
||||
if (match === null) {
|
||||
assert.fail(
|
||||
`Expected text '${text}' to match generated expression '${
|
||||
generatedExpression.source
|
||||
}'`
|
||||
)
|
||||
}
|
||||
assert.equal(match.length, expectedArgumentNames.length)
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
parameterTypeRegistry = new ParameterTypeRegistry()
|
||||
generator = new CucumberExpressionGenerator(parameterTypeRegistry)
|
||||
})
|
||||
|
||||
it('documents expression generation', () => {
|
||||
const parameterRegistry = new ParameterTypeRegistry()
|
||||
/// [generate-expression]
|
||||
const generator = new CucumberExpressionGenerator(parameterRegistry)
|
||||
const undefinedStepText = 'I have 2 cucumbers and 1.5 tomato'
|
||||
const generatedExpression = generator.generateExpressions(
|
||||
undefinedStepText
|
||||
)[0]
|
||||
assert.equal(
|
||||
generatedExpression.source,
|
||||
'I have {int} cucumbers and {float} tomato'
|
||||
)
|
||||
assert.equal(generatedExpression.parameterNames[0], 'int')
|
||||
assert.equal(generatedExpression.parameterTypes[1].name, 'float')
|
||||
/// [generate-expression]
|
||||
})
|
||||
|
||||
it('generates expression for no args', () => {
|
||||
assertExpression('hello', [], 'hello')
|
||||
})
|
||||
|
||||
it('generates expression with escaped left parenthesis', () => {
|
||||
assertExpression('\\(iii)', [], '(iii)')
|
||||
})
|
||||
|
||||
it('generates expression with escaped left curly brace', () => {
|
||||
assertExpression('\\{iii}', [], '{iii}')
|
||||
})
|
||||
|
||||
it('generates expression with escaped slashes', () => {
|
||||
assertExpression(
|
||||
'The {int}\\/{int}\\/{int} hey',
|
||||
['int', 'int2', 'int3'],
|
||||
'The 1814/05/17 hey'
|
||||
)
|
||||
})
|
||||
|
||||
it('generates expression for int float arg', () => {
|
||||
assertExpression(
|
||||
'I have {int} cukes and {float} euro',
|
||||
['int', 'float'],
|
||||
'I have 2 cukes and 1.5 euro'
|
||||
)
|
||||
})
|
||||
|
||||
it('generates expression for strings', () => {
|
||||
assertExpression(
|
||||
'I like {string} and {string}',
|
||||
['string', 'string2'],
|
||||
'I like "bangers" and \'mash\''
|
||||
)
|
||||
})
|
||||
|
||||
it('generates expression with % sign', () => {
|
||||
assertExpression('I am {int}%% foobar', ['int'], 'I am 20%% foobar')
|
||||
})
|
||||
|
||||
it('generates expression for just int', () => {
|
||||
assertExpression('{int}', ['int'], '99999')
|
||||
})
|
||||
|
||||
it('numbers only second argument when builtin type is not reserved keyword', () => {
|
||||
assertExpression(
|
||||
'I have {float} cukes and {float} euro',
|
||||
['float', 'float2'],
|
||||
'I have 2.5 cukes and 1.5 euro'
|
||||
)
|
||||
})
|
||||
|
||||
it('generates expression for custom type', () => {
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'currency',
|
||||
/[A-Z]{3}/,
|
||||
Currency,
|
||||
s => new Currency(s),
|
||||
true,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
assertExpression(
|
||||
'I have a {currency} account',
|
||||
['currency'],
|
||||
'I have a EUR account'
|
||||
)
|
||||
})
|
||||
|
||||
it('prefers leftmost match when there is overlap', () => {
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'currency',
|
||||
/cd/,
|
||||
Currency,
|
||||
s => new Currency(s),
|
||||
true,
|
||||
false
|
||||
)
|
||||
)
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType('date', /bc/, Date, s => new Date(s), true, false)
|
||||
)
|
||||
|
||||
assertExpression('a{date}defg', ['date'], 'abcdefg')
|
||||
})
|
||||
|
||||
// TODO: prefers widest match
|
||||
|
||||
it('generates all combinations of expressions when several parameter types match', () => {
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'currency',
|
||||
/x/,
|
||||
null,
|
||||
s => new Currency(s),
|
||||
true,
|
||||
false
|
||||
)
|
||||
)
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType('date', /x/, null, s => new Date(s), true, false)
|
||||
)
|
||||
|
||||
const generatedExpressions = generator.generateExpressions(
|
||||
'I have x and x and another x'
|
||||
)
|
||||
const expressions = generatedExpressions.map(e => e.source)
|
||||
assert.deepEqual(expressions, [
|
||||
'I have {currency} and {currency} and another {currency}',
|
||||
'I have {currency} and {currency} and another {date}',
|
||||
'I have {currency} and {date} and another {currency}',
|
||||
'I have {currency} and {date} and another {date}',
|
||||
'I have {date} and {currency} and another {currency}',
|
||||
'I have {date} and {currency} and another {date}',
|
||||
'I have {date} and {date} and another {currency}',
|
||||
'I have {date} and {date} and another {date}',
|
||||
])
|
||||
})
|
||||
|
||||
it('exposes parameter type names in generated expression', () => {
|
||||
const expression = generator.generateExpressions(
|
||||
'I have 2 cukes and 1.5 euro'
|
||||
)[0]
|
||||
const typeNames = expression.parameterTypes.map(parameter => parameter.name)
|
||||
assert.deepEqual(typeNames, ['int', 'float'])
|
||||
})
|
||||
|
||||
it('matches parameter types with optional capture groups', () => {
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'optional-flight',
|
||||
/(1st flight)?/,
|
||||
null,
|
||||
s => s,
|
||||
true,
|
||||
false
|
||||
)
|
||||
)
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'optional-hotel',
|
||||
/(1st hotel)?/,
|
||||
null,
|
||||
s => s,
|
||||
true,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
const expression = generator.generateExpressions(
|
||||
'I reach Stage4: 1st flight-1st hotel'
|
||||
)[0]
|
||||
// While you would expect this to be `I reach Stage{int}: {optional-flight}-{optional-hotel}` the `-1` causes
|
||||
// {int} to match just before {optional-hotel}.
|
||||
assert.equal(
|
||||
expression.source,
|
||||
'I reach Stage{int}: {optional-flight}{int}st hotel'
|
||||
)
|
||||
})
|
||||
|
||||
it('generates at most 256 expressions', () => {
|
||||
for (let i = 0; i < 4; i++) {
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType('my-type-' + i, /[a-z]/, null, s => s, true, false)
|
||||
)
|
||||
}
|
||||
// This would otherwise generate 4^11=419430 expressions and consume just shy of 1.5GB.
|
||||
const expressions = generator.generateExpressions('a simple step')
|
||||
assert.equal(expressions.length, 256)
|
||||
})
|
||||
|
||||
it('prefers expression with longest non empty match', () => {
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType('zero-or-more', /[a-z]*/, null, s => s, true, false)
|
||||
)
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType('exactly-one', /[a-z]/, null, s => s, true, false)
|
||||
)
|
||||
|
||||
const expressions = generator.generateExpressions('a simple step')
|
||||
assert.equal(expressions.length, 2)
|
||||
assert.equal(
|
||||
expressions[0].source,
|
||||
'{exactly-one} {zero-or-more} {zero-or-more}'
|
||||
)
|
||||
assert.equal(
|
||||
expressions[1].source,
|
||||
'{zero-or-more} {zero-or-more} {zero-or-more}'
|
||||
)
|
||||
})
|
||||
})
|
52
node_modules/cucumber-expressions/test/cucumber_expression_regexp_test.js
generated
vendored
Normal file
52
node_modules/cucumber-expressions/test/cucumber_expression_regexp_test.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/* eslint-env mocha */
|
||||
const assert = require('assert')
|
||||
const CucumberExpression = require('../src/cucumber_expression')
|
||||
const ParameterTypeRegistry = require('../src/parameter_type_registry')
|
||||
|
||||
describe('CucumberExpression', () => {
|
||||
describe('RegExp translation', () => {
|
||||
it('translates no arguments', () => {
|
||||
assertRegexp(
|
||||
'I have 10 cukes in my belly now',
|
||||
/^I have 10 cukes in my belly now$/
|
||||
)
|
||||
})
|
||||
|
||||
it('translates alternation', () => {
|
||||
assertRegexp(
|
||||
'I had/have a great/nice/charming friend',
|
||||
/^I (?:had|have) a (?:great|nice|charming) friend$/
|
||||
)
|
||||
})
|
||||
|
||||
it('translates alternation with non-alpha', () => {
|
||||
assertRegexp('I said Alpha1/Beta1', /^I said (?:Alpha1|Beta1)$/)
|
||||
})
|
||||
|
||||
it('translates parameters', () => {
|
||||
assertRegexp(
|
||||
"I have {float} cukes at {int} o'clock",
|
||||
/^I have (-?\d*\.\d+) cukes at ((?:-?\d+)|(?:\d+)) o'clock$/
|
||||
)
|
||||
})
|
||||
|
||||
it('translates parenthesis to non-capturing optional capture group', () => {
|
||||
assertRegexp(
|
||||
'I have many big(ish) cukes',
|
||||
/^I have many big(?:ish)? cukes$/
|
||||
)
|
||||
})
|
||||
|
||||
it('translates parenthesis with alpha unicode', () => {
|
||||
assertRegexp('Привет, Мир(ы)!', /^Привет, Мир(?:ы)?!$/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const assertRegexp = (expression, expectedRegexp) => {
|
||||
const cucumberExpression = new CucumberExpression(
|
||||
expression,
|
||||
new ParameterTypeRegistry()
|
||||
)
|
||||
assert.deepEqual(cucumberExpression.regexp, expectedRegexp)
|
||||
}
|
270
node_modules/cucumber-expressions/test/cucumber_expression_test.js
generated
vendored
Normal file
270
node_modules/cucumber-expressions/test/cucumber_expression_test.js
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
/* eslint-env mocha */
|
||||
const assert = require('assert')
|
||||
const {
|
||||
CucumberExpression,
|
||||
ParameterTypeRegistry,
|
||||
ParameterType,
|
||||
} = require('../src/index')
|
||||
|
||||
describe('CucumberExpression', () => {
|
||||
it('documents match arguments', () => {
|
||||
const parameterTypeRegistry = new ParameterTypeRegistry()
|
||||
|
||||
/// [capture-match-arguments]
|
||||
const expr = 'I have {int} cuke(s)'
|
||||
const expression = new CucumberExpression(expr, parameterTypeRegistry)
|
||||
const args = expression.match('I have 7 cukes')
|
||||
assert.equal(7, args[0].getValue(null))
|
||||
/// [capture-match-arguments]
|
||||
})
|
||||
|
||||
it('matches word', () => {
|
||||
assert.deepEqual(match('three {word} mice', 'three blind mice'), ['blind'])
|
||||
})
|
||||
|
||||
it('matches double quoted string', () => {
|
||||
assert.deepEqual(match('three {string} mice', 'three "blind" mice'), [
|
||||
'blind',
|
||||
])
|
||||
})
|
||||
|
||||
it('matches multiple double quoted strings', () => {
|
||||
assert.deepEqual(
|
||||
match(
|
||||
'three {string} and {string} mice',
|
||||
'three "blind" and "crippled" mice'
|
||||
),
|
||||
['blind', 'crippled']
|
||||
)
|
||||
})
|
||||
|
||||
it('matches single quoted string', () => {
|
||||
assert.deepEqual(match('three {string} mice', "three 'blind' mice"), [
|
||||
'blind',
|
||||
])
|
||||
})
|
||||
|
||||
it('matches multiple single quoted strings', () => {
|
||||
assert.deepEqual(
|
||||
match(
|
||||
'three {string} and {string} mice',
|
||||
"three 'blind' and 'crippled' mice"
|
||||
),
|
||||
['blind', 'crippled']
|
||||
)
|
||||
})
|
||||
|
||||
it('does not match misquoted string', () => {
|
||||
assert.deepEqual(match('three {string} mice', 'three "blind\' mice'), null)
|
||||
})
|
||||
|
||||
it('matches single quoted string with double quotes', () => {
|
||||
assert.deepEqual(match('three {string} mice', 'three \'"blind"\' mice'), [
|
||||
'"blind"',
|
||||
])
|
||||
})
|
||||
|
||||
it('matches double quoted string with single quotes', () => {
|
||||
assert.deepEqual(match('three {string} mice', 'three "\'blind\'" mice'), [
|
||||
"'blind'",
|
||||
])
|
||||
})
|
||||
|
||||
it('matches double quoted string with escaped double quote', () => {
|
||||
assert.deepEqual(match('three {string} mice', 'three "bl\\"nd" mice'), [
|
||||
'bl"nd',
|
||||
])
|
||||
})
|
||||
|
||||
it('matches single quoted string with escaped single quote', () => {
|
||||
assert.deepEqual(match('three {string} mice', "three 'bl\\'nd' mice"), [
|
||||
"bl'nd",
|
||||
])
|
||||
})
|
||||
|
||||
it('matches single quoted string with escaped single quote', () => {
|
||||
assert.deepEqual(match('three {string} mice', "three 'bl\\'nd' mice"), [
|
||||
"bl'nd",
|
||||
])
|
||||
})
|
||||
|
||||
it('matches escaped parenthesis', () => {
|
||||
assert.deepEqual(
|
||||
match(
|
||||
'three \\(exceptionally) {string} mice',
|
||||
'three (exceptionally) "blind" mice'
|
||||
),
|
||||
['blind']
|
||||
)
|
||||
})
|
||||
|
||||
it('matches escaped slash', () => {
|
||||
assert.deepEqual(match('12\\/2020', '12/2020'), [])
|
||||
})
|
||||
|
||||
it('matches int', () => {
|
||||
assert.deepEqual(match('{int}', '22'), [22])
|
||||
})
|
||||
|
||||
it("doesn't match float as int", () => {
|
||||
assert.deepEqual(match('{int}', '1.22'), null)
|
||||
})
|
||||
|
||||
it('matches float', () => {
|
||||
assert.deepEqual(match('{float}', '0.22'), [0.22])
|
||||
assert.deepEqual(match('{float}', '.22'), [0.22])
|
||||
})
|
||||
|
||||
it('matches anonymous', () => {
|
||||
assert.deepEqual(match('{}', '0.22'), ['0.22'])
|
||||
})
|
||||
|
||||
it('throws unknown parameter type', () => {
|
||||
try {
|
||||
match('{unknown}', 'something')
|
||||
assert.fail()
|
||||
} catch (expected) {
|
||||
assert.equal(expected.message, 'Undefined parameter type {unknown}')
|
||||
}
|
||||
})
|
||||
|
||||
it('does not allow optional parameter types', () => {
|
||||
try {
|
||||
match('({int})', '3')
|
||||
assert.fail()
|
||||
} catch (expected) {
|
||||
assert.equal(
|
||||
expected.message,
|
||||
'Parameter types cannot be optional: ({int})'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('allows escaped optional parameter types', () => {
|
||||
assert.deepEqual(match('\\({int})', '(3)'), [3])
|
||||
})
|
||||
|
||||
it('does not allow text/parameter type alternation', () => {
|
||||
try {
|
||||
match('x/{int}', '3')
|
||||
assert.fail()
|
||||
} catch (expected) {
|
||||
assert.equal(
|
||||
expected.message,
|
||||
'Parameter types cannot be alternative: x/{int}'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('does not allow parameter type/text alternation', () => {
|
||||
try {
|
||||
match('{int}/x', '3')
|
||||
assert.fail()
|
||||
} catch (expected) {
|
||||
assert.equal(
|
||||
expected.message,
|
||||
'Parameter types cannot be alternative: {int}/x'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
for (const c of '[]()$.|?*+'.split('')) {
|
||||
it(`does not allow parameter type with ${c}`, () => {
|
||||
try {
|
||||
match(`{${c}string}`, 'something')
|
||||
assert.fail()
|
||||
} catch (expected) {
|
||||
assert.equal(
|
||||
expected.message,
|
||||
`Illegal character '${c}' in parameter name {${c}string}`
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
it('exposes source', () => {
|
||||
const expr = 'I have {int} cuke(s)'
|
||||
assert.equal(
|
||||
new CucumberExpression(expr, new ParameterTypeRegistry()).source,
|
||||
expr
|
||||
)
|
||||
})
|
||||
|
||||
// JavaScript-specific
|
||||
|
||||
it('delegates transform to custom object', () => {
|
||||
const parameterTypeRegistry = new ParameterTypeRegistry()
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'widget',
|
||||
/\w+/,
|
||||
null,
|
||||
function(s) {
|
||||
return this.createWidget(s)
|
||||
},
|
||||
false,
|
||||
true
|
||||
)
|
||||
)
|
||||
const expression = new CucumberExpression(
|
||||
'I have a {widget}',
|
||||
parameterTypeRegistry
|
||||
)
|
||||
|
||||
const world = {
|
||||
createWidget(s) {
|
||||
return `widget:${s}`
|
||||
},
|
||||
}
|
||||
|
||||
const args = expression.match(`I have a bolt`)
|
||||
assert.equal(args[0].getValue(world), 'widget:bolt')
|
||||
})
|
||||
|
||||
describe('escapes special characters', () => {
|
||||
;['\\', '[', ']', '^', '$', '.', '|', '?', '*', '+'].forEach(character => {
|
||||
it(`escapes ${character}`, () => {
|
||||
const expr = `I have {int} cuke(s) and ${character}`
|
||||
const expression = new CucumberExpression(
|
||||
expr,
|
||||
new ParameterTypeRegistry()
|
||||
)
|
||||
const arg1 = expression.match(`I have 800 cukes and ${character}`)[0]
|
||||
assert.equal(arg1.getValue(null), 800)
|
||||
})
|
||||
})
|
||||
|
||||
it(`escapes .`, () => {
|
||||
const expr = `I have {int} cuke(s) and .`
|
||||
const expression = new CucumberExpression(
|
||||
expr,
|
||||
new ParameterTypeRegistry()
|
||||
)
|
||||
assert.equal(expression.match(`I have 800 cukes and 3`), null)
|
||||
const arg1 = expression.match(`I have 800 cukes and .`)[0]
|
||||
assert.equal(arg1.getValue(null), 800)
|
||||
})
|
||||
|
||||
it(`escapes |`, () => {
|
||||
const expr = `I have {int} cuke(s) and a|b`
|
||||
const expression = new CucumberExpression(
|
||||
expr,
|
||||
new ParameterTypeRegistry()
|
||||
)
|
||||
assert.equal(expression.match(`I have 800 cukes and a`), null)
|
||||
assert.equal(expression.match(`I have 800 cukes and b`), null)
|
||||
const arg1 = expression.match(`I have 800 cukes and a|b`)[0]
|
||||
assert.equal(arg1.getValue(null), 800)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const match = (expression, text) => {
|
||||
const cucumberExpression = new CucumberExpression(
|
||||
expression,
|
||||
new ParameterTypeRegistry()
|
||||
)
|
||||
const args = cucumberExpression.match(text)
|
||||
if (!args) return null
|
||||
return args.map(arg => arg.getValue(null))
|
||||
}
|
258
node_modules/cucumber-expressions/test/custom_parameter_type_test.js
generated
vendored
Normal file
258
node_modules/cucumber-expressions/test/custom_parameter_type_test.js
generated
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const assert = require('assert')
|
||||
const assertThrows = require('./assert_throws')
|
||||
const CucumberExpression = require('../src/cucumber_expression')
|
||||
const RegularExpression = require('../src/regular_expression')
|
||||
const ParameterTypeRegistry = require('../src/parameter_type_registry')
|
||||
const ParameterType = require('../src/parameter_type')
|
||||
require('@babel/polyfill')
|
||||
|
||||
class Color {
|
||||
/// [color-constructor]
|
||||
constructor(name) {
|
||||
this.name = name
|
||||
}
|
||||
/// [color-constructor]
|
||||
}
|
||||
|
||||
class CssColor {
|
||||
constructor(name) {
|
||||
this.name = name
|
||||
}
|
||||
}
|
||||
|
||||
describe('Custom parameter type', () => {
|
||||
let parameterTypeRegistry
|
||||
|
||||
beforeEach(() => {
|
||||
parameterTypeRegistry = new ParameterTypeRegistry()
|
||||
/* eslint-disable prettier/prettier */
|
||||
/// [add-color-parameter-type]
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'color', // name
|
||||
/red|blue|yellow/, // regexp
|
||||
Color, // type
|
||||
s => new Color(s), // transformer
|
||||
false, // useForSnippets
|
||||
true // preferForRegexpMatch
|
||||
)
|
||||
)
|
||||
/// [add-color-parameter-type]
|
||||
/* eslint-enable prettier/prettier */
|
||||
})
|
||||
|
||||
describe('CucumberExpression', () => {
|
||||
it('throws exception for illegal character in parameter name', () => {
|
||||
assertThrows(
|
||||
() => new ParameterType('[string]', /.*/, String, s => s, false, true),
|
||||
"Illegal character '[' in parameter name {[string]}"
|
||||
)
|
||||
})
|
||||
|
||||
it('matches parameters with custom parameter type', () => {
|
||||
const expression = new CucumberExpression(
|
||||
'I have a {color} ball',
|
||||
parameterTypeRegistry
|
||||
)
|
||||
const value = expression.match('I have a red ball')[0].getValue(null)
|
||||
assert.equal(value.name, 'red')
|
||||
})
|
||||
|
||||
it('matches parameters with multiple capture groups', () => {
|
||||
class Coordinate {
|
||||
constructor(x, y, z) {
|
||||
this.x = x
|
||||
this.y = y
|
||||
this.z = z
|
||||
}
|
||||
}
|
||||
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'coordinate',
|
||||
/(\d+),\s*(\d+),\s*(\d+)/,
|
||||
Coordinate,
|
||||
(x, y, z) => new Coordinate(parseInt(x), parseInt(y), parseInt(z)),
|
||||
true,
|
||||
true
|
||||
)
|
||||
)
|
||||
const expression = new CucumberExpression(
|
||||
'A {int} thick line from {coordinate} to {coordinate}',
|
||||
parameterTypeRegistry
|
||||
)
|
||||
const args = expression.match('A 5 thick line from 10,20,30 to 40,50,60')
|
||||
|
||||
const thick = args[0].getValue(null)
|
||||
assert.equal(thick, 5)
|
||||
|
||||
const from = args[1].getValue(null)
|
||||
assert.equal(from.x, 10)
|
||||
assert.equal(from.y, 20)
|
||||
assert.equal(from.z, 30)
|
||||
|
||||
const to = args[2].getValue(null)
|
||||
assert.equal(to.x, 40)
|
||||
assert.equal(to.y, 50)
|
||||
assert.equal(to.z, 60)
|
||||
})
|
||||
|
||||
it('matches parameters with custom parameter type using optional capture group', () => {
|
||||
parameterTypeRegistry = new ParameterTypeRegistry()
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'color',
|
||||
[/red|blue|yellow/, /(?:dark|light) (?:red|blue|yellow)/],
|
||||
Color,
|
||||
s => new Color(s),
|
||||
false,
|
||||
true
|
||||
)
|
||||
)
|
||||
const expression = new CucumberExpression(
|
||||
'I have a {color} ball',
|
||||
parameterTypeRegistry
|
||||
)
|
||||
const value = expression.match('I have a dark red ball')[0].getValue(null)
|
||||
assert.equal(value.name, 'dark red')
|
||||
})
|
||||
|
||||
it('defers transformation until queried from argument', () => {
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'throwing',
|
||||
/bad/,
|
||||
null,
|
||||
s => {
|
||||
throw new Error(`Can't transform [${s}]`)
|
||||
},
|
||||
false,
|
||||
true
|
||||
)
|
||||
)
|
||||
|
||||
const expression = new CucumberExpression(
|
||||
'I have a {throwing} parameter',
|
||||
parameterTypeRegistry
|
||||
)
|
||||
const args = expression.match('I have a bad parameter')
|
||||
assertThrows(() => args[0].getValue(null), "Can't transform [bad]")
|
||||
})
|
||||
|
||||
describe('conflicting parameter type', () => {
|
||||
it('is detected for type name', () => {
|
||||
assertThrows(
|
||||
() =>
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'color',
|
||||
/.*/,
|
||||
CssColor,
|
||||
s => new CssColor(s),
|
||||
false,
|
||||
true
|
||||
)
|
||||
),
|
||||
'There is already a parameter type with name color'
|
||||
)
|
||||
})
|
||||
|
||||
it('is not detected for type', () => {
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'whatever',
|
||||
/.*/,
|
||||
Color,
|
||||
s => new Color(s),
|
||||
false,
|
||||
false
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
it('is not detected for regexp', () => {
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'css-color',
|
||||
/red|blue|yellow/,
|
||||
CssColor,
|
||||
s => new CssColor(s),
|
||||
true,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
new CucumberExpression(
|
||||
'I have a {css-color} ball',
|
||||
parameterTypeRegistry
|
||||
)
|
||||
.match('I have a blue ball')[0]
|
||||
.getValue(null).constructor,
|
||||
CssColor
|
||||
)
|
||||
assert.equal(
|
||||
new CucumberExpression(
|
||||
'I have a {css-color} ball',
|
||||
parameterTypeRegistry
|
||||
)
|
||||
.match('I have a blue ball')[0]
|
||||
.getValue(null).name,
|
||||
'blue'
|
||||
)
|
||||
assert.equal(
|
||||
new CucumberExpression('I have a {color} ball', parameterTypeRegistry)
|
||||
.match('I have a blue ball')[0]
|
||||
.getValue(null).constructor,
|
||||
Color
|
||||
)
|
||||
assert.equal(
|
||||
new CucumberExpression('I have a {color} ball', parameterTypeRegistry)
|
||||
.match('I have a blue ball')[0]
|
||||
.getValue(null).name,
|
||||
'blue'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// JavaScript-specific
|
||||
it('creates arguments using async transform', async () => {
|
||||
parameterTypeRegistry = new ParameterTypeRegistry()
|
||||
/// [add-async-parameter-type]
|
||||
parameterTypeRegistry.defineParameterType(
|
||||
new ParameterType(
|
||||
'asyncColor',
|
||||
/red|blue|yellow/,
|
||||
Color,
|
||||
async s => new Color(s),
|
||||
false,
|
||||
true
|
||||
)
|
||||
)
|
||||
/// [add-async-parameter-type]
|
||||
|
||||
const expression = new CucumberExpression(
|
||||
'I have a {asyncColor} ball',
|
||||
parameterTypeRegistry
|
||||
)
|
||||
const args = await expression.match('I have a red ball')
|
||||
const value = await args[0].getValue(null)
|
||||
assert.equal(value.name, 'red')
|
||||
})
|
||||
})
|
||||
|
||||
describe('RegularExpression', () => {
|
||||
it('matches arguments with custom parameter type', () => {
|
||||
const expression = new RegularExpression(
|
||||
/I have a (red|blue|yellow) ball/,
|
||||
parameterTypeRegistry
|
||||
)
|
||||
const value = expression.match('I have a red ball')[0].getValue(null)
|
||||
assert.equal(value.constructor, Color)
|
||||
assert.equal(value.name, 'red')
|
||||
})
|
||||
})
|
||||
})
|
30
node_modules/cucumber-expressions/test/expression_examples_test.js
generated
vendored
Normal file
30
node_modules/cucumber-expressions/test/expression_examples_test.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/* eslint-env mocha */
|
||||
const fs = require('fs')
|
||||
const assert = require('assert')
|
||||
const CucumberExpression = require('../src/cucumber_expression')
|
||||
const RegularExpression = require('../src/regular_expression')
|
||||
const ParameterTypeRegistry = require('../src/parameter_type_registry')
|
||||
|
||||
describe('examples.txt', () => {
|
||||
const match = (expression_text, text) => {
|
||||
const m = /\/(.*)\//.exec(expression_text)
|
||||
const expression = m
|
||||
? new RegularExpression(new RegExp(m[1]), new ParameterTypeRegistry())
|
||||
: new CucumberExpression(expression_text, new ParameterTypeRegistry())
|
||||
const args = expression.match(text)
|
||||
if (!args) return null
|
||||
return args.map(arg => arg.getValue(null))
|
||||
}
|
||||
|
||||
const examples = fs.readFileSync('examples.txt', 'utf-8')
|
||||
const chunks = examples.split(/^---/m)
|
||||
for (const chunk of chunks) {
|
||||
const [expressionText, text, expectedArgs] = chunk.trim().split(/\n/m)
|
||||
it(`Works with: ${expressionText}`, () => {
|
||||
assert.deepEqual(
|
||||
JSON.stringify(match(expressionText, text)),
|
||||
expectedArgs
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
1
node_modules/cucumber-expressions/test/mocha.opts
generated
vendored
Normal file
1
node_modules/cucumber-expressions/test/mocha.opts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
--recursive
|
99
node_modules/cucumber-expressions/test/parameter_type_registry_test.js
generated
vendored
Normal file
99
node_modules/cucumber-expressions/test/parameter_type_registry_test.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
const assert = require('assert')
|
||||
const ParameterTypeRegistry = require('../src/parameter_type_registry')
|
||||
const ParameterType = require('../src/parameter_type')
|
||||
|
||||
class Name {}
|
||||
class Person {}
|
||||
class Place {}
|
||||
|
||||
const CAPITALISED_WORD = /[A-Z]+\w+/
|
||||
|
||||
describe('ParameterTypeRegistry', () => {
|
||||
let registry
|
||||
beforeEach(() => {
|
||||
registry = new ParameterTypeRegistry()
|
||||
})
|
||||
|
||||
it('does not allow more than one preferential parameter type for each regexp', () => {
|
||||
registry.defineParameterType(
|
||||
new ParameterType(
|
||||
'name',
|
||||
CAPITALISED_WORD,
|
||||
Name,
|
||||
s => new Name(s),
|
||||
true,
|
||||
true
|
||||
)
|
||||
)
|
||||
registry.defineParameterType(
|
||||
new ParameterType(
|
||||
'person',
|
||||
CAPITALISED_WORD,
|
||||
Person,
|
||||
s => new Person(s),
|
||||
true,
|
||||
false
|
||||
)
|
||||
)
|
||||
try {
|
||||
registry.defineParameterType(
|
||||
new ParameterType(
|
||||
'place',
|
||||
CAPITALISED_WORD,
|
||||
Place,
|
||||
s => new Place(s),
|
||||
true,
|
||||
true
|
||||
)
|
||||
)
|
||||
throw new Error('Should have failed')
|
||||
} catch (err) {
|
||||
assert.equal(
|
||||
err.message,
|
||||
`There can only be one preferential parameter type per regexp. The regexp ${CAPITALISED_WORD} is used for two preferential parameter types, {name} and {place}`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('looks up preferential parameter type by regexp', () => {
|
||||
const name = new ParameterType(
|
||||
'name',
|
||||
/[A-Z]+\w+/,
|
||||
null,
|
||||
s => new Name(s),
|
||||
true,
|
||||
false
|
||||
)
|
||||
const person = new ParameterType(
|
||||
'person',
|
||||
/[A-Z]+\w+/,
|
||||
null,
|
||||
s => new Person(s),
|
||||
true,
|
||||
true
|
||||
)
|
||||
const place = new ParameterType(
|
||||
'place',
|
||||
/[A-Z]+\w+/,
|
||||
null,
|
||||
s => new Place(s),
|
||||
true,
|
||||
false
|
||||
)
|
||||
|
||||
registry.defineParameterType(name)
|
||||
registry.defineParameterType(person)
|
||||
registry.defineParameterType(place)
|
||||
|
||||
assert.equal(
|
||||
registry.lookupByRegexp(
|
||||
'[A-Z]+\\w+',
|
||||
/([A-Z]+\w+) and ([A-Z]+\w+)/,
|
||||
'Lisa and Bob'
|
||||
),
|
||||
person
|
||||
)
|
||||
})
|
||||
})
|
20
node_modules/cucumber-expressions/test/parameter_type_test.js
generated
vendored
Normal file
20
node_modules/cucumber-expressions/test/parameter_type_test.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/* eslint-env mocha */
|
||||
const assertThrows = require('./assert_throws')
|
||||
const ParameterType = require('../src/parameter_type')
|
||||
|
||||
describe('ParameterType', () => {
|
||||
it('does not allow ignore flag on regexp', () => {
|
||||
assertThrows(
|
||||
() =>
|
||||
new ParameterType(
|
||||
'case-insensitive',
|
||||
/[a-z]+/i,
|
||||
String,
|
||||
s => s,
|
||||
true,
|
||||
true
|
||||
),
|
||||
"ParameterType Regexps can't use flag 'i'"
|
||||
)
|
||||
})
|
||||
})
|
106
node_modules/cucumber-expressions/test/regular_expression_test.js
generated
vendored
Normal file
106
node_modules/cucumber-expressions/test/regular_expression_test.js
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/* eslint-env mocha */
|
||||
const assert = require('assert')
|
||||
const RegularExpression = require('../src/regular_expression')
|
||||
const ParameterTypeRegistry = require('../src/parameter_type_registry')
|
||||
|
||||
describe('RegularExpression', () => {
|
||||
it('documents match arguments', () => {
|
||||
const parameterRegistry = new ParameterTypeRegistry()
|
||||
|
||||
/// [capture-match-arguments]
|
||||
const expr = /I have (\d+) cukes? in my (\w+) now/
|
||||
const expression = new RegularExpression(expr, parameterRegistry)
|
||||
const args = expression.match('I have 7 cukes in my belly now')
|
||||
assert.equal(7, args[0].getValue(null))
|
||||
assert.equal('belly', args[1].getValue(null))
|
||||
/// [capture-match-arguments]
|
||||
})
|
||||
|
||||
it('does no transform by default', () => {
|
||||
assert.deepEqual(match(/(\d\d)/, '22')[0], '22')
|
||||
})
|
||||
|
||||
it('does not transform anonymous', () => {
|
||||
assert.deepEqual(match(/(.*)/, '22')[0], '22')
|
||||
})
|
||||
|
||||
it('transforms negative int', () => {
|
||||
assert.deepEqual(match(/(-?\d+)/, '-22')[0], -22)
|
||||
})
|
||||
|
||||
it('transforms positive int', () => {
|
||||
assert.deepEqual(match(/(\d+)/, '22')[0], 22)
|
||||
})
|
||||
|
||||
it('transforms float without integer part', () => {
|
||||
assert.deepEqual(match(/(-?\d*\.?\d+)/, '.22')[0], 0.22)
|
||||
})
|
||||
|
||||
it('transforms float with sign', () => {
|
||||
assert.deepEqual(match(/(-?\d*\.?\d+)/, '-1.22')[0], -1.22)
|
||||
})
|
||||
|
||||
it('returns null when there is no match', () => {
|
||||
assert.equal(match(/hello/, 'world'), null)
|
||||
})
|
||||
|
||||
it('matches nested capture group without match', () => {
|
||||
assert.deepEqual(match(/^a user( named "([^"]*)")?$/, 'a user'), [null])
|
||||
})
|
||||
|
||||
it('matches nested capture group with match', () => {
|
||||
assert.deepEqual(
|
||||
match(/^a user( named "([^"]*)")?$/, 'a user named "Charlie"'),
|
||||
['Charlie']
|
||||
)
|
||||
})
|
||||
|
||||
it('matches capture group nested in optional one', () => {
|
||||
const regexp = /^a (pre-commercial transaction |pre buyer fee model )?purchase(?: for \$(\d+))?$/
|
||||
assert.deepEqual(match(regexp, 'a purchase'), [null, null])
|
||||
assert.deepEqual(match(regexp, 'a purchase for $33'), [null, 33])
|
||||
assert.deepEqual(match(regexp, 'a pre buyer fee model purchase'), [
|
||||
'pre buyer fee model ',
|
||||
null,
|
||||
])
|
||||
})
|
||||
|
||||
it('ignores non capturing groups', () => {
|
||||
assert.deepEqual(
|
||||
match(
|
||||
/(\S+) ?(can|cannot)? (?:delete|cancel) the (\d+)(?:st|nd|rd|th) (attachment|slide) ?(?:upload)?/,
|
||||
'I can cancel the 1st slide upload'
|
||||
),
|
||||
['I', 'can', 1, 'slide']
|
||||
)
|
||||
})
|
||||
|
||||
it('works with escaped parenthesis', () => {
|
||||
assert.deepEqual(match(/Across the line\(s\)/, 'Across the line(s)'), [])
|
||||
})
|
||||
|
||||
it('exposes regexp and source', () => {
|
||||
const regexp = /I have (\d+) cukes? in my (.+) now/
|
||||
let expression = new RegularExpression(regexp, new ParameterTypeRegistry())
|
||||
assert.deepEqual(expression.regexp, regexp)
|
||||
assert.deepEqual(expression.source, regexp.source)
|
||||
})
|
||||
|
||||
it('does not take consider parenthesis in character class as group', function() {
|
||||
const expression = new RegularExpression(
|
||||
/^drawings: ([A-Z_, ()]+)$/,
|
||||
new ParameterTypeRegistry()
|
||||
)
|
||||
const args = expression.match('drawings: ONE, TWO(ABC)')
|
||||
|
||||
assert.equal(args[0].getValue(), 'ONE, TWO(ABC)')
|
||||
})
|
||||
})
|
||||
|
||||
const match = (regexp, text) => {
|
||||
const parameterRegistry = new ParameterTypeRegistry()
|
||||
const regularExpression = new RegularExpression(regexp, parameterRegistry)
|
||||
const args = regularExpression.match(text)
|
||||
if (!args) return null
|
||||
return args.map(arg => arg.getValue(null))
|
||||
}
|
100
node_modules/cucumber-expressions/test/tree_regexp_test.js
generated
vendored
Normal file
100
node_modules/cucumber-expressions/test/tree_regexp_test.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/* eslint-env mocha */
|
||||
const assert = require('assert')
|
||||
const TreeRegexp = require('../src/tree_regexp')
|
||||
|
||||
describe('TreeRegexp', () => {
|
||||
it('exposes group source', () => {
|
||||
const tr = new TreeRegexp(/(a(?:b)?)(c)/)
|
||||
assert.deepEqual(tr.groupBuilder.children.map(gb => gb.source), [
|
||||
'a(?:b)?',
|
||||
'c',
|
||||
])
|
||||
})
|
||||
|
||||
it('builds tree', () => {
|
||||
const tr = new TreeRegexp(/(a(?:b)?)(c)/)
|
||||
const group = tr.match('ac')
|
||||
assert.equal(group.value, 'ac')
|
||||
assert.equal(group.children[0].value, 'a')
|
||||
assert.deepEqual(group.children[0].children, [])
|
||||
assert.equal(group.children[1].value, 'c')
|
||||
})
|
||||
|
||||
it('ignores non-capturing groups', () => {
|
||||
const tr = new TreeRegexp(/(a(?:b)?)(c)/)
|
||||
const group = tr.match('ac')
|
||||
assert.equal(group.value, 'ac')
|
||||
assert.equal(group.children[0].value, 'a')
|
||||
assert.deepEqual(group.children[0].children, [])
|
||||
assert.equal(group.children[1].value, 'c')
|
||||
})
|
||||
|
||||
it('matches optional group', () => {
|
||||
const tr = new TreeRegexp(/^Something( with an optional argument)?/)
|
||||
const group = tr.match('Something')
|
||||
assert.equal(group.children[0].value, null)
|
||||
})
|
||||
|
||||
it('matches nested groups', () => {
|
||||
const tr = new TreeRegexp(
|
||||
/^A (\d+) thick line from ((\d+),\s*(\d+),\s*(\d+)) to ((\d+),\s*(\d+),\s*(\d+))/
|
||||
)
|
||||
const group = tr.match('A 5 thick line from 10,20,30 to 40,50,60')
|
||||
|
||||
assert.equal(group.children[0].value, '5')
|
||||
assert.equal(group.children[1].value, '10,20,30')
|
||||
assert.equal(group.children[1].children[0].value, '10')
|
||||
assert.equal(group.children[1].children[1].value, '20')
|
||||
assert.equal(group.children[1].children[2].value, '30')
|
||||
assert.equal(group.children[2].value, '40,50,60')
|
||||
assert.equal(group.children[2].children[0].value, '40')
|
||||
assert.equal(group.children[2].children[1].value, '50')
|
||||
assert.equal(group.children[2].children[2].value, '60')
|
||||
})
|
||||
|
||||
it('detects multiple non capturing groups', () => {
|
||||
const tr = new TreeRegexp(/(?:a)(:b)(\?c)(d)/)
|
||||
const group = tr.match('a:b?cd')
|
||||
assert.equal(group.children.length, 3)
|
||||
})
|
||||
|
||||
it('works with escaped backslash', () => {
|
||||
const tr = new TreeRegexp(/foo\\(bar|baz)/)
|
||||
const group = tr.match('foo\\bar')
|
||||
assert.equal(group.children.length, 1)
|
||||
})
|
||||
|
||||
it('works with escaped slash', () => {
|
||||
const tr = new TreeRegexp(/^I go to '\/(.+)'$/)
|
||||
const group = tr.match("I go to '/hello'")
|
||||
assert.equal(group.children.length, 1)
|
||||
})
|
||||
|
||||
it('works with digit and word', () => {
|
||||
const tr = new TreeRegexp(/^(\d) (\w+)$/)
|
||||
const group = tr.match('2 you')
|
||||
assert.equal(group.children.length, 2)
|
||||
})
|
||||
|
||||
it('captures non capturing groups with capturing groups inside', () => {
|
||||
const tr = new TreeRegexp('the stdout(?: from "(.*?)")?')
|
||||
const group = tr.match('the stdout')
|
||||
assert.equal(group.value, 'the stdout')
|
||||
assert.equal(group.children[0].value, null)
|
||||
assert.equal(group.children.length, 1)
|
||||
})
|
||||
|
||||
it('works with flags', () => {
|
||||
const tr = new TreeRegexp(/HELLO/i)
|
||||
const group = tr.match('hello')
|
||||
assert.equal(group.value, 'hello')
|
||||
})
|
||||
|
||||
it('does not consider parenthesis in character class as group', () => {
|
||||
const tr = new TreeRegexp(/^drawings: ([A-Z, ()]+)$/)
|
||||
const group = tr.match('drawings: ONE(TWO)')
|
||||
assert.equal(group.value, 'drawings: ONE(TWO)')
|
||||
assert.equal(group.children.length, 1)
|
||||
assert.equal(group.children[0].value, 'ONE(TWO)')
|
||||
})
|
||||
})
|
3634
node_modules/cucumber-expressions/yarn.lock
generated
vendored
Normal file
3634
node_modules/cucumber-expressions/yarn.lock
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user