This commit is contained in:
Simon Priet
2021-09-05 22:53:58 +02:00
commit 9e2991e668
17888 changed files with 1263126 additions and 0 deletions

45
node_modules/cucumber-expressions/src/argument.js generated vendored Normal file
View 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

View 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

View 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

View 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
View 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,
}

View 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
View 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
View 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
View 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
View 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

View 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

View 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

View 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
View 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