init
This commit is contained in:
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
|
Reference in New Issue
Block a user