feat(complex-matcher): regexp support (#3199)

This commit is contained in:
Julien Fontanet 2018-07-19 12:01:57 +02:00 committed by GitHub
parent c3066921ab
commit 829beb84e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 1 deletions

View File

@ -12,6 +12,7 @@
### Released packages ### Released packages
- complex-matcher v0.4.0
- xo-server-backup-reports v0.12.3 - xo-server-backup-reports v0.12.3
- xo-server v5.23.0 - xo-server v5.23.0
- xo-web v5.23.0 - xo-web v5.23.0

View File

@ -1,7 +1,7 @@
import * as CM from './' import * as CM from './'
export const pattern = export const pattern =
'foo !"\\\\ \\"" name:|(wonderwoman batman) hasCape? age:32 chi*go' 'foo !"\\\\ \\"" name:|(wonderwoman batman) hasCape? age:32 chi*go /^foo\\/bar\\./i'
export const ast = new CM.And([ export const ast = new CM.And([
new CM.String('foo'), new CM.String('foo'),
@ -13,4 +13,5 @@ export const ast = new CM.And([
new CM.TruthyProperty('hasCape'), new CM.TruthyProperty('hasCape'),
new CM.Property('age', new CM.Number(32)), new CM.Property('age', new CM.Number(32)),
new CM.GlobPattern('chi*go'), new CM.GlobPattern('chi*go'),
new CM.RegExp('^foo/bar\\.', 'i'),
]) ])

View File

@ -220,6 +220,37 @@ export class GlobPattern extends Node {
return this.value return this.value
} }
} }
export class RegExpNode extends Node {
constructor (pattern, flags) {
super()
this.re = new RegExp(pattern, flags)
// should not be enumerable for the tests
Object.defineProperty(this, 'match', {
value: this.match.bind(this),
})
}
match (value) {
if (typeof value === 'string') {
return this.re.test(value)
}
if (Array.isArray(value) || isPlainObject(value)) {
return some(value, this.match)
}
return false
}
toString () {
return this.re.toString()
}
}
export { RegExpNode as RegExp }
export class StringNode extends Node { export class StringNode extends Node {
constructor (value) { constructor (value) {
super() super()
@ -471,6 +502,33 @@ const parser = P.grammar({
? new Failure(pos, 'a raw string') ? new Failure(pos, 'a raw string')
: new Success(pos, value) : new Success(pos, value)
}), }),
regex: new P((input, pos, end) => {
if (input[pos] !== '/') {
return new Failure(pos, '/')
}
++pos
let c
let pattern = ''
let escaped = false
while (pos < end && ((c = input[pos++]) !== '/' || escaped)) {
escaped = c === '\\'
pattern += c
}
if (c !== '/') {
return new Failure(pos, '/')
}
let flags = ''
if (pos < end && (c = input[pos]) === 'i') {
++pos
flags += c
}
return new Success(pos, new RegExpNode(pattern, flags))
}),
term: r => term: r =>
P.alt( P.alt(
P.seq(P.text('('), r.ws, r.term.repeat(1), P.text(')')).map( P.seq(P.text('('), r.ws, r.term.repeat(1), P.text(')')).map(
@ -501,6 +559,7 @@ const parser = P.grammar({
value: r => value: r =>
P.alt( P.alt(
r.quotedString.map(_ => new StringNode(_)), r.quotedString.map(_ => new StringNode(_)),
r.regex,
r.globPattern.map(str => { r.globPattern.map(str => {
const asNum = +str const asNum = +str
return Number.isNaN(asNum) return Number.isNaN(asNum)