cucumber-expressions
Version:
Cucumber Expressions - a simpler alternative to Regular Expressions
65 lines (61 loc) • 2.08 kB
text/typescript
import GroupBuilder from './GroupBuilder'
// @ts-ignore
import Regex from 'becke-ch--regex--s0-0-v1--base--pl--lib'
import RegexExecArray from './RegexExecArray'
export default class TreeRegexp {
public regexp: RegExp
private regex: any
public groupBuilder: GroupBuilder
constructor(regexp: RegExp | string) {
this.regexp = 'string' === typeof regexp ? new RegExp(regexp) : regexp
this.regex = new Regex(this.regexp.source, this.regexp.flags)
const stack: GroupBuilder[] = [new GroupBuilder()]
const groupStartStack: number[] = []
let last: string = null
let escaping = false
let nonCapturingMaybe = false
let charClass = false
this.regexp.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.regexp.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 === ':' || c === '!' || c === '=' || c === '<') &&
last === '?' &&
nonCapturingMaybe
) {
stack[stack.length - 1].setNonCapturing()
nonCapturingMaybe = false
}
escaping = c === '\\' && !escaping
last = c
})
this.groupBuilder = stack.pop()
}
public match(s: string) {
const match: RegexExecArray = this.regex.exec(s)
if (!match) {
return null
}
let groupIndex = 0
const nextGroupIndex = () => groupIndex++
return this.groupBuilder.build(match, nextGroupIndex)
}
}